o
    ohiQ                     @   s   d dl mZmZmZmZ d dlmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZmZ d dlmZmZ d d	lmZ d d
lmZ G dd deZG dd deZdddZdd Zdd Zdd Zdd ZdS )    )BasicDictsympifyTuple)Integerdefault_sort_key)_sympifybell)zeros)	FiniteSetUnion)flattengroup)as_int)defaultdictc                   @   sz   e Zd ZdZdZdZdd ZdddZedd Z	d	d
 Z
dd Zdd Zdd Zedd Zedd Zedd ZdS )	Partitionz
    This class represents an abstract partition.

    A partition is a set of disjoint sets whose union equals a given set.

    See Also
    ========

    sympy.utilities.iterables.partitions,
    sympy.utilities.iterables.multiset_partitions
    Nc                 G   s   g }d}|D ] }t |trt|}t|t|k rd} n
|}|t| qtdd |D s4tdt| }|sGt|t	dd |D k rKtdt
j| g|R  }t||_t||_|S )aW  
        Generates a new partition object.

        This method also verifies if the arguments passed are
        valid and raises a ValueError if they are not.

        Examples
        ========

        Creating Partition from Python lists:

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3])
        >>> a
        Partition({3}, {1, 2})
        >>> a.partition
        [[1, 2], [3]]
        >>> len(a)
        2
        >>> a.members
        (1, 2, 3)

        Creating Partition from Python sets:

        >>> Partition({1, 2, 3}, {4, 5})
        Partition({4, 5}, {1, 2, 3})

        Creating Partition from SymPy finite sets:

        >>> from sympy import FiniteSet
        >>> a = FiniteSet(1, 2, 3)
        >>> b = FiniteSet(4, 5)
        >>> Partition(a, b)
        Partition({4, 5}, {1, 2, 3})
        FTc                 s   s    | ]}t |tV  qd S N)
isinstancer   ).0part r   r/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/combinatorics/partitions.py	<genexpr>N   s    z$Partition.__new__.<locals>.<genexpr>z@Each argument to Partition should be a list, set, or a FiniteSetc                 s   s    | ]}t |V  qd S r   )len)r   argr   r   r   r   U       z'Partition contained duplicate elements.)r   listsetr   appendr	   all
ValueErrorr   sumr   __new__tuplememberssize)cls	partitionargsdupsr   as_setUobjr   r   r   r$      s*   $


zPartition.__new__c                    sB    du r| j }ntt| j  fddd}ttt| j|| jfS )a  Return a canonical key that can be used for sorting.

        Ordering is based on the size and sorted elements of the partition
        and ties are broken with the rank.

        Examples
        ========

        >>> from sympy import default_sort_key
        >>> from sympy.combinatorics import Partition
        >>> from sympy.abc import x
        >>> a = Partition([1, 2])
        >>> b = Partition([3, 4])
        >>> c = Partition([1, x])
        >>> d = Partition(list(range(4)))
        >>> l = [d, b, a + 1, a, c]
        >>> l.sort(key=default_sort_key); l
        [Partition({1, 2}), Partition({1}, {2}), Partition({1, x}), Partition({3, 4}), Partition({0, 1, 2, 3})]
        Nc                    s
   t |  S r   r   )worderr   r   <lambda>u   s   
 z$Partition.sort_key.<locals>.<lambda>key)r&   r%   sortedmapr   r'   rank)selfr1   r&   r   r0   r   sort_key]   s   
zPartition.sort_keyc                 C   s&   | j du rtdd | jD | _ | j S )zReturn partition as a sorted list of lists.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> Partition([1], [2, 3]).partition
        [[1], [2, 3]]
        Nc                 S   s   g | ]}t |td qS )r3   )r5   r   r   pr   r   r   
<listcomp>   s    z'Partition.partition.<locals>.<listcomp>)
_partitionr5   r*   r8   r   r   r   r)   x   s
   

