
    wgQ                     Z   d Z ddlZddlmZ ddlZddlmZm	Z	 g dZ
 e	d      ej                  d               Z e	d      ej                  d               Zd	 Z e	d
       e	d      ej                  d                      Z G d d      ZddZd Z ej                  d      d        Zy)aw  
Algorithms for finding k-edge-connected components and subgraphs.

A k-edge-connected component (k-edge-cc) is a maximal set of nodes in G, such
that all pairs of node have an edge-connectivity of at least k.

A k-edge-connected subgraph (k-edge-subgraph) is a maximal set of nodes in G,
such that the subgraph of G defined by the nodes has an edge-connectivity at
least k.
    N)partial)arbitrary_elementnot_implemented_for)k_edge_componentsk_edge_subgraphsbridge_componentsEdgeComponentAuxGraph
multigraphc                 b   |dk  rt        d      | j                         r@|dk(  rt        j                  |       S t        j                  |       }|j                  |      S |dk(  rt        j                  |       S |dk(  rt        |       S t        j                  |       }|j                  |      S )a  Generates nodes in each maximal k-edge-connected component in G.

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

    k : Integer
        Desired edge connectivity

    Returns
    -------
    k_edge_components : a generator of k-edge-ccs. Each set of returned nodes
       will have k-edge-connectivity in the graph G.

    See Also
    --------
    :func:`local_edge_connectivity`
    :func:`k_edge_subgraphs` : similar to this function, but the subgraph
        defined by the nodes must also have k-edge-connectivity.
    :func:`k_components` : similar to this function, but uses node-connectivity
        instead of edge-connectivity

    Raises
    ------
    NetworkXNotImplemented
        If the input graph is a multigraph.

    ValueError:
        If k is less than 1

    Notes
    -----
    Attempts to use the most efficient implementation available based on k.
    If k=1, this is simply connected components for directed graphs and
    connected components for undirected graphs.
    If k=2 on an efficient bridge connected component algorithm from _[1] is
    run based on the chain decomposition.
    Otherwise, the algorithm from _[2] is used.

    Examples
    --------
    >>> import itertools as it
    >>> from networkx.utils import pairwise
    >>> paths = [
    ...     (1, 2, 4, 3, 1, 4),
    ...     (5, 6, 7, 8, 5, 7, 8, 6),
    ... ]
    >>> G = nx.Graph()
    >>> G.add_nodes_from(it.chain(*paths))
    >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths]))
    >>> # note this returns {1, 4} unlike k_edge_subgraphs
    >>> sorted(map(sorted, nx.k_edge_components(G, k=3)))
    [[1, 4], [2], [3], [5, 6, 7, 8]]

    References
    ----------
    .. [1] https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29
    .. [2] Wang, Tianhao, et al. (2015) A simple algorithm for finding all
        k-edge-connected components.
        http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264
       k cannot be less than 1   )	
