
    VhF$                        d Z ddlmZ ddlmZmZ ddlmZ ddlZ	ddl
mZmZmZ g dZ ed      e	j                  dd	              Z ed      e	j                  dd
              Z ed      e	j                  dd              Zy)zDAlgorithms for finding the lowest common ancestor of trees and DAGs.    )defaultdict)MappingSet)combinations_with_replacementN)	UnionFindarbitrary_elementnot_implemented_for) all_pairs_lowest_common_ancestor%tree_all_pairs_lowest_common_ancestorlowest_common_ancestor
undirectedc                    t        j                  |       st        j                  d      t        |       dk(  rt        j                  d      |t        | d      }n]t        j                  |      }t        |       }|D ]8  }t        |      |z
  st        j                  dt        |      |z
   d| d       d } || |      S )	a  Return the lowest common ancestor of all pairs or the provided pairs

    Parameters
    ----------
    G : NetworkX directed graph

    pairs : iterable of pairs of nodes, optional (default: all pairs)
        The pairs of nodes of interest.
        If None, will find the LCA of all pairs of nodes.

    Yields
    ------
    ((node1, node2), lca) : 2-tuple
        Where lca is least common ancestor of node1 and node2.
        Note that for the default case, the order of the node pair is not considered,
        e.g. you will not get both ``(a, b)`` and ``(b, a)``

    Raises
    ------
    NetworkXPointlessConcept
        If `G` is null.
    NetworkXError
        If `G` is not a DAG.

    Examples
    --------
    >>> from pprint import pprint

    The default behavior is to yield the lowest common ancestor for all
    possible combinations of nodes in `G`, including self-pairings:

    >>> G = nx.DiGraph([(0, 1), (0, 3), (1, 2)])
    >>> pprint(dict(nx.all_pairs_lowest_common_ancestor(G)))
    {(0, 0): 0,
     (0, 1): 0,
     (0, 2): 0,
     (0, 3): 0,
     (1, 1): 1,
     (1, 2): 1,
     (1, 3): 0,
     (2, 2): 2,
     (3, 2): 0,
     (3, 3): 3}

    The pairs argument can be used to limit the output to only the
    specified node pairings:

    >>> dict(nx.all_pairs_lowest_common_ancestor(G, pairs=[(1, 2), (2, 3)]))
    {(1, 2): 1, (2, 3): 0}

    Notes
    -----
    Only defined on non-null directed acyclic graphs.

    See Also
    --------
    lowest_common_ancestor
    z,LCA only defined on directed acyclic graphs.r   LCA meaningless on null graphs.   zNode(s) z from pair z
 not in G.c              3     K   i }|D ]  \  }}||vr-t        j                  | |      ||<   ||   j                  |       ||vr-t        j                  | |      ||<   ||   j                  |       ||   ||   z  }|svt        t	        |            }	 d }| j                  |      D ]
  }||v s|} n |n|}&||f|f  y wN)nx	ancestorsaddnextiter
successors)	Gpairsancestor_cachevwcommon_ancestorscommon_ancestor	successorlower_ancestors	            [/home/dcms/DCMS/lib/python3.12/site-packages/networkx/algorithms/lowest_common_ancestors.pygenerate_lca_from_pairszAall_pairs_lowest_common_ancestor.<locals>.generate_lca_from_pairsa   s      	0DAq&$&LLA$6q!q!%%a(&$&LLA$6q!q!%%a(-a0>!3DD"&t,<'="> $I*+,,*G ")-==(6I!" !(&/O  1v//+	0s   A:C=/C-C)
r   is_directed_acyclic_graphNetworkXErrorlenNetworkXPointlessConceptr   dictfromkeyssetNodeNotFound)r   r   nodesetpairr#   s        r"   r
   r
      s    z ''*MNN
1v{))*KLL}-a3 e$a& 	D4y7"oos4y723;tfJO 	04 #1e,,    c                 l    t        t        | ||fg            }|rt        |      dk(  sJ |d   d   S |S )ag  Compute the lowest common ancestor of the given pair of nodes.

    Parameters
    ----------
    G : NetworkX directed graph

    node1, node2 : nodes in the graph.

    default : object
        Returned if no common ancestor between `node1` and `node2`

    Returns
    -------
    The lowest common ancestor of node1 and node2,
    or default if they have no common ancestors.

    Examples
    --------
    >>> G = nx.DiGraph()
    >>> nx.add_path(G, (0, 1, 2, 3))
    >>> nx.add_path(G, (0, 4, 3))
    >>> nx.lowest_common_ancestor(G, 2, 4)
    0

    See Also
    --------
    all_pairs_lowest_common_ancestor)r      r   )listr
   r&   )r   node1node2defaultanss        r"   r   r   ~   sC    > /5%.9IJ