zPartition.partitionc                 C   s6   t |}| j| }t|t| j | j}t|| jS )ai  
        Return permutation whose rank is ``other`` greater than current rank,
        (mod the maximum rank for the set).

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3])
        >>> a.rank
        1
        >>> (a + 1).rank
        2
        >>> (a + 100).rank
        1
        )r   r7   
RGS_unrankRGS_enumr'   r   from_rgsr&   )r8   otheroffsetresultr   r   r   __add__   s   
zPartition.__add__c                 C   s   |  | S )af  
        Return permutation whose rank is ``other`` less than current rank,
        (mod the maximum rank for the set).

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3])
        >>> a.rank
        1
        >>> (a - 1).rank
        0
        >>> (a - 100).rank
        1
        )rE   r8   rB   r   r   r   __sub__   s   zPartition.__sub__c                 C   s   |   t|  kS )a  
        Checks if a partition is less than or equal to
        the other based on rank.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3, 4, 5])
        >>> b = Partition([1], [2, 3], [4], [5])
        >>> a.rank, b.rank
        (9, 34)
        >>> a <= a
        True
        >>> a <= b
        True
        r9   r   rF   r   r   r   __le__   s   zPartition.__le__c                 C   s   |   t|  k S )aA  
        Checks if a partition is less than the other.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3, 4, 5])
        >>> b = Partition([1], [2, 3], [4], [5])
        >>> a.rank, b.rank
        (9, 34)
        >>> a < b
        True
        rH   rF   r   r   r   __lt__   s   zPartition.__lt__c                 C   s"   | j dur| j S t| j| _ | j S )z
        Gets the rank of a partition.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3], [4, 5])
        >>> a.rank
        13
        N)_rankRGS_rankRGSr>   r   r   r   r7      s   
zPartition.rankc                    sV   i  | j }t|D ]\}}|D ]}| |< qq	t fddtdd |D tdD S )a  
        Returns the "restricted growth string" of the partition.

        Explanation
        ===========

        The RGS is returned as a list of indices, L, where L[i] indicates
        the block in which element i appears. For example, in a partition
        of 3 elements (a, b, c) into 2 blocks ([c], [a, b]) the RGS is
        [1, 1, 0]: "a" is in block 1, "b" is in block 1 and "c" is in block 0.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> a = Partition([1, 2], [3], [4, 5])
        >>> a.members
        (1, 2, 3, 4, 5)
        >>> a.RGS
        (0, 0, 1, 2, 2)
        >>> a + 1
        Partition({3}, {4}, {5}, {1, 2})
        >>> _.RGS
        (0, 0, 1, 2, 3)
        c                    s   g | ]} | qS r   r   r   irgsr   r   r<   
      z!Partition.RGS.<locals>.<listcomp>c                 S   s   g | ]	}|D ]}|qqS r   r   )r   r;   rO   r   r   r   r<         r3   )r)   	enumerater%   r5   r   )r8   r)   rO   r   jr   rP   r   rM      s   
zPartition.RGSc                 C   s   t |t |krtdt|d }dd t|D }d}|D ]}|| ||  |d7 }qtdd |D s<tdt| S )	aB  
        Creates a set partition from a restricted growth string.

        Explanation
        ===========

        The indices given in rgs are assumed to be the index
        of the element as given in elements *as provided* (the
        elements are not sorted by this routine). Block numbering
        starts from 0. If any block was not referenced in ``rgs``
        an error will be raised.

        Examples
        ========

        >>> from sympy.combinatorics import Partition
        >>> Partition.from_rgs([0, 1, 2, 0, 1], list('abcde'))
        Partition({c}, {a, d}, {b, e})
        >>> Partition.from_rgs([0, 1, 2, 0, 1], list('cbead'))
        Partition({e}, {a, c}, {b, d})
        >>> a = Partition([1, 4], [2], [3, 5])
        >>> Partition.from_rgs(a.RGS, a.members)
        Partition({2}, {1, 4}, {3, 5})
        z#mismatch in rgs and element lengths   c                 S   s   g | ]}g qS r   r   rN   r   r   r   r<   *  s    z&Partition.from_rgs.<locals>.<listcomp>r   c                 s   s    | ]}|V  qd S r   r   r:   r   r   r   r   /  s    z%Partition.from_rgs.<locals>.<genexpr>z(some blocks of the partition were empty.)r   r"   maxranger    r!   r   )r8   rQ   elementsmax_elemr)   rU   rO   r   r   r   rA     s   