ValueErroris_directednxstrongly_connected_componentsr	   	constructr   connected_componentsr   )Gk	aux_graphs      v/home/mcse/projects/flask/flask-venv/lib/python3.12/site-packages/networkx/algorithms/connectivity/edge_kcomponents.pyr   r      s    B 	1u233}}633A66 .77:I..q116**1--!V$Q''-77:I..q11    c                     |dk  rt        d      | j                         r|dk  rt        | |      S t        | |      S |dk  rt        | |      S t        | |      S )u  Generates nodes in each maximal k-edge-connected subgraph in G.

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

    k : Integer
        Desired edge connectivity

    Returns
    -------
    k_edge_subgraphs : a generator of k-edge-subgraphs
        Each k-edge-subgraph is a maximal set of nodes that defines a subgraph
        of G that is k-edge-connected.

    See Also
    --------
    :func:`edge_connectivity`
    :func:`k_edge_components` : similar to this function, but nodes only
        need to have k-edge-connectivity within the graph G and the subgraphs
        might not be k-edge-connected.

    Raises
    ------
    NetworkXNotImplemented
        If the input graph is a multigraph.

    ValueError:
        If k is less than 1

    Notes
    -----
    Attempts to use the most efficient implementation available based on k.
    If k=1, or k=2 and the graph is undirected, then this simply calls
    `k_edge_components`.  Otherwise the algorithm from _[1] is used.

    Examples
    --------
    >>> import itertools as it
    >>> from networkx.utils import pairwise
    >>> paths = [
    ...     (1, 2, 4, 3, 1, 4),
    ...     (5, 6, 7, 8, 5, 7, 8, 6),
    ... ]
    >>> G = nx.Graph()
    >>> G.add_nodes_from(it.chain(*paths))
    >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths]))
    >>> # note this does not return {1, 4} unlike k_edge_components
    >>> sorted(map(sorted, nx.k_edge_subgraphs(G, k=3)))
    [[1], [2], [3], [4], [5, 6, 7, 8]]

    References
    ----------
    .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs
        from a large graph.  ACM International Conference on Extending Database
        Technology 2012 480-–491.
        https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf
    r   r   r   )r   r   r   _k_edge_subgraphs_nodes)r   r   s     r   r   r   n   sg    z 	1u233}}6 %Q***1a006 %Q***1a00r   c              #   d   K   t        | |      D ]  }t        |j                                 yw)ziHelper to get the nodes from the subgraphs.

    This allows k_edge_subgraphs to return a generator.
    N)general_k_edge_subgraphssetnodes)r   r   Cs      r   r   r      s.     
 &a+ !'')ns   .0directedc              #      K   | j                         }|j                  t        j                  |              t        j                  |      E d{    y7 w)a  Finds all bridge-connected components G.

    Parameters
    ----------
    G : NetworkX undirected graph

    Returns
    -------
    bridge_components : a generator of 2-edge-connected components


    See Also
    --------
    :func:`k_edge_subgraphs` : this function is a special case for an
        undirected graph where k=2.
    :func:`biconnected_components` : similar to this function, but is defined
        using 2-node-connectivity instead of 2-edge-connectivity.

    Raises
    ------
    NetworkXNotImplemented
        If the input graph is directed or a multigraph.

    Notes
    -----
    Bridge-connected components are also known as 2-edge-connected components.

    Examples
    --------
    >>> # The barbell graph with parameter zero has a single bridge
    >>> G = nx.barbell_graph(5, 0)
    >>> from networkx.algorithms.connectivity.edge_kcomponents import bridge_components
    >>> sorted(map(sorted, bridge_components(G)))
    [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
    N)copyremove_edges_fromr   bridgesr   )r   Hs     r   r   r      s>     N 	
A

