Skip to content

Commit 725a0b9

Browse files
authored
Remove from_graphblas; convert to class constructor (#35)
- Use proper constructors for classes rather than `from_graphblas`. - Add .matrix property for (Di)Graph
1 parent 70bddf2 commit 725a0b9

File tree

8 files changed

+62
-90
lines changed

8 files changed

+62
-90
lines changed

Diff for: graphblas_algorithms/algorithms/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ def k_truss(G: Graph, k) -> Graph:
3434
# Convert back to networkx graph with correct node ids
3535
keys = G.list_to_keys(indices)
3636
key_to_id = dict(zip(keys, range(len(indices))))
37-
return Graph.from_graphblas(Ktruss, key_to_id=key_to_id)
37+
return Graph(Ktruss, key_to_id=key_to_id)

Diff for: graphblas_algorithms/algorithms/tests/test_cluster.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ def test_triangles_full():
99
G = gb.Matrix(bool, 5, 5)
1010
G[:, :] = True
1111
G2 = gb.select.offdiag(G).new()
12-
G = Graph.from_graphblas(G)
13-
G2 = Graph.from_graphblas(G2)
12+
G = Graph(G)
13+
G2 = Graph(G2)
1414
result = cluster.triangles(G)
1515
expected = gb.Vector(int, 5)
1616
expected[:] = 6

Diff for: graphblas_algorithms/classes/_utils.py

+2-24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import numpy as np
33
from graphblas import Matrix, Vector, binary
44
from graphblas.core.matrix import TransposedMatrix
5-
from graphblas.core.utils import ensure_type
65

76
################
87
# Classmethods #
@@ -19,21 +18,6 @@ def from_networkx(cls, G, weight=None, dtype=None):
1918
return rv
2019

2120

22-
def from_graphblas(cls, A, *, key_to_id=None):
23-
# Does not copy if A is a Matrix!
24-
A = ensure_type(A, Matrix)
25-
if A.nrows != A.ncols:
26-
raise ValueError(f"Adjacency matrix must be square; got {A.nrows} x {A.ncols}")
27-
rv = cls()
28-
# If there is no mapping, it may be nice to keep this as None
29-
if key_to_id is None:
30-
rv._key_to_id = {i: i for i in range(A.nrows)}
31-
else:
32-
rv._key_to_id = key_to_id
33-
rv._A = A
34-
return rv
35-
36-
3721
##############
3822
# Properties #
3923
##############
@@ -144,23 +128,17 @@ def vector_to_nodemap(self, v, *, mask=None, fillvalue=None):
144128
elif fillvalue is not None and v.nvals < v.size:
145129
v(mask=~v.S) << fillvalue
146130

147-
rv = object.__new__(NodeMap)
148-
rv.vector = v
149-
rv._key_to_id = self._key_to_id
131+
rv = NodeMap(v, key_to_id=self._key_to_id)
150132
rv._id_to_key = self._id_to_key
151133
return rv
152-
# return NodeMap.from_graphblas(v, key_to_id=self._key_to_id)
153134

154135

155136
def vector_to_nodeset(self, v):
156137
from .nodeset import NodeSet
157138

158-
rv = object.__new__(NodeSet)
159-
rv.vector = v
160-
rv._key_to_id = self._key_to_id
139+
rv = NodeSet(v, key_to_id=self._key_to_id)
161140
rv._id_to_key = self._id_to_key
162141
return rv
163-
# return NodeSet.from_graphblas(v, key_to_id=self._key_to_id)
164142

165143

166144
def vector_to_set(self, v):

Diff for: graphblas_algorithms/classes/digraph.py

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import defaultdict
22

3+
import graphblas as gb
34
from graphblas import Matrix, Vector, binary, replace, select, unary
45

56
import graphblas_algorithms as ga
@@ -415,7 +416,7 @@ def to_directed_graph(G, weight=None, dtype=None):
415416
if isinstance(G, DiGraph):
416417
return G
417418
try:
418-
return DiGraph.from_graphblas(G)
419+
return DiGraph(G)
419420
except TypeError:
420421
pass
421422

@@ -435,7 +436,7 @@ def to_graph(G, weight=None, dtype=None):
435436
return G
436437
try:
437438
# Should we check if it can be undirected?
438-
return DiGraph.from_graphblas(G)
439+
return DiGraph(G)
439440
except TypeError:
440441
pass
441442

@@ -538,22 +539,28 @@ class DiGraph(Graph):
538539
}
539540
graph_attr_dict_factory = dict
540541

