Ë
    D^(h1  ã                   ó@  — d Z ddlmZmZ ddlmZ ddlZddgZd„ Z	d„ Z
dd	„Zej                  j                  d
«       ej                  ddid¬«      	 dd„«       «       Zej                  j                  d
«       ej                  ddid¬«      	 	 	 	 	 dd„«       «       Zy)z™
Functions for hashing graphs to strings.
Isomorphic graphs should be assigned identical hashes.
For now, only Weisfeiler-Lehman hashing is implemented.
é    )ÚCounterÚdefaultdict)Úblake2bNÚweisfeiler_lehman_graph_hashÚ!weisfeiler_lehman_subgraph_hashesc                 óV   — t        | j                  d«      |¬«      j                  «       S )NÚascii)Údigest_size)r   ÚencodeÚ	hexdigest)Úlabelr
   s     ú_/var/www/skyplay_api_hub/venv/lib/python3.12/site-packages/networkx/algorithms/graph_hashing.pyÚ_hash_labelr      s!   € Ü�5—<‘< Ó(°kÔB×LÑLÓNÐNó    c           	      ó  — |r2| j                  d¬«      D ��ci c]  \  }}|t        ||   «      “Œ c}}S |r| D �ci c]  }|d“Œ c}S | j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}S c c}}w c c}w c c}}w )NT)ÚdataÚ )ÚnodesÚstrÚdegree)ÚGÚ	edge_attrÚ	node_attrÚuÚddÚdegs         r   Ú_init_node_labelsr      sz   € ÙØ34·7±7À°7Ó3E×F©%¨!¨R�”3�r˜)‘}Ó%Ñ%ÓFÐFÙ	Ø Ö!˜!��2‘Ò!Ð!à*+¯(©(«*×5¡  3�”3�s“8‘Ó5Ð5ùó	 Gùâ!ùã5s   ˜A5»
A;ÁB c                 óÐ   — g }| j                  |«      D ]1  }|€dnt        | |   |   |   «      }|j                  |||   z   «       Œ3 ||   dj                  t	        |«      «      z   S )zc
    Compute new labels for given node by aggregating
    the labels of each node's neighbors.
    r   )Ú	neighborsr   ÚappendÚjoinÚsorted)r   ÚnodeÚnode_labelsr   Ú
