Skip to content

Commit 70bddf2

Browse files
authored
Update to use to_coo/from_coo instead of to_values/from_values (#32)
1 parent ffac8cd commit 70bddf2

File tree

17 files changed

+40
-44
lines changed

17 files changed

+40
-44
lines changed

Diff for: .github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
conda install -c conda-forge python-graphblas scipy pandas \
3434
pytest-cov pytest-randomly black flake8-comprehensions flake8-bugbear
3535
# matplotlib lxml pygraphviz pydot sympy # Extra networkx deps we don't need yet
36-
pip install git+https://github.com/jim22k/networkx.git@nx-sparse --no-deps
36+
pip install git+https://github.com/networkx/networkx.git@main --no-deps
3737
pip install -e . --no-deps
3838
- name: Style checks
3939
run: |

Diff for: .pre-commit-config.yaml

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#
33
# Before first use: `pre-commit install`
44
# To run: `pre-commit run --all-files`
5+
# To update: `pre-commit autoupdate`
6+
# - &flake8_dependencies below needs updated manually
57
fail_fast: true
68
repos:
79
- repo: https://github.com/pre-commit/pre-commit-hooks
@@ -26,7 +28,7 @@ repos:
2628
- id: isort
2729
language_version: python3
2830
- repo: https://github.com/asottile/pyupgrade
29-
rev: v3.1.0
31+
rev: v3.2.2
3032
hooks:
3133
- id: pyupgrade
3234
args: [--py38-plus]
@@ -45,9 +47,10 @@ repos:
4547
hooks:
4648
- id: flake8
4749
additional_dependencies: &flake8_dependencies
50+
# These versions need updated manually
4851
- flake8==5.0.4
49-
- flake8-comprehensions==3.10.0
50-
- flake8-bugbear==22.9.23
52+
- flake8-comprehensions==3.10.1
53+
- flake8-bugbear==22.10.27
5154
- repo: https://github.com/asottile/yesqa
5255
rev: v1.4.0
5356
hooks:

Diff for: graphblas_algorithms/algorithms/cluster.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def square_clustering(G, node_ids=None):
241241
A, degrees = G.get_properties("A degrees+") # TODO" how to handle self-edges?
242242
# P2 from https://arxiv.org/pdf/2007.11111.pdf; we'll also use it as scratch
243243
if node_ids is not None:
244-
v = Vector.from_values(node_ids, True, size=degrees.size)
244+
v = Vector.from_coo(node_ids, True, size=degrees.size)
245245
Asubset = binary.second(v & A).new(name="A_subset")
246246
else:
247247
Asubset = A
@@ -298,10 +298,10 @@ def generalized_degree(G, *, mask=None):
298298
else:
299299
Tri(A.S) << 0
300300
Tri(Tri.S, binary.second) << plus_pair(Tri @ A.T)
301-
rows, cols, vals = Tri.to_values()
301+
rows, cols, vals = Tri.to_coo()
302302
# The column index indicates the number of triangles an edge participates in.
303303
# The largest this can be is `A.ncols - 1`. Values is count of edges.
304-
return Matrix.from_values(
304+
return Matrix.from_coo(
305305
rows,
306306
vals,
307307
np.ones(vals.size, dtype=int),

Diff for: graphblas_algorithms/algorithms/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def k_truss(G: Graph, k) -> Graph:
2828
S = C
2929

3030
# Remove isolate nodes
31-
indices, _ = C.reduce_rowwise(monoid.any).to_values()
31+
indices, _ = C.reduce_rowwise(monoid.any).to_coo()
3232
Ktruss = C[indices, indices].new()
3333

3434
# Convert back to networkx graph with correct node ids

Diff for: graphblas_algorithms/algorithms/dag.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def descendants(G, source):
1010
raise KeyError(f"The node {source} is not in the graph")
1111
index = G._key_to_id[source]
1212
A = G._A
13-
q = Vector.from_values(index, True, size=A.nrows, name="q")
13+
q = Vector.from_coo(index, True, size=A.nrows, name="q")
1414
rv = q.dup(name="descendants")
1515
for _ in range(A.nrows):
1616
q(~rv.S, replace) << lor_pair(q @ A)
@@ -26,7 +26,7 @@ def ancestors(G, source):
2626
raise KeyError(f"The node {source} is not in the graph")
2727
index = G._key_to_id[source]
2828
A = G._A
29-
q = Vector.from_values(index, True, size=A.nrows, name="q")
29+
q = Vector.from_coo(index, True, size=A.nrows, name="q")
3030
rv = q.dup(name="descendants")
3131
for _ in range(A.nrows):
3232
q(~rv.S, replace) << lor_pair(A @ q)

Diff for: graphblas_algorithms/algorithms/shortest_paths/generic.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ def has_path(G, source, target):
1111
if src == dst:
1212
return True
1313
A = G._A
14-
q_src = Vector.from_values(src, True, size=A.nrows, name="q_src")
14+
q_src = Vector.from_coo(src, True, size=A.nrows, name="q_src")
1515
seen_src = q_src.dup(name="seen_src")
16-
q_dst = Vector.from_values(dst, True, size=A.nrows, name="q_dst")
16+
q_dst = Vector.from_coo(dst, True, size=A.nrows, name="q_dst")
1717
seen_dst = q_dst.dup(name="seen_dst")
1818
for _ in range(A.nrows // 2):
1919
q_src(~seen_src.S, replace) << lor_pair(q_src @ A)

Diff for: graphblas_algorithms/algorithms/simple_paths.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def is_simple_path(G, nodes):
1616
if len(indices) != len(nodes) or len(indices) > len(set(indices)):
1717
return False
1818
# Check all steps in path at once
19-
P = Matrix.from_values(indices[:-1], indices[1:], True, nrows=A.nrows, ncols=A.ncols)
19+
P = Matrix.from_coo(indices[:-1], indices[1:], True, nrows=A.nrows, ncols=A.ncols)
2020
P << binary.second(A & P)
2121
return P.nvals == len(indices) - 1
2222
# Alternative

Diff for: graphblas_algorithms/algorithms/tournament.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def is_tournament(G):
1515

1616
def score_sequence(G):
1717
degrees = G.get_property("row_degrees+")
18-
_, values = degrees.to_values(indices=False, sort=False)
18+
_, values = degrees.to_coo(indices=False, sort=False)
1919
values.sort()
2020
if degrees.nvals != degrees.size:
2121
values = np.pad(values, (degrees.size - degrees.nvals, 0))

Diff for: graphblas_algorithms/classes/_utils.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def dict_to_vector(self, d, *, size=None, dtype=None, name=None):
7878
size = len(self)
7979
key_to_id = self._key_to_id
8080
indices, values = zip(*((key_to_id[key], val) for key, val in d.items()))
81-
return Vector.from_values(indices, values, size=size, dtype=dtype, name=name)
81+
return Vector.from_coo(indices, values, size=size, dtype=dtype, name=name)
8282

8383

8484
def list_to_vector(self, nodes, dtype=bool, *, size=None, name=None):
@@ -88,7 +88,7 @@ def list_to_vector(self, nodes, dtype=bool, *, size=None, name=None):
8888
size = len(self)
8989
key_to_id = self._key_to_id
9090
index = [key_to_id[key] for key in nodes]
91-
return Vector.from_values(index, True, size=size, dtype=dtype, name=name)
91+
return Vector.from_coo(index, True, size=size, dtype=dtype, name=name)
9292

9393

9494
def list_to_mask(self, nodes, *, size=None, name="mask"):
@@ -122,7 +122,7 @@ def set_to_vector(self, nodes, dtype=bool, *, ignore_extra=False, size=None, nam
122122
nodes = set(nodes)
123123
nodes = nodes & key_to_id.keys()
124124
index = [key_to_id[key] for key in nodes]
125-
return Vector.from_values(index, True, size=size, dtype=dtype, name=name)
125+
return Vector.from_coo(index, True, size=size, dtype=dtype, name=name)
126126

127127

128128
def vector_to_dict(self, v, *, mask=None, fillvalue=None):
@@ -132,7 +132,7 @@ def vector_to_dict(self, v, *, mask=None, fillvalue=None):
132132
elif fillvalue is not None and v.nvals < v.size:
133133
v(mask=~v.S) << fillvalue
134134
id_to_key = self.id_to_key
135-
return {id_to_key[index]: value for index, value in zip(*v.to_values(sort=False))}
135+
return {id_to_key[index]: value for index, value in zip(*v.to_coo(sort=False))}
136136

137137

138138
def vector_to_nodemap(self, v, *, mask=None, fillvalue=None):
@@ -165,7 +165,7 @@ def vector_to_nodeset(self, v):
165165

166166
def vector_to_set(self, v):
167167
id_to_key = self.id_to_key
168-
indices, _ = v.to_values(values=False, sort=False)
168+
indices, _ = v.to_coo(values=False, sort=False)
169169
return {id_to_key[index] for index in indices}
170170

171171

@@ -227,7 +227,7 @@ def to_networkx(self, edge_attribute="weight"):
227227
A = self.get_property("L+")
228228
G.add_nodes_from(self._key_to_id)
229229
id_to_key = self.id_to_key
230-
rows, cols, vals = A.to_values()
230+
rows, cols, vals = A.to_coo()
231231
rows = (id_to_key[row] for row in rows.tolist())
232232
cols = (id_to_key[col] for col in cols.tolist())
233233
if edge_attribute is None:

Diff for: graphblas_algorithms/classes/nodemap.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __getitem__(self, key):
5252
def __iter__(self):
5353
# Slow if we iterate over one; fast if we iterate over all
5454
return map(
55-
self.id_to_key.__getitem__, self.vector.to_values(values=False, sort=False)[0].tolist()
55+
self.id_to_key.__getitem__, self.vector.to_coo(values=False, sort=False)[0].tolist()
5656
)
5757

5858
def __len__(self):
@@ -123,7 +123,7 @@ def __getitem__(self, key):
123123

124124
def __iter__(self):
125125
# Slow if we iterate over one; fast if we iterate over all
126-
return iter(self.vector.to_values(values=False, sort=False)[0].tolist())
126+
return iter(self.vector.to_coo(values=False, sort=False)[0].tolist())
127127

128128
def __len__(self):
129129
return self.vector.nvals
@@ -232,7 +232,7 @@ def __iter__(self):
232232
# Slow if we iterate over one; fast if we iterate over all
233233
return map(
234234
self.id_to_key.__getitem__,
235-
self._get_rows().to_values(values=False, sort=False)[0].tolist(),
235+
self._get_rows().to_coo(values=False, sort=False)[0].tolist(),
236236
)
237237

238238
def __len__(self):

Diff for: graphblas_algorithms/classes/nodeset.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __contains__(self, x):
4646
def __iter__(self):
4747
# Slow if we iterate over one; fast if we iterate over all
4848
return map(
49-
self.id_to_key.__getitem__, self.vector.to_values(values=False, sort=False)[0].tolist()
49+
self.id_to_key.__getitem__, self.vector.to_coo(values=False, sort=False)[0].tolist()
5050
)
5151

5252
def __len__(self):

Diff for: graphblas_algorithms/interface.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import pytest
2-
31
from . import nxapi
42

53

@@ -93,6 +91,10 @@ def convert_to_nx(obj, *, name=None):
9391

9492
@staticmethod
9593
def on_start_tests(items):
94+
try:
95+
import pytest
96+
except ImportError: # pragma: no cover (import)
97+
return
9698
skip = [
9799
("test_attributes", {"TestBoruvka", "test_mst.py"}),
98100
("test_weight_attribute", {"TestBoruvka", "test_mst.py"}),

Diff for: graphblas_algorithms/nxapi/boundary.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def edge_boundary(G, nbunch1, nbunch2=None, data=False, keys=False, default=None
2121
v1 = G.set_to_vector(nbunch1, ignore_extra=True)
2222
v2 = G.set_to_vector(nbunch2, ignore_extra=True)
2323
result = algorithms.edge_boundary(G, v1, v2, is_weighted=is_multigraph or data)
24-
rows, cols, vals = result.to_values(values=is_multigraph or data)
24+
rows, cols, vals = result.to_coo(values=is_multigraph or data)
2525
id_to_key = G.id_to_key
2626
if data:
2727
it = zip(

Diff for: graphblas_algorithms/nxapi/cluster.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def _split(L, k):
9595
# TODO: should this move into algorithms?
9696
def _square_clustering_split(G, node_ids=None, *, nsplits):
9797
if node_ids is None:
98-
node_ids = G._A.reduce_rowwise(monoid.any).to_values()[0]
98+
node_ids = G._A.reduce_rowwise(monoid.any).to_coo()[0]
9999
result = None
100100
for chunk_ids in _split(node_ids, nsplits):
101101
res = algorithms.square_clustering(G, chunk_ids)

Diff for: graphblas_algorithms/tests/test_match_nx.py

+4-13
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,17 @@
2828

2929
def isdispatched(func):
3030
"""Can this NetworkX function dispatch to other backends?"""
31-
# Haha, there should be a better way to know this
32-
registered_algorithms = backends._registered_algorithms
33-
try:
34-
return (
35-
func.__globals__.get("_registered_algorithms") is registered_algorithms
36-
and func.__module__.startswith("networkx")
37-
and func.__module__ != "networkx.classes.backends"
38-
and set(func.__code__.co_freevars) == {"func", "name"}
39-
)
40-
except Exception:
41-
return False
31+
return (
32+
callable(func) and hasattr(func, "dispatchname") and func.__module__.startswith("networkx")
33+
)
4234

4335

4436
def dispatchname(func):
4537
"""The dispatched name of the dispatchable NetworkX function"""
4638
# Haha, there should be a better way to get this
4739
if not isdispatched(func):
4840
raise ValueError(f"Function is not dispatched in NetworkX: {func.__name__}")
49-
index = func.__code__.co_freevars.index("name")
50-
return func.__closure__[index].cell_contents
41+
return func.dispatchname
5142

5243

5344
def fullname(func):

Diff for: requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
python-graphblas >=2022.10.1
1+
python-graphblas >=2022.11.0

Diff for: scripts/bench_pagerank.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,14 @@ def main(filename, backend, time, n, verify, alpha, tol, _get_result=False):
178178

179179
start = timeit.default_timer()
180180
df = pd.read_csv(filename, delimiter="\t", names=["row", "col"])
181-
G = Matrix.from_values(df["row"].values, df["col"].values, 1)
181+
G = Matrix.from_coo(df["row"].values, df["col"].values, 1)
182182
stop = timeit.default_timer()
183183
num_nodes = G.nrows
184184
num_edges = G.nvals
185185
if _get_result:
186186
result = pagerank(G, alpha=alpha, tol=tol)
187187
result(~result.S) << 0 # Densify just in case
188-
return result.to_values()[1]
188+
return result.to_coo()[1]
189189

190190
elif backend == "scipy":
191191
import pandas as pd

0 commit comments

Comments
 (0)