541-
def __init__(self, incoming_graph_data=None, **attr):
542+
def __init__(self, incoming_graph_data=None, *, key_to_id=None, **attr):
542543
if incoming_graph_data is not None:
543-
raise NotImplementedError("incoming_graph_data is not None")
544+
# Does not copy if A is a Matrix!
545+
A = gb.core.utils.ensure_type(incoming_graph_data, Matrix)
546+
if A.nrows != A.ncols:
547+
raise ValueError(f"Adjacency matrix must be square; got {A.nrows} x {A.ncols}")
548+
else:
549+
A = Matrix()
544550
self.graph_attr_dict_factory = self.graph_attr_dict_factory
545551
self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes
546552
self.graph.update(attr)
547553

548554
# Graphblas-specific properties
549-
self._A = Matrix()
550-
self._key_to_id = {}
555+
self._A = A
556+
if key_to_id is None:
557+
key_to_id = {i: i for i in range(A.nrows)}
558+
self._key_to_id = key_to_id
551559
self._id_to_key = None
552560
self._cache = {}
553561

554562
# Graphblas-specific methods
555563
from_networkx = classmethod(_utils.from_networkx)
556-
from_graphblas = classmethod(_utils.from_graphblas)
557564
id_to_key = property(_utils.id_to_key)
558565
get_property = _utils.get_property
559566
get_properties = _utils.get_properties
@@ -586,6 +593,10 @@ def name(self, s):
586593
self._A.name = s
587594
self.graph["name"] = s
588595

596+
@property
597+
def matrix(self):
598+
return self._A
599+
589600
def __iter__(self):
590601
return iter(self._key_to_id)
591602

Diff for: graphblas_algorithms/classes/graph.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import defaultdict
22

3+
import graphblas as gb
34
from graphblas import Matrix, Vector, select
45

56
import graphblas_algorithms as ga
@@ -153,7 +154,7 @@ def to_undirected_graph(G, weight=None, dtype=None):
153154
if isinstance(G, Graph):
154155
return G
155156
try:
156-
return Graph.from_graphblas(G)
157+
return Graph(G)
157158
except TypeError:
158159
pass
159160

@@ -243,22 +244,28 @@ class Graph:
243244
}
244245
graph_attr_dict_factory = dict
245246

246-
def __init__(self, incoming_graph_data=None, **attr):
247+
def __init__(self, incoming_graph_data=None, *, key_to_id=None, **attr):
247248
if incoming_graph_data is not None:
248-
raise NotImplementedError("incoming_graph_data is not None")
249+
# Does not copy if A is a Matrix!
250+
A = gb.core.utils.ensure_type(incoming_graph_data, Matrix)
251+
if A.nrows != A.ncols:
252+
raise ValueError(f"Adjacency matrix must be square; got {A.nrows} x {A.ncols}")
253+
else:
254+
A = Matrix()
249255
self.graph_attr_dict_factory = self.graph_attr_dict_factory
250256
self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes
251257
self.graph.update(attr)
252258

253259
# Graphblas-specific properties
254-
self._A = Matrix()
255-
self._key_to_id = {}
260+
self._A = A
261+
if key_to_id is None:
262+
key_to_id = {i: i for i in range(A.nrows)}
263+
self._key_to_id = key_to_id
256264
self._id_to_key = None
257265
self._cache = {}
258266

259267
# Graphblas-specific methods
260268
from_networkx = classmethod(_utils.from_networkx)
261-
from_graphblas = classmethod(_utils.from_graphblas)
262269
id_to_key = property(_utils.id_to_key)
263270
get_property = _utils.get_property
264271
get_properties = _utils.get_properties
@@ -292,6 +299,10 @@ def name(self, s):
292299
self._A.name = s
293300
self.graph["name"] = s
294301

302+
@property
303+
def matrix(self):
304+
return self._A
305+
295306
def __iter__(self):
296307
return iter(self._key_to_id)
297308

Diff for: graphblas_algorithms/classes/nodemap.py

+16-37
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,13 @@
66

77

88
class NodeMap(MutableMapping):
9-
def __init__(self):
10-
raise NotImplementedError()
11-
# .vector, ._key_to_id, ._id_to_key
12-
13-
@classmethod
14-
def from_graphblas(cls, v, *, key_to_id=None):
15-
rv = object.__new__(cls)
16-
rv.vector = v
9+
def __init__(self, v, *, key_to_id=None):
10+
self.vector = v
1711
if key_to_id is None:
18-
rv._key_to_id = {i: i for i in range(v.size)}
12+
self._key_to_id = {i: i for i in range(v.size)}
1913
else:
20-
rv._key_to_id = key_to_id
21-
rv._id_to_key = None
22-
return rv
14+
self._key_to_id = key_to_id
15+
self._id_to_key = None
2316