label_listÚnbrÚprefixs          r   Ú_neighborhood_aggregater(      sw   € ð
 €JØ�{‰{˜4Ó ò 5ˆØ Ð(‘¬c°!°D±'¸#±,¸yÑ2IÓ.JˆØ×Ñ˜& ;¨sÑ#3Ñ3Õ4ð5ð �tÑ˜rŸw™w¤v¨jÓ'9Ó:Ñ:Ð:r   Ú
multigraphr   r   )Ú
edge_attrsÚ
node_attrsc                 ó(  ‡— dˆfd„	}t        | ||«      }g }t        |«      D ]Q  } || ||¬«      }t        |j                  «       «      }	|j	                  t        |	j                  «       d„ ¬«      «       ŒS t        t        t        |«      «      ‰«      S )aƒ  Return Weisfeiler Lehman (WL) graph hash.

    The function iteratively aggregates and hashes neighborhoods of each node.
    After each node's neighbors are hashed to obtain updated node labels,
    a hashed histogram of resulting labels is returned as the final hash.

    Hashes are identical for isomorphic graphs and strong guarantees that
    non-isomorphic graphs will get different hashes. See [1]_ for details.

    If no node or edge attributes are provided, the degree of each node
    is used as its initial label.
    Otherwise, node and/or edge labels are used to compute the hash.

    Parameters
    ----------
    G : graph
        The graph to be hashed.
        Can have node and/or edge attributes. Can also have no attributes.
    edge_attr : string, optional (default=None)
        The key in edge attribute dictionary to be used for hashing.
        If None, edge labels are ignored.
    node_attr: string, optional (default=None)
        The key in node attribute dictionary to be used for hashing.
        If None, and no edge_attr given, use the degrees of the nodes as labels.
    iterations: int, optional (default=3)
        Number of neighbor aggregations to perform.
        Should be larger for larger graphs.
    digest_size: int, optional (default=16)
        Size (in bits) of blake2b hash digest to use for hashing node labels.

    Returns
    -------
    h : string
        Hexadecimal string corresponding to hash of the input graph.

    Examples
    --------
    Two graphs with edge attributes that are isomorphic, except for
    differences in the edge labels.

    >>> G1 = nx.Graph()
    >>> G1.add_edges_from(
    ...     [
    ...         (1, 2, {"label": "A"}),
    ...         (2, 3, {"label": "A"}),
    ...         (3, 1, {"label": "A"}),
    ...         (1, 4, {"label": "B"}),
    ...     ]
    ... )
    >>> G2 = nx.Graph()
    >>> G2.add_edges_from(
    ...     [
    ...         (5, 6, {"label": "B"}),
    ...         (6, 7, {"label": "A"}),
    ...         (7, 5, {"label": "A"}),
    ...         (7, 8, {"label": "A"}),
    ...     ]
    ... )

    Omitting the `edge_attr` option, results in identical hashes.

    >>> nx.weisfeiler_lehman_graph_hash(G1)
    '7bc4dde9a09d0b94c5097b219891d81a'
    >>> nx.weisfeiler_lehman_graph_hash(G2)
    '7bc4dde9a09d0b94c5097b219891d81a'

    With edge labels, the graphs are no longer assigned
    the same hash digest.

    >>> nx.weisfeiler_lehman_graph_hash(G1, edge_attr="label")
    'c653d85538bcf041d88c011f4f905f10'
    >>> nx.weisfeiler_lehman_graph_hash(G2, edge_attr="label")
    '3dcd84af1ca855d0eff3c978d88e7ec7'

    Notes
    -----
    To return the WL hashes of each subgraph of a graph, use
    `weisfeiler_lehman_subgraph_hashes`

    Similarity between hashes does not imply similarity between graphs.

    References
    ----------
    .. [1] Shervashidze, Nino, Pascal Schweitzer, Erik Jan Van Leeuwen,
       Kurt Mehlhorn, and Karsten M. Borgwardt. Weisfeiler Lehman
       Graph Kernels. Journal of Machine Learning Research. 2011.
       http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf

    See also
    --------
    weisfeiler_lehman_subgraph_hashes
    c                 ór   •— i }| j                  «       D ]   }t        | |||¬«      }t        |‰«      ||<   Œ" |S )zŒ
        Apply neighborhood aggregation to each node
        in the graph.
        Computes a dictionary with labels for each node.
        ©r   )r   r(   r   )r   Úlabelsr   Ú
new_labelsr#   r   r
   s         €r   Úweisfeiler_lehman_stepz<weisfeiler_lehman_graph_hash.<locals>.weisfeiler_lehman_stepŠ   sH   ø€ ð ˆ
Ø—G‘G“Iò 	?ˆDÜ+¨A¨t°VÀyÔQˆEÜ*¨5°+Ó>ˆJ�tÒð	?ð Ðr   r.   c                 ó   — | d   S )Nr   © )Úxs    r   ú<lambda>z.weisfeiler_lehman_graph_hash.<locals>.<lambda>ž   s
   € È!ÈAÉ$€ r   )Úkey©N)