zPartition.from_rgsr   )__name__
__module____qualname____doc__rK   r=   r$   r9   propertyr)   rE   rG   rI   rJ   r7   rM   classmethodrA   r   r   r   r   r      s$    
>


"r   c                   @   sh   e Zd ZdZdZdZdddZdd Zdd Zd	d
 Z	e
dd Zdd Zdd ZdddZdd ZdS )IntegerPartitionaZ  
    This class represents an integer partition.

    Explanation
    ===========

    In number theory and combinatorics, a partition of a positive integer,
    ``n``, also called an integer partition, is a way of writing ``n`` as a
    list of positive integers that sum to n. Two partitions that differ only
    in the order of summands are considered to be the same partition; if order
    matters then the partitions are referred to as compositions. For example,
    4 has five partitions: [4], [3, 1], [2, 2], [2, 1, 1], and [1, 1, 1, 1];
    the compositions [1, 2, 1] and [1, 1, 2] are the same as partition
    [2, 1, 1].

    See Also
    ========

    sympy.utilities.iterables.partitions,
    sympy.utilities.iterables.multiset_partitions

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Partition_%28number_theory%29
    Nc                 C   s  |dur	||}}t |ttfr8g }t| ddD ]\}}|s!qt|t|}}||g|  qt|}ntttt|dd}d}|du rPt	|}d}nt|}|sbt	||krbt
d| tdd |D rot
dt| t|t| }t||_||_|S )	a  
        Generates a new IntegerPartition object from a list or dictionary.

        Explanation
        ===========

        The partition can be given as a list of positive integers or a
        dictionary of (integer, multiplicity) items. If the partition is
        preceded by an integer an error will be raised if the partition
        does not sum to that given integer.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> a = IntegerPartition([5, 4, 3, 1, 1])
        >>> a
        IntegerPartition(14, (5, 4, 3, 1, 1))
        >>> print(a)
        [5, 4, 3, 1, 1]
        >>> IntegerPartition({1:3, 2:1})
        IntegerPartition(5, (2, 1, 1, 1))

        If the value that the partition should sum to is given first, a check
        will be made to see n error will be raised if there is a discrepancy:

        >>> IntegerPartition(10, [5, 4, 3, 1])
        Traceback (most recent call last):
        ...
        ValueError: The partition is not valid

        NTreverseFzPartition did not add to %sc                 s   s    | ]}|d k V  qdS )rV   Nr   rN   r   r   r   r     r   z+IntegerPartition.__new__.<locals>.<genexpr>z-All integer summands must be greater than one)r   dictr   r5   itemsr   extendr%   r6   r#   r"   anyr   r$   r   r   r   r)   integer)r(   r)   rh   _kvsum_okr.   r   r   r   r$   S  s0   !


zIntegerPartition.__new__c                 C   s  t t}||   | j}|dgkrt| jdiS |d dkrB||d   d8  < |d dkr5d|d< nGd ||d d < |d< n:||d   d8  < |d |d  }|d }d|d< |r||d8 }|| dkrz||  || 7  < ||| | 8 }|s^t| j|S )a  Return the previous partition of the integer, n, in lexical order,
        wrapping around to [1, ..., 1] if the partition is [n].

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> p = IntegerPartition([4])
        >>> print(p.prev_lex())
        [3, 1]
        >>> p.partition > p.prev_lex().partition
        True
        rV      r   )r   intupdateas_dict_keysra   rh   )r8   dkeysleftnewr   r   r   prev_lex  s*   

