123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- """
- ====================
- Biadjacency matrices
- ====================
- """
- import itertools
- import networkx as nx
- from networkx.convert_matrix import _generate_weighted_edges
- __all__ = ["biadjacency_matrix", "from_biadjacency_matrix"]
- def biadjacency_matrix(
- G, row_order, column_order=None, dtype=None, weight="weight", format="csr"
- ):
- r"""Returns the biadjacency matrix of the bipartite graph G.
- Let `G = (U, V, E)` be a bipartite graph with node sets
- `U = u_{1},...,u_{r}` and `V = v_{1},...,v_{s}`. The biadjacency
- matrix [1]_ is the `r` x `s` matrix `B` in which `b_{i,j} = 1`
- if, and only if, `(u_i, v_j) \in E`. If the parameter `weight` is
- not `None` and matches the name of an edge attribute, its value is
- used instead of 1.
- Parameters
- ----------
- G : graph
- A NetworkX graph
- row_order : list of nodes
- The rows of the matrix are ordered according to the list of nodes.
- column_order : list, optional
- The columns of the matrix are ordered according to the list of nodes.
- If column_order is None, then the ordering of columns is arbitrary.
- dtype : NumPy data-type, optional
- A valid NumPy dtype used to initialize 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.
- format : str in {'bsr', 'csr', 'csc', 'coo', 'lil', 'dia', 'dok'}
- The type of the matrix to be returned (default 'csr'). For
- some algorithms different implementations of sparse matrices
- can perform better. See [2]_ for details.
- Returns
- -------
- M : SciPy sparse array
- Biadjacency matrix representation of the bipartite graph G.
- Notes
- -----
- No attempt is made to check that the input graph is bipartite.
- For directed bipartite graphs only successors are considered as neighbors.
- To obtain an adjacency matrix with ones (or weight values) for both
- predecessors and successors you have to generate two biadjacency matrices
- where the rows of one of them are the columns of the other, and then add
- one to the transpose of the other.
- See Also
- --------
- adjacency_matrix
- from_biadjacency_matrix
- References
- ----------
- .. [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph
- .. [2] Scipy Dev. References, "Sparse Matrices",
- https://docs.scipy.org/doc/scipy/reference/sparse.html
- """
- import scipy as sp
- import scipy.sparse # call as sp.sparse
- nlen = len(row_order)
- if nlen == 0:
- raise nx.NetworkXError("row_order is empty list")
- if len(row_order) != len(set(row_order)):
- msg = "Ambiguous ordering: `row_order` contained duplicates."
- raise nx.NetworkXError(msg)
- if column_order is None:
- column_order = list(set(G) - set(row_order))
- mlen = len(column_order)
- if len(column_order) != len(set(column_order)):
- msg = "Ambiguous ordering: `column_order` contained duplicates."
- raise nx.NetworkXError(msg)
- row_index = dict(zip(row_order, itertools.count()))
- col_index = dict(zip(column_order, itertools.count()))
- if G.number_of_edges() == 0:
- row, col, data = [], [], []
- else:
- row, col, data = zip(
- *(
- (row_index[u], col_index[v], d.get(weight, 1))
- for u, v, d in G.edges(row_order, data=True)
- if u in row_index and v in col_index
- )
- )
- A = sp.sparse.coo_array((data, (row, col)), shape=(nlen, mlen), dtype=dtype)
- try:
- return A.asformat(format)
- except ValueError as err:
- raise nx.NetworkXError(f"Unknown sparse array format: {format}") from err
- def from_biadjacency_matrix(A, create_using=None, edge_attribute="weight"):
- r"""Creates a new bipartite graph from a biadjacency matrix given as a
- SciPy sparse array.
- Parameters
- ----------
- A: scipy sparse array
- A biadjacency matrix representation of a graph
- create_using: NetworkX graph
- Use specified graph for result. The default is Graph()
- edge_attribute: string
- Name of edge attribute to store matrix numeric value. The data will
- have the same type as the matrix entry (int, float, (real,imag)).
- Notes
- -----
- The nodes are labeled with the attribute `bipartite` set to an integer
- 0 or 1 representing membership in part 0 or part 1 of the bipartite graph.
- If `create_using` is an instance of :class:`networkx.MultiGraph` or
- :class:`networkx.MultiDiGraph` and the entries of `A` are of
- type :class:`int`, then this function returns a multigraph (of the same
- type as `create_using`) with parallel edges. In this case, `edge_attribute`
- will be ignored.
- See Also
- --------
- biadjacency_matrix
- from_numpy_array
- References
- ----------
- [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph
- """
- G = nx.empty_graph(0, create_using)
- n, m = A.shape
- # Make sure we get even the isolated nodes of the graph.
- G.add_nodes_from(range(n), bipartite=0)
- G.add_nodes_from(range(n, n + m), bipartite=1)
- # Create an iterable over (u, v, w) triples and for each triple, add an
- # edge from u to v with weight w.
- triples = ((u, n + v, d) for (u, v, d) in _generate_weighted_edges(A))
- # If the entries in the adjacency matrix are integers and the graph is a
- # multigraph, then create parallel edges, each with weight 1, for each
- # entry in the adjacency matrix. Otherwise, create one edge for each
- # positive entry in the adjacency matrix and set the weight of that edge to
- # be the entry in the matrix.
- if A.dtype.kind in ("i", "u") and G.is_multigraph():
- chain = itertools.chain.from_iterable
- triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples)
- G.add_weighted_edges_from(triples, weight=edge_attribute)
- return G
|