
    h                     `   S r SSKrSSKrSSKrSSKJr  SSKJr  SSKr	SSK
Jr  / SQrS r\	R                  " SSS	.S
S
S9           SS j5       r\	R                  " SSS	.S9         SS j5       r\	R                  " SSS	.S9         SS j5       r\	R                  " SSS	.S
S
S9            SS j5       r\	R                       SS j5       r     SS jr     SS jr\	R                  " SS9 SS j5       r\" S5      \	R                  " SS9 SS j5       5       rg)aO  Functions measuring similarity using graph edit distance.

The graph edit distance is the number of edge/node changes needed
to make two graphs isomorphic.

The default algorithm/implementation is sub-optimal for some graphs.
The problem of finding the exact Graph Edit Distance (GED) is NP-hard
so it is often slow. If the simple interface `graph_edit_distance`
takes too long for your graph, try `optimize_graph_edit_distance`
and/or `optimize_edit_paths`.

At the same time, I encourage capable people to investigate
alternative GED algorithms, in order to improve the choices available.
    N)	dataclass)product)np_random_state)graph_edit_distanceoptimal_edit_pathsoptimize_graph_edit_distanceoptimize_edit_pathssimrank_similaritypanther_similaritygenerate_random_pathsc                      [        U 0 UD6  g N)print)argskwargss     P/var/www/html/env/lib/python3.13/site-packages/networkx/algorithms/similarity.pydebug_printr   $   s    	46       )G1G2T)graphspreserve_edge_attrspreserve_node_attrsc                 R    Sn[        U UUUUUUUUU	USU
U5       H  u    pUnM
     U$ )ae  Returns GED (graph edit distance) between graphs G1 and G2.

Graph edit distance is a graph similarity measure analogous to
Levenshtein distance for strings.  It is defined as minimum cost
of edit path (sequence of node and edge edit operations)
transforming graph G1 to graph isomorphic to G2.

Parameters
----------
G1, G2: graphs
    The two graphs G1 and G2 must be of the same type.

node_match : callable
    A function that returns True if node n1 in G1 and n2 in G2
    should be considered equal during matching.

    The function will be called like

       node_match(G1.nodes[n1], G2.nodes[n2]).

    That is, the function will receive the node attribute
    dictionaries for n1 and n2 as inputs.

    Ignored if node_subst_cost is specified.  If neither
    node_match nor node_subst_cost are specified then node
    attributes are not considered.

edge_match : callable
    A function that returns True if the edge attribute dictionaries
    for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should
    be considered equal during matching.

    The function will be called like

       edge_match(G1[u1][v1], G2[u2][v2]).

    That is, the function will receive the edge attribute
    dictionaries of the edges under consideration.

    Ignored if edge_subst_cost is specified.  If neither
    edge_match nor edge_subst_cost are specified then edge
    attributes are not considered.

node_subst_cost, node_del_cost, node_ins_cost : callable
    Functions that return the costs of node substitution, node
    deletion, and node insertion, respectively.

    The functions will be called like

       node_subst_cost(G1.nodes[n1], G2.nodes[n2]),
       node_del_cost(G1.nodes[n1]),
       node_ins_cost(G2.nodes[n2]).

    That is, the functions will receive the node attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function node_subst_cost overrides node_match if specified.
    If neither node_match nor node_subst_cost are specified then
    default node substitution cost of 0 is used (node attributes
    are not considered during matching).

    If node_del_cost is not specified then default node deletion
    cost of 1 is used.  If node_ins_cost is not specified then
    default node insertion cost of 1 is used.

edge_subst_cost, edge_del_cost, edge_ins_cost : callable
    Functions that return the costs of edge substitution, edge
    deletion, and edge insertion, respectively.

    The functions will be called like

       edge_subst_cost(G1[u1][v1], G2[u2][v2]),
       edge_del_cost(G1[u1][v1]),
       edge_ins_cost(G2[u2][v2]).

    That is, the functions will receive the edge attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function edge_subst_cost overrides edge_match if specified.
    If neither edge_match nor edge_subst_cost are specified then
    default edge substitution cost of 0 is used (edge attributes
    are not considered during matching).

    If edge_del_cost is not specified then default edge deletion
    cost of 1 is used.  If edge_ins_cost is not specified then
    default edge insertion cost of 1 is used.

roots : 2-tuple
    Tuple where first element is a node in G1 and the second
    is a node in G2.
    These nodes are forced to be matched in the comparison to
    allow comparison between rooted graphs.

upper_bound : numeric
    Maximum edit distance to consider.  Return None if no edit
    distance under or equal to upper_bound exists.

timeout : numeric
    Maximum number of seconds to execute.
    After timeout is met, the current best GED is returned.

Examples
--------
>>> G1 = nx.cycle_graph(6)
>>> G2 = nx.wheel_graph(7)
>>> nx.graph_edit_distance(G1, G2)
7.0

>>> G1 = nx.star_graph(5)
>>> G2 = nx.star_graph(5)
>>> nx.graph_edit_distance(G1, G2, roots=(0, 0))
0.0
>>> nx.graph_edit_distance(G1, G2, roots=(1, 0))
8.0

See Also
--------
optimal_edit_paths, optimize_graph_edit_distance,

is_isomorphic: test for graph edit distance of 0

References
----------
.. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick
   Martineau. An Exact Graph Edit Distance Algorithm for Solving
   Pattern Recognition Problems. 4th International Conference on
   Pattern Recognition Applications and Methods 2015, Jan 2015,
   Lisbon, Portugal. 2015,
   <10.5220/0005209202710278>. <hal-01168816>
   https://hal.archives-ouvertes.fr/hal-01168816

NTr	   )r   r   
node_match
edge_matchnode_subst_costnode_del_costnode_ins_costedge_subst_costedge_del_costedge_ins_costrootsupper_boundtimeoutbestcost_costs                   r   r   r   (   sU    p H)


1" #$ Or   )r   c                     / nSn[        U UUUUUUUUU	U
S5       H$  u  pnUb  X:  a  / nUR                  X45        UnM&     X4$ )a  Returns all minimum-cost edit paths transforming G1 to G2.

Graph edit path is a sequence of node and edge edit operations
transforming graph G1 to graph isomorphic to G2.  Edit operations
include substitutions, deletions, and insertions.

Parameters
----------
G1, G2: graphs
    The two graphs G1 and G2 must be of the same type.

node_match : callable
    A function that returns True if node n1 in G1 and n2 in G2
    should be considered equal during matching.

    The function will be called like

       node_match(G1.nodes[n1], G2.nodes[n2]).

    That is, the function will receive the node attribute
    dictionaries for n1 and n2 as inputs.

    Ignored if node_subst_cost is specified.  If neither
    node_match nor node_subst_cost are specified then node
    attributes are not considered.

edge_match : callable
    A function that returns True if the edge attribute dictionaries
    for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should
    be considered equal during matching.

    The function will be called like

       edge_match(G1[u1][v1], G2[u2][v2]).

    That is, the function will receive the edge attribute
    dictionaries of the edges under consideration.

    Ignored if edge_subst_cost is specified.  If neither
    edge_match nor edge_subst_cost are specified then edge
    attributes are not considered.

node_subst_cost, node_del_cost, node_ins_cost : callable
    Functions that return the costs of node substitution, node
    deletion, and node insertion, respectively.

    The functions will be called like

       node_subst_cost(G1.nodes[n1], G2.nodes[n2]),
       node_del_cost(G1.nodes[n1]),
       node_ins_cost(G2.nodes[n2]).

    That is, the functions will receive the node attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function node_subst_cost overrides node_match if specified.
    If neither node_match nor node_subst_cost are specified then
    default node substitution cost of 0 is used (node attributes
    are not considered during matching).

    If node_del_cost is not specified then default node deletion
    cost of 1 is used.  If node_ins_cost is not specified then
    default node insertion cost of 1 is used.

edge_subst_cost, edge_del_cost, edge_ins_cost : callable
    Functions that return the costs of edge substitution, edge
    deletion, and edge insertion, respectively.

    The functions will be called like

       edge_subst_cost(G1[u1][v1], G2[u2][v2]),
       edge_del_cost(G1[u1][v1]),
       edge_ins_cost(G2[u2][v2]).

    That is, the functions will receive the edge attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function edge_subst_cost overrides edge_match if specified.
    If neither edge_match nor edge_subst_cost are specified then
    default edge substitution cost of 0 is used (edge attributes
    are not considered during matching).

    If edge_del_cost is not specified then default edge deletion
    cost of 1 is used.  If edge_ins_cost is not specified then
    default edge insertion cost of 1 is used.

upper_bound : numeric
    Maximum edit distance to consider.

Returns
-------
edit_paths : list of tuples (node_edit_path, edge_edit_path)
   - node_edit_path : list of tuples ``(u, v)`` indicating node transformations
     between `G1` and `G2`. ``u`` is `None` for insertion, ``v`` is `None`
     for deletion.
   - edge_edit_path : list of tuples ``((u1, v1), (u2, v2))`` indicating edge
     transformations between `G1` and `G2`. ``(None, (u2,v2))`` for insertion
     and ``((u1,v1), None)`` for deletion.

cost : numeric
    Optimal edit path cost (graph edit distance). When the cost
    is zero, it indicates that `G1` and `G2` are isomorphic.

Examples
--------
>>> G1 = nx.cycle_graph(4)
>>> G2 = nx.wheel_graph(5)
>>> paths, cost = nx.optimal_edit_paths(G1, G2)
>>> len(paths)
40
>>> cost
5.0

Notes
-----
To transform `G1` into a graph isomorphic to `G2`, apply the node
and edge edits in the returned ``edit_paths``.
In the case of isomorphic graphs, the cost is zero, and the paths
represent different isomorphic mappings (isomorphisms). That is, the
edits involve renaming nodes and edges to match the structure of `G2`.

See Also
--------
graph_edit_distance, optimize_edit_paths

References
----------
.. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick
   Martineau. An Exact Graph Edit Distance Algorithm for Solving
   Pattern Recognition Problems. 4th International Conference on
   Pattern Recognition Applications and Methods 2015, Jan 2015,
   Lisbon, Portugal. 2015,
   <10.5220/0005209202710278>. <hal-01168816>
   https://hal.archives-ouvertes.fr/hal-01168816

NF)r	   append)r   r   r   r   r   r    r!   r"   r#   r$   r&   pathsr(   vertex_path	edge_pathr*   s                   r   r   r      sv    p EH(;

)$ DOEk-.%)& ?r   c              #   T   #    [        U UUUUUUUUU	U
S5       H
  u    pUv   M     g7f)a  Returns consecutive approximations of GED (graph edit distance)
between graphs G1 and G2.

Graph edit distance is a graph similarity measure analogous to
Levenshtein distance for strings.  It is defined as minimum cost
of edit path (sequence of node and edge edit operations)
transforming graph G1 to graph isomorphic to G2.

Parameters
----------
G1, G2: graphs
    The two graphs G1 and G2 must be of the same type.

node_match : callable
    A function that returns True if node n1 in G1 and n2 in G2
    should be considered equal during matching.

    The function will be called like

       node_match(G1.nodes[n1], G2.nodes[n2]).

    That is, the function will receive the node attribute
    dictionaries for n1 and n2 as inputs.

    Ignored if node_subst_cost is specified.  If neither
    node_match nor node_subst_cost are specified then node
    attributes are not considered.

edge_match : callable
    A function that returns True if the edge attribute dictionaries
    for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should
    be considered equal during matching.

    The function will be called like

       edge_match(G1[u1][v1], G2[u2][v2]).

    That is, the function will receive the edge attribute
    dictionaries of the edges under consideration.

    Ignored if edge_subst_cost is specified.  If neither
    edge_match nor edge_subst_cost are specified then edge
    attributes are not considered.

node_subst_cost, node_del_cost, node_ins_cost : callable
    Functions that return the costs of node substitution, node
    deletion, and node insertion, respectively.

    The functions will be called like

       node_subst_cost(G1.nodes[n1], G2.nodes[n2]),
       node_del_cost(G1.nodes[n1]),
       node_ins_cost(G2.nodes[n2]).

    That is, the functions will receive the node attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function node_subst_cost overrides node_match if specified.
    If neither node_match nor node_subst_cost are specified then
    default node substitution cost of 0 is used (node attributes
    are not considered during matching).

    If node_del_cost is not specified then default node deletion
    cost of 1 is used.  If node_ins_cost is not specified then
    default node insertion cost of 1 is used.

edge_subst_cost, edge_del_cost, edge_ins_cost : callable
    Functions that return the costs of edge substitution, edge
    deletion, and edge insertion, respectively.

    The functions will be called like

       edge_subst_cost(G1[u1][v1], G2[u2][v2]),
       edge_del_cost(G1[u1][v1]),
       edge_ins_cost(G2[u2][v2]).

    That is, the functions will receive the edge attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function edge_subst_cost overrides edge_match if specified.
    If neither edge_match nor edge_subst_cost are specified then
    default edge substitution cost of 0 is used (edge attributes
    are not considered during matching).

    If edge_del_cost is not specified then default edge deletion
    cost of 1 is used.  If edge_ins_cost is not specified then
    default edge insertion cost of 1 is used.

upper_bound : numeric
    Maximum edit distance to consider.

Returns
-------
Generator of consecutive approximations of graph edit distance.

Examples
--------
>>> G1 = nx.cycle_graph(6)
>>> G2 = nx.wheel_graph(7)
>>> for v in nx.optimize_graph_edit_distance(G1, G2):
...     minv = v
>>> minv
7.0

See Also
--------
graph_edit_distance, optimize_edit_paths

References
----------
.. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick
   Martineau. An Exact Graph Edit Distance Algorithm for Solving
   Pattern Recognition Problems. 4th International Conference on
   Pattern Recognition Applications and Methods 2015, Jan 2015,
   Lisbon, Portugal. 2015,
   <10.5220/0005209202710278>. <hal-01168816>
   https://hal.archives-ouvertes.fr/hal-01168816
TNr   )r   r   r   r   r   r    r!   r"   r#   r$   r&   r)   r*   s                r   r   r     sF     L *


1 
s   &(c              #   T  ^ ^^
^^^&^'^(^)^*^+^,^-^.^/^0^1^2^3^4#    SSK m.SSKm3[         " S S5      5       m&U&U34S jm+S m'S m0S m2SU&U UU'U*U+U.4S	 jjm,U+U04S
 jm1U&U+U,U/U0U1U24S jm(U(U)U-U/4S jm)[        T R                  5      n[        TR                  5      nSnU(       aI  Uu  nnUU;  d  UU;  a  [
        R                  " S5      eUR                  U5        UR                  U5        [        U5      n[        U5      nT.R                  UU-   UU-   45      nU(       a  T.R                  U VVs/ s H0  nU  H&  nU" T R                  U   TR                  U   5      PM(     M2     snn5      R                  UU5      USU2SU24'   U(       a#  U" T R                  W   TR                  W   5      nOU(       a  T.R                  U VVs/ s H<  nU  H2  nS[        U" T R                  U   TR                  U   5      5      -
  PM4     M>     snn5      R                  UU5      USU2SU24'   U(       a&  SU" T R                  W   TR                  W   5      -
  nO U(       a&  U Vs/ s H  nU" T R                  U   5      PM     nnOS/[        U5      -  nU(       a&  U Vs/ s H  nU" TR                  U   5      PM     nnOS/[        U5      -  nUSU2SU24   R                  5       [        U5      -   [        U5      -   S-   m*T.R                  [        U5       VVs/ s H#  n[        U5        H  nUU:X  a  UU   OT*PM     M%     snn5      R                  UU5      USU2UUU-   24'   T.R                  [        U5       VVs/ s H#  n[        U5        H  nUU:X  a  UU   OT*PM     M%     snn5      R                  UU5      UUUU-   2SU24'   T+" UUU5      n[        T R                  5      n[        TR                  5      n[        U5      n[        U5      nT.R                  UU-   UU-   45      nU(       ai  T.R                  U VV s/ s H0  nU  H&  n U" T R                  U   TR                  U    5      PM(     M2     sn n5      R                  UU5      USU2SU24'   O}U(       au  T.R                  U VV s/ s H<  nU  H2  n S[        U" T R                  U   TR                  U    5      5      -
  PM4     M>     sn n5      R                  UU5      USU2SU24'   O U(       a&  U Vs/ s H  nU" T R                  U   5      PM     nnOS/[        U5      -  nU	(       a&  U V s/ s H  n U	" TR                  U    5      PM     nn OS/[        U5      -  nUSU2SU24   R                  5       [        U5      -   [        U5      -   S-   m*T.R                  [        U5       VVs/ s H#  n[        U5        H  nUU:X  a  UU   OT*PM     M%     snn5      R                  UU5      USU2UUU-   24'   T.R                  [        U5       VVs/ s H#  n[        U5        H  nUU:X  a  UU   OT*PM     M%     snn5      R                  UU5      UUUU-   2SU24'   T+" UUU5      n!UR                   R                  5       U!R                   R                  5       -   S-   m-Tb1  TS::  a  [
        R"                  " S5      e[$        R&                  " 5       m4U-U4UUU
4S jm/Uc  / OU/n"T)" U"XU/ UUU!U5	       H)  u  n#n$n%[        U#5      [        U$5      [)        U%5      4v   M+     gs  snnf s  snnf s  snf s  snf s  snnf s  snnf s  sn nf s  sn nf s  snf s  sn f s  snnf s  snnf 7f)a  GED (graph edit distance) calculation: advanced interface.

Graph edit path is a sequence of node and edge edit operations
transforming graph G1 to graph isomorphic to G2.  Edit operations
include substitutions, deletions, and insertions.

Graph edit distance is defined as minimum cost of edit path.

Parameters
----------
G1, G2: graphs
    The two graphs G1 and G2 must be of the same type.

node_match : callable
    A function that returns True if node n1 in G1 and n2 in G2
    should be considered equal during matching.

    The function will be called like

       node_match(G1.nodes[n1], G2.nodes[n2]).

    That is, the function will receive the node attribute
    dictionaries for n1 and n2 as inputs.

    Ignored if node_subst_cost is specified.  If neither
    node_match nor node_subst_cost are specified then node
    attributes are not considered.

edge_match : callable
    A function that returns True if the edge attribute dictionaries
    for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should
    be considered equal during matching.

    The function will be called like

       edge_match(G1[u1][v1], G2[u2][v2]).

    That is, the function will receive the edge attribute
    dictionaries of the edges under consideration.

    Ignored if edge_subst_cost is specified.  If neither
    edge_match nor edge_subst_cost are specified then edge
    attributes are not considered.

node_subst_cost, node_del_cost, node_ins_cost : callable
    Functions that return the costs of node substitution, node
    deletion, and node insertion, respectively.

    The functions will be called like

       node_subst_cost(G1.nodes[n1], G2.nodes[n2]),
       node_del_cost(G1.nodes[n1]),
       node_ins_cost(G2.nodes[n2]).

    That is, the functions will receive the node attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function node_subst_cost overrides node_match if specified.
    If neither node_match nor node_subst_cost are specified then
    default node substitution cost of 0 is used (node attributes
    are not considered during matching).

    If node_del_cost is not specified then default node deletion
    cost of 1 is used.  If node_ins_cost is not specified then
    default node insertion cost of 1 is used.

edge_subst_cost, edge_del_cost, edge_ins_cost : callable
    Functions that return the costs of edge substitution, edge
    deletion, and edge insertion, respectively.

    The functions will be called like

       edge_subst_cost(G1[u1][v1], G2[u2][v2]),
       edge_del_cost(G1[u1][v1]),
       edge_ins_cost(G2[u2][v2]).

    That is, the functions will receive the edge attribute
    dictionaries as inputs.  The functions are expected to return
    positive numeric values.

    Function edge_subst_cost overrides edge_match if specified.
    If neither edge_match nor edge_subst_cost are specified then
    default edge substitution cost of 0 is used (edge attributes
    are not considered during matching).

    If edge_del_cost is not specified then default edge deletion
    cost of 1 is used.  If edge_ins_cost is not specified then
    default edge insertion cost of 1 is used.

upper_bound : numeric
    Maximum edit distance to consider.

strictly_decreasing : bool
    If True, return consecutive approximations of strictly
    decreasing cost.  Otherwise, return all edit paths of cost
    less than or equal to the previous minimum cost.

roots : 2-tuple
    Tuple where first element is a node in G1 and the second
    is a node in G2.
    These nodes are forced to be matched in the comparison to
    allow comparison between rooted graphs.

timeout : numeric
    Maximum number of seconds to execute.
    After timeout is met, the current best GED is returned.

Returns
-------
Generator of tuples (node_edit_path, edge_edit_path, cost)
    node_edit_path : list of tuples (u, v)
    edge_edit_path : list of tuples ((u1, v1), (u2, v2))
    cost : numeric

See Also
--------
graph_edit_distance, optimize_graph_edit_distance, optimal_edit_paths

References
----------
.. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick
   Martineau. An Exact Graph Edit Distance Algorithm for Solving
   Pattern Recognition Problems. 4th International Conference on
   Pattern Recognition Applications and Methods 2015, Jan 2015,
   Lisbon, Portugal. 2015,
   <10.5220/0005209202710278>. <hal-01168816>
   https://hal.archives-ouvertes.fr/hal-01168816

r   Nc                   >    \ rS rSr% S\S'   S\S'   S\S'   S\S'   Srg)	'optimize_edit_paths.<locals>.CostMatrixi  .Clsa_row_indlsa_col_indls N)__name__
__module____qualname____firstlineno____annotations____static_attributes__r8   r   r   
CostMatrixr3     s    r   r?   c                    > TR                   R                  U 5      u  p4X1:  XB:  -  nX1:  XB:  -  nXE   U-   X6'   X5   U-   XF'   T" XX@X44   R                  5       5      $ r   )optimizelinear_sum_assignmentsum)	r4   mnr5   r6   is_substis_dummyr?   sps	          r   make_CostMatrix,optimize_edit_paths.<locals>.make_CostMatrix  s    #%;;#D#DQ#G   O8$)9: !, 5 9 + 5 9K;+C)D)H)H)J
 	
r   c                     [        X4-   5       Vs/ s H  oUU;   =(       d    XS-
  U;   PM     nn[        X4-   5       Vs/ s H  oUU;   =(       d    XT-
  U;   PM     nnXS S 24   S S 2U4   $ s  snf s  snf r   ranger4   ijrD   rE   krow_indcol_inds           r   	extract_C&optimize_edit_paths.<locals>.extract_C  ss    16qu>A6'QUaZ'>16qu>A6'QUaZ'>!}QZ(( ?>
   A*A/c                     [        X4-   5       Vs/ s H  oUU;  =(       a    XS-
  U;  PM     nn[        X4-   5       Vs/ s H  oUU;  =(       a    XT-
  U;  PM     nnXS S 24   S S 2U4   $ s  snf s  snf r   rL   rN   s           r   reduce_C%optimize_edit_paths.<locals>.reduce_C  st    :?,G,QA:0!%q.0,G:?,G,QA:0!%q.0,G!}QZ(( HGrV   c                     X  Vs/ s H  o"U;  PM	     sn   n[        U5       H  nX3U:  ==   S-  ss'   M     U$ s  snf )Nr   )set)indrO   rQ   rinds       r   
reduce_ind'optimize_edit_paths.<locals>.reduce_ind  sE    ,1QJ,-QAOq O  -s   ;c                 8  >^ ^^^^
^^^ [        T5      n[        T5      nUb  [        U5      S:X  a  / n/ n	O[        U5       V
^
s/ s H1  m
TT
   SS T T 4:X  d  [        U
UU 4S jU 5       5      (       d  M/  T
PM3     nn
[        U5       V^s/ s H1  mTT   SS TT4:X  d  [        UUU4S jU 5       5      (       d  M/  TPM3     n	n[        U5      n[        U	5      nU(       d  U(       Ga  T" UR                  XXg5      n[	        U5       H  u  nm
TT
   SS m[	        U	5       H  u  nmTT   SS m[
        R                  " T5      (       d  [
        R                  " T5      (       a   [        UUU U4S jU 5       5      (       a  Mc  O[        UUU U4S jU 5       5      (       a  M  TT T 4:X  d  [        U4S jU 5       5      (       a  M  TTT4:X  d  [        U4S	 jU 5       5      (       a  M  TXU4'   M     M     T" XU5      n[        UR                  UR                  5       VVs/ s H5  u  nnX:  d  UU:  d  M  X:  a  X   OXiU   -   UU:  a  U	U   OXxU   -   4PM7     nnnUU4$ / nT" TR                  S
5      / / S5      nUU4$ s  sn
f s  snf s  snnf )a  
Parameters:
    u, v: matched vertices, u=None or v=None for
       deletion/insertion
    pending_g, pending_h: lists of edges not yet mapped
    Ce: CostMatrix of pending edge mappings
    matched_uv: partial vertex edit path
        list of tuples (u, v) of previously matched vertex
            mappings u<->v, u=None or v=None for
            deletion/insertion

Returns:
    list of (i, j): indices of edge mappings g<->h
    localCe: local CostMatrix of edge mappings
        (basically submatrix of Ce at cross of rows i, cols j)
Nr      c              3   N   >#    U  H  u  pTT   S S UT4TU4X44;   v   M     g 7fNra   r8   ).0pqrO   	pending_gus      r   	<genexpr>;optimize_edit_paths.<locals>.match_edges.<locals>.<genexpr>  7      MWTQIaL!$!Q!Q!(@@Z   "%c              3   N   >#    U  H  u  pTT   S S UT4TU4X"44;   v   M     g 7frc   r8   )rd   re   rf   rP   	pending_hvs      r   ri   rj     rk   rl   c              3      >#    U  H8  u  pTUT4:H  =(       a    TUT4:H  =(       d    TTU4:H  =(       a    TTU4:H  v   M:     g 7fr   r8   rd   re   rf   ghrh   ro   s      r   ri   rj     sO      (2 !QK7A!QKV1A;;V1QRTUPV;V(2s   A Ac              3   b   >#    U  H$  u  pTUT4TU44;   =(       a    TUT4TU44;   v   M&     g 7fr   r8   rq   s      r   ri   rj   %  sF      (2 1a&1a&!11KaQFQF;K6KK(2s   ,/c              3   4   >#    U  H  u  pTX4:H  v   M     g 7fr   r8   )rd   re   rf   rr   s      r   ri   rj   *       )M*$!!v+*   c              3   4   >#    U  H  u  pTX"4:H  v   M     g 7fr   r8   )rd   re   rf   rs   s      r   ri   rj   ,  rv   rw   )r   r   )lenrM   anyr4   	enumeratenxis_directedzipr5   r6   empty)rh   ro   rg   rn   Ce
matched_uvMNg_indh_indrO   rP   rD   rE   r4   rQ   llocalCeijrr   rs   r?   r   r   rT   infrI   nps   ````      ``       @@r   match_edges(optimize_edit_paths.<locals>.match_edges  s   " 	N	N ZA!5EE q!AQ<#1v- MW  !   q!AQ<#1v- MW  !   JJ"$$a3A
 "%(1aL!$%e,DAq!!Ra(A~~b))R^^B-?-? (2   %	  (2   %QF{c)M*)M&M&M QF{c)M*)M&M&M !AdG% - ), &aA.G   3 3W5H5HI
 JDAq5AE !EH1Qx< !AE!H1Qx< J   7{ B &!12r1=G7{}Rs$   .J7J.J?J)J?&Jc           	         >^^ [        U5      (       aV  [        U6 u  pET[        U4S jU 5       5      -
  nT[        U4S jU 5       5      -
  nT" T	" U R                  XETT5      Xg5      $ U $ )Nc              3   6   >#    U  H  oT:  d  M
  S v   M     g7fr   Nr8   )rd   trD   s     r   ri   9optimize_edit_paths.<locals>.reduce_Ce.<locals>.<genexpr>C       0Qa%!!Q   		c              3   6   >#    U  H  oT:  d  M
  S v   M     g7fr   r8   )rd   r   rE   s     r   ri   r   D  r   r   )ry   r~   rC   r4   )
r   r   rD   rE   rO   rP   m_in_jrI   rX   s
     ``    r   	reduce_Ce&optimize_edit_paths.<locals>.reduce_Ce@  sb    r778DAc0Q000Cc0Q000C"8BDD!1#=sHH	r   c           
   3     >^^^^#    [        U5      m[        U5      m[        UU4S j[        UR                  UR                  5       5       5      u  pT" UT:  a  X   OSU	T:  a  X)   OSUUUU 5      u  pT" Xj[        U5      [        U5      5      nT" XsR
                  -   UR
                  -   UR
                  -   5      (       a  OT" T" UR                  U4U	4TT5      T" UR                  UTU	-   45      T" UR                  U	TU-   45      UR
                  UR                  X4   -
  5      nX4XXR                  X4   UR
                  -   4v   / nXsmmTT::  a  UUU4S j[        TT-   5       5       nOUUU4S j[        TT-   5       5       nU GH  u  pT" XsR                  X4   -   UR
                  -   5      (       a  M2  T" T" UR                  U4U	4TT5      UT:  a  TS-
  OTU	T:  a  TS-
  OT5      nT" XsR                  X4   -   UR
                  -   UR
                  -   5      (       a  M  T" UT:  a  X   OSU	T:  a  X)   OSUUUU 5      u  pT" XsR                  X4   -   UR
                  -   UR
                  -   5      (       a  M  T" Xj[        U5      [        U5      5      nT" XsR                  X4   -   UR
                  -   UR
                  -   UR
                  -   5      (       a  GM`  UR                  X4XXR                  X4   UR
                  -   45        GM     [        US S9 Sh  vN   g N7f)aJ  
