stochastic.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. """Functions for generating stochastic graphs from a given weighted directed
  2. graph.
  3. """
  4. import networkx as nx
  5. from networkx.classes import DiGraph, MultiDiGraph
  6. from networkx.utils import not_implemented_for
  7. __all__ = ["stochastic_graph"]
  8. @not_implemented_for("undirected")
  9. @nx._dispatchable(
  10. edge_attrs="weight", mutates_input={"not copy": 1}, returns_graph=True
  11. )
  12. def stochastic_graph(G, copy=True, weight="weight"):
  13. """Returns a right-stochastic representation of directed graph `G`.
  14. A right-stochastic graph is a weighted digraph in which for each
  15. node, the sum of the weights of all the out-edges of that node is
  16. 1. If the graph is already weighted (for example, via a 'weight'
  17. edge attribute), the reweighting takes that into account.
  18. Parameters
  19. ----------
  20. G : directed graph
  21. A :class:`~networkx.DiGraph` or :class:`~networkx.MultiDiGraph`.
  22. copy : boolean, optional
  23. If this is True, then this function returns a new graph with
  24. the stochastic reweighting. Otherwise, the original graph is
  25. modified in-place (and also returned, for convenience).
  26. weight : edge attribute key (optional, default='weight')
  27. Edge attribute key used for reading the existing weight and
  28. setting the new weight. If no attribute with this key is found
  29. for an edge, then the edge weight is assumed to be 1. If an edge
  30. has a weight, it must be a positive number.
  31. """
  32. if copy:
  33. G = MultiDiGraph(G) if G.is_multigraph() else DiGraph(G)
  34. # There is a tradeoff here: the dictionary of node degrees may
  35. # require a lot of memory, whereas making a call to `G.out_degree`
  36. # inside the loop may be costly in computation time.
  37. degree = dict(G.out_degree(weight=weight))
  38. for u, v, d in G.edges(data=True):
  39. if degree[u] == 0:
  40. d[weight] = 0
  41. else:
  42. d[weight] = d.get(weight, 1) / degree[u]
  43. nx._clear_cache(G)
  44. return G