1&&&q)))s   AAAAc                   ,    e Zd ZdZed        Zd Zd Zy)r	   a  A simple algorithm to find all k-edge-connected components in a graph.

    Constructing the auxiliary graph (which may take some time) allows for the
    k-edge-ccs to be found in linear time for arbitrary k.

    Notes
    -----
    This implementation is based on [1]_. The idea is to construct an auxiliary
    graph from which the k-edge-ccs can be extracted in linear time. The
    auxiliary graph is constructed in $O(|V|\cdot F)$ operations, where F is the
    complexity of max flow. Querying the components takes an additional $O(|V|)$
    operations. This algorithm can be slow for large graphs, but it handles an
    arbitrary k and works for both directed and undirected inputs.

    The undirected case for k=1 is exactly connected components.
    The undirected case for k=2 is exactly bridge connected components.
    The directed case for k=1 is exactly strongly connected components.

    References
    ----------
    .. [1] Wang, Tianhao, et al. (2015) A simple algorithm for finding all
        k-edge-connected components.
        http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264

    Examples
    --------
    >>> import itertools as it
    >>> from networkx.utils import pairwise
    >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph
    >>> # Build an interesting graph with multiple levels of k-edge-ccs
    >>> paths = [
    ...     (1, 2, 3, 4, 1, 3, 4, 2),  # a 3-edge-cc (a 4 clique)
    ...     (5, 6, 7, 5),  # a 2-edge-cc (a 3 clique)
    ...     (1, 5),  # combine first two ccs into a 1-edge-cc
    ...     (0,),  # add an additional disconnected 1-edge-cc
    ... ]
    >>> G = nx.Graph()
    >>> G.add_nodes_from(it.chain(*paths))
    >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths]))
    >>> # Constructing the AuxGraph takes about O(n ** 4)
    >>> aux_graph = EdgeComponentAuxGraph.construct(G)
    >>> # Once constructed, querying takes O(n)
    >>> sorted(map(sorted, aux_graph.k_edge_components(k=1)))
    [[0], [1, 2, 3, 4, 5, 6, 7]]
    >>> sorted(map(sorted, aux_graph.k_edge_components(k=2)))
    [[0], [1, 2, 3, 4], [5, 6, 7]]
    >>> sorted(map(sorted, aux_graph.k_edge_components(k=3)))
    [[0], [1, 2, 3, 4], [5], [6], [7]]
    >>> sorted(map(sorted, aux_graph.k_edge_components(k=4)))
    [[0], [1], [2], [3], [4], [5], [6], [7]]

    The auxiliary graph is primarily used for k-edge-ccs but it
    can also speed up the queries of k-edge-subgraphs by refining the
    search space.

    >>> import itertools as it
    >>> from networkx.utils import pairwise
    >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph
    >>> paths = [
    ...     (1, 2, 4, 3, 1, 4),
    ... ]
    >>> G = nx.Graph()
    >>> G.add_nodes_from(it.chain(*paths))
    >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths]))
    >>> aux_graph = EdgeComponentAuxGraph.construct(G)
    >>> sorted(map(sorted, aux_graph.k_edge_subgraphs(k=3)))
    [[1], [2], [3], [4]]
    >>> sorted(map(sorted, aux_graph.k_edge_components(k=3)))
    [[1, 4], [2], [3]]
    c                      t        d      d       |       fd|j                         }|j                  |j                                |j	                  |j                         d       t        j                         }|j                         dkD  r=t        |j                               }t        |j                               } ||||        |        }||_        ||_        |S )aM  Builds an auxiliary graph encoding edge-connectivity between nodes.

        Notes
        -----
        Given G=(V, E), initialize an empty auxiliary graph A.
        Choose an arbitrary source node s.  Initialize a set N of available
        nodes (that can be used as the sink). The algorithm picks an
        arbitrary node t from N - {s}, and then computes the minimum st-cut
        (S, T) with value w. If G is directed the minimum of the st-cut or
        the ts-cut is used instead. Then, the edge (s, t) is added to the
        auxiliary graph with weight w. The algorithm is called recursively
        first using S as the available nodes and s as the source, and then
        using T and t. Recursion stops when the source is the only available
        node.

        Parameters
        ----------
        G : NetworkX graph
        r
   c                     | S N )r   s    r   <lambda>z1EdgeComponentAuxGraph.construct.<locals>.<lambda>Q  s    A r   c                 l   |h|k(  ry t        ||hz
        }t        j                  | ||      \  }\  }}| j                         r(t        j                  | ||      \  }\  }	}