zIntegerPartition.prev_lexc                 C   s  t t}||   | j}|d }|| jkr!|  | j|d< n|dkr[|| dkr>||d   d7  < ||  d8  < n|d }||d   d7  < || d | |d< d||< ne|| dkrt|dkr{|  d||d < | j| d |d< nE|d }||  d7  < || | | |d< d||< n*|d }|d }||  d7  < || | || |  | }d ||< ||< ||d< t| j|S )a  Return the next partition of the integer, n, in lexical order,
        wrapping around to [n] if the partition is [1, ..., 1].

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> p = IntegerPartition([3, 1])
        >>> print(p.next_lex())
        [4]
        >>> p.partition < p.next_lex().partition
        True
        rm   rV   rn   ro   r   )	r   rp   rq   rr   rs   rh   clearr   ra   )r8   rt   r4   aba1b1needr   r   r   next_lex  s>   


zIntegerPartition.next_lexc                 C   s8   | j du rt| jdd}dd |D | _t|| _ | j S )a[  Return the partition as a dictionary whose keys are the
        partition integers and the values are the multiplicity of that
        integer.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> IntegerPartition([1]*3 + [2] + [3]*4).as_dict()
        {1: 3, 2: 1, 3: 4}
        NF)multiplec                 S   s   g | ]}|d  qS )r   r   )r   gr   r   r   r<     rR   z,IntegerPartition.as_dict.<locals>.<listcomp>)_dictr   r)   rs   rd   )r8   groupsr   r   r   rr     s
   

zIntegerPartition.as_dictc                 C   sn   d}t | jdg }|d }dg| }|dkr5||| kr-|||d < |d8 }||| ks|d7 }|dks|S )a  
        Computes the conjugate partition of itself.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> a = IntegerPartition([6, 3, 3, 2, 1])
        >>> a.conjugate
        [5, 4, 3, 1, 1, 1]
        rV   r   )r   r)   )r8   rU   temp_arrrj   r{   r   r   r   	conjugate  s   
zIntegerPartition.conjugatec                 C   s   t t| jt t|jk S )a  Return True if self is less than other when the partition
        is listed from smallest to biggest.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> a = IntegerPartition([3, 1])
        >>> a < a
        False
        >>> b = a.next_lex()
        >>> a < b
        True
        >>> a == b
        False
        r   reversedr)   rF   r   r   r   rJ     s   zIntegerPartition.__lt__c                 C   s   t t| jt t|jkS )a   Return True if self is less than other when the partition
        is listed from smallest to biggest.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> a = IntegerPartition([4])
        >>> a <= a
        True
        r   rF   r   r   r   rI   %  s   zIntegerPartition.__le__#c                    s   d  fdd| jD S )a  
        Prints the ferrer diagram of a partition.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import IntegerPartition
        >>> print(IntegerPartition([1, 1, 5]).as_ferrers())
        #####
        #
        #
        
c                    s   g | ]} | qS r   r   rN   charr   r   r<   @  rR   z/IntegerPartition.as_ferrers.<locals>.<listcomp>)joinr)   )r8   r   r   r   r   
as_ferrers3  s   zIntegerPartition.as_ferrersc                 C   s   t t| jS r   )strr   r)   r>   r   r   r   __str__B  s   zIntegerPartition.__str__r   )r   )r[   r\   r]   r^   r   rs   r$   rx   r   rr   r_   r   rJ   rI   r   r   r   r   r   r   ra   4  s    
>%2

ra   Nc                 C   s   ddl m} t| } | dk rtd||}g }| dkr9|d| }|d| | }|||f | || 8 } | dks|jdd tdd |D }|S )	a  
    Generates a random integer partition summing to ``n`` as a list
    of reverse-sorted integers.

    Examples
    ========

    >>> from sympy.combinatorics.partitions import random_integer_partition

    For the following, a seed is given so a known value can be shown; in
    practice, the seed would not be given.

    >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1])
    [85, 12, 2, 1]
    >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1])
    [5, 3, 1, 1]
    >>> random_integer_partition(1)
    [1]
    r   )_randintrV   zn must be a positive integerTrb   c                 S   s   g | ]	\}}|g| qS r   r   )r   rj   mr   r   r   r<   i  rS   z,random_integer_partition.<locals>.<listcomp>)sympy.core.randomr   r   r"   r    sortr   )nseedr   randintr)   rj   multr   r   r   random_integer_partitionF  s   
