B
    [N                 @   s   d dl mZmZ d dlmZmZmZ d dl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mZ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 )    )print_functiondivision)BasicDictsympify)as_intdefault_sort_keyrange)bell)zeros)	FiniteSet)has_dupsflattengroup)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   sr   |}t dd |D stdtt|g td}t|r@tdtj| fdd |D  }t||_	t
||_|S )a  
        Generates a new partition object.

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

        Examples
        ========

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

        c             s   s   | ]}t |ttfV  qd S )N)
isinstancelistr   ).0part r   =lib/python3.7/site-packages/sympy/combinatorics/partitions.py	<genexpr>4   s    z$Partition.__new__.<locals>.<genexpr>z:Each argument to Partition should be a list or a FiniteSet)keyz(Partition contained duplicated elements.c             S   s   g | ]}t | qS r   )r   )r   xr   r   r   
<listcomp>=   s    z%Partition.__new__.<locals>.<listcomp>)all
ValueErrorsortedsumr   r   r   __new__tuplememberslensize)cls	partitionargs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.utilities.iterables import default_sort_key
        >>> from sympy.combinatorics.partitions 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
        [{{1, 2}}, {{1}, {2}}, {{1, x}}, {{3, 4}}, {{0, 1, 2, 3}}]
        Nc                s
   t |  S )N)r   )w)orderr   r   <lambda>Z   s    z$Partition.sort_key.<locals>.<lambda>)r   )r"   r!   r   r   mapr   r$   rank)selfr*   r"   r   )r*   r   sort_keyB   s
    zPartition.sort_keyc             C   s&   | j dkr tdd | jD | _ | j S )zReturn partition as a sorted list of lists.

        Examples
        ========

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

        Examples
        ========

        >>> from sympy.combinatorics.partitions import Partition
        >>> a = Partition([1, 2], [3])
        >>> a.rank
        1
        >>> (a + 1).rank
        2
        >>> (a + 100).rank
        1
        )r   r-   
RGS_unrankRGS_enumr$   r   from_rgsr"   )r.   otheroffsetresultr   r   r   __add__m   s    

zPartition.__add__c             C   s   |  | S )aq  
        Return permutation whose rank is ``other`` less than current rank,
        (mod the maximum rank for the set).

        Examples
        ========

        >>> from sympy.combinatorics.partitions import Partition
        >>> a = Partition([1, 2], [3])
        >>> a.rank
        1
        >>> (a - 1).rank
        0
        >>> (a - 100).rank
        1
        )r8   )r.   r5   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.partitions 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
        )r/   r   )r.   r5   r   r   r   __le__   s    zPartition.__le__c             C   s   |   t|  k S )aL  
        Checks if a partition is less than the other.

        Examples
        ========

        >>> from sympy.combinatorics.partitions 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
        )r/   r   )r.   r5   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.partitions import Partition
        >>> a = Partition([1, 2], [3], [4, 5])
        >>> a.rank
        13
        N)_rankRGS_rankRGS)r.   r   r   r   r-      s    
zPartition.rankc                s^   i  | j }x*t|D ]\}}x|D ]}| |< q"W qW t fddtdd |D tdD S )a  
        Returns the "restricted growth string" of the partition.

        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.partitions 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
        {{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   r0   r?   r   r   r   r      s    )r   )r&   	enumerater!   r   r   )r.   r&   r?   r   jr   )r@   r   r>      s    
zPartition.RGSc             C   s   t |t |krtdt|d }dd t|D }d}x&|D ]}|| ||  |d7 }q@W tdd |D s|tdt| S )	a	  
        Creates a set partition from a restricted growth string.

        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.partitions import Partition
        >>> Partition.from_rgs([0, 1, 2, 0, 1], list('abcde'))
        {{c}, {a, d}, {b, e}}
        >>> Partition.from_rgs([0, 1, 2, 0, 1], list('cbead'))
        {{e}, {a, c}, {b, d}}
        >>> a = Partition([1, 4], [2], [3, 5])
        >>> Partition.from_rgs(a.RGS, a.members)
        {{2}, {1, 4}, {3, 5}}
        z#mismatch in rgs and element lengths   c             S   s   g | ]}g qS r   r   )r   r?   r   r   r   r   	  s    z&Partition.from_rgs.<locals>.<listcomp>r   c             s   s   | ]
}|V  qd S )Nr   )r   r0   r   r   r   r     s    z%Partition.from_rgs.<locals>.<genexpr>z(some blocks of the partition were empty.)r#   r   maxr	   appendr   r   )r.   r@   elementsZmax_elemr&   rB   r?   r   r   r   r4      s    
zPartition.from_rgs)N)__name__
__module____qualname____doc__r<   r1   r    r/   propertyr&   r8   r9   r:   r;   r-   r>   classmethodr4   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 )IntegerPartitiona  
    This class represents an integer partition.

    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

    Reference: http://en.wikipedia.org/wiki/Partition_%28number_theory%29
    Nc             C   s  |dk	r|| }}t |ttfrxg }xHtt| ddD ]0\}}|sHq:t|t| }}||g|  q:W t|}nttt	t|dd}d}|dkrt
