o
    hA                     @   s  d Z ddlmZ ddlmZmZ ddlZddlm	Z	m
Z
 g dZdZdZd	d
 eeD Zdd Ze	dejd ddZejdd Ze	dejdd Ze	dejdddd Ze	dejdd Ze	dejdd Ze	de
dejdddd ddZdS )!z*Functions for analyzing triads of a graph.    )defaultdict)combinationspermutationsN)not_implemented_forpy_random_state)triadic_censusis_triadall_triplets
all_triadstriads_by_type
triad_typerandom_triad)@      r      r            r   r         r   r   r      r   r   r   r   r   	   r      r   
   r      r   r         r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      )003012102021D021U021C111D111U030T030C201120D120U120C210300c                 C   s   i | ]\}}|t |d   qS )r   )TRIAD_NAMES).0icode r2   n/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/networkx/algorithms/triads.py
<dictcomp>t   s    r4   c                    sJ   ||df||df||df||df||df||dff}t  fdd|D S )	zReturns the integer code of the given triad.

    This is some fancy magic that comes from Batagelj and Mrvar's paper. It
    treats each edge joining a pair of `v`, `u`, and `w` as a bit in
    the binary representation of an integer.

    r   r   r   r   r       c                 3   s&    | ]\}}}| | v r|V  qd S Nr2   )r/   uvxGr2   r3   	<genexpr>   s   $ z_tricode.<locals>.<genexpr>)sum)r;   r8   r7   wcombosr2   r:   r3   _tricodew   s   4r@   
undirectedc                    s  t  ||durt|tkrtdt t }dd tD }|r? j }|fddt|D   fdd D } fdd D |r| fd	d|D tfd
d|D }|d }tfdd|D }|d }	dd tD }
D ]}|| }| }|rd } } }}|D ]}|| || krq|| }||B ||h }|D ]3}|| || k s|| ||   k r|| k rn q||| vrt	 |||}|
t
|   d7  < q||v r|
d  t| d 7  < n|
d  t| d 7  < |rA|vrA| }|t|| @ 7 }|t||  7 }| }|t|| @ 7 }|t||  7 }q|ra|
d  |||d   7  < |
d  |	||d   7  < qd  d  d }||d  |d  d }|| }|t|
  |
d< |
S )am  Determines the triadic census of a directed graph.

    The triadic census is a count of how many of the 16 possible types of
    triads are present in a directed graph. If a list of nodes is passed, then
    only those triads are taken into account which have elements of nodelist in them.

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph
    nodelist : list
        List of nodes for which you want to calculate triadic census

    Returns
    -------
    census : dict
       Dictionary with triad type as keys and number of occurrences as values.

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1), (3, 4), (4, 1), (4, 2)])
    >>> triadic_census = nx.triadic_census(G)
    >>> for key, value in triadic_census.items():
    ...     print(f"{key}: {value}")
    003: 0
    012: 0
    102: 0
    021D: 0
    021U: 0
    021C: 0
    111D: 0
    111U: 0
    030T: 2
    030C: 2
    201: 0
    120D: 0
    120U: 0
    120C: 0
    210: 0
    300: 0

    Notes
    -----
    This algorithm has complexity $O(m)$ where $m$ is the number of edges in
    the graph.

    For undirected graphs, the triadic census can be computed by first converting
    the graph into a directed graph using the ``G.to_directed()`` method.
    After this conversion, only the triad types 003, 102, 201 and 300 will be
    present in the undirected scenario.

    Raises
    ------
    ValueError
        If `nodelist` contains duplicate nodes or nodes not in `G`.
        If you want to ignore this you can preprocess with `set(nodelist) & G.nodes`

    See also
    --------
    triad_graph

    References
    ----------
    .. [1] Vladimir Batagelj and Andrej Mrvar, A subquadratic triad census
        algorithm for large sparse networks with small maximum degree,
        University of Ljubljana,
        http://vlado.fmf.uni-lj.si/pub/networks/doc/triads/triads.pdf

    Nz3nodelist includes duplicate nodes or nodes not in Gc                 S   s   i | ]\}}||qS r2   r2   r/   r0   nr2   r2   r3   r4      s    z"triadic_census.<locals>.<dictcomp>c                 3   s     | ]\}}||  fV  qd S r6   r2   rB   )Nr2   r3   r<          z!triadic_census.<locals>.<genexpr>c                    s*   i | ]}| j |   j|  B qS r2   predkeyssuccr/   rC   r:   r2   r3   r4         * c                    s*   i | ]}| j |   j|  @ qS r2   rF   rJ   r:   r2   r3   r4      rK   c                    s*   i | ]}| j |   j|  A qS r2   rF   rJ   r:   r2   r3   r4      rK   c                 3   s*    | ]}| D ]	}| vrd V  qqdS r   Nr2   r/   rC   nbr)nodesetsgl_nbrsr2   r3   r<         ( r   c                 3   s*    | ]} | D ]	}|vrd V  qqdS rL   r2   rM   )dbl_nbrsrO   r2   r3   r<      rQ   c                 S   s   i | ]}|d qS )r   r2   )r/   namer2   r2   r3   r4      s    r   r   r    r   r   r   )setnbunch_iterlen