Parameters:
    matched_uv: partial vertex edit path
        list of tuples (u, v) of vertex mappings u<->v,
        u=None or v=None for deletion/insertion
    pending_u, pending_v: lists of vertices not yet mapped
    Cv: CostMatrix of pending vertex mappings
    pending_g, pending_h: lists of edges not yet mapped
    Ce: CostMatrix of pending edge mappings
    matched_cost: cost of partial edit path

Returns:
    sequence of
        (i, j): indices of vertex mapping u<->v
        Cv_ij: reduced CostMatrix of pending vertex mappings
            (basically Cv with row i, col j removed)
        list of (x, y): indices of edge mappings g<->h
        Ce_xy: reduced CostMatrix of pending edge mappings
            (basically Ce with rows x, cols y removed)
        cost: total cost of edit operation
    NOTE: most promising ops first
c              3   J   >#    U  H  u  pUT:  d  UT:  d  M  X4v   M     g 7fr   r8   )rd   rQ   r   rD   rE   s      r   ri   <optimize_edit_paths.<locals>.get_edit_ops.<locals>.<genexpr>f  s(      
Btqa!eqSTuFQFBs   #
#Nc              3   ^   >#    U  H"  nUT:w  d  M  UT:  d  UTT-   :X  d  M  UT4v   M$     g 7fr   r8   )rd   r   fixed_ifixed_jrD   s     r   ri   r     s<      %A< %&Ua1w;.> G%   
---c              3   ^   >#    U  H"  nUT:w  d  M  UT:  d  UTT-   :X  d  M  TU4v   M$     g 7fr   r8   )rd   r   r   r   rE   s     r   ri   r     s<      %A< %&Ua1w;.> !%r   r   c                 L    U S   U S   R                   -   U S   R                   -   $ )N   r      )r7   )r   s    r   <lambda>;optimize_edit_paths.<locals>.get_edit_ops.<locals>.<lambda>  s!    qtadgg~!/Gr   )key)
ry   minr~   r5   r6   r7   r4   rM   r,   sorted)r   	pending_u	pending_vCvrg   rn   r   matched_costrO   rP   xyr   Ce_xyCv_ijother
candidatesr   r   rD   rE   r?   rI   r   prunerX   r   r^   s                   @@@@r   get_edit_ops)optimize_edit_paths.<locals>.get_edit_opsH  s    2 	N	N  
"2>>2>>B
 
 "EILtEILt
 "#i.#i.A%