|}d}nt|}|st
||krtd| tdd |D rtdt| ||}t||_||_|S )	a  
        Generates a new IntegerPartition object from a list or dictionary.

        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 )rC   Nr   )r   r?   r   r   r   r   _  s    z+IntegerPartition.__new__.<locals>.<genexpr>z"The summands must all be positive.)r   dictr   r   r   itemsr   extendr!   r,   r   r   anyr   r    r&   integer)r%   r&   rS   _kvZsum_okr(   r   r   r   r    ,  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< qd ||d d < |d< nv||d   d8  < |d |d  }|d }d|d< x@|r|d8 }|| dkr||  || 7  < ||| | 8 }qW 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
        rC      r   )r   intupdateas_dict_keysrM   rS   )r.   dkeysleftnewr   r   r   prev_lexg  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
        rW   rC   rX   rY   r   )	r   rZ   r[   r\   r]   rS   clearr#   rM   )r.   r^   r   abZa1Z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&   r]   rO   )r.   groupsr   r   r   r\     s
    

zIntegerPartition.as_dictc             C   sf   d}t | jdg }|d }dg| }x:|dkr`x$||| krT|||d < |d8 }q2W |d7 }q(W |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]
        rC   r   )r   r&   )r.   rB   Ztemp_arrrU   re   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&   )r.   r5   r   r   r   r;     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   rk   r&   )r.   r5   r   r   r   r:     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   )r   r?   )charr   r   r     s    z/IntegerPartition.as_ferrers.<locals>.<listcomp>)joinr&   )r.   rn   r   )rn   r   
as_ferrers	  s    zIntegerPartition.as_ferrersc             C   s   t t| jS )N)strr   r&   )r.   r   r   r   __str__  s    zIntegerPartition.__str__)N)rl   )rG   rH   rI   rJ   rh   r]   r    rb   rf   r\   rK   rj   r;   r:   rp   rr   r   r   r   r   rM     s   
;%2
rM   Nc             C   s   ddl m} t| } | dk r$td||}g }x>| dkrn|d| }|d| | }|||f | || 8 } q2W |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   )_randintrC   zn must be a positive integerT)rN   c             S   s   g | ]\}}|g| qS r   r   )r   rU   mr   r   r   r   ?  s    z,random_integer_partition.<locals>.<listcomp>)Zsympy.utilities.randtestrs   r   r   rE   sortr   )nZseedrs   Zrandintr&   rU   Zmultr   r   r   random_integer_partition  s    

rw   c             C   s   t | d }x"td| d D ]}d|d|f< qW xrtd| d D ]`}xZt| D ]N}|| | kr|||d |f  ||d |d f  |||f< qNd|||f< qNW q@W |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]])
    rC   r   )r   r	   )rt   r^   r?   rB   r   r   r   RGS_generalizedC  s    2rx   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.partitions 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

    rC   r   N)r
   )rt   r   r   r   r3   c  s
    r3   c             C   s   |dk rt d| dk s$t|| kr,t ddg|d  }d}t|}xptd|d D ]^}||| |f }|| }|| kr|d ||< | |8 } |d7 }qVt| | d ||< | |; } qVW 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]
    rC   zThe superset size must be >= 1r   zInvalid argumentsrX   c             S   s   g | ]}|d  qS )rC   r   )r   r   r   r   r   r     s    zRGS_unrank.<locals>.<listcomp>N)r   r3   rx   r	   rZ   )r-   rt   LrB   Dr?   rV   Zcrr   r   r   r2     s"    
r2   c             C   sl   t | }d}t|}xRtd|D ]D}t | |d d }t| d| }||||d f | |  7 }q W |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   rC   N)r#   rx   r	   rD   )r@   Zrgs_sizer-   rz   r?   rv   rt   r   r   r   r=     s     r=   )N)Z
__future__r   r   Z
sympy.corer   r   r   Zsympy.core.compatibilityr   r   r	   Z%sympy.functions.combinatorial.numbersr
   Zsympy.matricesr   Zsympy.sets.setsr   Zsympy.utilities.iterablesr   r   r   collectionsr   r   rM   rw   rx   r3   r2   r=   r   r   r   r   <module>   s$       
' %#