ValueError	enumeratenodesupdater=   r.   r@   TRICODE_TO_NAMEvalues)r;   nodelistNnotmnot_nodesetnbrssglsgl_edges_outsidedbldbl_edges_outsidecensusr8   vnbrs	dbl_vnbrssgl_unbrs_bdysgl_unbrs_outdbl_unbrs_bdydbl_unbrs_outr7   unbrs	neighborsr>   r1   	sgl_unbrs	dbl_unbrstotal_trianglestriangles_without_nodesettotal_censusr2   )r;   rD   rR   rO   rP   r3   r      sj   H
@r   c                    sD   t  tjr   dkr t r t fdd  D s dS dS )at  Returns True if the graph G is a triad, else False.

    Parameters
    ----------
    G : graph
       A NetworkX Graph

    Returns
    -------
    istriad : boolean
       Whether G is a valid triad

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
    >>> nx.is_triad(G)
    True
    >>> G.add_edge(0, 1)
    >>> nx.is_triad(G)
    False
    r   c                 3   s     | ]}||f   v V  qd S r6   )edgesrJ   r:   r2   r3   r<   4  rE   zis_triad.<locals>.<genexpr>TF)
isinstancenxGraphorderis_directedanyrY   r:   r2   r:   r3   r     s
   r   c                 C   s*   ddl }|jdtdd t|  d}|S )a`  Returns a generator of all possible sets of 3 nodes in a DiGraph.

    .. deprecated:: 3.3

       all_triplets is deprecated and will be removed in NetworkX version 3.5.
       Use `itertools.combinations` instead::

          all_triplets = itertools.combinations(G, 3)

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph

    Returns
    -------
    triplets : generator of 3-tuples
       Generator of tuples of 3 nodes

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
    >>> list(nx.all_triplets(G))
    [(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]

    r   Nze

all_triplets is deprecated and will be removed in v3.5.
Use `itertools.combinations(G, 3)` instead.r   category
stacklevelr   )warningswarnDeprecationWarningr   rY   )r;   r~   tripletsr2   r2   r3   r	   9  s   r	   T)returns_graphc                 c   s.    t |  d}|D ]
}| | V  q
dS )a  A generator of all possible triads in G.

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph

    Returns
    -------
    all_triads : generator of DiGraphs
       Generator of triads (order-3 DiGraphs)

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1), (3, 4), (4, 1), (4, 2)])
    >>> for triad in nx.all_triads(G):
    ...     print(triad.edges)
    [(1, 2), (2, 3), (3, 1)]
    [(1, 2), (4, 1), (4, 2)]
    [(3, 1), (3, 4), (4, 1)]
    [(2, 3), (3, 4), (4, 2)]

    r   N)r   rY   subgraphcopy)r;   r   tripletr2   r2   r3   r
   d  s
   r
   c                 C   s4   t | }tt}|D ]}t|}|| | q
|S )a  Returns a list of all triads for each triad type in a directed graph.
    There are exactly 16 different types of triads possible. Suppose 1, 2, 3 are three
    nodes, they will be classified as a particular triad type if their connections
    are as follows:

    - 003: 1, 2, 3
    - 012: 1 -> 2, 3
    - 102: 1 <-> 2, 3
    - 021D: 1 <- 2 -> 3
    - 021U: 1 -> 2 <- 3
    - 021C: 1 -> 2 -> 3
    - 111D: 1 <-> 2 <- 3
    - 111U: 1 <-> 2 -> 3
    - 030T: 1 -> 2 -> 3, 1 -> 3
    - 030C: 1 <- 2 <- 3, 1 -> 3
    - 201: 1 <-> 2 <-> 3
    - 120D: 1 <- 2 -> 3, 1 <-> 3
    - 120U: 1 -> 2 <- 3, 1 <-> 3
    - 120C: 1 -> 2 -> 3, 1 <-> 3
    - 210: 1 -> 2 <-> 3, 1 <-> 3
    - 300: 1 <-> 2 <-> 3, 1 <-> 3

    Refer to the :doc:`example gallery </auto_examples/graph/plot_triad_types>`
    for visual examples of the triad types.

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph

    Returns
    -------
    tri_by_type : dict
       Dictionary with triad types as keys and lists of triads as values.

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 1), (5, 6), (5, 4), (6, 7)])
    >>> dict = nx.triads_by_type(G)
    >>> dict["120C"][0].edges()
    OutEdgeView([(1, 2), (1, 3), (2, 3), (3, 1)])
    >>> dict["012"][0].edges()
    OutEdgeView([(1, 2)])

    References
    ----------
    .. [1] Snijders, T. (2012). "Transitivity and triads." University of
        Oxford.
        https://web.archive.org/web/20170830032057/http://www.stats.ox.ac.uk/~snijders/Trans_Triads_ha.pdf
    )r
   r   listr   append)r;   all_tritri_by_typetriadrS   r2   r2   r3   r     s   7r   c                 C   s^  t | s	tdt|  }|dkrdS |dkrdS |dkrW|  \}}t|t|kr/dS |d |d kr9dS |d |d krCd	S |d |d ksS|d |d krUd
S dS |dkrt|  dD ]O\}}}t|t|kr{|d |v rx dS  dS t|t|t|kr|d |d |d h|d |d |d h  krt|  kr dS   dS  dS qbdS |dkrt|  dD ]\\}}}}t|t|krt|t|kr dS |d h|d h  krt|	t|kr dS  |d h|d h  krt|	t|kr dS  |d |d kr dS qdS |dkr&dS |dkr-dS dS )a  Returns the sociological triad type for a triad.

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph with 3 nodes

    Returns
    -------
    triad_type : str
       A string identifying the triad type

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
    >>> nx.triad_type(G)
    '030C'
    >>> G.add_edge(1, 3)
    >>> nx.triad_type(G)
    '120C'

    Notes
    -----
    There can be 6 unique edges in a triad (order-3 DiGraph) (so 2^^6=64 unique
    triads given 3 nodes). These 64 triads each display exactly 1 of 16
    topologies of triads (topologies can be permuted). These topologies are
    identified by the following notation:

    {m}{a}{n}{type} (for example: 111D, 210, 102)

    Here:

    {m}     = number of mutual ties (takes 0, 1, 2, 3); a mutual tie is (0,1)
              AND (1,0)
    {a}     = number of asymmetric ties (takes 0, 1, 2, 3); an asymmetric tie
              is (0,1) BUT NOT (1,0) or vice versa
    {n}     = number of null ties (takes 0, 1, 2, 3); a null tie is NEITHER
              (0,1) NOR (1,0)
    {type}  = a letter (takes U, D, C, T) corresponding to up, down, cyclical
              and transitive. This is only used for topologies that can have
              more than one form (eg: 021D and 021U).

    References
    ----------
    .. [1] Snijders, T. (2012). "Transitivity and triads." University of
        Oxford.
        https://web.archive.org/web/20170830032057/http://www.stats.ox.ac.uk/~snijders/Trans_Triads_ha.pdf
    z"G is not a triad (order-3 DiGraph)r   r   r   r   r   r    r!   r"   r#   r   r%   r$   r'   r&   r   r(   r)   r*   r+   r   r,   r   r-   N)
r   rv   NetworkXAlgorithmErrorrV   rt   rT   r   symmetric_differencerY   intersection)r;   	num_edgese1e2e3e4r2   r2   r3   r     sf   3
 >
,0

r   r   )preserve_all_attrsr   c                 C   s\   ddl }|jdtdd t| dk rtdt|  d|t|  d}| 	|}|S )	aV  Returns a random triad from a directed graph.

    .. deprecated:: 3.3

       random_triad is deprecated and will be removed in version 3.5.
       Use random sampling directly instead::

          G.subgraph(random.sample(list(G), 3))

    Parameters
    ----------
    G : digraph
       A NetworkX DiGraph
    seed : integer, random_state, or None (default)
        Indicator of random number generation state.
        See :ref:`Randomness<randomness>`.

    Returns
    -------
    G2 : subgraph
       A randomly selected triad (order-3 NetworkX DiGraph)

    Raises
    ------
    NetworkXError
        If the input Graph has less than 3 nodes.

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 3), (3, 1), (5, 6), (5, 4), (6, 7)])
    >>> triad = nx.random_triad(G, seed=1)
    >>> triad.edges
    OutEdgeView([(1, 2)])

    r   Nz

random_triad is deprecated and will be removed in NetworkX v3.5.
Use random.sample instead, e.g.::

	G.subgraph(random.sample(list(G), 3))
r   r{   r   z2G needs at least 3 nodes to form a triad; (it has z nodes))
r~   r   r   rV   rv   NetworkXErrorsampler   rY   r   )r;   seedr~   rY   G2r2   r2   r3   r   $  s   '	
r   r6   )__doc__collectionsr   	itertoolsr   r   networkxrv   networkx.utilsr   r   __all__TRICODESr.   rX   r[   r@   _dispatchabler   r   r	   r
   r   r   r   r2   r2   r2   r3   <module>   s@   E 
)
=`