o
    oh/                     @   sl   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 d dlmZ G dd	 d	eZd
S )    )Basic)Tuple)Array_sympify)flatteniterable)as_int)defaultdictc                   @   s   e Zd ZdZdZdZdZdZedd Z	edd Z
edd Zed	d
 Zedd Zedd Zedd Zedd Zdd Zedd Zdd ZdddZdddZdS )Prufera  
    The Prufer correspondence is an algorithm that describes the
    bijection between labeled trees and the Prufer code. A Prufer
    code of a labeled tree is unique up to isomorphism and has
    a length of n - 2.

    Prufer sequences were first used by Heinz Prufer to give a
    proof of Cayley's formula.

    References
    ==========

    .. [1] https://mathworld.wolfram.com/LabeledTree.html

    Nc                 C   s*   | j du r| | jdd | j| _ | j S )aH  Returns Prufer sequence for the Prufer object.

        This sequence is found by removing the highest numbered vertex,
        recording the node it was attached to, and continuing until only
        two vertices remain. The Prufer sequence is the list of recorded nodes.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).prufer_repr
        [3, 3, 3, 4]
        >>> Prufer([1, 0, 0]).prufer_repr
        [1, 0, 0]

        See Also
        ========

        to_prufer

        N)_prufer_repr	to_prufer
_tree_reprnodesself r   n/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/combinatorics/prufer.pyprufer_repr    s   
zPrufer.prufer_reprc                 C   s&   | j du r| | jdd | _ | j S )a  Returns the tree representation of the Prufer object.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).tree_repr
        [[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]
        >>> Prufer([1, 0, 0]).tree_repr
        [[1, 2], [0, 1], [0, 3], [0, 4]]

        See Also
        ========

        to_tree

        N)r   to_treer   r   r   r   r   	tree_repr;   s   
zPrufer.tree_reprc                 C   s   | j S )a  Returns the number of nodes in the tree.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).nodes
        6
        >>> Prufer([1, 0, 0]).nodes
        5

        )_nodesr   r   r   r   r   R   s   zPrufer.nodesc                 C   s   | j du r
|  | _ | j S )a  Returns the rank of the Prufer sequence.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> p = Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]])
        >>> p.rank
        778
        >>> p.next(1).rank
        779
        >>> p.prev().rank
        777

        See Also
        ========

        prufer_rank, next, prev, size

        N)_rankprufer_rankr   r   r   r   rankb   s   

zPrufer.rankc                 C   s   |  | j  jd S )a6  Return the number of possible trees of this Prufer object.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer([0]*4).size == Prufer([6]*4).size == 1296
        True

        See Also
        ========

        prufer_rank, rank, next, prev

           )prevr   r   r   r   r   size|   s   zPrufer.sizec           	      C   s   t t}g }| D ]}||d   d7  < ||d   d7  < qt|d D ]U}t|D ]
}|| dkr5 nq+d}| D ]}||d krG|d }n
||d krQ|d }|durW nq:|| ||fD ]}||  d8  < || st|| qa| | q%|S )a  Return the Prufer sequence for a tree given as a list of edges where
        ``n`` is the number of nodes in the tree.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> a = Prufer([[0, 1], [0, 2], [0, 3]])
        >>> a.prufer_repr
        [0, 0]
        >>> Prufer.to_prufer([[0, 1], [0, 2], [0, 3]], 4)
        [0, 0]

        See Also
        ========
        prufer_repr: returns Prufer sequence of a Prufer object.

        r   r      N)r
   intrangeappendpopremove)	treendLedgeixyjr   r   r   r      s6   


zPrufer.to_pruferc                    s   g }g }t | d }tdd  | D ]
} |  d7  < q| D ]*}t|D ]
} | dkr/ nq% |  d8  <  |  d8  < |t||g q fddt|D pXddg}|| |S )aB  Return the tree (as a list of edges) of the given Prufer sequence.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> a = Prufer([0, 2], 4)
        >>> a.tree_repr
        [[0, 1], [0, 2], [2, 3]]
        >>> Prufer.to_tree([0, 2])
        [[0, 1], [0, 2], [2, 3]]

        References
        ==========

        .. [1] https://hamberg.no/erlend/posts/2010-11-06-prufer-sequence-compact-tree-representation.html

        See Also
        ========
        tree_repr: returns tree representation of a Prufer object.

        r   c                   S   s   dS )Nr   r   r   r   r   r   <lambda>   s    z Prufer.to_tree.<locals>.<lambda>r   c                    s   g | ]
} | d kr|qS r   r   .0r)   r&   r   r   
<listcomp>   s    z"Prufer.to_tree.<locals>.<listcomp>r   )lenr
   r    r!   sorted)pruferr$   lastr%   pr)   r,   r   r1   r   r      s"   
zPrufer.to_treec                     s~  t  }| d d  | D ]'}tt|d D ]}|||d  \}}||k r*||}}|||f qqg }t  }d  }|D ],}	||	  durPt|	d  n|	d  |dur_t|	d |n|	d }|t|	 q>t t |d | }
|
r fdd|
D }
t|
dkrd|
	  }t|dt
|
 }t| dkrt|D ]\}}	 fd	d|	D ||< q| 8 }t
