U
    ZÊ¹jiQ  ã                   @   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} qN|}| t|ƒ¡ qtdd„ |D ƒƒshtdƒ‚t|Ž }|sŽt|ƒt	dd„ |D ƒƒk r–tdƒ‚t
j| f|žŽ }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   ú]/var/www/html/bwave/python/venv/lib/python3.8/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   s     z'Partition contained duplicate elements.)r   ÚlistÚsetr   Úappendr	   ÚallÚ
ValueErrorr   Úsumr   Ú__new__ÚtupleÚmembersÚsize)ÚclsÚ	partitionÚargsZdupsr   Zas_setÚUÚobjr   r   r   r#      s*    $
ÿ

zPartition.__new__c                    sB   ˆ dk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   ó    z$Partition.sort_key.<locals>.<lambda>©Úkey)r%   r$   ÚsortedÚmapr   r&   Úrank)Úselfr.   r%   r   r-   r   Úsort_key]   s    
ÿzPartition.sort_keyc                 C   s&   | j dkr tdd„ | jD ƒƒ| _ | j S )zÑReturn 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 )r1   )r3   r   ©r   Úpr   r   r   Ú
<listcomp>„   s   ÿz'Partition.partition.<locals>.<listcomp>)Ú
_partitionr3   r)   ©r6   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   r5   Ú
RGS_unrankÚRGS_enumr&   r   Úfrom_rgsr%   )r6   Ú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
        )rC   ©r6   r@   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
        ©r7   r   rD   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
        rF   rD   r   r   r   Ú__lt__Ç   s    zPartition.__lt__c                 C   s"   | j dk	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   r5   Ø   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:   
  s     z!Partition.RGS.<locals>.<listcomp>c                 S   s   g | ]}|D ]}|‘qqS r   r   )r   r9   rM   r   r   r   r:     s       r1   )r(   Ú	enumerater$   r3   r   )r6   r(   rM   r   Újr   rN   r   rK   ê   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 ƒƒsxt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   rL   r   r   r   r:   *  s     z&Partition.from_rgs.<locals>.<listcomp>r   c                 s   s   | ]
}|V  qd S r   r   r8   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   )r6   rO   ÚelementsZmax_elemr(   rQ   rM   r   r   r   r?     s    
zPartition.from_rgs)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rI   r;   r#   r7   Úpropertyr(   rC   rE   rG   rH   r5   rK   Úclassmethodr?   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k	r|| }}t |ttfƒrpg }t| ¡ dd�D ]0\}}|sBq4t|ƒt|ƒ }}| |g| ¡ q4t|ƒ}ntttt|ƒdd�ƒ}d}|dkr t	|ƒ}d}nt|ƒ}|sÄt	|ƒ|krÄt
d| ƒ‚tdd„ |D ƒƒrÞt
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 )rR   Nr   rL   r   r   r   r   ‰  s     z+IntegerPartition.__new__.<locals>.<genexpr>z-All integer summands must be greater than one)r   Údictr   r3   Úitemsr   Úextendr$   r4   r"   r!   Úanyr   r#   r   r   r   r(   Úinteger)r'   r(   rc   Ú_ÚkÚvZsum_okr+   r   r   r   r#   S  s0    !


zIntegerPartition.__new__c                 C   s  t tƒ}| |  ¡ ¡ | j}|dgkr4t| jdiƒS |d dkr„||d   d8  < |d dkrjd|d< qöd ||d d < |d< nr||d   d8  < |d |d  }|d }d|d< |rö|d8 }|| dkr¸||  || 7  < ||| | 8 }q¸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
        rR   éÿÿÿÿé   éþÿÿÿr   )r   ÚintÚupdateÚas_dictÚ_keysr\   rc   )r6   ÚdÚkeysÚleftÚnewr   r   r   Úprev_lex‘  s(    

zIntegerPartition.prev_lexc                 C   s�  t tƒ}| |  ¡ ¡ | j}|d }|| jkrD| ¡  | j|d< �n@|dkr¸|| dkr~||d   d7  < ||  d8  < n8|d }||d   d7  < || d | |d< d||< nÌ|| dk�r0t|ƒdkrú| ¡  d||d < | j| d |d< n4|d }||  d7  < || | | |d< d||< nT|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
        rg   rR   rh   ri   r   )	r   rj   rk   rl   rm   rc   Úclearr   r\   )r6   rn   r2   ÚaÚbZa1Úb1Zneedr   r   r   Únext_lex¶  s>    


zIntegerPartition.next_lexc                 C   s8   | j dkr2t| 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)Zmultiplec                 S   s   g | ]}|d  ‘qS )r   r   )r   Úgr   r   r   r:   ö  s     z,IntegerPartition.as_dict.<locals>.<listcomp>)Ú_dictr   r(   rm   r_   )r6   Úgroupsr   r   r   rl   è  s
    

zIntegerPartition.as_dictc                 C   s^   d}t | jƒdg }|d }dg| }|dkrZ||| krP|||d < |d8 }q.|d7 }q&|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]
        rR   r   )r   r(   )r6   rQ   Ztemp_arrre   ru   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(   rD   r   r   r   rH     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|   rD   r   r   r   rG   %  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   rL   ©Úcharr   r   r:   @  s     z/IntegerPartition.as_ferrers.<locals>.<listcomp>)Újoinr(   )r6   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__)N)r~   )rV   rW   rX   rY   ry   rm   r#   rr   rw   rl   rZ   r{   rH   rG   rƒ   r…   r   r   r   r   r\   4  s   
>%2

r\   Nc                 C   sŽ   ddl m} t| ƒ} | dk r$tdƒ‚||ƒ}g }| dkrl|d| ƒ}|d| | ƒ}| ||f¡ | || 8 } q0|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   )Ú_randintrR   zn must be a positive integerTr]   c                 S   s   g | ]\}}|g| ‘qS r   r   )r   re   Úmr   r   r   r:   i  s     z,random_integer_partition.<locals>.<listcomp>)Zsympy.core.randomr†   r   r!   r   Úsortr   )ÚnÚseedr†   Úrandintr(   re   Z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 ]N}|| | kr†|||d |f  ||d |d f  |||f< qDd|||f< qDq8|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]])
    rR   r   )r   rT   )r‡   rn   rM   rQ   r   r   r   ÚRGS_generalizedm  s    2r�   c                 C   s$   | dk rdS | dkrdS t | ƒS d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

    rR   r   Nr
   )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r–|d ||< | |8 } |d7 }qTt| | d ƒ||< | |; } qTd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]
    rR   zThe superset size must be >= 1r   zInvalid argumentsrh   c                 S   s   g | ]}|d  ‘qS )rR   r   )r   Úxr   r   r   r:   Ò  s     zRGS_unrank.<locals>.<listcomp>N)r!   r>   r�   rT   rj   )r5   r‡   ÚLrQ   ÚDrM   rf   Úcrr   r   r   r=   ²  s"    

r=   c                 C   sh   t | ƒ}d}t|ƒ}td|ƒ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   rR   N)r   r�   rT   rS   )rO   Zrgs_sizer5   r�   rM   r‰   r‡   r   r   r   rJ   Õ  s    rJ   )N) Z
sympy.corer   r   r   r   Zsympy.core.numbersr   Zsympy.core.sortingr   Zsympy.core.sympifyr	   Z%sympy.functions.combinatorial.numbersr   Zsympy.matricesr   Zsympy.sets.setsr   r   Zsympy.utilities.iterablesr   r   Zsympy.utilities.miscr   Úcollectionsr   r   r\   rŒ   r�   r>   r=   rJ   r   r   r   r   Ú<module>   s(     '  
' %#