forked from igraph/python-igraph
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadjacency.py
More file actions
159 lines (133 loc) · 5.66 KB
/
Copy pathadjacency.py
File metadata and controls
159 lines (133 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from igraph.sparse_matrix import (
_graph_from_sparse_matrix,
_graph_from_weighted_sparse_matrix,
)
def _sp_cls():
try:
from scipy import sparse
except ImportError:
return ()
if not hasattr(sparse, "sparray"): # scipy < 1.11
return sparse.spmatrix
return (sparse.sparray, sparse.spmatrix)
def _construct_graph_from_adjacency(cls, matrix, mode="directed", loops="once"):
"""Generates a graph from its adjacency matrix.
@param matrix: the adjacency matrix. Possible types are:
- a list of lists
- a numpy 2D array or matrix (will be converted to list of lists)
- a scipy.sparse array or matrix (will be converted to COO format, but not
to a dense matrix)
- a pandas.DataFrame (column/row names must match, and will be used
as vertex names).
@param mode: the mode to be used. Possible values are:
- C{"directed"} - the graph will be directed and a matrix element
specifies the number of edges between two vertices.
- C{"undirected"} - the graph will be undirected and a matrix element
specifies the number of edges between two vertices. The matrix must
be symmetric.
- C{"max"} - undirected graph will be created and the number of
edges between vertex M{i} and M{j} is M{max(A(i,j), A(j,i))}
- C{"min"} - like C{"max"}, but with M{min(A(i,j), A(j,i))}
- C{"plus"} - like C{"max"}, but with M{A(i,j) + A(j,i)}
- C{"upper"} - undirected graph with the upper right triangle of
the matrix (including the diagonal)
- C{"lower"} - undirected graph with the lower left triangle of
the matrix (including the diagonal)
@param loops: specifies how to handle loop edges. When C{False} or
C{"ignore"}, the diagonal of the adjacency matrix will be ignored. When
C{True} or C{"once"}, the diagonal is assumed to contain the multiplicity
of the corresponding loop edge. When C{"twice"}, the diagonal is assumed
to contain I{twice} the multiplicity of the corresponding loop edge.
"""
# Deferred import to avoid cycles
from igraph import Graph
try:
import numpy as np
except ImportError:
np = None
try:
import pandas as pd
except ImportError:
pd = None
if isinstance(matrix, _sp_cls()):
return _graph_from_sparse_matrix(cls, matrix, mode=mode, loops=loops)
if (pd is not None) and isinstance(matrix, pd.DataFrame):
vertex_names = matrix.index.tolist()
matrix = matrix.values
else:
vertex_names = None
if (np is not None) and isinstance(matrix, np.ndarray):
matrix = matrix.tolist()
graph = super(Graph, cls).Adjacency(matrix, mode=mode, loops=loops)
# Add vertex names if present
if vertex_names is not None:
graph.vs["name"] = vertex_names
return graph
def _construct_graph_from_weighted_adjacency(
cls, matrix, mode="directed", attr="weight", loops="once"
):
"""Generates a graph from its weighted adjacency matrix.
Only edges with a non-zero weight are created.
@param matrix: the adjacency matrix. Possible types are:
- a list of lists
- a numpy 2D array or matrix (will be converted to list of lists)
- a scipy.sparse matrix (will be converted to a COO matrix, but not
to a dense matrix)
@param mode: the mode to be used. Possible values are:
- C{"directed"} - the graph will be directed and a matrix element
specifies the weight of the corresponding edge.
- C{"undirected"} - the graph will be undirected and a matrix element
specifies the weight of the corresponding edge. The matrix must
be symmetric.
- C{"max"} - undirected graph will be created and the weight of the
edge between vertex M{i} and M{j} is M{max(A(i,j), A(j,i))}
- C{"min"} - like C{"max"}, but with M{min(A(i,j), A(j,i))}
- C{"plus"} - like C{"max"}, but with M{A(i,j) + A(j,i)}
- C{"upper"} - undirected graph with the upper right triangle of
the matrix (including the diagonal)
- C{"lower"} - undirected graph with the lower left triangle of
the matrix (including the diagonal)
These values can also be given as strings without the C{ADJ} prefix.
@param attr: the name of the edge attribute that stores the edge
weights.
@param loops: specifies how to handle loop edges. When C{False} or
C{"ignore"}, the diagonal of the adjacency matrix will be ignored. When
C{True} or C{"once"}, the diagonal is assumed to contain the weight of the
corresponding loop edge. When C{"twice"}, the diagonal is assumed to
contain I{twice} the weight of the corresponding loop edge.
"""
# Deferred import to avoid cycles
from igraph import Graph
try:
import numpy as np
except ImportError:
np = None
try:
import pandas as pd
except ImportError:
pd = None
if isinstance(matrix, _sp_cls()):
return _graph_from_weighted_sparse_matrix(
cls,
matrix,
mode=mode,
attr=attr,
loops=loops,
)
if (pd is not None) and isinstance(matrix, pd.DataFrame):
vertex_names = matrix.index.tolist()
matrix = matrix.values
else:
vertex_names = None
if (np is not None) and isinstance(matrix, np.ndarray):
matrix = matrix.tolist()
graph, weights = super(Graph, cls)._Weighted_Adjacency(
matrix,
mode=mode,
loops=loops,
)
graph.es[attr] = weights
# Add vertex names if present
if vertex_names is not None:
graph.vs["name"] = vertex_names
return graph