
    hA                     V   S r SSKJr  SSKJrJr  SSKrSSKJ	r	J
r
  / SQrSrSr\" \5       V Vs0 s H  u  pU \US	-
     _M     snn rS
 r\	" S5      \R"                  SS j5       5       r\R"                  S 5       r\	" S5      \R"                  S 5       5       r\	" S5      \R"                  " SS9S 5       5       r\	" S5      \R"                  S 5       5       r\	" S5      \R"                  S 5       5       r\	" S5      \
" S	5      \R"                  " SSS9SS j5       5       5       rgs  snn f )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300r   c                 V   ^  XS4X!S4XS4X1S4X#S4X2S44n[        U 4S jU 5       5      $ )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   B   >#    U  H  u  po2TU   ;   d  M  Uv   M     g 7fN ).0uvxGs       L/var/www/html/env/lib/python3.13/site-packages/networkx/algorithms/triads.py	<genexpr>_tricode.<locals>.<genexpr>   s     4WQ1qt)qqs   	)sum)r8   r6   r5   wcomboss   `    r9   _tricoder?   w   s@     Qi!Q1Iay1*qRjQF4444    
undirectedc           	        ^^ ^!^" [        U R                  U5      5      m!Ub#  [        U5      [        T!5      :w  a  [        S5      e[        U 5      mT[        T!5      -
  n[	        T!5       VVs0 s H  u  p4XC_M	     nnnU(       a3  U R
                  T!-
  nUR                  U4S j[	        U5       5       5        U  Vs0 s H>  oDU R                  U   R                  5       U R                  U   R                  5       -  _M@     nnU  Vs0 s H>  oDU R                  U   R                  5       U R                  U   R                  5       -  _M@     snm U(       a  W Vs0 s H>  oDU R                  U   R                  5       U R                  U   R                  5       -  _M@     snm"[        U!U"4S jU 5       5      nUS-  n	[        U U!4S jU 5       5      n
U
S-  n[         Vs0 s H  oS_M     nnT! GH~  nX~   nT U   nU(       a  S=n=n=nnU GH%  nUU   X^   ::  a  M  UU   nUU-  UU1-
  nU HU  nUU   UU   :  d%  X^   UU   s=:  a  UU   :  d  M&  O  M*  XU   ;  d  M4  [        XUU5      nU[        U   ==   S-  ss'   MW     UU;   a  US==   T[        U5      -
  S-
  -  ss'   OUS	==   T[        U5      -
  S-
  -  ss'   U(       d  M  UT!;  d  M  T"U   nW[        UUT!-
  -  5      -  nW[        UU-
  T!-
  5      -  nT U   nW[        UUT!-
  -  5      -  nW[        UU-
  T!-
  5      -  nGM(     U(       d  GMR  US	==   W	WWS-  -   -
  -  ss'   US==   WWWS-  -   -
  -  ss'   GM     TTS-
  -  TS-
  -  S
-  nX"S-
  -  US-
  -  S
-  nUU-
  nU[        UR                  5       5      -
  US'   U$ s  snnf s  snf s  snf s  snf s  snf )a  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   4   >#    U  H  u  pX!T-   4v   M     g 7fr2   r3   )r4   inNs      r9   r:   !triadic_census.<locals>.<genexpr>   s     ?(>!U(>s   c              3   P   >#    U  H  nTU     H  o"T;  d  M
  S v   M     M     g7fr   Nr3   )r4   rE   nbrnodesetsgl_nbrss      r9   r:   rG      $     V[HQKSgCU!!K![   &&r   c              3   P   >#    U  H  nTU     H  o"T;  d  M
  S v   M     M     g7frI   r3   )r4   rE   rJ   dbl_nbrsrK   s      r9   r:   rG      rM   rN   r   r   r!   r    r   r   )setnbunch_iterlen
ValueError	enumeratenodesupdatepredkeyssuccr<   TRIAD_NAMESr?   TRICODE_TO_NAMEvalues)#r8   nodelistNnotrD   rE   mnot_nodesetnbrssglsgl_edges_outsidedbldbl_edges_outsidenamecensusr6   vnbrs	dbl_vnbrssgl_unbrs_bdysgl_unbrs_outdbl_unbrs_bdydbl_unbrs_outr5   unbrs	neighborsr=   code	sgl_unbrs	dbl_unbrstotal_trianglestriangles_without_nodesettotal_censusrF   rP   rK   rL   s#                                  @@@@r9   r   r      s   P !--)*GHW =NOOAAs7|D $G,-,$!,A-gg'	?	+(>??
 =>>Aqqvvay~~!&&).."222AD>@AB1166!9>>#affQinn&666BHDOPKqqvvay~~'!&&)..*:::KPV[VV1HV[VV1H #..+$Ag+F.QK	LMMMMMMMMAtqt|GE1a&0IQ4!A$;14!A$#51#5#5!7:J#A!Q/D?401Q61  I~uS^!3a!77uS^!3a!77
 t($QK	Y%@!AAY%6%@!AA$QK	Y%@!AAY%6%@!AA5 8 45M.--STBT2TUUM5M.--STBT2TUUMK R AE{a!e,2O!%!2dQh!?A E"%>>L 3v}}#77F5MMK 	. ?B Q /s!   ,N9;AN?AOAO	Oc                    ^  [        T [        R                  5      (       aX  T R                  5       S:X  aD  [        R                  " T 5      (       a)  [        U 4S jT R                  5        5       5      (       d  gg)a0  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   L   >#    U  H  oU4TR                  5       ;   v   M     g 7fr2   )edges)r4   rE   r8   s     r9   r:   is_triad.<locals>.<genexpr>4  s     >Iq1v*Is   !$TF)
isinstancenxGraphorderis_directedanyrV   )r8   s   `r9   r	   r	     sN    . !RXX779>bnnQ//>AGGI>>>r@   c                 l    SSK nUR                  S[        SS9  [        U R	                  5       S5      nU$ )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   rV   )r8   r   tripletss      r9   r
   r
   9  s>    : MM: $   AGGIq)HOr@   T)returns_graphc              #      #    [        U R                  5       S5      nU H$  nU R                  U5      R                  5       v   M&     g7f)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   rV   subgraphcopy)r8   r   triplets      r9   r   r   d  s;     4 AGGIq)Hjj!&&(( s   AAc                     [        U 5      n[        [        5      nU H!  n[        U5      nX$   R	                  U5        M#     U$ )aR  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)r8   all_tritri_by_typetriadrg   s        r9   r   r     sE    n mGd#K%   '  r@   c                    [        U 5      (       d  [        R                  " S5      e[        U R	                  5       5      nUS:X  a  gUS:X  a  gUS:X  a_  U R	                  5       u  p#[        U5      [        U5      :X  a  gUS   US   :X  a  gUS   US   :X  a  g	US   US   :X  d  US   US   :X  a  g
gUS:X  a  [        U R	                  5       S5       H  u  p#n[        U5      [        U5      :X  a  US   U;   a    g  g[        U5      R                  [        U5      5      [        U5      :X  d  M]  US   US   US   1US   US   US   1s=:X  a  [        U R                  5       5      :X  a     g    g  g   gUS:X  a  [        U R	                  5       S5       H  u  p#pE[        U5      [        U5      :X  d  M   [        U5      [        U5      :X  a    gUS   1US   1s=:X  a)  [        U5      R                  [        U5      5      :X  a     g  US   1US   1s=:X  a)  [        U5      R                  [        U5      5      :X  a     g  US   US   :X  d  M    g   gUS:X  a  gUS:X  a  gg)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	   r|   NetworkXAlgorithmErrorrS   ry   rQ   r   symmetric_differencerV   intersection)r8   	num_edgese1e2e3e4s         r9   r   r     s>   f A;;''(LMMAGGIIA~	a	ar7c"gUbe^Ube^Ube^r!u1~  .	a&qwwy!4JBB2w#b'!a5B;!R--c"g6#b'AqE2a5"Q%(RUBqE2a5,ASS^S! T  5 
a*1779a8NBB2w#b'!r7c"g% qE7r!ugFR)=)=c"g)FF! GqE7r!ugFR)=)=c"g)FF! Ga5BqE>! 9 
a	a 
r@   )preserve_all_attrsr   c                    SSK nUR                  S[        SS9  [        U 5      S:  a#  [        R
                  " S[        U 5       S35      eUR                  [        U R                  5       5      S5      nU R                  U5      nU$ )	a  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   rS   r|   NetworkXErrorsampler   rV   r   )r8   seedr   rV   G2s        r9   r   r   $  s    N MM8 $   1vz@QP
 	
 KKQWWY+E	
E	BIr@   r2   )__doc__collectionsr   	itertoolsr   r   networkxr|   networkx.utilsr   r   __all__TRICODESr[   rU   r\   r?   _dispatchabler   r	   r
   r   r   r   r   )rD   rq   s   00r9   <module>r      s  
 1 # 0  ?AJ* <EX;NO;N1k$(++;NO	5 \"S  #Sl  : \"&  #&R \"%) & #): \":  #:z \"]  #]@ \"T>5 ?  #5g Ps   D%