KC
3x1}}1vayNr.   c              #     K   t        |       dk(  rt        j                  d      |t        t              }t        |t        t        z        st	        |      }|D ]^  \  }}||fD ]*  }|| vsdt        |       d}t        j                  |       ||   j                  |       ||   j                  |       ` |m| j                  D ]^  \  }}|dk(  r|d}t        j                  |      |}'|dkD  s-t        | j                  |         dkD  sId}t        j                  |       |t        j                  d	      t               }	i }
| D ]
  }|	|   |
|<    t        t              }t        j                   | |      D ]  }d
||<   ||   n| D ]5  }||   s	|||f|v r||f|
|	|      f |||f|v s(||f|
|	|      f 7 ||k7  sOt#        | j                  |         }|	j%                  ||       ||
|	|   <    yw)a  Yield the lowest common ancestor for sets of pairs in a tree.

    Parameters
    ----------
    G : NetworkX directed graph (must be a tree)

    root : node, optional (default: None)
        The root of the subtree to operate on.
        If None, assume the entire graph has exactly one source and use that.

    pairs : iterable or iterator of pairs of nodes, optional (default: None)
        The pairs of interest. If None, Defaults to all pairs of nodes
        under `root` that have a lowest common ancestor.

    Returns
    -------
    lcas : generator of tuples `((u, v), lca)` where `u` and `v` are nodes
        in `pairs` and `lca` is their lowest common ancestor.

    Examples
    --------
    >>> import pprint
    >>> G = nx.DiGraph([(1, 3), (2, 4), (1, 2)])
    >>> pprint.pprint(dict(nx.tree_all_pairs_lowest_common_ancestor(G)))
    {(1, 1): 1,
     (2, 1): 1,
     (2, 2): 2,
     (3, 1): 1,
     (3, 2): 1,
     (3, 3): 3,
     (3, 4): 1,
     (4, 1): 1,
     (4, 2): 2,
     (4, 4): 4}

    We can also use `pairs` argument to specify the pairs of nodes for which we
    want to compute lowest common ancestors. Here is an example:

    >>> dict(nx.tree_all_pairs_lowest_common_ancestor(G, pairs=[(1, 4), (2, 3)]))
    {(2, 3): 1, (1, 4): 1}

    Notes
    -----
    Only defined on non-null trees represented with directed edges from
    parents to children. Uses Tarjan's off-line lowest-common-ancestors
    algorithm. Runs in time $O(4 \times (V + E + P))$ time, where 4 is the largest
    value of the inverse Ackermann function likely to ever come up in actual
    use, and $P$ is the number of pairs requested (or $V^2$ if all are needed).

    Tarjan, R. E. (1979), "Applications of path compression on balanced trees",
    Journal of the ACM 26 (4): 690-715, doi:10.1145/322154.322161.

    See Also
    --------
    all_pairs_lowest_common_ancestor: similar routine for general DAGs
    lowest_common_ancestor: just a single pair for general DAGs
    r   r   Nz	The node z is not in the digraph.z0No root specified and tree has multiple sources.r0   z0Tree LCA only defined on trees; use DAG routine.zGraph contains a cycle.T)r&   r   r'   r   r*   
isinstancer   r   strr+   r   	in_degreer%   predr   booldfs_postorder_nodesr   union)r   rootr   	pair_dictur   nmsgdegufr   nodecolorsparents                 r"   r   r      sY    x 1v{))*KLL $	%3/JE 	 DAqV /A:%c!fX-DEC//#../ aLQaLQ	  |kk 		,FAsax#LC**3//qS^a/H&&s++		, |899 
BI #T(	$# F&&q$/ +t$)$541 	6Aay $$e);)Yr!u%555=QI$6d)Yr!u%555	6 4<&qvvd|4FHHVT"$*Ibj!+s,   A*H-B	H7HBHH;H5Hr   )NN)__doc__collectionsr   collections.abcr   r   	itertoolsr   networkxr   networkx.utilsr   r   r	   __all___dispatchabler
   r   r    r.   r"   <module>rQ      s    J # ( 3  L L \"h-  #h-V \"!  #!H \"r+  #r+r.   