||k  r||
|	}}}|j	                  |||        | |||j                  |              | |||j                  |             y )N)weight)r   r   minimum_cutr   add_edgeintersection)r&   AsourceavailsinkvalueSTvalue_T_S__recursive_builds              r   r<   z9EdgeComponentAuxGraph.construct.<locals>._recursive_buildS  s    x5 $UfX%56DNN1fd;ME6Aq}}#%>>!T6#B RE>"("ba1EJJvtEJ2Q65+=+=a+@AQ4););A)>?r   r   )capacityr   )r   	__class__add_nodes_fromr   add_edges_fromedgesr   Graphnumber_of_nodesr   r   r2   r&   )r	   r   r&   r2   r3   r4   selfr<   s          @r   r   zEdgeComponentAuxGraph.construct;  s    , 	7)L)+6q9	@( KKM	#	Q/ HHJ "&qwwy1F	NE Q651 %&r   c              #   f  K   dk  rt        d      | j                  }t        j                  |d      }t        j                         }|j                  |j                                |j                  fd|j                         D               t        j                  |      E d{    y7 w)a-  Queries the auxiliary graph for k-edge-connected components.

        Parameters
        ----------
        k : Integer
            Desired edge connectivity

        Returns
        -------
        k_edge_components : a generator of k-edge-ccs

        Notes
        -----
        Given the auxiliary graph, the k-edge-connected components can be
        determined in linear time by removing all edges with weights less than
        k from the auxiliary graph.  The resulting connected components are the
        k-edge-ccs in the original graph.
        r   r   r.   c              3   4   K   | ]  \  }}|k\  s|  y wr*   r+   .0ewr   s      r   	<genexpr>z:EdgeComponentAuxGraph.k_edge_components.<locals>.<genexpr>       Etq!a1fE   N)
r   r2   r   get_edge_attributesrB   r?   r   r@   itemsr   )rD   r   r2   aux_weightsRs    `   r   r   z'EdgeComponentAuxGraph.k_edge_components  s     & q5677FF ,,Q9HHJ	#	E{'8'8':EE **1---s   B&B1)B/*B1c              #     K   dk  rt        d      | j                  }| j                  }t        j                  |d      }t        j
                         }|j                  |j                                |j                  fd|j                         D               t        j                  |      D ]B  }t        |      k  r|D ]  }|h 	 |j                  |      }t        |      E d{    D y7 w)a:  Queries the auxiliary graph for k-edge-connected subgraphs.

        Parameters
        ----------
        k : Integer
            Desired edge connectivity

        Returns
        -------
        k_edge_subgraphs : a generator of k-edge-subgraphs

        Notes
        -----
        Refines the k-edge-ccs into k-edge-subgraphs. The running time is more
        than $O(|V|)$.

        For single values of k it is faster to use `nx.k_edge_subgraphs`.
        But for multiple values of k, it can be faster to build AuxGraph and
        then use this method.
        r   r   r.   c              3   4   K   | ]  \  }}|k\  s|  y wr*   r+   rG   s      r   rK   z9EdgeComponentAuxGraph.k_edge_subgraphs.<locals>.<genexpr>  rL   rM   N)r   r&   r2   r   rN   rB   r?   r   r@   rO   r   lensubgraphr   )	rD   r   r&   r2   rP   rQ   ccnoder    s	    `       r   r   z&EdgeComponentAuxGraph.k_edge_subgraphs  s     * q5677FFFF ,,Q9HHJ	#	E{'8'8':EE ))!, 	2B2w{ !D&L! JJrN+Aq111	2 2s   C-C:0C81C:N)__name__
__module____qualname____doc__classmethodr   r   r   r+   r   r   r	   r	      s+    EP A AF.B*2r   r	   c              #   b  K   | j                         rxt               }| j                  |      D ]   \  }}||k  s|j                  |       | " | j	                  |      D ]%  \  }}||vs||k  s|j                  |       | ' y| j                  |      D ]  \  }}||k  s|  yw)z1Helper for finding nodes with degree less than k.N)r   r   
out_degreeadd	in_degreedegree)r   r   nbunchseenrW   ra   s         r   _low_degree_nodesrd     s      	}}uLL0 	LD&z
	 KK/ 	LD&4FQJ
	 HHV, 	LD&z
	s   7B/2B/-B/34B/(B/c              #     K   | j                         }t        t        ||            }|rt        t        j                  j                  t        |j                  |                  }|j                  |       |j                  |       |D ]  }|h 	 t        t        |||            }|r| j                         rt        j                  |      E d{    yt        j                  |      E d{    y7 #7 w)zHelper for filtering components that can't be k-edge-connected.

    Removes and generates each node with degree less than k.  Then generates
    remaining components where all nodes have degree at least k.
    N)r#   r   rd   itchainfrom_iterablemap	neighborsdifference_updateremove_nodes_fromr   r   r   r   )r   r   r&   