2417
id_to_key = property(_utils.id_to_key)
2518
# get_property = _utils.get_property
@@ -104,15 +97,8 @@ def setdefault(self, key, default=None):
10497

10598

10699
class VectorMap(MutableMapping):
107-
def __init__(self):
108-
raise NotImplementedError()
109-
# .vector
110-
111-
@classmethod
112-
def from_graphblas(cls, v):
113-
rv = object.__new__(cls)
114-
rv.vector = v
115-
return rv
100+
def __init__(self, v):
101+
self.vector = v
116102

117103
# Requirements for MutableMapping
118104
def __delitem__(self, key):
@@ -176,21 +162,14 @@ def setdefault(self, key, default=None):
176162

177163

178164
class VectorNodeMap(MutableMapping):
179-
def __init__(self):
180-
raise NotImplementedError()
181-
# .matrix, ._key_to_id, ._id_to_key, ._rows
182-
183-
@classmethod
184-
def from_graphblas(cls, A, *, key_to_id=None):
185-
rv = object.__new__(cls)
186-
rv.matrix = A
165+
def __init__(self, A, *, key_to_id=None):
166+
self.matrix = A
187167
if key_to_id is None:
188-
rv._key_to_id = {i: i for i in range(A.size)}
168+
self._key_to_id = {i: i for i in range(A.size)}
189169
else:
190-
rv._key_to_id = key_to_id
191-
rv._id_to_key = None
192-
rv._rows = None
193-
return rv
170+
self._key_to_id = key_to_id
171+
self._id_to_key = None
172+
self._rows = None
194173

195174
def _get_rows(self):
196175
if self._rows is None:
@@ -226,7 +205,7 @@ def __getitem__(self, key):
226205
idx = self._key_to_id[key]
227206
if self._get_rows().get(idx) is None:
228207
raise KeyError(key)
229-
return VectorMap.from_graphblas(self.matrix[idx, :].new())
208+
return VectorMap(self.matrix[idx, :].new())
230209

231210
def __iter__(self):
232211
# Slow if we iterate over one; fast if we iterate over all
@@ -273,7 +252,7 @@ def get(self, key, default=None):
273252
idx = self._key_to_id[key]
274253
if self._get_rows().get(idx) is None:
275254
return default
276-
return VectorMap.from_graphblas(self.matrix[idx, :].new())
255+
return VectorMap(self.matrix[idx, :].new())
277256

278257
# items
279258
# keys
@@ -285,7 +264,7 @@ def popitem(self):
285264
idx = next(rows.ss.iterkeys())
286265
except StopIteration:
287266
raise KeyError from None
288-
value = VectorMap.from_graphblas(self.matrix[idx, :].new())
267+
value = VectorMap(self.matrix[idx, :].new())
289268
del self.matrix[idx, :]
290269
del rows[idx]
291270
return self.id_to_key[idx], value

Diff for: graphblas_algorithms/classes/nodeset.py

+5-12
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,13 @@
66

77

88
class NodeSet(MutableSet):
9-
def __init__(self):
10-
raise NotImplementedError()
11-
# .vector, ._key_to_id, ._id_to_key
12-
13-
@classmethod
14-
def from_graphblas(cls, v, *, key_to_id=None):
15-
rv = object.__new__(cls)
16-
rv.vector = v
9+
def __init__(self, v, *, key_to_id=None):
10+
self.vector = v
1711
if key_to_id is None:
18-
rv._key_to_id = {i: i for i in range(v.size)}
12+
self._key_to_id = {i: i for i in range(v.size)}
1913
else:
20-
rv._key_to_id = key_to_id
21-
rv._id_to_key = None
22-
return rv
14+
self._key_to_id = key_to_id
15+
self._id_to_key = None
2316

2417
id_to_key = property(_utils.id_to_key)
2518
# get_property = _utils.get_property

Diff for: graphblas_algorithms/nxapi/cluster.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,6 @@ def generalized_degree(G, nodes=None):
139139
return G.vector_to_nodemap(result)
140140
mask = G.list_to_mask(nodes)
141141
result = algorithms.generalized_degree(G, mask=mask)
142-
rv = VectorNodeMap.from_graphblas(result, key_to_id=G._key_to_id)
142+
rv = VectorNodeMap(result, key_to_id=G._key_to_id)
143143
rv._id_to_key = G._id_to_key
144144
return rv

0 commit comments

Comments
 (0)