r   Úranger   ÚvaluesÚextendr"   Úitemsr   r   Útuple)
r   r   r   Ú
iterationsr
   r1   r$   Úsubgraph_hash_countsÚ_Úcounters
       `     r   r   r   (   s‹   ø€ õD
ô $ A y°)Ó<€KàÐÜ�:Óò QˆÙ,¨Q°ÀyÔQˆÜ˜+×,Ñ,Ó.Ó/ˆà×#Ñ#¤F¨7¯=©=«?ÁÔ$OÕPð	Qô ”sœ5Ð!5Ó6Ó7¸ÓEÐEr   c           	      ó  ‡— dˆfd„	}t        | ||«      }|r/|j                  «       D ��	ci c]  \  }}	|t        |	‰«      g“Œ }
}}	nt        t        «      }
t        |«      D ]  } || ||
|«      }Œ t        |
«      S c c}	}w )aÑ  
    Return a dictionary of subgraph hashes by node.

    Dictionary keys are nodes in `G`, and values are a list of hashes.
    Each hash corresponds to a subgraph rooted at a given node u in `G`.
    Lists of subgraph hashes are sorted in increasing order of depth from
    their root node, with the hash at index i corresponding to a subgraph
    of nodes at most i edges distance from u. Thus, each list will contain
    `iterations` elements - a hash for a subgraph at each depth. If
    `include_initial_labels` is set to `True`, each list will additionally
    have contain a hash of the initial node label (or equivalently a
    subgraph of depth 0) prepended, totalling ``iterations + 1`` elements.

    The function iteratively aggregates and hashes neighborhoods of each node.
    This is achieved for each step by replacing for each node its label from
    the previous iteration with its hashed 1-hop neighborhood aggregate.
    The new node label is then appended to a list of node labels for each
    node.

    To aggregate neighborhoods for a node $u$ at each step, all labels of
    nodes adjacent to $u$ are concatenated. If the `edge_attr` parameter is set,
    labels for each neighboring node are prefixed with the value of this attribute
    along the connecting edge from this neighbor to node $u$. The resulting string
    is then hashed to compress this information into a fixed digest size.

    Thus, at the $i$-th iteration, nodes within $i$ hops influence any given
    hashed node label. We can therefore say that at depth $i$ for node $u$
    we have a hash for a subgraph induced by the $i$-hop neighborhood of $u$.

    The output can be used to create general Weisfeiler-Lehman graph kernels,
    or generate features for graphs or nodes - for example to generate 'words' in
    a graph as seen in the 'graph2vec' algorithm.
    See [1]_ & [2]_ respectively for details.

    Hashes are identical for isomorphic subgraphs and there exist strong
    guarantees that non-isomorphic graphs will get different hashes.
    See [1]_ for details.

    If no node or edge attributes are provided, the degree of each node
    is used as its initial label.
    Otherwise, node and/or edge labels are used to compute the hash.

    Parameters
    ----------
    G : graph
        The graph to be hashed.
        Can have node and/or edge attributes. Can also have no attributes.
    edge_attr : string, optional (default=None)
        The key in edge attribute dictionary to be used for hashing.
        If None, edge labels are ignored.
    node_attr : string, optional (default=None)
        The key in node attribute dictionary to be used for hashing.
        If None, and no edge_attr given, use the degrees of the nodes as labels.
        If None, and edge_attr is given, each node starts with an identical label.
    iterations : int, optional (default=3)
        Number of neighbor aggregations to perform.
        Should be larger for larger graphs.
    digest_size : int, optional (default=16)
        Size (in bits) of blake2b hash digest to use for hashing node labels.
        The default size is 16 bits.
    include_initial_labels : bool, optional (default=False)
        If True, include the hashed initial node label as the first subgraph
        hash for each node.

    Returns
    -------
    node_subgraph_hashes : dict
        A dictionary with each key given by a node in G, and each value given
        by the subgraph hashes in order of depth from the key node.

    Examples
    --------
    Finding similar nodes in different graphs:

    >>> G1 = nx.Graph()
    >>> G1.add_edges_from([(1, 2), (2, 3), (2, 4), (3, 5), (4, 6), (5, 7), (6, 7)])
    >>> G2 = nx.Graph()
    >>> G2.add_edges_from([(1, 3), (2, 3), (1, 6), (1, 5), (4, 6)])
    >>> g1_hashes = nx.weisfeiler_lehman_subgraph_hashes(
    ...     G1, iterations=3, digest_size=8
    ... )
    >>> g2_hashes = nx.weisfeiler_lehman_subgraph_hashes(
    ...     G2, iterations=3, digest_size=8
    ... )

    Even though G1 and G2 are not isomorphic (they have different numbers of edges),
    the hash sequence of depth 3 for node 1 in G1 and node 5 in G2 are similar:

    >>> g1_hashes[1]
    ['a93b64973cfc8897', 'db1b43ae35a1878f', '57872a7d2059c1c0']
    >>> g2_hashes[5]
    ['a93b64973cfc8897', 'db1b43ae35a1878f', '1716d2a4012fa4bc']

    The first 2 WL subgraph hashes match. From this we can conclude that it's very
    likely the neighborhood of 2 hops around these nodes are isomorphic.

    However the 3-hop neighborhoods of ``G1`` and ``G2`` are not isomorphic since the
    3rd hashes in the lists above are not equal.

    These nodes may be candidates to be classified together since their local topology
    is similar.

    Notes
    -----
    To hash the full graph when subgraph hashes are not needed, use
    `weisfeiler_lehman_graph_hash` for efficiency.

    Similarity between hashes does not imply similarity between graphs.

    References
    ----------
    .. [1] Shervashidze, Nino, Pascal Schweitzer, Erik Jan Van Leeuwen,
       Kurt Mehlhorn, and Karsten M. Borgwardt. Weisfeiler Lehman
       Graph Kernels. Journal of Machine Learning Research. 2011.
       http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf
    .. [2] Annamalai Narayanan, Mahinthan Chandramohan, Rajasekar Venkatesan,
       Lihui Chen, Yang Liu and Shantanu Jaiswa. graph2vec: Learning
       Distributed Representations of Graphs. arXiv. 2017
       https://arxiv.org/pdf/1707.05005.pdf

    See also
    --------
    weisfeiler_lehman_graph_hash
    c                 óž   •— i }| j                  «       D ]6  }t        | |||¬«      }t        |‰«      }|||<   ||   j                  |«       Œ8 |S )a  
        Apply neighborhood aggregation to each node
        in the graph.
        Computes a dictionary with labels for each node.
        Appends the new hashed label to the dictionary of subgraph hashes
        originating from and indexed by each node in G
        r.   )r   r(   r   r    )	r   r/   Únode_subgraph_hashesr   r0   r#   r   Úhashed_labelr
   s	           €r   r1   zAweisfeiler_lehman_subgraph_hashes.<locals>.weisfeiler_lehman_step+  s`   ø€ ð ˆ
