graphmatrix.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. """
  2. Adjacency matrix and incidence matrix of graphs.
  3. """
  4. import networkx as nx
  5. __all__ = ["incidence_matrix", "adjacency_matrix"]
  6. @nx._dispatchable(edge_attrs="weight")
  7. def incidence_matrix(
  8. G, nodelist=None, edgelist=None, oriented=False, weight=None, *, dtype=None
  9. ):
  10. """Returns incidence matrix of G.
  11. The incidence matrix assigns each row to a node and each column to an edge.
  12. For a standard incidence matrix a 1 appears wherever a row's node is
  13. incident on the column's edge. For an oriented incidence matrix each
  14. edge is assigned an orientation (arbitrarily for undirected and aligning to
  15. direction for directed). A -1 appears for the source (tail) of an edge and
  16. 1 for the destination (head) of the edge. The elements are zero otherwise.
  17. Parameters
  18. ----------
  19. G : graph
  20. A NetworkX graph
  21. nodelist : list, optional (default= all nodes in G)
  22. The rows are ordered according to the nodes in nodelist.
  23. If nodelist is None, then the ordering is produced by G.nodes().
  24. edgelist : list, optional (default= all edges in G)
  25. The columns are ordered according to the edges in edgelist.
  26. If edgelist is None, then the ordering is produced by G.edges().
  27. oriented: bool, optional (default=False)
  28. If True, matrix elements are +1 or -1 for the head or tail node
  29. respectively of each edge. If False, +1 occurs at both nodes.
  30. weight : string or None, optional (default=None)
  31. The edge data key used to provide each value in the matrix.
  32. If None, then each edge has weight 1. Edge weights, if used,
  33. should be positive so that the orientation can provide the sign.
  34. dtype : a NumPy dtype or None (default=None)
  35. The dtype of the output sparse array. This type should be a compatible
  36. type of the weight argument, eg. if weight would return a float this
  37. argument should also be a float.
  38. If None, then the default for SciPy is used.
  39. Returns
  40. -------
  41. A : SciPy sparse array
  42. The incidence matrix of G.
  43. Notes
  44. -----
  45. For MultiGraph/MultiDiGraph, the edges in edgelist should be
  46. (u,v,key) 3-tuples.
  47. "Networks are the best discrete model for so many problems in
  48. applied mathematics" [1]_.
  49. References
  50. ----------
  51. .. [1] Gil Strang, Network applications: A = incidence matrix,
  52. http://videolectures.net/mit18085f07_strang_lec03/
  53. """
  54. import scipy as sp
  55. if nodelist is None:
  56. nodelist = list(G)
  57. if edgelist is None:
  58. if G.is_multigraph():
  59. edgelist = list(G.edges(keys=True))
  60. else:
  61. edgelist = list(G.edges())
  62. A = sp.sparse.lil_array((len(nodelist), len(edgelist)), dtype=dtype)
  63. node_index = {node: i for i, node in enumerate(nodelist)}
  64. for ei, e in enumerate(edgelist):
  65. (u, v) = e[:2]
  66. if u == v:
  67. continue # self loops give zero column
  68. try:
  69. ui = node_index[u]
  70. vi = node_index[v]
  71. except KeyError as err:
  72. raise nx.NetworkXError(
  73. f"node {u} or {v} in edgelist but not in nodelist"
  74. ) from err
  75. if weight is None:
  76. wt = 1
  77. else:
  78. if G.is_multigraph():
  79. ekey = e[2]
  80. wt = G[u][v][ekey].get(weight, 1)
  81. else:
  82. wt = G[u][v].get(weight, 1)
  83. if oriented:
  84. A[ui, ei] = -wt
  85. A[vi, ei] = wt
  86. else:
  87. A[ui, ei] = wt
  88. A[vi, ei] = wt
  89. return A.asformat("csc")
  90. @nx._dispatchable(edge_attrs="weight")
  91. def adjacency_matrix(G, nodelist=None, dtype=None, weight="weight"):
  92. """Returns adjacency matrix of `G`.
  93. Parameters
  94. ----------
  95. G : graph
  96. A NetworkX graph
  97. nodelist : list, optional
  98. The rows and columns are ordered according to the nodes in `nodelist`.
  99. If ``nodelist=None`` (the default), then the ordering is produced by
  100. ``G.nodes()``.
  101. dtype : NumPy data-type, optional
  102. The desired data-type for the array.
  103. If `None`, then the NumPy default is used.
  104. weight : string or None, optional (default='weight')
  105. The edge data key used to provide each value in the matrix.
  106. If None, then each edge has weight 1.
  107. Returns
  108. -------
  109. A : SciPy sparse array
  110. Adjacency matrix representation of G.
  111. Notes
  112. -----
  113. For directed graphs, entry ``i, j`` corresponds to an edge from ``i`` to ``j``.
  114. If you want a pure Python adjacency matrix representation try
  115. :func:`~networkx.convert.to_dict_of_dicts` which will return a
  116. dictionary-of-dictionaries format that can be addressed as a
  117. sparse matrix.
  118. For multigraphs with parallel edges the weights are summed.
  119. See :func:`networkx.convert_matrix.to_numpy_array` for other options.
  120. The convention used for self-loop edges in graphs is to assign the
  121. diagonal matrix entry value to the edge weight attribute
  122. (or the number 1 if the edge has no weight attribute). If the
  123. alternate convention of doubling the edge weight is desired the
  124. resulting SciPy sparse array can be modified as follows::
  125. >>> G = nx.Graph([(1, 1)])
  126. >>> A = nx.adjacency_matrix(G)
  127. >>> A.toarray()
  128. array([[1]])
  129. >>> A.setdiag(A.diagonal() * 2)
  130. >>> A.toarray()
  131. array([[2]])
  132. See Also
  133. --------
  134. to_numpy_array
  135. to_scipy_sparse_array
  136. to_dict_of_dicts
  137. adjacency_spectrum
  138. """
  139. return nx.to_scipy_sparse_array(G, nodelist=nodelist, dtype=dtype, weight=weight)