Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions graphblas/io/_networkx.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@ def from_networkx(G, nodelist=None, dtype=None, weight="weight", name=None):
dup_op = plus

values = np.array(vals, dtype=dtype)
if dtype is None and values.dtype == np.int32: # pragma: no cover (win64 numpy < 2)
# numpy < 2 infers the platform C long for a sequence of Python ints, which
# is 32-bit on Windows. values_to_numpy_buffer widens the same way for
# non-numpy input, so this keeps from_networkx agreeing with
# Matrix.from_coo on INT64 for an unweighted graph on every platform.
if dtype is None and values.dtype == np.int32:
# ``vals`` is a Python sequence, and from_coo widens an int32 dtype
# INFERRED from sequence input to int64 (values_to_numpy_buffer): python
# ints infer int32 on win64 with numpy < 2, and np.int32 scalar weights
# infer it on every platform. Widen the same way so from_networkx and
# Matrix.from_coo given the same weights agree on the result dtype.
# An explicit dtype= is applied above and never reaches this branch.
values = values.astype(np.int64)
if values.ndim != 1 or values.dtype.kind not in "biufc":
# Defer to scipy so the error matches the previous behavior exactly.
Expand Down
22 changes: 22 additions & 0 deletions graphblas/tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,28 @@ def test_from_networkx_undirected():
assert M_none.isequal(expected_none, check_dtype=True)


@pytest.mark.skipif("not nx")
def test_from_networkx_int32_weights_widen_like_from_coo():
# np.int32 scalar weights infer an int32 array from the edge sequence on
# every platform (python ints do too on win64 with numpy < 2), and from_coo
# widens int32 inferred from sequence input to INT64. from_networkx must
# widen the same way or identical weights would produce different dtypes
# depending on which constructor they came through.
G = nx.DiGraph()
G.add_weighted_edges_from([(0, 1, np.int32(2)), (1, 0, np.int32(3))])
M = gb.io.from_networkx(G)
expected = gb.Matrix.from_coo([0, 1], [1, 0], [np.int32(2), np.int32(3)])
assert expected.dtype == dtypes.INT64
assert M.isequal(expected, check_dtype=True)
# An explicit dtype bypasses inference and is preserved exactly.
assert gb.io.from_networkx(G, dtype="int32").dtype == dtypes.INT32
# Narrower ints are not special-cased; this also matches from_coo.
H = nx.DiGraph()
H.add_weighted_edges_from([(0, 1, np.int16(2))])
assert gb.io.from_networkx(H).dtype == dtypes.INT16
assert gb.Matrix.from_coo([0], [1], [np.int16(2)]).dtype == dtypes.INT16


@pytest.mark.skipif("not nx or not ss")
@pytest.mark.parametrize(
"graph_cls", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph] if nx else []
Expand Down