|
""" |
|
Adjacency matrix and incidence matrix of graphs. |
|
""" |
|
|
|
import networkx as nx |
|
|
|
__all__ = ["incidence_matrix", "adjacency_matrix"] |
|
|
|
|
|
@nx._dispatchable(edge_attrs="weight") |
|
def incidence_matrix( |
|
G, nodelist=None, edgelist=None, oriented=False, weight=None, *, dtype=None |
|
): |
|
"""Returns incidence matrix of G. |
|
|
|
The incidence matrix assigns each row to a node and each column to an edge. |
|
For a standard incidence matrix a 1 appears wherever a row's node is |
|
incident on the column's edge. For an oriented incidence matrix each |
|
edge is assigned an orientation (arbitrarily for undirected and aligning to |
|
direction for directed). A -1 appears for the source (tail) of an edge and |
|
1 for the destination (head) of the edge. The elements are zero otherwise. |
|
|
|
Parameters |
|
---------- |
|
G : graph |
|
A NetworkX graph |
|
|
|
nodelist : list, optional (default= all nodes in G) |
|
The rows are ordered according to the nodes in nodelist. |
|
If nodelist is None, then the ordering is produced by G.nodes(). |
|
|
|
edgelist : list, optional (default= all edges in G) |
|
The columns are ordered according to the edges in edgelist. |
|
If edgelist is None, then the ordering is produced by G.edges(). |
|
|
|
oriented: bool, optional (default=False) |
|
If True, matrix elements are +1 or -1 for the head or tail node |
|
respectively of each edge. If False, +1 occurs at both nodes. |
|
|
|
weight : string or None, optional (default=None) |
|
The edge data key used to provide each value in the matrix. |
|
If None, then each edge has weight 1. Edge weights, if used, |
|
should be positive so that the orientation can provide the sign. |
|
|
|
dtype : a NumPy dtype or None (default=None) |
|
The dtype of the output sparse array. This type should be a compatible |
|
type of the weight argument, eg. if weight would return a float this |
|
argument should also be a float. |
|
If None, then the default for SciPy is used. |
|
|
|
Returns |
|
------- |
|
A : SciPy sparse array |
|
The incidence matrix of G. |
|
|
|
Notes |
|
----- |
|
For MultiGraph/MultiDiGraph, the edges in edgelist should be |
|
(u,v,key) 3-tuples. |
|
|
|
"Networks are the best discrete model for so many problems in |
|
applied mathematics" [1]_. |
|
|
|
References |
|
---------- |
|
.. [1] Gil Strang, Network applications: A = incidence matrix, |
|
http://videolectures.net/mit18085f07_strang_lec03/ |
|
""" |
|
import scipy as sp |
|
|
|
if nodelist is None: |
|
nodelist = list(G) |
|
if edgelist is None: |
|
if G.is_multigraph(): |
|
edgelist = list(G.edges(keys=True)) |
|
else: |
|
edgelist = list(G.edges()) |
|
A = sp.sparse.lil_array((len(nodelist), len(edgelist)), dtype=dtype) |
|
node_index = {node: i for i, node in enumerate(nodelist)} |
|
for ei, e in enumerate(edgelist): |
|
(u, v) = e[:2] |
|
if u == v: |
|
continue |
|
try: |
|
ui = node_index[u] |
|
vi = node_index[v] |
|
except KeyError as err: |
|
raise nx.NetworkXError( |
|
f"node {u} or {v} in edgelist but not in nodelist" |
|
) from err |
|
if weight is None: |
|
wt = 1 |
|
else: |
|
if G.is_multigraph(): |
|
ekey = e[2] |
|
wt = G[u][v][ekey].get(weight, 1) |
|
else: |
|
wt = G[u][v].get(weight, 1) |
|
if oriented: |
|
A[ui, ei] = -wt |
|
A[vi, ei] = wt |
|
else: |
|
A[ui, ei] = wt |
|
A[vi, ei] = wt |
|
return A.asformat("csc") |
|
|
|
|
|
@nx._dispatchable(edge_attrs="weight") |
|
def adjacency_matrix(G, nodelist=None, dtype=None, weight="weight"): |
|
"""Returns adjacency matrix of `G`. |
|
|
|
Parameters |
|
---------- |
|
G : graph |
|
A NetworkX graph |
|
|
|
nodelist : list, optional |
|
The rows and columns are ordered according to the nodes in `nodelist`. |
|
If ``nodelist=None`` (the default), then the ordering is produced by |
|
``G.nodes()``. |
|
|
|
dtype : NumPy data-type, optional |
|
The desired data-type for the array. |
|
If `None`, then the NumPy default is used. |
|
|
|
weight : string or None, optional (default='weight') |
|
The edge data key used to provide each value in the matrix. |
|
If None, then each edge has weight 1. |
|
|
|
Returns |
|
------- |
|
A : SciPy sparse array |
|
Adjacency matrix representation of G. |
|
|
|
Notes |
|
----- |
|
For directed graphs, entry ``i, j`` corresponds to an edge from ``i`` to ``j``. |
|
|
|
If you want a pure Python adjacency matrix representation try |
|
:func:`~networkx.convert.to_dict_of_dicts` which will return a |
|
dictionary-of-dictionaries format that can be addressed as a |
|
sparse matrix. |
|
|
|
For multigraphs with parallel edges the weights are summed. |
|
See :func:`networkx.convert_matrix.to_numpy_array` for other options. |
|
|
|
The convention used for self-loop edges in graphs is to assign the |
|
diagonal matrix entry value to the edge weight attribute |
|
(or the number 1 if the edge has no weight attribute). If the |
|
alternate convention of doubling the edge weight is desired the |
|
resulting SciPy sparse array can be modified as follows:: |
|
|
|
>>> G = nx.Graph([(1, 1)]) |
|
>>> A = nx.adjacency_matrix(G) |
|
>>> A.toarray() |
|
array([[1]]) |
|
>>> A.setdiag(A.diagonal() * 2) |
|
>>> A.toarray() |
|
array([[2]]) |
|
|
|
See Also |
|
-------- |
|
to_numpy_array |
|
to_scipy_sparse_array |
|
to_dict_of_dicts |
|
adjacency_spectrum |
|
""" |
|
return nx.to_scipy_sparse_array(G, nodelist=nodelist, dtype=dtype, weight=weight) |
|
|