
    h%                         d Z ddlmZmZ ddlZg dZ ej                  ddd      dd       Z ej                  ddd      d	        Z	 ej                  ddd      d
        Z
 ej                  dd      d        Zy)zOperations on many graphs.    )chainrepeatN)	union_allcompose_alldisjoint_union_allintersection_allz[graphs]T)graphspreserve_all_attrsreturns_graphc                 V   d}t               }d t        |t        d            }fdt        | |      D        } t	        |       D ]R  \  }}t        |j
                        }|dk(  r|j                         }n|j                         |j                         k7  rt        j                  d      |j                         |j                         k7  rt        j                  d      |j                  |      st        j                  d      ||z  }|j                  j                  |j                         |j                  |j                  d	             |j                  |j                         r|j!                  dd
      n|j!                  d	             U |t#        d      |S )ag  Returns the union of all graphs.

    The graphs must be disjoint, otherwise an exception is raised.

    Parameters
    ----------
    graphs : iterable
       Iterable of NetworkX graphs

    rename : iterable , optional
       Node names of graphs can be changed by specifying the tuple
       rename=('G-','H-') (for example).  Node "u" in G is then renamed
       "G-u" and "v" in H is renamed "H-v". Infinite generators (like itertools.count)
       are also supported.

    Returns
    -------
    U : a graph with the same type as the first graph in list

    Raises
    ------
    ValueError
       If `graphs` is an empty list.

    NetworkXError
        In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.

    Notes
    -----
    For operating on mixed type graphs, they should be converted to the same type.
    >>> G = nx.Graph()
    >>> H = nx.DiGraph()
    >>> GH = union_all([nx.DiGraph(G), H])

    To force a disjoint union with node relabeling, use
    disjoint_union_all(G,H) or convert_node_labels_to integers().

    Graph, edge, and node attributes are propagated to the union graph.
    If a graph attribute is present in multiple graphs, then the value
    from the last graph in the list with that attribute is used.

    Examples
    --------
    >>> G1 = nx.Graph([(1, 2), (2, 3)])
    >>> G2 = nx.Graph([(4, 5), (5, 6)])
    >>> result_graph = nx.union_all([G1, G2])
    >>> result_graph.nodes()
    NodeView((1, 2, 3, 4, 5, 6))
    >>> result_graph.edges()
    EdgeView([(1, 2), (2, 3), (4, 5), (5, 6)])

    See Also
    --------
    union
    disjoint_union_all
    Nc                 B    | S fd}t        j                  | |      S )Nc                      |  S N )xprefixs    ^/var/www/django_project/virt/lib/python3.12/site-packages/networkx/algorithms/operators/all.pylabelz,union_all.<locals>.add_prefix.<locals>.labelL   s    XaS>!    )nxrelabel_nodes)graphr   r   s    ` r   
add_prefixzunion_all.<locals>.add_prefixH   s'    >L	" u--r   c              3   6   K   | ]  \  }} ||        y wr   r   ).0Gnamer   s      r   	<genexpr>zunion_all.<locals>.<genexpr>R   s     EgajD!Es   r   *All graphs must be directed or undirected.)All graphs must be graphs or multigraphs.zThe node sets of the graphs are not disjoint.
Use `rename` to specify prefixes for the graphs or use
disjoint_union(G1, G2, ..., GN).Tdatakeysr"   z'cannot apply union_all to an empty list)setr   r   zip	enumeratenodes	__class__is_directedr   NetworkXErroris_multigraph
isdisjointr   updateadd_nodes_fromadd_edges_fromedges
ValueError)r	   renameR
seen_nodesir   G_nodes_setr   s          @r   r   r   
   sk   t 	AJ. 66$<(FEVV1DEF&! 
1!''l6A]]_/""#OPP__!//"33""#NOO&&{3""3  	k!
	qww	d+,	-.__->AGGDG)AGGQUGDV	
'
. 	yBCCHr   c                 .    d }t         ||             }|S )ad  Returns the disjoint union of all graphs.

    This operation forces distinct integer node labels starting with 0
    for the first graph in the list and numbering consecutively.

    Parameters
    ----------
    graphs : iterable
       Iterable of NetworkX graphs

    Returns
    -------
    U : A graph with the same type as the first graph in list

    Raises
    ------
    ValueError
       If `graphs` is an empty list.

    NetworkXError
        In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.

    Examples
    --------
    >>> G1 = nx.Graph([(1, 2), (2, 3)])
    >>> G2 = nx.Graph([(4, 5), (5, 6)])
    >>> U = nx.disjoint_union_all([G1, G2])
    >>> list(U.nodes())
    [0, 1, 2, 3, 4, 5]
    >>> list(U.edges())
    [(0, 1), (1, 2), (3, 4), (4, 5)]

    Notes
    -----
    For operating on mixed type graphs, they should be converted to the same type.

    Graph, edge, and node attributes are propagated to the union graph.
    If a graph attribute is present in multiple graphs, then the value
    from the last graph in the list with that attribute is used.
    c              3   l   K   d}| D ])  }t        j                  ||       |t        |      z  }+ y w)Nr   )first_label)r   convert_node_labels_to_integerslen)r	   r:   r   s      r   yield_relabeledz+disjoint_union_all.<locals>.yield_relabeled   s;      	"A44QKPP3q6!K	"s   24)r   )r	   r=   r4   s      r   r   r   q   s    V" 	/&)*AHr   c                 f   d}t        |       D ]  \  }}|dk(  r|j                         }nl|j                         |j                         k7  rt        j                  d      |j                         |j                         k7  rt        j                  d      |j                  j                  |j                         |j                  |j                  d             |j                  |j                         r|j                  dd      n|j                  d              |t        d      |S )	aU  Returns the composition of all graphs.

    Composition is the simple union of the node sets and edge sets.
    The node sets of the supplied graphs need not be disjoint.

    Parameters
    ----------
    graphs : iterable
       Iterable of NetworkX graphs

    Returns
    -------
    C : A graph with the same type as the first graph in list

    Raises
    ------
    ValueError
       If `graphs` is an empty list.

    NetworkXError
        In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.

    Examples
    --------
    >>> G1 = nx.Graph([(1, 2), (2, 3)])
    >>> G2 = nx.Graph([(3, 4), (5, 6)])
    >>> C = nx.compose_all([G1, G2])
    >>> list(C.nodes())
    [1, 2, 3, 4, 5, 6]
    >>> list(C.edges())
    [(1, 2), (2, 3), (3, 4), (5, 6)]

    Notes
    -----
    For operating on mixed type graphs, they should be converted to the same type.

    Graph, edge, and node attributes are propagated to the union graph.
    If a graph attribute is present in multiple graphs, then the value
    from the last graph in the list with that attribute is used.
    Nr   r   r    Tr!   r#   z)cannot apply compose_all to an empty list)r'   r)   r*   r   r+   r,   r   r.   r/   r(   r0   r1   r2   )r	   r4   r6   r   s       r   r   r      s    T 	A &! 
16A]]_/""#OPP__!//"33""#NOO	qww	d+,	-.__->AGGDG)AGGQUGDV	

 	yDEEHr   )r	   r   c                    d}t        |       D ]#  \  }}t        |j                        }t        |j                        }|j	                         sS|j                         r"|j                  d t        |      D               n!|j                  d t        |      D               |dk(  r|j                         }|}|}|j	                         |j	                         k7  rt        j                  d      |j                         |j                         k7  rt        j                  d      |z  }|z  }& |t        d      |j                         |j                         |S )a   Returns a new graph that contains only the nodes and the edges that exist in
    all graphs.

    Parameters
    ----------
    graphs : iterable
       Iterable of NetworkX graphs

    Returns
    -------
    R : A new graph with the same type as the first graph in list

    Raises
    ------
    ValueError
       If `graphs` is an empty list.

    NetworkXError
        In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.

    Notes
    -----
    For operating on mixed type graphs, they should be converted to the same type.

    Attributes from the graph, nodes, and edges are not copied to the new
    graph.

    The resulting graph can be updated with attributes if desired. For example, code which adds the minimum attribute for each node across all graphs could work.
    >>> g = nx.Graph()
    >>> g.add_node(0, capacity=4)
    >>> g.add_node(1, capacity=3)
    >>> g.add_edge(0, 1)

    >>> h = g.copy()
    >>> h.nodes[0]["capacity"] = 2

    >>> gh = nx.intersection_all([g, h])

    >>> new_node_attr = {
    ...     n: min(*(anyG.nodes[n].get("capacity", float("inf")) for anyG in [g, h]))
    ...     for n in gh
    ... }
    >>> nx.set_node_attributes(gh, new_node_attr, "new_capacity")
    >>> gh.nodes(data=True)
    NodeDataView({0: {'new_capacity': 2}, 1: {'new_capacity': 3}})

    Examples
    --------
    >>> G1 = nx.Graph([(1, 2), (2, 3)])
    >>> G2 = nx.Graph([(2, 3), (3, 4)])
    >>> R = nx.intersection_all([G1, G2])
    >>> list(R.nodes())
    [2, 3]
    >>> list(R.edges())
    [(2, 3)]

    Nc              3   .   K   | ]  \  }}}|||f  y wr   r   )r   uvks       r   r   z#intersection_all.<locals>.<genexpr>+  s     "NAqAq!9"Ns   c              3   *   K   | ]  \  }}||f  y wr   r   )r   rA   rB   s      r   r   z#intersection_all.<locals>.<genexpr>-  s     "HdaAq6"Hs   r   r   r    z.cannot apply intersection_all to an empty list)r'   r%   r(   r1   r*   r,   r.   listr)   r   r+   r2   r/   r0   )r	   r4   r6   r   r7   G_edges_setnode_intersectionedge_intersections           r   r   r      s9   v 	A&! -1!''l!''l}} """ND<M"NN"""Hd;6G"HH6A + +]]_/""#OPP__!//"33""#NOO,,'-* 	yIJJ&'&'Hr   )r   )__doc__	itertoolsr   r   networkxr   __all___dispatchabler   r   r   r   r   r   r   <module>rN      s      # 
P DQc RcL DQ2 R2j DQ> R>B 48W 9Wr   