Yc@sdZddlmZddlmZddlZddlmZdddd d gZ dej fd YZ ed e d Z e dZed dZdZdS(sFunctions 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. i(tCounter(tchainN(tnot_implemented_fortfrom_nested_tupletfrom_prufer_sequencetNotATreetto_nested_tupletto_prufer_sequencecBseZdZRS(sRaised when a function expects a tree (that is, a connected undirected graph with no cycles) but gets a non-tree graph as input instead. (t__name__t __module__t__doc__(((su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyRstdirectedcsmfdtj|s3tjdn||kr]tjdj||n||dS(sReturns 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) ((((),),),) csht|h}t|dkr-dSfd|D}r^t|}nt|S(stRecursively 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. ic3s!|]}|VqdS(N((t.0tv(tTt _make_tupletroot(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys ys((tsettlentsortedttuple(RRt_parenttchildrentnested(Rtcanonical_form(RRsu/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyRjs sprovided graph is not a treesGraph {} contains no node {}N(tnxtis_treeRt NodeNotFoundtformattNone(RRR((RRsu/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyR's C csxfd|}|rttdgdtj|dD}dt|D}tj||}n|S(s0Returns 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 csNt|dkrtjdStjjg|D]}|df^q/S(sRecursively 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. ii(RRt empty_graphttreetjoin(tsequencetchild(t _make_tree(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyR#s  icss|]\}}|VqdS(N((R tuR ((su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys scSsi|]\}}||qS(((R tiR ((su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys s (RRt bfs_edgest enumeratet relabel_nodes(R!tsensible_relabelingRt bfs_nodestlabels((R#su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyRs2 (c sht}|dkr0d}tj|ntjsQtjdnttt|kr~tdntj fd}t fdt|D}}g}xt|dD]}||}|j ||cd8<||kr3|dkr3|}qt fdt|d|D}}qW|S( s$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 \log 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. 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 is>Prüfer sequence undefined for trees with fewer than two nodessprovided graph is not a trees*tree must have node labels {0, ..., n - 1}cstfd|DS(Nc3s%|]}|dkr|VqdS(iN((R R (tdegree(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys 0s(tnext(R$(RR,(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pytparents/sc3s%|]}|dkr|VqdS(iN((R tk(R,(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys 2sic3s%|]}|dkr|VqdS(iN((R R/(R,(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys ;s( RRtNetworkXPointlessConceptRRRtrangetKeyErrortdictR,tmintappend( RtntmsgR.tindexR$tresultR%R ((RR,su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyRs(J  &   1cs)t|d}tt|t|tj|}t}tfdt|D}}x|D]}|j|||j ||cd8<||kr|dkr|}qptfdt|d|D}}qpWt||}|\}}|j|||S(sReturns 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. 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 \log 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. 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 ic3s%|]}|dkr|VqdS(iN((R R/(R,(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys sic3s%|]}|dkr|VqdS(iN((R R/(R,(su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pys s( RRRR1RRRR4tadd_edgetadd(R!R6Rt not_orphanedR8R$R torphans((R,su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyR?s = &   1 (R t collectionsRt itertoolsRtnetworkxRtnetworkx.utilsRt__all__tNetworkXExceptionRtFalseRRRR(((su/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/algorithms/tree/coding.pyts    _ Se