
    Vh7                        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 ee      D  ci c]  \  } }| e|d	z
      c}} Zd
 Z e	d      ej"                  dd              Zej"                  d        Z e	d       ej"                  d      d               Z e	d      ej"                  d               Z e	d      ej"                  d               Zyc c}} w )z*Functions for analyzing triads of a graph.    )defaultdict)combinationspermutationsN)not_implemented_forpy_random_state)triadic_censusis_triad
all_triadstriads_by_type
triad_type)@      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300r   c                 `     ||df||df||df||df||df||dff}t         f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   :   K   | ]  \  }}}||   v s|  y wN ).0uvxGs       J/home/dcms/DCMS/lib/python3.12/site-packages/networkx/algorithms/triads.py	<genexpr>z_tricode.<locals>.<genexpr>~   s!     4WQ1!qt)q4s   )sum)r6   r4   r3   wcomboss   `    r7   _tricoder<   u   sL     !Qi!QQ1I1ay1a*q!RjQF4444    
undirectedc           	      8   ! t        | j                  |             |"t        |      t               k7  rt        d      t        |       t               z
  }t	               D ci c]  \  }}||
 }}}|r2| j
                   z
  }|j                  fdt	        |      D               | D ci c]>  }|| j                  |   j                         | j                  |   j                         z  @ }}| D ci c]>  }|| j                  |   j                         | j                  |   j                         z  @ c}|r~D ci c]>  }|| j                  |   j                         | j                  |   j                         z  @ c}!t         !fd|D              }|dz  }	t         fd|D              }
|
dz  }t        j                  t        d      } D ]^  }||   }|   }|rdx}x}x}}|D ]  }||   ||   k  r||   }||z  ||hz
  }|D ]O  }||   ||   k  s ||   ||   cxk  r	||   k  s#n &|||   vs.t        | |||      }|t        |   xx   dz  cc<   Q ||v r|dxx   t        |      z
  dz
  z  cc<   n|d	xx   t        |      z
  dz
  z  cc<   |s| vs!|   }t        || z
  z        z  }t        ||z
   z
        z  }|   }t        || z
  z        z  }t        ||z
   z
        z  } |s3|d	xx   	dz  z   z
  z  cc<   |dxx   dz  z   z
  z  cc<   a dz
  z  dz
  z  d
z  }||dz
  z  |dz
  z  d
z  }||z
  }|t        |j!                               z
  |d<   |S c c}}w c c}w c c}w c c}w )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

    z3nodelist includes duplicate nodes or nodes not in Gc              3   2   K   | ]  \  }}||z   f  y wr0   r1   )r2   inNs      r7   r8   z!triadic_census.<locals>.<genexpr>   s     ?1!QU?s   c              3   @   K   | ]  }|   D ]  }|vsd    ywr   Nr1   )r2   rB   nbrnodesetsgl_nbrss      r7   r8   z!triadic_census.<locals>.<genexpr>   (     VHQKVS3gCU!V!V   	r   c              3   @   K   | ]  }|   D ]  }|vsd    ywrE   r1   )r2   rB   rF   dbl_nbrsrG   s      r7   r8   z!triadic_census.<locals>.<genexpr>   rI   rJ   r   r   r   r   r   r   )setnbunch_iterlen
ValueError	enumeratenodesupdatepredkeyssuccr9   dictfromkeysTRIAD_NAMESr<   TRICODE_TO_NAMEvalues)"r6   nodelistNnotrA   rB   mnot_nodesetnbrssglsgl_edges_outsidedbldbl_edges_outsidecensusr4   vnbrs	dbl_vnbrssgl_unbrs_bdysgl_unbrs_outdbl_unbrs_bdydbl_unbrs_outr3   unbrs	neighborsr:   code	sgl_unbrs	dbl_unbrstotal_trianglestriangles_without_nodesettotal_censusrC   rL   rG   rH   s"                                 @@@@r7   r   r      s   P !--)*GHW =NOOAAs7|D $G,-$!QA-A-gg'	?	+(>??
 =>>qAqvvay~~!&&).."222>D>@AB1166!9>>#affQinn&666BHDOPqAqvvay~~'!&&)..*:::PV[VV1HV[VV1H ]];*F %VQQK	LMMMMMMMM 	BAtqt|GE1a&0I 7Q4!A$;1Q4!A$#51#5!47:J#Aq!Q/D?401Q617 I~uS^!3a!77uS^!3a!77
 ($QK	Y%@!AAY%6%@!AA$QK	Y%@!AAY%6%@!AA5	B8 5M.--STBT2TUUM5M.--STBT2TUUMK%VR AE{a!e,2O!%!2dQh!?A E"%>>L 3v}}#77F5MMK 	. ?B Qs   *N2AN;ANANc                      t         t        j                        rK j                         dk(  r8t        j                         r#t         fd j                         D              syy)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   F   K   | ]  }||fj                         v   y wr0   )edges)r2   rB   r6   s     r7   r8   zis_triad.<locals>.<genexpr>2  s      >q1v*>s   !TF)
isinstancenxGraphorderis_directedanyrR   )r6   s   `r7   r	   r	     sE    . !RXX779>bnnQ/>AGGI>>r=   T)returns_graphc              #      K   t        | j                         d      }|D ]#  }| j                  |      j                          % yw)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   rR   subgraphcopy)r6   tripletstriplets      r7   r
   r
   7  sA     4 AGGIq)H )jj!&&(()s   AAc                     t        |       }t        t              }|D ]!  }t        |      }||   j	                  |       # |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)r6   all_tritri_by_typetriadnames        r7   r   r   V  sL    n mGd#K (% D  '( r=   c                    t        |       st        j                  d      t        | j	                               }|dk(  ry|dk(  ry|dk(  r[| j	                         \  }}t        |      t        |      k(  ry|d   |d   k(  ry|d   |d   k(  ry	|d   |d   k(  s|d   |d   k(  ry
y|dk(  rt        | j	                         d      D ]  \  }}}t        |      t        |      k(  r|d   |v r y yt        |      j                  t        |            t        |      k(  sY|d   |d   |d   h|d   |d   |d   hcxk(  rt        | j                               k(  r y  y y y|dk(  rt        | j	                         d      D ]  \  }}}}t        |      t        |      k(  s t        |      t        |      k(  r y|d   h|d   hcxk(  r't        |      j                  t        |            k(  r y |d   h|d   hcxk(  r't        |      j                  t        |            k(  r y |d   |d   k(  s y y|dk(  ry|dk(  ryy)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	   rx   NetworkXAlgorithmErrorrO   rv   rM   r   symmetric_differencerR   intersection)r6   	num_edgese1e2e3e4s         r7   r   r     sN   f A;''(LMMAGGIIA~	a	aBr7c"gUbe^Ube^Ube^r!u1~  .	a&qwwy!4 
	JBB2w#b'!a5B;!R--c"g6#b'AqE2a5"Q%(RUBqE2a5,ASS^S! T 
	 
a*1779a8 
	"NBB2w#b'!r7c"g% qE7r!ugFR)=)=c"g)FF! GqE7r!ugFR)=)=c"g)FF! Ga5BqE>!
	" 
a	a 
r=   r0   )__doc__collectionsr   	itertoolsr   r   networkxrx   networkx.utilsr   r   __all__TRICODESrY   rQ   rZ   r<   _dispatchabler   r	   r
   r   r   )rA   rn   s   00r7   <module>r      s&  
 1 # 0  ?AJ* <EX;NO41k$(++O	5 \"S  #Sl  : \"%) & #): \":  #:z \"]  #]K	 Ps   C