||d fS )
aA  Return a list of edges and the number of nodes from the given runs
        that connect nodes in an integer-labelled tree.

        All node numbers will be shifted so that the minimum node is 0. It is
        not a problem if edges are repeated in the runs; only unique edges are
        returned. There is no assumption made about what the range of the node
        labels should be, but all nodes from the smallest through the largest
        must be present.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer.edges([1, 2, 3], [2, 4, 5]) # a T
        ([[0, 1], [1, 2], [1, 3], [3, 4]], 5)

        Duplicate edges are removed:

        >>> Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) # a K
        ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7)

        r   r   r   Nc                    s   g | ]}|  qS r   r   r/   nminr   r   r2         z Prufer.edges.<locals>.<listcomp>Node %s is missing.Nodes %s are missing.c                    s   g | ]}|  qS r   r   )r0   r%   r8   r   r   r2   !  r:   )setr    r3   addupdateminmaxr!   listr"   r4   
ValueError	enumerate)runserr)   abrvgotnmaxeimissingmsgr   r8   r   edges   s<   

zPrufer.edgesc                 C   s@   d}d}t | jd ddD ]}||| j|  7 }|| j9 }q|S )a)  Computes the rank of a Prufer sequence.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> a = Prufer([[0, 1], [0, 2], [0, 3]])
        >>> a.prufer_rank()
        0

        See Also
        ========

        rank, next, prev, size

        r   r      )r    r   r   )r   rG   r7   r)   r   r   r   r   %  s   zPrufer.prufer_rankc                    sj   t |t |}}tt t|d ddD ]}||  |< | |  | }qt fddtt D S )zFinds the unranked Prufer sequence.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> Prufer.unrank(0, 4)
        Prufer([0, 0])

        rQ   rR   c                    s   g | ]} | qS r   r   r/   r'   r   r   r2   N  r:   z!Prufer.unrank.<locals>.<listcomp>)r	   r
   r   r    r   r3   )r   r   r%   r)   r   rS   r   unrank=  s   zPrufer.unrankc           	      O   sJ  |d r
t |d nt }|ftdd |dd D  }tj| g|R i |}t|d g}|d rt|d d r|d d sFtdt|dkrQ|d }n6t	t
|d }t|d }|t|krt	t|| }t|dkr}d|  }t|dt| }t|d	d
 |d D |_||_|S |d |_t|jd |_|S )a  The constructor for the Prufer object.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer

        A Prufer object can be constructed from a list of edges:

        >>> a = Prufer([[0, 1], [0, 2], [0, 3]])
        >>> a.prufer_repr
        [0, 0]

        If the number of nodes is given, no checking of the nodes will
        be performed; it will be assumed that nodes 0 through n - 1 are
        present:

        >>> Prufer([[0, 1], [0, 2], [0, 3]], 4)
        Prufer([[0, 1], [0, 2], [0, 3]], 4)

        A Prufer object can be constructed from a Prufer sequence:

        >>> b = Prufer([1, 3])
        >>> b.tree_repr
        [[0, 1], [1, 3], [2, 3]]

        r   c                 s   s    | ]}t |V  qd S )Nr   )r0   argr   r   r   	<genexpr>m  s    z!Prufer.__new__.<locals>.<genexpr>r   Nz-Prufer expects at least one edge in the tree.r;   r<   c                 S   s   g | ]}t |qS r   )rB   r/   r   r   r   r2     r:   z"Prufer.__new__.<locals>.<listcomp>r   )r   r   tupler   __new__rB   r   rC   r3   r=   r   rA   r    r"   r4   r   r   r   )	clsargskw_argsarg0ret_objnnodesr   rN   rO   r   r   r   rX   P  s4    

zPrufer.__new__r   c                 C   s   t | j| | jS )a  Generates the Prufer sequence that is delta beyond the current one.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> a = Prufer([[0, 1], [0, 2], [0, 3]])
        >>> b = a.next(1) # == a.next()
        >>> b.tree_repr
        [[0, 2], [0, 1], [1, 3]]
        >>> b.rank
        1

        See Also
        ========

        prufer_rank, rank, prev, size

        r   rT   r   r   r   deltar   r   r   next  s   zPrufer.nextc                 C   s   t | j| | jS )a  Generates the Prufer sequence that is -delta before the current one.

        Examples
        ========

        >>> from sympy.combinatorics.prufer import Prufer
        >>> a = Prufer([[0, 1], [1, 2], [2, 3], [1, 4]])
        >>> a.rank
        36
        >>> b = a.prev()
        >>> b
        Prufer([1, 2, 0])
        >>> b.rank
        35

        See Also
        ========

        prufer_rank, rank, next, size

        r_   r`   r   r   r   r     s   zPrufer.prevr.   )__name__
__module____qualname____doc__r   r   r   r   propertyr   r   r   r   r   staticmethodr   r   rP   r   classmethodrT   rX   rb   r   r   r   r   r   r      s8    





2
,
5

7r   N)
sympy.corer   sympy.core.containersr   sympy.tensor.arrayr   sympy.core.sympifyr   sympy.utilities.iterablesr   r   sympy.utilities.miscr	   collectionsr
   r   r   r   r   r   <module>   s    