
    \Mh4                        d Z ddlmZ ddlmZ ddlZddlmZ g dZ	 G d dej
                  Z ed	           ej        d
          dd                        Z ej        dd          dd            Z ed	           ej        d
          d                         Z ej        dd          d             ZdS )u  Functions for encoding and decoding trees.

Since a tree is a highly restricted form of graph, it can be represented
concisely in several ways. This module includes functions for encoding
and decoding trees in the form of nested tuples and Prüfer
sequences. The former requires a rooted tree, whereas the latter can be
applied to unrooted trees. Furthermore, there is a bijection from Prüfer
sequences to labeled trees.

    )Counter)chainN)not_implemented_for)from_nested_tuplefrom_prufer_sequenceNotATreeto_nested_tupleto_prufer_sequencec                       e Zd ZdZdS )r   zRaised when a function expects a tree (that is, a connected
    undirected graph with no cycles) but gets a non-tree graph as input
    instead.

    N)__name__
__module____qualname____doc__     _/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/networkx/algorithms/tree/coding.pyr   r      s           r   r   directedT)graphsFc                     fdt          j        |           st          j        d          || vrt          j        d|  d|            | |d          S )a  Returns a nested tuple representation of the given tree.

    The nested tuple representation of a tree is defined
    recursively. The tree with one node and no edges is represented by
    the empty tuple, ``()``. A tree with ``k`` subtrees is represented
    by a tuple of length ``k`` in which each element is the nested tuple
    representation of a subtree.

    Parameters
    ----------
    T : NetworkX graph
        An undirected graph object representing a tree.

    root : node
        The node in ``T`` to interpret as the root of the tree.

    canonical_form : bool
        If ``True``, each tuple is sorted so that the function returns
        a canonical form for rooted trees. This means "lighter" subtrees
        will appear as nested tuples before "heavier" subtrees. In this
        way, each isomorphic rooted tree has the same nested tuple
        representation.

    Returns
    -------
    tuple
        A nested tuple representation of the tree.

    Notes
    -----
    This function is *not* the inverse of :func:`from_nested_tuple`; the
    only guarantee is that the rooted trees are isomorphic.

    See also
    --------
    from_nested_tuple
    to_prufer_sequence

    Examples
    --------
    The tree need not be a balanced binary tree::

        >>> T = nx.Graph()
        >>> T.add_edges_from([(0, 1), (0, 2), (0, 3)])
        >>> T.add_edges_from([(1, 4), (1, 5)])
        >>> T.add_edges_from([(3, 6), (3, 7)])
        >>> root = 0
        >>> nx.to_nested_tuple(T, root)
        (((), ()), (), ((), ()))

    Continuing the above example, if ``canonical_form`` is ``True``, the
    nested tuples will be sorted::

        >>> nx.to_nested_tuple(T, root, canonical_form=True)
        ((), ((), ()), ((), ()))

    Even the path graph can be interpreted as a tree::

        >>> T = nx.path_graph(4)
        >>> root = 0
        >>> nx.to_nested_tuple(T, root)
        ((((),),),)

    c                      t                              |hz
  }t          |          dk    rdS  fd|D             }rt          |          }t          |          S )at  Recursively compute the nested tuple representation of the
        given rooted tree.

        ``_parent`` is the parent node of ``root`` in the supertree in
        which ``T`` is a subtree, or ``None`` if ``root`` is the root of
        the supertree. This argument is used to determine which
        neighbors of ``root`` are children and which is the parent.

        r   r   c              3   2   K   | ]} |          V  d S Nr   ).0vr   _make_tupleroots     r   	<genexpr>z7to_nested_tuple.<locals>._make_tuple.<locals>.<genexpr>v   s1      <<a++aD))<<<<<<r   )setlensortedtuple)r   r   _parentchildrennestedr   canonical_forms   ``   r   r   z$to_nested_tuple.<locals>._make_tupleg   sq     qw<<7)+x==A2<<<<<<8<<< 	$F^^FV}}r   provided graph is not a treezGraph z contains no node N)nxis_treer   NodeNotFound)r   r   r&   r   s     `@r   r	   r	   #   s    H     * :a== :k89991}}oBqBBDBBCCC;q$%%%r   T)r   returns_graphc                     fd |           }|r\t          dgd t          j        |d          D                       }d t          |          D             }t          j        ||          }|S )a0  Returns the rooted tree corresponding to the given nested tuple.

    The nested tuple representation of a tree is defined
    recursively. The tree with one node and no edges is represented by
    the empty tuple, ``()``. A tree with ``k`` subtrees is represented
    by a tuple of length ``k`` in which each element is the nested tuple
    representation of a subtree.

    Parameters
    ----------
    sequence : tuple
        A nested tuple representing a rooted tree.

    sensible_relabeling : bool
        Whether to relabel the nodes of the tree so that nodes are
        labeled in increasing order according to their breadth-first
        search order from the root node.

    Returns
    -------
    NetworkX graph
        The tree corresponding to the given nested tuple, whose root
        node is node 0. If ``sensible_labeling`` is ``True``, nodes will
        be labeled in breadth-first search order starting from the root
        node.

    Notes
    -----
    This function is *not* the inverse of :func:`to_nested_tuple`; the
    only guarantee is that the rooted trees are isomorphic.

    See also
    --------
    to_nested_tuple
    from_prufer_sequence

    Examples
    --------
    Sensible relabeling ensures that the nodes are labeled from the root
    starting at 0::

        >>> balanced = (((), ()), ((), ()))
        >>> T = nx.from_nested_tuple(balanced, sensible_relabeling=True)
        >>> edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]
        >>> all((u, v) in T.edges() or (v, u) in T.edges() for (u, v) in edges)
        True

    c                     t          |           dk    rt          j        d          S t          j                            fd| D                       S )zRecursively creates a tree from the given sequence of nested
        tuples.

        This function employs the :func:`~networkx.tree.join` function
        to recursively join subtrees into a larger tree.

        r      c                 *    g | ]} |          d fS )r   r   )r   child
_make_trees     r   
<listcomp>z9from_nested_tuple.<locals>._make_tree.<locals>.<listcomp>   s(    "P"P"PeJJu$5$5q#9"P"P"Pr   )r    r(   empty_graphtree
join_trees)sequencer1   s    r   r1   z%from_nested_tuple.<locals>._make_tree   sS     x==A>!$$$ w!!"P"P"P"Px"P"P"PQQQr   r   c              3       K   | ]	\  }}|V  
d S r   r   )r   ur   s      r   r   z$from_nested_tuple.<locals>.<genexpr>   s&      AAdaAAAAAAr   c                     i | ]\  }}||	S r   r   )r   ir   s      r   
<dictcomp>z%from_nested_tuple.<locals>.<dictcomp>   s    88841a!Q888r   )r   r(   	bfs_edges	enumeraterelabel_nodes)r6   sensible_relabelingr   	bfs_nodeslabelsr1   s        @r   r   r      s    fR R R R R* 	
8A ( 1#AAbl1a.@.@AAABB	889Y#7#7888 Q''Hr   c                    	 t                     }|dk     rd}t          j        |          t          j                   st          j        d          t                     t          t          |                    k    rt          d          t           	                                          	 	fd}t          	fdt          |          D                       x}}g }t          |dz
            D ]u} ||          }|                    |           	|xx         dz  cc<   ||k     r	|         dk    r|}Gt          	fdt          |dz   |          D                       x}}v|S )	u  Returns the Prüfer sequence of the given tree.

    A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and
    *n* - 1, inclusive. The tree corresponding to a given Prüfer
    sequence can be recovered by repeatedly joining a node in the
    sequence with a node with the smallest potential degree according to
    the sequence.

    Parameters
    ----------
    T : NetworkX graph
        An undirected graph object representing a tree.

    Returns
    -------
    list
        The Prüfer sequence of the given tree.

    Raises
    ------
    NetworkXPointlessConcept
        If the number of nodes in `T` is less than two.

    NotATree
        If `T` is not a tree.

    KeyError
        If the set of nodes in `T` is not {0, …, *n* - 1}.

    Notes
    -----
    There is a bijection from labeled trees to Prüfer sequences. This
    function is the inverse of the :func:`from_prufer_sequence`
    function.

    Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead
    of from 0 to *n* - 1. This function requires nodes to be labeled in
    the latter form. You can use :func:`~networkx.relabel_nodes` to
    relabel the nodes of your tree to the appropriate format.

    This implementation is from [1]_ and has a running time of
    $O(n)$.

    See also
    --------
    to_nested_tuple
    from_prufer_sequence

    References
    ----------
    .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu.
           "An optimal algorithm for Prufer codes."
           *Journal of Software Engineering and Applications* 2.02 (2009): 111.
           <https://doi.org/10.4236/jsea.2009.22016>

    Examples
    --------
    There is a bijection between Prüfer sequences and labeled trees, so
    this function is the inverse of the :func:`from_prufer_sequence`
    function:

    >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)]
    >>> tree = nx.Graph(edges)
    >>> sequence = nx.to_prufer_sequence(tree)
    >>> sequence
    [3, 3, 3, 4]
    >>> tree2 = nx.from_prufer_sequence(sequence)
    >>> list(tree2.edges()) == edges
    True

       u>   Prüfer sequence undefined for trees with fewer than two nodesr'   z*tree must have node labels {0, ..., n - 1}c                 F    t          fd|          D                       S )Nc              3   4   K   | ]}|         d k    |V  dS r.   Nr   )r   r   degrees     r   r   z6to_prufer_sequence.<locals>.parents.<locals>.<genexpr>/  s+      55!vay1}}A}}}}55r   )next)r8   r   rG   s    r   parentsz#to_prufer_sequence.<locals>.parents.  s*    5555qt555555r   c              3   4   K   | ]}|         d k    |V  dS rF   r   r   krG   s     r   r   z%to_prufer_sequence.<locals>.<genexpr>1  +      ;;1F1INNQNNNN;;r   r.   c              3   4   K   | ]}|         d k    |V  dS rF   r   rK   s     r   r   z%to_prufer_sequence.<locals>.<genexpr>:  +      NN1vayA~~Q~~~~NNr   )r    r(   NetworkXPointlessConceptr)   r   r   rangeKeyErrordictrG   rH   append)
r   nmsgrI   indexr8   resultr:   r   rG   s
   `        @r   r
   r
      s   V 	AA1uuN)#...:a== :k8999
