o
    ˷e                      @   s   d Z ddlmZ ddlmZ ddlmZ ddlZddl	m
Z
 ddlmZ e
ZdgZed	dd
dZdd Zdd Zdd Zdd ZdS )z,
Moody and White algorithm for k-components
    )defaultdict)combinations)
itemgetterN)edmonds_karp)not_implemented_fork_componentsdirectedc              	      s  t t}|du r
t}t D ]}t|}t|dkr"|d | q fddt D }|D ]}t|}t|dkrD|d | q1|D ]}t|dkrPqGtj	||d}	|	dkrd||	 t| ttj
||	|d}
|	t||
|	fg}|r|d \}}z:t|}||}tj	||d}||kr|dkr|| t| ttj
|||d}
|
r||t||
|f W n ty   |  Y nw |syqGt|S )	a7  Returns the k-component structure of a graph G.

    A `k`-component is a maximal subgraph of a graph G that has, at least,
    node connectivity `k`: we need to remove at least `k` nodes to break it
    into more components. `k`-components have an inherent hierarchical
    structure because they are nested in terms of connectivity: a connected
    graph can contain several 2-components, each of which can contain
    one or more 3-components, and so forth.

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

    flow_func : function
        Function to perform the underlying flow computations. Default value
        :meth:`edmonds_karp`. This function performs better in sparse graphs with
        right tailed degree distributions. :meth:`shortest_augmenting_path` will
        perform better in denser graphs.

    Returns
    -------
    k_components : dict
        Dictionary with all connectivity levels `k` in the input Graph as keys
        and a list of sets of nodes that form a k-component of level `k` as
        values.

    Raises
    ------
    NetworkXNotImplemented
        If the input graph is directed.

    Examples
    --------
    >>> # Petersen graph has 10 nodes and it is triconnected, thus all
    >>> # nodes are in a single component on all three connectivity levels
    >>> G = nx.petersen_graph()
    >>> k_components = nx.k_components(G)

    Notes
    -----
    Moody and White [1]_ (appendix A) provide an algorithm for identifying
    k-components in a graph, which is based on Kanevsky's algorithm [2]_
    for finding all minimum-size node cut-sets of a graph (implemented in
    :meth:`all_node_cuts` function):

        1. Compute node connectivity, k, of the input graph G.

        2. Identify all k-cutsets at the current level of connectivity using
           Kanevsky's algorithm.

        3. Generate new graph components based on the removal of
           these cutsets. Nodes in a cutset belong to both sides
           of the induced cut.

        4. If the graph is neither complete nor trivial, return to 1;
           else end.

    This implementation also uses some heuristics (see [3]_ for details)
    to speed up the computation.

    See also
    --------
    node_connectivity
    all_node_cuts
    biconnected_components : special case of this function when k=2
    k_edge_components : similar to this function, but uses edge-connectivity
        instead of node-connectivity

    References
    ----------
    .. [1]  Moody, J. and D. White (2003). Social cohesion and embeddedness:
            A hierarchical conception of social groups.
            American Sociological Review 68(1), 103--28.
            http://www2.asanet.org/journals/ASRFeb03MoodyWhite.pdf

    .. [2]  Kanevsky, A. (1993). Finding all minimum-size separating vertex
            sets in a graph. Networks 23(6), 533--541.
            http://onlinelibrary.wiley.com/doi/10.1002/net.3230230604/abstract

    .. [3]  Torrents, J. and F. Ferraro (2015). Structural Cohesion:
            Visualization and Heuristics for Fast Computation.
            https://arxiv.org/pdf/1503.04476v1

    N   c                    s   g | ]}  |qS  )subgraph.0cGr
   c/var/www/ideatree/venv/lib/python3.10/site-packages/networkx/algorithms/connectivity/kcomponents.py
<listcomp>v       z k_components.<locals>.<listcomp>   )	flow_func)kr   )r   listdefault_flow_funcnxconnected_componentssetlenappendbiconnected_componentsnode_connectivityall_node_cuts_generate_partitionnextr   StopIterationpop_reconstruct_k_components)r   r   r   	componentcompbicomponentsbicomponentbicompBr   cutsstackparent_k	partitionnodesCthis_kr
   r   r   r      sP   Y
c                 #   st    t  }dd t| D | | fddtdD  t |D ]}tjfdd|D  V  q(dS )	as  Merge sets that share k or more elements.

    See: http://rosettacode.org/wiki/Set_consolidation

    The iterative python implementation posted there is
    faster than this because of the overhead of building a
    Graph and calling nx.connected_components, but it's not
    clear for us if we can use it in NetworkX because there
    is no licence for the code.

    c                 S   s   i | ]\}}||qS r
   r
   )r   isr
   r
   r   
<dictcomp>   r   z _consolidate.<locals>.<dictcomp>c                 3   s4    | ]\}}t | | @  kr||fV  qd S N)r   )r   uvr   r1   r
   r   	<genexpr>   s    *z_consolidate.<locals>.<genexpr>r   c                    s   g | ]} | qS r
   r
   r   n)r1   r
   r   r      s    z _consolidate.<locals>.<listcomp>N)	r   Graph	enumerateadd_nodes_fromadd_edges_fromr   r   r   union)setsr   r   r'   r
   r:   r   _consolidate   s   
rD   c                 #   s    dd }g } fdd|   D dd |D  }| |}t|D ](}t|}|D ]}	|	D ]}
|| |
|r<||
 q/q+t||  k rK|| q#t	| d E d H  d S )Nc                 S   s    | | D ]	}||v r dS qdS )NTFr
   )r   noder0   r=   r
   r
   r   has_nbrs_in_partition   s
   z2_generate_partition.<locals>.has_nbrs_in_partitionc                    s   h | ]
\}}| kr|qS r
   r
   )r   r=   dr   r
   r   	<setcomp>   s    z&_generate_partition.<locals>.<setcomp>c                 S   s   h | ]	}|D ]}|qqS r
   r
   )r   cutr=   r
   r
   r   rI      s    r	   )
degreer   r   r   r   addr   orderr   rD   )r   r-   r   rF   
componentsr1   Hccr'   rJ   rE   r
   rH   r   r"      s"   $


r"   c                    s   t  }t| }ttd|d D ]S}||kr"tt| | |||< q|| vr4tt||d  |||< qtj| |    fdd||d  D }|rXtt| | | |||< qtt| | |||< q|S )Nr	   c                    s&   g | ]}t  fd d|D r|qS )c                 3   s    | ]}| vV  qd S r7   r
   r<   
nodes_at_kr
   r   r;      s    z7_reconstruct_k_components.<locals>.<listcomp>.<genexpr>)anyr   rQ   r
   r   r      s   & z-_reconstruct_k_components.<locals>.<listcomp>)dictmaxreversedranger   rD   r   rB   )k_compsresultmax_kr   to_addr
   rQ   r   r&      s   r&   c                 C   sB   i }t |  tddD ]\}}|D ]}|D ]}|||< qqq|S )Nr   )key)sorteditemsr   )kcompsrY   r   compsr(   rE   r
   r
   r   build_k_number_dict   s   
ra   r7   )__doc__collectionsr   	itertoolsr   operatorr   networkxr   networkx.algorithms.flowr   networkx.utilsr   r   __all__r   rD   r"   r&   ra   r
   r
   r
   r   <module>   s      