r   c                 C   s   t | d }t| d D ]}d|d|f< qtd| d D ].}t| D ]'}|| | krC|||d |f  ||d |d f  |||f< q"d|||f< q"q|S )a  
    Computes the m + 1 generalized unrestricted growth strings
    and returns them as rows in matrix.

    Examples
    ========

    >>> from sympy.combinatorics.partitions import RGS_generalized
    >>> RGS_generalized(6)
    Matrix([
    [  1,   1,   1,  1,  1, 1, 1],
    [  1,   2,   3,  4,  5, 6, 0],
    [  2,   5,  10, 17, 26, 0, 0],
    [  5,  15,  37, 77,  0, 0, 0],
    [ 15,  52, 151,  0,  0, 0, 0],
    [ 52, 203,   0,  0,  0, 0, 0],
    [203,   0,   0,  0,  0, 0, 0]])
    rV   r   )r   rX   )r   rt   rO   rU   r   r   r   RGS_generalizedm  s   2r   c                 C   s    | dk rdS | dkrdS t | S )a}  
    RGS_enum computes the total number of restricted growth strings
    possible for a superset of size m.

    Examples
    ========

    >>> from sympy.combinatorics.partitions import RGS_enum
    >>> from sympy.combinatorics import Partition
    >>> RGS_enum(4)
    15
    >>> RGS_enum(5)
    52
    >>> RGS_enum(6)
    203

    We can check that the enumeration is correct by actually generating
    the partitions. Here, the 15 partitions of 4 items are generated:

    >>> a = Partition(list(range(4)))
    >>> s = set()
    >>> for i in range(20):
    ...     s.add(a)
    ...     a += 1
    ...
    >>> assert len(s) == 15

    rV   r   r
   )r   r   r   r   r@     s
   r@   c                 C   s   |dk rt d| dk st|| krt ddg|d  }d}t|}td|d D ]/}||| |f }|| }|| krK|d ||< | |8 } |d7 }q*t| | d ||< | |; } q*dd |dd D S )	a  
    Gives the unranked restricted growth string for a given
    superset size.

    Examples
    ========

    >>> from sympy.combinatorics.partitions import RGS_unrank
    >>> RGS_unrank(14, 4)
    [0, 1, 2, 3]
    >>> RGS_unrank(0, 4)
    [0, 0, 0, 0]
    rV   zThe superset size must be >= 1r   zInvalid argumentsrn   c                 S   s   g | ]}|d  qS )rV   r   )r   xr   r   r   r<     rR   zRGS_unrank.<locals>.<listcomp>N)r"   r@   r   rX   rp   )r7   r   LrU   DrO   rk   crr   r   r   r?     s"   

r?   c                 C   sh   t | }d}t|}td|D ]"}t | |d d }t| d| }||||d f | |  7 }q|S )z
    Computes the rank of a restricted growth string.

    Examples
    ========

    >>> from sympy.combinatorics.partitions import RGS_rank, RGS_unrank
    >>> RGS_rank([0, 1, 2, 1, 3])
    42
    >>> RGS_rank(RGS_unrank(4, 7))
    4
    r   rV   N)r   r   rX   rW   )rQ   rgs_sizer7   r   rO   r   r   r   r   r   rL     s   rL   r   ) 
sympy.corer   r   r   r   sympy.core.numbersr   sympy.core.sortingr   sympy.core.sympifyr	   %sympy.functions.combinatorial.numbersr   sympy.matricesr   sympy.sets.setsr   r   sympy.utilities.iterablesr   r   sympy.utilities.miscr   collectionsr   r   ra   r   r   r@   r?   rL   r   r   r   r   <module>   s*      '  
' %#