1vvU1XXCDDD!((**F6 6 6 6 6 6 ;;;;a;;;;;;EAF1q5\\ O OGAJJaq			Q			u99aAANNNNeai(;(;NNNNNNEAAMr   c                    t          |           dz   }t          t          | t          |                              t	          j        |          }t                      }t          fdt          |          D                       x}}| D ]}|dk     s	||dz
  k    rt	          j        d|dz
   d|           |	                    ||           |
                    |           |xx         dz  cc<   ||k     r|         dk    r|}~t          fdt          |dz   |          D                       x}}t          |          |z
  }|\  }}|	                    ||           |S )u  Returns the tree corresponding to the given Prüfer sequence.

    A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and
    *n* - 1, inclusive. The tree corresponding to a given Prüfer
    sequence can be recovered by repeatedly joining a node in the
    sequence with a node with the smallest potential degree according to
    the sequence.

    Parameters
    ----------
    sequence : list
        A Prüfer sequence, which is a list of *n* - 2 integers between
        zero and *n* - 1, inclusive.

    Returns
    -------
    NetworkX graph
        The tree corresponding to the given Prüfer sequence.

    Raises
    ------
    NetworkXError
        If the Prüfer sequence is not valid.

    Notes
    -----
    There is a bijection from labeled trees to Prüfer sequences. This
    function is the inverse of the :func:`from_prufer_sequence` function.

    Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead
    of from 0 to *n* - 1. This function requires nodes to be labeled in
    the latter form. You can use :func:`networkx.relabel_nodes` to
    relabel the nodes of your tree to the appropriate format.

    This implementation is from [1]_ and has a running time of
    $O(n)$.

    References
    ----------
    .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu.
           "An optimal algorithm for Prufer codes."
           *Journal of Software Engineering and Applications* 2.02 (2009): 111.
           <https://doi.org/10.4236/jsea.2009.22016>

    See also
    --------
    from_nested_tuple
    to_prufer_sequence

    Examples
    --------
    There is a bijection between Prüfer sequences and labeled trees, so
    this function is the inverse of the :func:`to_prufer_sequence`
    function:

    >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)]
    >>> tree = nx.Graph(edges)
    >>> sequence = nx.to_prufer_sequence(tree)
    >>> sequence
    [3, 3, 3, 4]
    >>> tree2 = nx.from_prufer_sequence(sequence)
    >>> list(tree2.edges()) == edges
    True

    rC   c              3   4   K   | ]}|         d k    |V  dS rF   r   rK   s     r   r   z'from_prufer_sequence.<locals>.<genexpr>  rM   r   r   r.   z6Invalid Prufer sequence: Values must be between 0 and z, got c              3   4   K   | ]}|         d k    |V  dS rF   r   rK   s     r   r   z'from_prufer_sequence.<locals>.<genexpr>  rO   r   )r    r   r   rQ   r(   r3   r   rH   NetworkXErroradd_edgeadd)	r6   rU   r   not_orphanedrW   r8   r   orphansrG   s	           @r   r   r   >  s   F 	HA U8U1XX..//F
qA 55L;;;;a;;;;;;EA O Oq55AAII"YQYYVWYY   	


1aq			Q			u99aAANNNNeai(;(;NNNNNNEAA!ff|#GDAqJJq!Hr   )F)r   collectionsr   	itertoolsr   networkxr(   networkx.utilsr   __all__NetworkXExceptionr   _dispatchabler	   r   r
   r   r   r   r   <module>rh      s  	 	                  . . . . . .      r#    Z  \& \& \&  ! \&~ T222P P P 32Pf Z  a a  ! aH T222^ ^ 32^ ^ ^r   