Ø—G‘G“Iò 	<ˆDÜ+¨A¨t°VÀyÔQˆEÜ& u¨kÓ:ˆLØ+ˆJ�tÑØ  Ñ&×-Ñ-¨lÕ;ð		<ð
 Ðr   r7   )r   r;   r   r   Úlistr8   Údict)r   r   r   r=   r
   Úinclude_initial_labelsr1   r$   ÚkÚvrC   r?   s       `       r   r   r   ¤   s›   ø€ õNô  $ A y°)Ó<€KÙà9D×9JÑ9JÓ9L÷ 
Ù15°°AˆA”˜A˜{Ó+Ð,Ñ,ð 
Ðò  
ô  +¬4Ó0Ðä�:Óò 
ˆÙ,Øˆ{Ð0°)ó
‰ð
ô
 Ð$Ó%Ð%ùó 
s   ªA;r7   )NNé   é   )NNrJ   rK   F)Ú__doc__Úcollectionsr   r   Úhashlibr   ÚnetworkxÚnxÚ__all__r   r   r(   ÚutilsÚnot_implemented_forÚ_dispatchabler   r   r3   r   r   ú<module>rU      sË   ðñ÷ -Ý ã à)Ð+NÐ
O€òOò6ó	;ð ‡�×Ñ˜lÓ+Ø€×Ñ˜k¨4Ð0¸[ÔIàACòwFó Jó ,ðwFðt ‡�×Ñ˜lÓ+Ø€×Ñ˜k¨4Ð0¸[ÔIð ØØØØ òb&ó Jó ,ñb&r   