2UXX=>> taT1a02>>Aq1u:62>>Aq1u:6QT
"	E &%UDDJ,CCC 6q1uJq1uJ
 DA\DDJ.677#taT1a0QAAQAAE \DDJ.9BEEABB% !A	4 !A	4KB \DDJ.9GJJFGGbc)nc)nEE\DDJ.9GJJFQRRLL1&%UDDJ4KLM3 6 %%GHHHs   L1M 8L>9M c	              3     >#    T!" XR                   -   UR                   -   5      (       a  g[        [        U5      [        U5      5      (       d  [        T U5      m XU4v   gT" U UUUUUUU5      n	U	 GHM  u  ppnU
u  nnT!" X-   UR                   -   UR                   -   5      (       a  M8  U[        U5      :  a  UR	                  U5      OSnU[        U5      :  a  UR	                  U5      OSnU R                  UU45        U HE  u  nn[        U5      n[        U5      nUR                  UU:  a  UU   OSUU:  a  UU   OS45        MG     [        S U 5       5      n[        S U 5       5      n[        U5       Vs/ s H%  nU[        U5      :  a  UR	                  U5      OSPM'     nn[        U5       Vs/ s H%  nU[        U5      :  a  UR	                  U5      OSPM'     nnT" U UUUUUUUX-   5	       Sh  vN   Ub  UR                  UU5        Ub  UR                  UU5        U R	                  5         [        U[        U5      5       H  u  nnUc  M  UR                  UU5        M     [        U[        U5      5       H  u  nnUc  M  UR                  UU5        M     U H  nUR	                  5         M     GMP     gs  snf s  snf  N7f)a  
Parameters:
    matched_uv: partial vertex edit path
        list of tuples (u, v) of vertex mappings u<->v,
        u=None or v=None for deletion/insertion
    pending_u, pending_v: lists of vertices not yet mapped
    Cv: CostMatrix of pending vertex mappings
    matched_gh: partial edge edit path
        list of tuples (g, h) of edge mappings g<->h,
        g=None or h=None for deletion/insertion
    pending_g, pending_h: lists of edges not yet mapped
    Ce: CostMatrix of pending edge mappings
    matched_cost: cost of partial edit path

Returns:
    sequence of (vertex_path, edge_path, cost)
        vertex_path: complete vertex edit path
            list of tuples (u, v) of vertex mappings u<->v,
            u=None or v=None for deletion/insertion
        edge_path: complete edge edit path
            list of tuples (g, h) of edge mappings g<->h,
            g=None or h=None for deletion/insertion
        cost: total cost of edit path
    NOTE: path costs are non-increasing
Nc              3   *   #    U  H	  u  pUv   M     g 7fr   r8   rd   xys      r   ri   >optimize_edit_paths.<locals>.get_edit_paths.<locals>.<genexpr>        2rtqr   c              3   *   #    U  H	  u  pUv   M     g 7fr   r8   r   s      r   ri   r   	  r   r   )
r7   maxry   r   popr,   r   reversedinsertr~   )"r   r   r   r   
matched_ghrg   rn   r   r   edit_opsr   r   r   r   	edit_costrO   rP   rh   ro   r   r   len_glen_hsortedxsortedyGHrr   rs   r)   r   get_edit_pathsmaxcost_valuer   s"                                 r   r   +optimize_edit_paths.<locals>.get_edit_paths  s    f %-..3y>3y>22  |<M,66 $	H 4</2i11EHH<uxxGHH )*C	N(:IMM!$()C	N(:IMM!$!!1a&)DAq	NE	NE%%,-IIaL4,-IIaL4  ! 2r 22  2r 22 &g.. *+S^);Y]]1%E.   &g.. *+S^);Y]]1%E.  
 * ,
 
 
 =$$Q*=$$Q* !5DAq}!((A. 6  !5DAq}!((A. 6 ANN$ m 4<*

s8   E:K=,K)K8,K
$K;K<AK2KA KzRoot node not in graph.r   z$Timeout value must be greater than 0c                    > Tb  [         R                  " 5       T-
  T:  a  gTb  U T:  a  gU T:  a  gT(       a  U T:  a  gg)NTF)timeperf_counter)r*   r   startstrictly_decreasingr'   r&   s    r   r   "optimize_edit_paths.<locals>.prune  sN      "U*W4"k!-4=#8r   r   )numpyscipyr   listnodesr|   NodeNotFoundremovery   zerosarrayreshapeintrC   rM   edgesr4   NetworkXErrorr   r   float)5r   r   r   r   r   r    r!   r"   r#   r$   r&   r   r%   r'   r   r   initial_costroot_uroot_vrD   rE   r4   rh   ro   	del_costs	ins_costsrO   rP   r   rg   rn   rr   rs   r   done_uvr.   r/   r*   r?   rT   r   r   r   rI   r   r   r   r   rX   r   r^   rH   r   s5   ``        `` `                        @@@@@@@@@@@@@@@r   r	   r	     sb    n   
&))Z ZxaI aIFA% A%J RXXIRXXIL"fI&=//";<< 	   	IAIA
!a%Q Ahh #"A"A  RXXa[9" :"
 '!Q- 	
!A#qs( *288F+;RXXf=MNL	hh #"A"A C
288A;<==" >"
 '!Q- 	
!A#qs( z"((6*:BHHV<LMML 	9BCA]288A;/	C	C#i.(	9BCA]288A;/	C	C#i.(	
AaC1H+//
c)n
,s9~
=
AC27(M(QE!Hqa1S	(H	((Mgam ac1q1u9n 27(M(QE!Hqa1S	(H	((Mgam a!a%i1n 
Aq	!B RXXIRXXI 	IAIA
!a%Q Ahh #"A"A  RXXa[9" :"
 '!Q- 	
!A#qs( 
hh #"A"A C
288A;<==" >"
 '!Q- 	
!A#qs( 	9BCA]288A;/	C	C#i.(	9BCA]288A;/	C	C#i.(	
AaC1H+//
c)n
,s9~
=
AC27(M(QE!Hqa1S	(H	((Mgam ac1q1u9n 27(M(QE!Hqa1S	(H	((Mgam a!a%i1n 
Aq	!B
 DDHHJ+a/Ma<""#IJJ!!#  MbwG(6r2y)R)$Y ;i%+==)i D
 D 	N 	N D
 D 	N 	Ns   D^(.7]$
%A#^(A]*
A^(&]0^("]5A^( *]:

=^(*^ 
1B^(7^
9^(?A^
.^(0^^(,^A^(**^
=^(*^"
;D-^(c                 N   SSK n[        U 5      nUb1  X;  a  [        R                  " SU S35      eUR	                  U5      nOSnUb1  X';  a  [        R                  " SU S35      eUR	                  U5      n	OSn	[        XXXE5      n
[        XR                  5      (       as  U
R                  S:X  a"  [        [        X
R                  5       5      5      $ [        X
R                  5       5       VVs0 s H  u  pU[        [        X5      5      _M     snn$ [        U
5      $ s  snnf )a  Returns the SimRank similarity of nodes in the graph ``G``.

SimRank is a similarity metric that says "two objects are considered
to be similar if they are referenced by similar objects." [1]_.

The pseudo-code definition from the paper is::

    def simrank(G, u, v):
        in_neighbors_u = G.predecessors(u)
        in_neighbors_v = G.predecessors(v)
        scale = C / (len(in_neighbors_u) * len(in_neighbors_v))
        return scale * sum(
            simrank(G, w, x) for w, x in product(in_neighbors_u, in_neighbors_v)
        )

where ``G`` is the graph, ``u`` is the source, ``v`` is the target,
and ``C`` is a float decay or importance factor between 0 and 1.

The SimRank algorithm for determining node similarity is defined in
[2]_.

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

source : node
    If this is specified, the returned dictionary maps each node
    ``v`` in the graph to the similarity between ``source`` and
    ``v``.

target : node
    If both ``source`` and ``target`` are specified, the similarity
    value between ``source`` and ``target`` is returned. If
    ``target`` is specified but ``source`` is not, this argument is
    ignored.

importance_factor : float
    The relative importance of indirect neighbors with respect to
    direct neighbors.

max_iterations : integer
    Maximum number of iterations.

tolerance : float
    Error tolerance used to check convergence. When an iteration of
    the algorithm finds that no similarity value changes more than
    this amount, the algorithm halts.

Returns
-------
similarity : dictionary or float
    If ``source`` and ``target`` are both ``None``, this returns a
    dictionary of dictionaries, where keys are node pairs and value
    are similarity of the pair of nodes.

    If ``source`` is not ``None`` but ``target`` is, this returns a
    dictionary mapping node to the similarity of ``source`` and that
    node.

    If neither ``source`` nor ``target`` is ``None``, this returns
    the similarity value for the given pair of nodes.

Raises
------
ExceededMaxIterations
    If the algorithm does not converge within ``max_iterations``.

NodeNotFound
    If either ``source`` or ``target`` is not in `G`.

Examples
--------
>>> G = nx.cycle_graph(2)
>>> nx.simrank_similarity(G)
{0: {0: 1.0, 1: 0.0}, 1: {0: 0.0, 1: 1.0}}
>>> nx.simrank_similarity(G, source=0)
{0: 1.0, 1: 0.0}
>>> nx.simrank_similarity(G, source=0, target=0)
1.0

The result of this function can be converted to a numpy array
representing the SimRank matrix by using the node order of the
graph to determine which row and column represent each node.
Other ordering of nodes is also possible.

>>> import numpy as np
>>> sim = nx.simrank_similarity(G)
>>> np.array([[sim[u][v] for v in G] for u in G])
array([[1., 0.],
       [0., 1.]])
>>> sim_1d = nx.simrank_similarity(G, source=0)
>>> np.array([sim[0][v] for v in G])
array([1., 0.])

References
----------
.. [1] https://en.wikipedia.org/wiki/SimRank
.. [2] G. Jeh and J. Widom.
       "SimRank: a measure of structural-context similarity",
       In KDD'02: Proceedings of the Eighth ACM SIGKDD
       International Conference on Knowledge Discovery and Data Mining,
       pp. 538--543. ACM Press, 2002.
r   NSource node 	 not in GzTarget node r   )r   r   r|   r   index_simrank_similarity_numpy
isinstancendarrayndimdictr~   tolistr   )r   sourcetargetimportance_factormax_iterations	tolerancer   nodelists_indxt_indxr   rh   rows                r   r
   r
     s   b AwH!//L	"BCC^^F+F!//L	"BCC^^F+F!	6n	A !ZZ  66Q;Axxz*++36q((*3EF3E4A$$3EFF8O Gs   1!D!c                 f  ^^^^^ U  VVs0 s H  ofU  Vs0 s H  owXg:X  a  SOS_M     sn_M     snnmU4S jmU R                  5       (       a  U R                  OU R                  mUUU4S jn[        U5       He  n	Tn
U  VVs0 s H#  ofU  Vs0 s H  owXg:w  a  U" Xg5      OS_M     sn_M%     snnm[	        UU4S jU
R                  5        5       5      nU(       d  Me    O   W	S-   U:X  a  [        R                  " SU S35      eUb  Ub  TU   U   $ Ub  TU   $ T$ s  snf s  snnf s  snf s  snnf )a  Returns the SimRank similarity of nodes in the graph ``G``.

This pure Python version is provided for pedagogical purposes.

Examples
--------
>>> G = nx.cycle_graph(2)
>>> nx.similarity._simrank_similarity_python(G)
{0: {0: 1, 1: 0.0}, 1: {0: 0.0, 1: 1}}
>>> nx.similarity._simrank_similarity_python(G, source=0)
{0: 1, 1: 0.0}
>>> nx.similarity._simrank_similarity_python(G, source=0, target=0)
1
r   r   c                 X   > U (       a!  [        U4S jU  5       5      [        U 5      -  $ S$ )Nc              3   8   >#    U  H  u  pTU   U   v   M     g 7fr   r8   )rd   wr   newsims      r   ri   >_simrank_similarity_python.<locals>.avg_sim.<locals>.<genexpr>o  s     0aFQ6!9Q<as   g        )rC   ry   )sr   s    r   avg_sim+_simrank_similarity_python.<locals>.avg_simn  s$    =>s0a003q69GCGr   c           
      L   > TT" [        [        TU    TU   5      5      5      -  $ r   )r   r   )rh   ro   Gadjr  r   s     r   sim'_simrank_similarity_python.<locals>.sims  s'     74Qa0I+J#KKKr   c              3   v   >^#    U  H-  u  mn[        UUU4S  jUR                  5        5       5      v   M/     g7f)c              3   t   >#    U  H-  u  p[        TT   U   U-
  5      TS [        U5      -   -  :*  v   M/     g7fr   )abs)rd   ro   oldr   r   rh   s      r   ri   7_simrank_similarity_python.<locals>.<genexpr>.<genexpr>z  s>      *FA F1IaL3&'9CH+EE*s   58N)allitems)rd   nbrsrh   r   r   s     @r   ri   -_simrank_similarity_python.<locals>.<genexpr>y  s=      

 *4	  "jjl   *s   59simrank did not converge after  iterations.)r}   predadjrM   r  r  r|   ExceededMaxIterations)r   r   r   r   r   r   rh   ro   r  itsoldsimis_closer  r  r   s      ` `      @@@r   _simrank_similarity_pythonr  S  s>   . >??Q3A!&Qa'33Q?FH ]]__166!%%DL ^$IJKAQ?QafQ!3Q??K 

 "<<>
 
 8 % Qw. &&-n-=\J
 	
 f0f~f%%f~ME 4? @Ks-   
D"DD"
D-D(&D-D"(D-c                    SSK n[        R                  " U 5      nUR                  UR	                  SS95      nSXS:H  '   Xx-  nUR                  [        U 5      UR                  S9n	[        U5       HP  n
U	R                  5       nX7R                  U-  U-  -  n	UR                  U	S5        UR                  XUS9(       d  MP    O   W
S-   U:X  a  [        R                  " SU S	35      eUb  Ub  [        XU4   5      $ Ub  X   $ U	$ )
a  Calculate SimRank of nodes in ``G`` using matrices with ``numpy``.

The SimRank algorithm for determining node similarity is defined in
[1]_.

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

source : node
    If this is specified, the returned dictionary maps each node
    ``v`` in the graph to the similarity between ``source`` and
    ``v``.

target : node
    If both ``source`` and ``target`` are specified, the similarity
    value between ``source`` and ``target`` is returned. If
    ``target`` is specified but ``source`` is not, this argument is
    ignored.

importance_factor : float
    The relative importance of indirect neighbors with respect to
    direct neighbors.

max_iterations : integer
    Maximum number of iterations.

tolerance : float
    Error tolerance used to check convergence. When an iteration of
    the algorithm finds that no similarity value changes more than
    this amount, the algorithm halts.

Returns
-------
similarity : numpy array or float
    If ``source`` and ``target`` are both ``None``, this returns a
    2D array containing SimRank scores of the nodes.

    If ``source`` is not ``None`` but ``target`` is, this returns an
    1D array containing SimRank scores of ``source`` and that
    node.

    If neither ``source`` nor ``target`` is ``None``, this returns
    the similarity value for the given pair of nodes.

Examples
--------
>>> G = nx.cycle_graph(2)
>>> nx.similarity._simrank_similarity_numpy(G)
array([[1., 0.],
       [0., 1.]])
>>> nx.similarity._simrank_similarity_numpy(G, source=0)
array([1., 0.])
>>> nx.similarity._simrank_similarity_numpy(G, source=0, target=0)
1.0

References
----------
.. [1] G. Jeh and J. Widom.
       "SimRank: a measure of structural-context similarity",
       In KDD'02: Proceedings of the Eighth ACM SIGKDD
       International Conference on Knowledge Discovery and Data Mining,
       pp. 538--543. ACM Press, 2002.
r   Naxisr   )dtype      ?)atolr  r  )r   r|   to_numpy_arrayr   rC   eyery   float64rM   copyTfill_diagonalallcloser  r   )r   r   r   r   r   r   r   adjacency_matrixr   r   r  prevsims               r   r   r     s   ^ ((+ 	!%%1%-.AA1fIVVCF"**V-F^$++-"'9'9G'CGW&WX
%;;wY;77 % Qw. &&-n-=\J
 	
 f0VFN+,,~Mr   weight)
edge_attrs   c           
         SSK nX;  a  [        R                  " SU S35      e[        [        R                  " U 5      5      n	X;   a  [        R
                  " SU S35      eU R                  U R                   V
s/ s H  oU	;  d  M
  U
PM     sn
5      R                  5       n U R                  5       nX:  a  [        R                  " SU SU S	35        UnUc"  UR                  S
U R                  5       -  5      n[        U R                  5       VVs0 s H  u  pX_M	     nnnUR                  U 5      n[         R"                  " US5      n[%        XFS-  -  UR'                  U5      S-   UR)                  SU-  5      -   -  5      n0 n[+        [-        U UUUUS95      nUR/                  U5      nSU-  n[        UU   5      nUR1                  5        H*  u  n
nUR3                  U5      n[5        U5      U-  UX   '   M,     UR7                  UU* 5      U* S nUUR9                  UU   5         SSS2   n[;        [=        UU   R?                  5       UU   R?                  5       5      5      nURA                  US5        U$ s  sn
f s  snnf )u  Returns the Panther similarity of nodes in the graph `G` to node ``v``.

Panther is a similarity metric that says "two objects are considered
to be similar if they frequently appear on the same paths." [1]_.

Parameters
----------
G : NetworkX graph
    A NetworkX graph
source : node
    Source node for which to find the top `k` similar other nodes
k : int (default = 5)
    The number of most similar nodes to return.
path_length : int (default = 5)
    How long the randomly generated paths should be (``T`` in [1]_)
c : float (default = 0.5)
    A universal positive constant used to scale the number
    of sample random paths to generate.
delta : float (default = 0.1)
    The probability that the similarity $S$ is not an epsilon-approximation to (R, phi),
    where $R$ is the number of random paths and $\phi$ is the probability
    that an element sampled from a set $A \subseteq D$, where $D$ is the domain.
eps : float or None (default = None)
    The error bound. Per [1]_, a good value is ``sqrt(1/|E|)``. Therefore,
    if no value is provided, the recommended computed value will be used.
weight : string or None, optional (default="weight")
    The name of an edge attribute that holds the numerical value
    used as a weight. If None then each edge has weight 1.

Returns
-------
similarity : dictionary
    Dictionary of nodes to similarity scores (as floats). Note:
    the self-similarity (i.e., ``v``) will not be included in
    the returned dictionary. So, for ``k = 5``, a dictionary of
    top 4 nodes and their similarity scores will be returned.

Raises
------
NetworkXUnfeasible
    If `source` is an isolated node.

NodeNotFound
    If `source` is not in `G`.

Notes
-----
    The isolated nodes in `G` are ignored.

Examples
--------
>>> G = nx.star_graph(10)
>>> sim = nx.panther_similarity(G, 0)

References
----------
.. [1] Zhang, J., Tang, J., Ma, C., Tong, H., Jing, Y., & Li, J.
       Panther: Fast top-k similarity search on large networks.
       In Proceedings of the ACM SIGKDD International Conference
       on Knowledge Discovery and Data Mining (Vol. 2015-August, pp. 1445–1454).
       Association for Computing Machinery. https://doi.org/10.1145/2783258.2783267.
r   Nr   r   z?Panther similarity is not defined for the isolated source node .zNumber of nodes is z, but requested k is z. Setting k to number of nodes.r  ra   r   )path_length	index_mapr(  )!r   r|   r   r[   isolatesNetworkXUnfeasiblesubgraphr   r"  number_of_nodeswarningswarnsqrtnumber_of_edgesr{   r   mathcombr   log2logr   r   r   r  intersectionry   argpartitionargsortr   r~   r   r   )r   r   rQ   r-  cdeltaepsr(  r   r0  node	num_nodesr   nameinv_node_mapnode_map
t_choose_2sample_sizer.  r)   Sinv_sample_sizesource_pathsr-   common_pathstop_k_unsortedtop_k_sortedtop_k_with_vals                               r   r   r     s   D ooVHI>??2;;q>"H##MfXUVW
 	
 	


QWWEWTH0DDWEFKKMA!!#I}!),A! E, ,	
  {ggcA--//03<QWW3EF3EKEDK3ELFxx{H ;*Jq6zbggj&9A&=q5y@Q&QRSKI{yQW	
	A
 	A+oOy()L !(e $007 #L 1O C,
	 ) __Q+QBC0N!"**Q~->"?@2FL H\"))+Q|_-C-C-EFN
 vt$q F Gs   ;	J J Jc              #     #    SSK n[        XVR                  R                  5      (       a  UR                  OUR
                  n[        R                  " XS9nUR                  UR                  SS95      R                  SS5      n	X-  n
[        U 5      nU R                  5       n[        U5       H  nU" U5      nX   nU/nUb  X;   a  X?   R                  U5        OU1X?'   Un[        U5       HT  nUR                  XU   S9nUnUU   nUR!                  U5        Uc  M2  UU;   a  UU   R                  U5        MN  U1UU'   MV     Uv   M     g7f)uR  Randomly generate `sample_size` paths of length `path_length`.

Parameters
----------
G : NetworkX graph
    A NetworkX graph
sample_size : integer
    The number of paths to generate. This is ``R`` in [1]_.
path_length : integer (default = 5)
    The maximum size of the path to randomly generate.
    This is ``T`` in [1]_. According to the paper, ``T >= 5`` is
    recommended.
index_map : dictionary, optional
    If provided, this will be populated with the inverted
    index of nodes mapped to the set of generated random path
    indices within ``paths``.
weight : string or None, optional (default="weight")
    The name of an edge attribute that holds the numerical value
    used as a weight. If None then each edge has weight 1.
seed : integer, random_state, or None (default)
    Indicator of random number generation state.
    See :ref:`Randomness<randomness>`.

Returns
-------
paths : generator of lists
    Generator of `sample_size` paths each with length `path_length`.

Examples
--------
Note that the return value is the list of paths:

>>> G = nx.star_graph(3)
>>> random_path = nx.generate_random_paths(G, 2)

By passing a dictionary into `index_map`, it will build an
inverted index mapping of nodes to the paths in which that node is present:

>>> G = nx.star_graph(3)
>>> index_map = {}
>>> random_path = nx.generate_random_paths(G, 3, index_map=index_map)
>>> paths_containing_node_0 = [
...     random_path[path_idx] for path_idx in index_map.get(0, [])
... ]

References
----------
.. [1] Zhang, J., Tang, J., Ma, C., Tong, H., Jing, Y., & Li, J.
       Panther: Fast top-k similarity search on large networks.
       In Proceedings of the ACM SIGKDD International Conference
       on Knowledge Discovery and Data Mining (Vol. 2015-August, pp. 1445–1454).
       Association for Computing Machinery. https://doi.org/10.1145/2783258.2783267.
r   N)r(  r   r  r/  )re   )r   r   random	Generatorintegersrandintr|   r  
reciprocalrC   r   r   r3  rM   addchoicer,   )r   rH  r-  r.  r(  seedr   
randint_fnadj_matinv_row_sumstransition_probabilitiesrF  rC  
path_index
node_indexrB  pathstarting_indexr)   	nbr_indexnbr_nodes                        r   r   r     sc    t  $D))*=*=>>DLL  1G==!!45==b!DL&5AwH!!#IK(
	*
# v   ##J/#-,	#{#A nE $ I
 'N  	*HKK! $y(h'++J7+5,Ih'' $* 
M )s   DE!/E)NNNNNNNNNNN)	NNNNNNNNN)NNNNNNNNNTNN)NNg?i  g-C6?)r*  r*  g      ?g?Nr(  )r*  Nr(  N)__doc__r8  r   r4  dataclassesr   	itertoolsr   networkxr|   networkx.utilsr   __all__r   _dispatchabler   r   r   r	   r
   r  r   r   r   r8   r   r   <module>rj     s      !   * 14T 
hhV +, l -l^ +, S -Sl 14T 
`
>`
>F  L Lb 9| jZ X&FNE 'EP X&IMm ' mr   