U
    ¹mœdÐ?  ã                   @   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
 dddd	d
ddgZdZdZdd„ eeƒD ƒZdd„ Ze	dƒddd„ƒZe ¡ dd„ ƒZe	dƒdd„ ƒZe	dƒdd	„ ƒZe	dƒdd
„ ƒZe	dƒdd„ ƒZe	dƒe
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   úS/home/sam/Atlas/atlas_env/lib/python3.8/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 )	zñReturns 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$   | ]\}}}|ˆ | kr|V  qd S ©Nr2   )r/   ÚuÚvÚx©ÚGr2   r3   Ú	<genexpr>€   s      z_tricode.<locals>.<genexpr>)Úsum)r;   r8   r7   ÚwZcombosr2   r:   r3   Ú_tricodew   s    4r?   Z
undirectedc                    s.  t ˆ  |¡ƒ‰|dk	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 �]Ð}|| }ˆ| }|�r6d } } }}|D �]^}|| || k�rV�q:|| }||B ||h }|D ]p}|| || k �s¾|| ||   k �r¬|| k �rrn n0||| k�rrt	ˆ |||ƒ}|
t
|   d7  < �qr||k�r|
d  ˆt|ƒ d 7  < n|
d  ˆt|ƒ d 7  < |�r:|ˆk�r:ˆ| }|t||ˆ @ ƒ7 }|t|| ˆ ƒ7 }ˆ| }|t||ˆ @ ƒ7 }|t|| ˆ ƒ7 }�q:|�r
|
d  |||d   7  < |
d  |	||d   7  < �q
ˆˆd  ˆd  d }||d  |d  d }|| }|t|
 ¡ ƒ |
d< |
S )ab  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.

    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   r@   )ÚNr2   r3   r<   Ò   s     z!triadic_census.<locals>.<genexpr>c                    s*   i | ]"}|ˆ j |  ¡ ˆ j|  ¡ B “qS r2   ©ÚpredÚkeysÚsucc©r/   rA   r:   r2   r3   r4   ×   s      c                    s*   i | ]"}|ˆ j |  ¡ ˆ j|  ¡ @ “qS r2   rC   rG   r:   r2   r3   r4   Ø   s      c                    s*   i | ]"}|ˆ j |  ¡ ˆ j|  ¡ A “qS r2   rC   rG   r:   r2   r3   r4   Û   s      c                 3   s(   | ] }ˆ| D ]}|ˆ krd V  qqdS ©r   Nr2   ©r/   rA   Znbr)ÚnodesetÚsgl_nbrsr2   r3   r<   Ý   s
     
   r   c                 3   s(   | ] }ˆ | D ]}|ˆkrd V  qqdS rH   r2   rI   )Údbl_nbrsrJ   r2   r3   r<   ß   s
     
   c                 S   s   i | ]
}|d “qS )r   r2   )r/   Únamer2   r2   r3   r4   ã   s      r   r   r    r   r   r   )ÚsetZnbunch_iterÚlenÚ
ValueErrorÚ	enumerateÚnodesÚupdater=   r.   r?   ÚTRICODE_TO_NAMEÚvalues)r;   ZnodelistZNnotÚmZnot_nodesetZnbrsZsglZsgl_edges_outsideZdblZdbl_edges_outsideZcensusr8   ZvnbrsZ	dbl_vnbrsZsgl_unbrs_bdyZsgl_unbrs_outZdbl_unbrs_bdyZdbl_unbrs_outr7   ZunbrsZ	neighborsr>   r1   Z	sgl_unbrsZ	dbl_unbrsZtotal_trianglesZtriangles_without_nodesetZtotal_censusr2   )r;   rB   rL   rJ   rK   r3   r   ƒ   sd    C


H
 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ˆ   ¡ kV  qd S r6   )ÚedgesrG   r:   r2   r3   r<   /  s     zis_triad.<locals>.<genexpr>TF)Ú
isinstanceÚnxZGraphÚorderZis_directedÚanyrR   r:   r2   r:   r3   r     s
    c                 C   s   t |  ¡ dƒ}|S )a’  Returns a generator of all possible sets of 3 nodes in a DiGraph.

    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   )r   rR   )r;   Útripletsr2   r2   r3   r	   4  s    c                 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   rR   ÚsubgraphÚcopy)r;   r\   Útripletr2   r2   r3   r
   M  s    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;   Zall_triZtri_by_typeZtriadrM   r2   r2   r3   r   k  s    6c                 C   st  t | ƒst d¡‚t|  ¡ ƒ}|dkr*dS |dkr6dS |dkr®|  ¡ \}}t|ƒt|ƒkr^dS |d |d krrdS |d |d kr†d	S |d |d ks¦|d |d krªd
S �nÂ|dk�rpt|  ¡ dƒD ]¤\}}}t|ƒt|ƒk� rü|d |k� rö dS  dS t|ƒ t|ƒ¡t|ƒkrÆ|d |d |d h|d |d |d h  k�rZt|  ¡ ƒk�rdn n dS  dS qÆ�n |dk�rTt|  ¡ dƒD ]È\}}}}t|ƒt|ƒk�rˆt|ƒt|ƒk�r¾ dS |d h|d h  k�rðt|ƒ 	t|ƒ¡k�rún n dS |d h|d h  k�r,t|ƒ 	t|ƒ¡k�r6n n dS |d |d k�rˆ dS �qˆn|dk�rbdS |dk�rpd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   rY   ZNetworkXAlgorithmErrorrO   rW   rN   r   Úsymmetric_differencerR   Úintersection)r;   Z	num_edgesÚe1Úe2Ze3Ze4r2   r2   r3   r   ©  sT    2
 
H
66

r   c                 C   s"   |  t|  ¡ ƒd¡}|  |¡}|S )a<  Returns a random triad from a directed graph.

    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)

    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   )Úsampler`   rR   r]   )r;   ÚseedrR   ZG2r2   r2   r3   r   
  s    
)N)N)Ú__doc__Úcollectionsr   Ú	itertoolsr   r   ZnetworkxrY   Znetworkx.utilsr   r   Ú__all__ZTRICODESr.   rQ   rT   r?   r   Ú	_dispatchr   r	   r
   r   r   r   r2   r2   r2   r3   Ú<module>   sB   ùE 



=
`