walks.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. """Function for computing walks in a graph."""
  2. import networkx as nx
  3. __all__ = ["number_of_walks"]
  4. @nx._dispatchable
  5. def number_of_walks(G, walk_length):
  6. """Returns the number of walks connecting each pair of nodes in `G`
  7. A *walk* is a sequence of nodes in which each adjacent pair of nodes
  8. in the sequence is adjacent in the graph. A walk can repeat the same
  9. edge and go in the opposite direction just as people can walk on a
  10. set of paths, but standing still is not counted as part of the walk.
  11. This function only counts the walks with `walk_length` edges. Note that
  12. the number of nodes in the walk sequence is one more than `walk_length`.
  13. The number of walks can grow very quickly on a larger graph
  14. and with a larger walk length.
  15. Parameters
  16. ----------
  17. G : NetworkX graph
  18. walk_length : int
  19. A nonnegative integer representing the length of a walk.
  20. Returns
  21. -------
  22. dict
  23. A dictionary of dictionaries in which outer keys are source
  24. nodes, inner keys are target nodes, and inner values are the
  25. number of walks of length `walk_length` connecting those nodes.
  26. Raises
  27. ------
  28. ValueError
  29. If `walk_length` is negative
  30. Examples
  31. --------
  32. >>> G = nx.Graph([(0, 1), (1, 2)])
  33. >>> walks = nx.number_of_walks(G, 2)
  34. >>> walks
  35. {0: {0: 1, 1: 0, 2: 1}, 1: {0: 0, 1: 2, 2: 0}, 2: {0: 1, 1: 0, 2: 1}}
  36. >>> total_walks = sum(sum(tgts.values()) for _, tgts in walks.items())
  37. You can also get the number of walks from a specific source node using the
  38. returned dictionary. For example, number of walks of length 1 from node 0
  39. can be found as follows:
  40. >>> walks = nx.number_of_walks(G, 1)
  41. >>> walks[0]
  42. {0: 0, 1: 1, 2: 0}
  43. >>> sum(walks[0].values()) # walks from 0 of length 1
  44. 1
  45. Similarly, a target node can also be specified:
  46. >>> walks[0][1]
  47. 1
  48. """
  49. import scipy as sp
  50. if walk_length < 0:
  51. raise ValueError(f"`walk_length` cannot be negative: {walk_length}")
  52. A = nx.adjacency_matrix(G, weight=None)
  53. power = sp.sparse.linalg.matrix_power(A, walk_length).tocsr()
  54. result = {
  55. u: {v: power[u_idx, v_idx].item() for v_idx, v in enumerate(G)}
  56. for u_idx, u in enumerate(G)
  57. }
  58. return result