singletonsrb   rW   s         r   _high_degree_componentsrn     s      	
A&q!,-J
RXX++CZ,HIJ  ,	J' 	D&L	*1a89
  	}}33A666**1--- 	7-s*   B*C=-(C=C9C=3C;4C=;C=T)returns_graphc              #     K   |dk  rt        d      t        t        |      }| j                         |k  r8| j	                         D ]$  }| j                  |g      j                          & y ||       D ch c]!  }| j                  |      j                         # }}|r|j                         }|j                         dk(  r| nvt        j                  |      }t        |      }||k  rM|j                  |        ||      D ]0  }|j                  |j                  |      j                                2 n| |ryyc c}w w)u  General algorithm to find all maximal k-edge-connected subgraphs in `G`.

    Parameters
    ----------
    G : nx.Graph
       Graph in which all maximal k-edge-connected subgraphs will be found.

    k : int

    Yields
    ------
    k_edge_subgraphs : Graph instances that are k-edge-subgraphs
        Each k-edge-subgraph contains a maximal set of nodes that defines a
        subgraph of `G` that is k-edge-connected.

    Notes
    -----
    Implementation of the basic algorithm from [1]_.  The basic idea is to find
    a global minimum cut of the graph. If the cut value is at least k, then the
    graph is a k-edge-connected subgraph and can be added to the results.
    Otherwise, the cut is used to split the graph in two and the procedure is
    applied recursively. If the graph is just a single node, then it is also
    added to the results. At the end, each result is either guaranteed to be
    a single node or a subgraph of G that is k-edge-connected.

    This implementation contains optimizations for reducing the number of calls
    to max-flow, but there are other optimizations in [1]_ that could be
    implemented.

    References
    ----------
    .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs
        from a large graph.  ACM International Conference on Extending Database
        Technology 2012 480-–491.
        https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf

    Examples
    --------
    >>> from networkx.utils import pairwise
    >>> paths = [
    ...     (11, 12, 13, 14, 11, 13, 14, 12),  # a 4-clique
    ...     (21, 22, 23, 24, 21, 23, 24, 22),  # another 4-clique
    ...     # connect the cliques with high degree but low connectivity
    ...     (50, 13),
    ...     (12, 50, 22),
    ...     (13, 102, 23),
    ...     (14, 101, 24),
    ... ]
    >>> G = nx.Graph(it.chain(*[pairwise(path) for path in paths]))
    >>> sorted(len(k_sg) for k_sg in k_edge_subgraphs(G, k=3))
    [1, 1, 1, 4, 4]
    r   r   )r   N)r   r   rn   rC   r   rU   r#   popr   minimum_edge_cutrT   r$   r_   )	r   r   find_ccsrW   rV   R0G1	cut_edges	cut_values	            r   r   r     s/    l 	1u233 .!4H 	QGGI 	,D**dV$))++	, +31+	6B!**R.


	6B	6
VVX1$H ++B/III1}$$Y/"2, 3BFF2;;r?//123   
7s   A7E9&EB$EEr*   )r[   	itertoolsrf   	functoolsr   networkxr   networkx.utilsr   r   __all___dispatchabler   r   r   r   r	   rd   rn   r   r+   r   r   <module>r~      s   	    A \"O2  #O2d \"J1  #J1Z Z \"&*  # !&*RX2 X2v*.2 %T &Tr   