python-graphblas 2024.2.0__tar.gz → 2025.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python-graphblas-2024.2.0/python_graphblas.egg-info → python_graphblas-2025.2.0}/PKG-INFO +58 -19
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/README.md +40 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/base.py +1 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/dtypes.py +15 -4
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/formatting.py +1 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/infix.py +1 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/matrix.py +8 -3
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/base.py +1 -2
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/scalar.py +1 -1
- python_graphblas-2025.2.0/graphblas/core/ss/__init__.py +5 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/config.py +1 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/matrix.py +37 -4
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/vector.py +33 -2
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/utils.py +15 -5
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/vector.py +2 -2
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/exceptions.py +11 -3
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/_networkx.py +4 -2
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/conftest.py +8 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_dtype.py +8 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_io.py +1 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_matrix.py +13 -10
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_numpyops.py +10 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_scalar.py +5 -1
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_ssjit.py +49 -3
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_vector.py +16 -5
- python_graphblas-2025.2.0/pyproject.toml +499 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0/python_graphblas.egg-info}/PKG-INFO +58 -19
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/python_graphblas.egg-info/requires.txt +15 -13
- python-graphblas-2024.2.0/graphblas/core/ss/__init__.py +0 -3
- python-graphblas-2024.2.0/pyproject.toml +0 -485
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/LICENSE +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/MANIFEST.in +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/conftest.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/agg/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/agg/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/binary/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/binary/numpy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/binary/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/automethods.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/descriptor.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/expr.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/infixmethods.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/mask.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/agg.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/binary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/indexunary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/monoid.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/select.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/semiring.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/unary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/operator/utils.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/recorder.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/slice.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/binary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/context.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/descriptor.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/dtypes.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/indexunary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/prefix_scan.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/select.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/core/ss/unary.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/dtypes/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/dtypes/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/graphblas.yaml +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/indexunary/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/indexunary/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/_awkward.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/_matrixmarket.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/_scipy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/io/_sparse.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/monoid/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/monoid/numpy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/monoid/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/op/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/op/numpy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/op/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/select/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/select/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/semiring/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/semiring/numpy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/semiring/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/ss/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/ss/_core.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle1-vanilla.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle1.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle2-vanilla.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle2.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle3-vanilla.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/pickle3.pkl +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_auto_init.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_core.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_descriptor.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_external_init.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_formatting.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_infix.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_mask.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_op.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_operator_types.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_pickle.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_prefix_scan.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_recorder.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_resolving.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/tests/test_ss_utils.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/unary/__init__.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/unary/numpy.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/unary/ss.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/graphblas/viz.py +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/python_graphblas.egg-info/SOURCES.txt +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/python_graphblas.egg-info/dependency_links.txt +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/python_graphblas.egg-info/top_level.txt +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/setup.cfg +0 -0
- {python-graphblas-2024.2.0 → python_graphblas-2025.2.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: python-graphblas
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2025.2.0
|
|
4
4
|
Summary: Python library for GraphBLAS: high-performance sparse linear algebra for scalable graph analytics
|
|
5
5
|
Author: Jim Kitchen, Python-graphblas contributors
|
|
6
6
|
Author-email: Erik Welch <erik.n.welch@gmail.com>
|
|
@@ -219,10 +219,10 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
219
219
|
Classifier: Operating System :: Microsoft :: Windows
|
|
220
220
|
Classifier: Programming Language :: Python
|
|
221
221
|
Classifier: Programming Language :: Python :: 3
|
|
222
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
223
222
|
Classifier: Programming Language :: Python :: 3.10
|
|
224
223
|
Classifier: Programming Language :: Python :: 3.11
|
|
225
224
|
Classifier: Programming Language :: Python :: 3.12
|
|
225
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
226
226
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
227
227
|
Classifier: Intended Audience :: Developers
|
|
228
228
|
Classifier: Intended Audience :: Other Audience
|
|
@@ -231,22 +231,22 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
231
231
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
232
232
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
233
233
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
234
|
-
Requires-Python: >=3.
|
|
234
|
+
Requires-Python: >=3.10
|
|
235
235
|
Description-Content-Type: text/markdown
|
|
236
236
|
License-File: LICENSE
|
|
237
|
-
Requires-Dist: numpy>=1.
|
|
237
|
+
Requires-Dist: numpy>=1.23
|
|
238
238
|
Requires-Dist: donfig>=0.6
|
|
239
239
|
Requires-Dist: pyyaml>=5.4
|
|
240
|
-
Requires-Dist: suitesparse-graphblas<
|
|
241
|
-
Requires-Dist: numba>=0.55; python_version < "3.
|
|
240
|
+
Requires-Dist: suitesparse-graphblas<10,>=7.4.0.0
|
|
241
|
+
Requires-Dist: numba>=0.55; python_version < "3.14"
|
|
242
242
|
Provides-Extra: suitesparse
|
|
243
|
-
Requires-Dist: suitesparse-graphblas<
|
|
243
|
+
Requires-Dist: suitesparse-graphblas<10,>=7.4.0.0; extra == "suitesparse"
|
|
244
244
|
Provides-Extra: networkx
|
|
245
245
|
Requires-Dist: networkx>=2.8; extra == "networkx"
|
|
246
246
|
Provides-Extra: numba
|
|
247
247
|
Requires-Dist: numba>=0.55; extra == "numba"
|
|
248
248
|
Provides-Extra: pandas
|
|
249
|
-
Requires-Dist: pandas>=1.
|
|
249
|
+
Requires-Dist: pandas>=1.5; extra == "pandas"
|
|
250
250
|
Provides-Extra: scipy
|
|
251
251
|
Requires-Dist: scipy>=1.9; extra == "scipy"
|
|
252
252
|
Provides-Extra: suitesparse-udf
|
|
@@ -255,17 +255,17 @@ Provides-Extra: repr
|
|
|
255
255
|
Requires-Dist: python-graphblas[pandas]; extra == "repr"
|
|
256
256
|
Provides-Extra: io
|
|
257
257
|
Requires-Dist: python-graphblas[networkx,scipy]; extra == "io"
|
|
258
|
-
Requires-Dist: python-graphblas[numba]; python_version < "3.
|
|
259
|
-
Requires-Dist: awkward>=
|
|
260
|
-
Requires-Dist: sparse>=0.
|
|
261
|
-
Requires-Dist: fast-matrix-market>=1.4.5; extra == "io"
|
|
258
|
+
Requires-Dist: python-graphblas[numba]; python_version < "3.14" and extra == "io"
|
|
259
|
+
Requires-Dist: awkward>=2.0; extra == "io"
|
|
260
|
+
Requires-Dist: sparse>=0.14; python_version < "3.13" and extra == "io"
|
|
261
|
+
Requires-Dist: fast-matrix-market>=1.4.5; python_version < "3.13" and extra == "io"
|
|
262
262
|
Provides-Extra: viz
|
|
263
263
|
Requires-Dist: python-graphblas[networkx,scipy]; extra == "viz"
|
|
264
|
-
Requires-Dist: matplotlib>=3.
|
|
264
|
+
Requires-Dist: matplotlib>=3.6; extra == "viz"
|
|
265
265
|
Provides-Extra: datashade
|
|
266
266
|
Requires-Dist: python-graphblas[numba,pandas,scipy]; extra == "datashade"
|
|
267
|
-
Requires-Dist: datashader>=0.
|
|
268
|
-
Requires-Dist: hvplot>=0.
|
|
267
|
+
Requires-Dist: datashader>=0.14; extra == "datashade"
|
|
268
|
+
Requires-Dist: hvplot>=0.8; extra == "datashade"
|
|
269
269
|
Provides-Extra: test
|
|
270
270
|
Requires-Dist: python-graphblas[pandas,scipy,suitesparse]; extra == "test"
|
|
271
271
|
Requires-Dist: packaging>=21; extra == "test"
|
|
@@ -273,10 +273,10 @@ Requires-Dist: pytest>=6.2; extra == "test"
|
|
|
273
273
|
Requires-Dist: tomli>=1; extra == "test"
|
|
274
274
|
Provides-Extra: default
|
|
275
275
|
Requires-Dist: python-graphblas[pandas,scipy,suitesparse]; extra == "default"
|
|
276
|
-
Requires-Dist: python-graphblas[numba]; python_version < "3.
|
|
276
|
+
Requires-Dist: python-graphblas[numba]; python_version < "3.14" and extra == "default"
|
|
277
277
|
Provides-Extra: all
|
|
278
278
|
Requires-Dist: python-graphblas[default,io,test,viz]; extra == "all"
|
|
279
|
-
Requires-Dist: python-graphblas[datashade]; python_version < "3.
|
|
279
|
+
Requires-Dist: python-graphblas[datashade]; python_version < "3.14" and extra == "all"
|
|
280
280
|
|
|
281
281
|

|
|
282
282
|
|
|
@@ -315,14 +315,19 @@ For algorithms, see
|
|
|
315
315
|
</p>
|
|
316
316
|
|
|
317
317
|
## Install
|
|
318
|
+
|
|
318
319
|
Install the latest version of Python-graphblas via conda:
|
|
320
|
+
|
|
319
321
|
```
|
|
320
322
|
$ conda install -c conda-forge python-graphblas
|
|
321
323
|
```
|
|
324
|
+
|
|
322
325
|
or pip:
|
|
326
|
+
|
|
323
327
|
```
|
|
324
|
-
$ pip install python-graphblas[default]
|
|
328
|
+
$ pip install 'python-graphblas[default]'
|
|
325
329
|
```
|
|
330
|
+
|
|
326
331
|
This will also install the [SuiteSparse:GraphBLAS](https://github.com/DrTimothyAldenDavis/GraphBLAS) compiled C library.
|
|
327
332
|
We currently support the [GraphBLAS C API 2.0 specification](https://graphblas.org/docs/GraphBLAS_API_C_v2.0.0.pdf).
|
|
328
333
|
|
|
@@ -337,6 +342,7 @@ The following are not required by python-graphblas, but may be needed for certai
|
|
|
337
342
|
- `fast-matrix-market` - for faster read/write of Matrix Market files with `gb.io.mmread` and `gb.io.mmwrite`.
|
|
338
343
|
|
|
339
344
|
## Description
|
|
345
|
+
|
|
340
346
|
Currently works with [SuiteSparse:GraphBLAS](https://github.com/DrTimothyAldenDavis/GraphBLAS), but the goal is to make it work with all implementations of the GraphBLAS spec.
|
|
341
347
|
|
|
342
348
|
The approach taken with this library is to follow the C-API 2.0 specification as closely as possible while making improvements
|
|
@@ -350,10 +356,12 @@ with how Python handles assignment, so instead we (ab)use the left-shift `<<` no
|
|
|
350
356
|
assignment. This opens up all kinds of nice possibilities.
|
|
351
357
|
|
|
352
358
|
This is an example of how the mapping works:
|
|
359
|
+
|
|
353
360
|
```C
|
|
354
361
|
// C call
|
|
355
362
|
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, NULL)
|
|
356
363
|
```
|
|
364
|
+
|
|
357
365
|
```python
|
|
358
366
|
# Python call
|
|
359
367
|
M(mask.V, accum=binary.plus) << A.mxm(B, semiring.min_plus)
|
|
@@ -371,10 +379,12 @@ is a much better approach, even if it doesn't feel very Pythonic.
|
|
|
371
379
|
Descriptor flags are set on the appropriate elements to keep logic close to what it affects. Here is the same call
|
|
372
380
|
with descriptor bits set. `ttcsr` indicates transpose the first and second matrices, complement the structure of the mask,
|
|
373
381
|
and do a replacement on the output.
|
|
382
|
+
|
|
374
383
|
```C
|
|
375
384
|
// C call
|
|
376
385
|
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, desc.ttcsr)
|
|
377
386
|
```
|
|
387
|
+
|
|
378
388
|
```python
|
|
379
389
|
# Python call
|
|
380
390
|
M(~mask.S, accum=binary.plus, replace=True) << A.T.mxm(B.T, semiring.min_plus)
|
|
@@ -384,16 +394,20 @@ The objects receiving the flag operations (A.T, ~mask, etc) are also delayed obj
|
|
|
384
394
|
do no computation, allowing the correct descriptor bits to be set in a single GraphBLAS call.
|
|
385
395
|
|
|
386
396
|
**If no mask or accumulator is used, the call looks like this**:
|
|
397
|
+
|
|
387
398
|
```python
|
|
388
399
|
M << A.mxm(B, semiring.min_plus)
|
|
389
400
|
```
|
|
401
|
+
|
|
390
402
|
The use of `<<` to indicate updating is actually just syntactic sugar for a real `.update()` method. The above
|
|
391
403
|
expression could be written as:
|
|
404
|
+
|
|
392
405
|
```python
|
|
393
406
|
M.update(A.mxm(B, semiring.min_plus))
|
|
394
407
|
```
|
|
395
408
|
|
|
396
409
|
## Operations
|
|
410
|
+
|
|
397
411
|
```python
|
|
398
412
|
M(mask, accum) << A.mxm(B, semiring) # mxm
|
|
399
413
|
w(mask, accum) << A.mxv(v, semiring) # mxv
|
|
@@ -403,14 +417,18 @@ M(mask, accum) << A.ewise_mult(B, binaryop) # eWiseMult
|
|
|
403
417
|
M(mask, accum) << A.kronecker(B, binaryop) # kronecker
|
|
404
418
|
M(mask, accum) << A.T # transpose
|
|
405
419
|
```
|
|
420
|
+
|
|
406
421
|
## Extract
|
|
422
|
+
|
|
407
423
|
```python
|
|
408
424
|
M(mask, accum) << A[rows, cols] # rows and cols are a list or a slice
|
|
409
425
|
w(mask, accum) << A[rows, col_index] # extract column
|
|
410
426
|
w(mask, accum) << A[row_index, cols] # extract row
|
|
411
427
|
s = A[row_index, col_index].value # extract single element
|
|
412
428
|
```
|
|
429
|
+
|
|
413
430
|
## Assign
|
|
431
|
+
|
|
414
432
|
```python
|
|
415
433
|
M(mask, accum)[rows, cols] << A # rows and cols are a list or a slice
|
|
416
434
|
M(mask, accum)[rows, col_index] << v # assign column
|
|
@@ -420,31 +438,42 @@ M[row_index, col_index] << s # assign scalar to single element
|
|
|
420
438
|
# (mask and accum not allowed)
|
|
421
439
|
del M[row_index, col_index] # remove single element
|
|
422
440
|
```
|
|
441
|
+
|
|
423
442
|
## Apply
|
|
443
|
+
|
|
424
444
|
```python
|
|
425
445
|
M(mask, accum) << A.apply(unaryop)
|
|
426
446
|
M(mask, accum) << A.apply(binaryop, left=s) # bind-first
|
|
427
447
|
M(mask, accum) << A.apply(binaryop, right=s) # bind-second
|
|
428
448
|
```
|
|
449
|
+
|
|
429
450
|
## Reduce
|
|
451
|
+
|
|
430
452
|
```python
|
|
431
453
|
v(mask, accum) << A.reduce_rowwise(op) # reduce row-wise
|
|
432
454
|
v(mask, accum) << A.reduce_columnwise(op) # reduce column-wise
|
|
433
455
|
s(accum) << A.reduce_scalar(op)
|
|
434
456
|
s(accum) << v.reduce(op)
|
|
435
457
|
```
|
|
458
|
+
|
|
436
459
|
## Creating new Vectors / Matrices
|
|
460
|
+
|
|
437
461
|
```python
|
|
438
462
|
A = Matrix.new(dtype, num_rows, num_cols) # new_type
|
|
439
463
|
B = A.dup() # dup
|
|
440
464
|
A = Matrix.from_coo([row_indices], [col_indices], [values]) # build
|
|
441
465
|
```
|
|
466
|
+
|
|
442
467
|
## New from delayed
|
|
468
|
+
|
|
443
469
|
Delayed objects can be used to create a new object using `.new()` method
|
|
470
|
+
|
|
444
471
|
```python
|
|
445
472
|
C = A.mxm(B, semiring).new()
|
|
446
473
|
```
|
|
474
|
+
|
|
447
475
|
## Properties
|
|
476
|
+
|
|
448
477
|
```python
|
|
449
478
|
size = v.size # size
|
|
450
479
|
nrows = M.nrows # nrows
|
|
@@ -452,10 +481,13 @@ ncols = M.ncols # ncols
|
|
|
452
481
|
nvals = M.nvals # nvals
|
|
453
482
|
rindices, cindices, vals = M.to_coo() # extractTuples
|
|
454
483
|
```
|
|
484
|
+
|
|
455
485
|
## Initialization
|
|
486
|
+
|
|
456
487
|
There is a mechanism to initialize `graphblas` with a context prior to use. This allows for setting the backend to
|
|
457
488
|
use as well as the blocking/non-blocking mode. If the context is not initialized, a default initialization will
|
|
458
489
|
be performed automatically.
|
|
490
|
+
|
|
459
491
|
```python
|
|
460
492
|
import graphblas as gb
|
|
461
493
|
|
|
@@ -466,10 +498,13 @@ gb.init("suitesparse", blocking=True)
|
|
|
466
498
|
from graphblas import binary, semiring
|
|
467
499
|
from graphblas import Matrix, Vector, Scalar
|
|
468
500
|
```
|
|
501
|
+
|
|
469
502
|
## Performant User Defined Functions
|
|
503
|
+
|
|
470
504
|
Python-graphblas requires `numba` which enables compiling user-defined Python functions to native C for use in GraphBLAS.
|
|
471
505
|
|
|
472
506
|
Example customized UnaryOp:
|
|
507
|
+
|
|
473
508
|
```python
|
|
474
509
|
from graphblas import unary
|
|
475
510
|
|
|
@@ -484,9 +519,11 @@ v = Vector.from_coo([0, 1, 3], [1, 2, 3])
|
|
|
484
519
|
w = v.apply(unary.force_odd).new()
|
|
485
520
|
w # indexes=[0, 1, 3], values=[1, 3, 3]
|
|
486
521
|
```
|
|
522
|
+
|
|
487
523
|
Similar methods exist for BinaryOp, Monoid, and Semiring.
|
|
488
524
|
|
|
489
525
|
## Relation to other network analysis libraries
|
|
526
|
+
|
|
490
527
|
Python-graphblas aims to provide an efficient and consistent expression
|
|
491
528
|
of graph operations using linear algebra. This allows the development of
|
|
492
529
|
high-performance implementations of existing and new graph algorithms
|
|
@@ -503,7 +540,9 @@ other libraries, `graphblas.io` contains multiple connectors, see the
|
|
|
503
540
|
following section.
|
|
504
541
|
|
|
505
542
|
## Import/Export connectors to the Python ecosystem
|
|
543
|
+
|
|
506
544
|
`graphblas.io` contains functions for converting to and from:
|
|
545
|
+
|
|
507
546
|
```python
|
|
508
547
|
import graphblas as gb
|
|
509
548
|
|
|
@@ -35,14 +35,19 @@ For algorithms, see
|
|
|
35
35
|
</p>
|
|
36
36
|
|
|
37
37
|
## Install
|
|
38
|
+
|
|
38
39
|
Install the latest version of Python-graphblas via conda:
|
|
40
|
+
|
|
39
41
|
```
|
|
40
42
|
$ conda install -c conda-forge python-graphblas
|
|
41
43
|
```
|
|
44
|
+
|
|
42
45
|
or pip:
|
|
46
|
+
|
|
43
47
|
```
|
|
44
|
-
$ pip install python-graphblas[default]
|
|
48
|
+
$ pip install 'python-graphblas[default]'
|
|
45
49
|
```
|
|
50
|
+
|
|
46
51
|
This will also install the [SuiteSparse:GraphBLAS](https://github.com/DrTimothyAldenDavis/GraphBLAS) compiled C library.
|
|
47
52
|
We currently support the [GraphBLAS C API 2.0 specification](https://graphblas.org/docs/GraphBLAS_API_C_v2.0.0.pdf).
|
|
48
53
|
|
|
@@ -57,6 +62,7 @@ The following are not required by python-graphblas, but may be needed for certai
|
|
|
57
62
|
- `fast-matrix-market` - for faster read/write of Matrix Market files with `gb.io.mmread` and `gb.io.mmwrite`.
|
|
58
63
|
|
|
59
64
|
## Description
|
|
65
|
+
|
|
60
66
|
Currently works with [SuiteSparse:GraphBLAS](https://github.com/DrTimothyAldenDavis/GraphBLAS), but the goal is to make it work with all implementations of the GraphBLAS spec.
|
|
61
67
|
|
|
62
68
|
The approach taken with this library is to follow the C-API 2.0 specification as closely as possible while making improvements
|
|
@@ -70,10 +76,12 @@ with how Python handles assignment, so instead we (ab)use the left-shift `<<` no
|
|
|
70
76
|
assignment. This opens up all kinds of nice possibilities.
|
|
71
77
|
|
|
72
78
|
This is an example of how the mapping works:
|
|
79
|
+
|
|
73
80
|
```C
|
|
74
81
|
// C call
|
|
75
82
|
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, NULL)
|
|
76
83
|
```
|
|
84
|
+
|
|
77
85
|
```python
|
|
78
86
|
# Python call
|
|
79
87
|
M(mask.V, accum=binary.plus) << A.mxm(B, semiring.min_plus)
|
|
@@ -91,10 +99,12 @@ is a much better approach, even if it doesn't feel very Pythonic.
|
|
|
91
99
|
Descriptor flags are set on the appropriate elements to keep logic close to what it affects. Here is the same call
|
|
92
100
|
with descriptor bits set. `ttcsr` indicates transpose the first and second matrices, complement the structure of the mask,
|
|
93
101
|
and do a replacement on the output.
|
|
102
|
+
|
|
94
103
|
```C
|
|
95
104
|
// C call
|
|
96
105
|
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, desc.ttcsr)
|
|
97
106
|
```
|
|
107
|
+
|
|
98
108
|
```python
|
|
99
109
|
# Python call
|
|
100
110
|
M(~mask.S, accum=binary.plus, replace=True) << A.T.mxm(B.T, semiring.min_plus)
|
|
@@ -104,16 +114,20 @@ The objects receiving the flag operations (A.T, ~mask, etc) are also delayed obj
|
|
|
104
114
|
do no computation, allowing the correct descriptor bits to be set in a single GraphBLAS call.
|
|
105
115
|
|
|
106
116
|
**If no mask or accumulator is used, the call looks like this**:
|
|
117
|
+
|
|
107
118
|
```python
|
|
108
119
|
M << A.mxm(B, semiring.min_plus)
|
|
109
120
|
```
|
|
121
|
+
|
|
110
122
|
The use of `<<` to indicate updating is actually just syntactic sugar for a real `.update()` method. The above
|
|
111
123
|
expression could be written as:
|
|
124
|
+
|
|
112
125
|
```python
|
|
113
126
|
M.update(A.mxm(B, semiring.min_plus))
|
|
114
127
|
```
|
|
115
128
|
|
|
116
129
|
## Operations
|
|
130
|
+
|
|
117
131
|
```python
|
|
118
132
|
M(mask, accum) << A.mxm(B, semiring) # mxm
|
|
119
133
|
w(mask, accum) << A.mxv(v, semiring) # mxv
|
|
@@ -123,14 +137,18 @@ M(mask, accum) << A.ewise_mult(B, binaryop) # eWiseMult
|
|
|
123
137
|
M(mask, accum) << A.kronecker(B, binaryop) # kronecker
|
|
124
138
|
M(mask, accum) << A.T # transpose
|
|
125
139
|
```
|
|
140
|
+
|
|
126
141
|
## Extract
|
|
142
|
+
|
|
127
143
|
```python
|
|
128
144
|
M(mask, accum) << A[rows, cols] # rows and cols are a list or a slice
|
|
129
145
|
w(mask, accum) << A[rows, col_index] # extract column
|
|
130
146
|
w(mask, accum) << A[row_index, cols] # extract row
|
|
131
147
|
s = A[row_index, col_index].value # extract single element
|
|
132
148
|
```
|
|
149
|
+
|
|
133
150
|
## Assign
|
|
151
|
+
|
|
134
152
|
```python
|
|
135
153
|
M(mask, accum)[rows, cols] << A # rows and cols are a list or a slice
|
|
136
154
|
M(mask, accum)[rows, col_index] << v # assign column
|
|
@@ -140,31 +158,42 @@ M[row_index, col_index] << s # assign scalar to single element
|
|
|
140
158
|
# (mask and accum not allowed)
|
|
141
159
|
del M[row_index, col_index] # remove single element
|
|
142
160
|
```
|
|
161
|
+
|
|
143
162
|
## Apply
|
|
163
|
+
|
|
144
164
|
```python
|
|
145
165
|
M(mask, accum) << A.apply(unaryop)
|
|
146
166
|
M(mask, accum) << A.apply(binaryop, left=s) # bind-first
|
|
147
167
|
M(mask, accum) << A.apply(binaryop, right=s) # bind-second
|
|
148
168
|
```
|
|
169
|
+
|
|
149
170
|
## Reduce
|
|
171
|
+
|
|
150
172
|
```python
|
|
151
173
|
v(mask, accum) << A.reduce_rowwise(op) # reduce row-wise
|
|
152
174
|
v(mask, accum) << A.reduce_columnwise(op) # reduce column-wise
|
|
153
175
|
s(accum) << A.reduce_scalar(op)
|
|
154
176
|
s(accum) << v.reduce(op)
|
|
155
177
|
```
|
|
178
|
+
|
|
156
179
|
## Creating new Vectors / Matrices
|
|
180
|
+
|
|
157
181
|
```python
|
|
158
182
|
A = Matrix.new(dtype, num_rows, num_cols) # new_type
|
|
159
183
|
B = A.dup() # dup
|
|
160
184
|
A = Matrix.from_coo([row_indices], [col_indices], [values]) # build
|
|
161
185
|
```
|
|
186
|
+
|
|
162
187
|
## New from delayed
|
|
188
|
+
|
|
163
189
|
Delayed objects can be used to create a new object using `.new()` method
|
|
190
|
+
|
|
164
191
|
```python
|
|
165
192
|
C = A.mxm(B, semiring).new()
|
|
166
193
|
```
|
|
194
|
+
|
|
167
195
|
## Properties
|
|
196
|
+
|
|
168
197
|
```python
|
|
169
198
|
size = v.size # size
|
|
170
199
|
nrows = M.nrows # nrows
|
|
@@ -172,10 +201,13 @@ ncols = M.ncols # ncols
|
|
|
172
201
|
nvals = M.nvals # nvals
|
|
173
202
|
rindices, cindices, vals = M.to_coo() # extractTuples
|
|
174
203
|
```
|
|
204
|
+
|
|
175
205
|
## Initialization
|
|
206
|
+
|
|
176
207
|
There is a mechanism to initialize `graphblas` with a context prior to use. This allows for setting the backend to
|
|
177
208
|
use as well as the blocking/non-blocking mode. If the context is not initialized, a default initialization will
|
|
178
209
|
be performed automatically.
|
|
210
|
+
|
|
179
211
|
```python
|
|
180
212
|
import graphblas as gb
|
|
181
213
|
|
|
@@ -186,10 +218,13 @@ gb.init("suitesparse", blocking=True)
|
|
|
186
218
|
from graphblas import binary, semiring
|
|
187
219
|
from graphblas import Matrix, Vector, Scalar
|
|
188
220
|
```
|
|
221
|
+
|
|
189
222
|
## Performant User Defined Functions
|
|
223
|
+
|
|
190
224
|
Python-graphblas requires `numba` which enables compiling user-defined Python functions to native C for use in GraphBLAS.
|
|
191
225
|
|
|
192
226
|
Example customized UnaryOp:
|
|
227
|
+
|
|
193
228
|
```python
|
|
194
229
|
from graphblas import unary
|
|
195
230
|
|
|
@@ -204,9 +239,11 @@ v = Vector.from_coo([0, 1, 3], [1, 2, 3])
|
|
|
204
239
|
w = v.apply(unary.force_odd).new()
|
|
205
240
|
w # indexes=[0, 1, 3], values=[1, 3, 3]
|
|
206
241
|
```
|
|
242
|
+
|
|
207
243
|
Similar methods exist for BinaryOp, Monoid, and Semiring.
|
|
208
244
|
|
|
209
245
|
## Relation to other network analysis libraries
|
|
246
|
+
|
|
210
247
|
Python-graphblas aims to provide an efficient and consistent expression
|
|
211
248
|
of graph operations using linear algebra. This allows the development of
|
|
212
249
|
high-performance implementations of existing and new graph algorithms
|
|
@@ -223,7 +260,9 @@ other libraries, `graphblas.io` contains multiple connectors, see the
|
|
|
223
260
|
following section.
|
|
224
261
|
|
|
225
262
|
## Import/Export connectors to the Python ecosystem
|
|
263
|
+
|
|
226
264
|
`graphblas.io` contains functions for converting to and from:
|
|
265
|
+
|
|
227
266
|
```python
|
|
228
267
|
import graphblas as gb
|
|
229
268
|
|
|
@@ -513,7 +513,7 @@ class BaseType:
|
|
|
513
513
|
_expect_op = _expect_op
|
|
514
514
|
|
|
515
515
|
# Don't let non-scalars be coerced to numpy arrays
|
|
516
|
-
def __array__(self, dtype=None):
|
|
516
|
+
def __array__(self, dtype=None, *, copy=None):
|
|
517
517
|
raise TypeError(
|
|
518
518
|
f"{type(self).__name__} can't be directly converted to a numpy array; "
|
|
519
519
|
f"perhaps use `{self.name}.to_coo()` method instead."
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import warnings
|
|
2
|
+
from ast import literal_eval
|
|
2
3
|
|
|
3
4
|
import numpy as np
|
|
4
5
|
from numpy import promote_types, result_type
|
|
@@ -97,7 +98,7 @@ def register_anonymous(dtype, name=None):
|
|
|
97
98
|
# Allow dtypes such as `"INT64[3, 4]"` for convenience
|
|
98
99
|
base_dtype, shape = dtype.split("[", 1)
|
|
99
100
|
base_dtype = lookup_dtype(base_dtype)
|
|
100
|
-
shape =
|
|
101
|
+
shape = literal_eval(f"[{shape}")
|
|
101
102
|
dtype = np.dtype((base_dtype.np_type, shape))
|
|
102
103
|
else:
|
|
103
104
|
raise
|
|
@@ -115,7 +116,17 @@ def register_anonymous(dtype, name=None):
|
|
|
115
116
|
from ..exceptions import check_status_carg
|
|
116
117
|
|
|
117
118
|
gb_obj = ffi.new("GrB_Type*")
|
|
118
|
-
|
|
119
|
+
|
|
120
|
+
if hasattr(lib, "GrB_Type_set_String"):
|
|
121
|
+
# We name this so that we can serialize and deserialize UDTs
|
|
122
|
+
# We don't yet have C definitions
|
|
123
|
+
np_repr = _dtype_to_string(dtype)
|
|
124
|
+
status = lib.GrB_Type_new(gb_obj, dtype.itemsize)
|
|
125
|
+
check_status_carg(status, "Type", gb_obj[0])
|
|
126
|
+
val_obj = ffi.new("char[]", np_repr.encode())
|
|
127
|
+
status = lib.GrB_Type_set_String(gb_obj[0], val_obj, lib.GrB_NAME)
|
|
128
|
+
elif backend == "suitesparse":
|
|
129
|
+
# For SuiteSparse < 9
|
|
119
130
|
# We name this so that we can serialize and deserialize UDTs
|
|
120
131
|
# We don't yet have C definitions
|
|
121
132
|
np_repr = _dtype_to_string(dtype).encode()
|
|
@@ -429,7 +440,7 @@ def _dtype_to_string(dtype):
|
|
|
429
440
|
np_type = dtype.np_type
|
|
430
441
|
s = str(np_type)
|
|
431
442
|
try:
|
|
432
|
-
if np.dtype(
|
|
443
|
+
if np.dtype(literal_eval(s)) == np_type: # pragma: no branch (safety)
|
|
433
444
|
return s
|
|
434
445
|
except Exception:
|
|
435
446
|
pass
|
|
@@ -448,5 +459,5 @@ def _string_to_dtype(s):
|
|
|
448
459
|
return lookup_dtype(s)
|
|
449
460
|
except Exception:
|
|
450
461
|
pass
|
|
451
|
-
np_type = np.dtype(
|
|
462
|
+
np_type = np.dtype(literal_eval(s))
|
|
452
463
|
return lookup_dtype(np_type)
|
|
@@ -630,7 +630,7 @@ def create_header(type_name, keys, vals, *, lower_border=False, name="", quote=T
|
|
|
630
630
|
name = f'"{name}"'
|
|
631
631
|
key_text = []
|
|
632
632
|
val_text = []
|
|
633
|
-
for key, val in zip(keys, vals):
|
|
633
|
+
for key, val in zip(keys, vals, strict=True):
|
|
634
634
|
width = max(len(key), len(val)) + 2
|
|
635
635
|
key_text.append(key.rjust(width))
|
|
636
636
|
val_text.append(val.rjust(width))
|
|
@@ -184,6 +184,7 @@ class Matrix(BaseType):
|
|
|
184
184
|
ndim = 2
|
|
185
185
|
_is_transposed = False
|
|
186
186
|
_name_counter = itertools.count()
|
|
187
|
+
__networkx_backend__ = "graphblas"
|
|
187
188
|
__networkx_plugin__ = "graphblas"
|
|
188
189
|
|
|
189
190
|
def __new__(cls, dtype=FP64, nrows=0, ncols=0, *, name=None):
|
|
@@ -360,7 +361,7 @@ class Matrix(BaseType):
|
|
|
360
361
|
def __iter__(self):
|
|
361
362
|
"""Iterate over (row, col) indices which are present in the matrix."""
|
|
362
363
|
rows, columns, _ = self.to_coo(values=False)
|
|
363
|
-
return zip(rows.flat, columns.flat)
|
|
364
|
+
return zip(rows.flat, columns.flat, strict=True)
|
|
364
365
|
|
|
365
366
|
def __sizeof__(self):
|
|
366
367
|
if backend == "suitesparse":
|
|
@@ -961,7 +962,7 @@ class Matrix(BaseType):
|
|
|
961
962
|
rows = edgelist[:, 0]
|
|
962
963
|
cols = edgelist[:, 1]
|
|
963
964
|
else:
|
|
964
|
-
unzipped = list(zip(*edgelist))
|
|
965
|
+
unzipped = list(zip(*edgelist, strict=True))
|
|
965
966
|
if len(unzipped) == 2:
|
|
966
967
|
rows, cols = unzipped
|
|
967
968
|
elif len(unzipped) == 3:
|
|
@@ -1826,10 +1827,11 @@ class Matrix(BaseType):
|
|
|
1826
1827
|
cols = cols.tolist()
|
|
1827
1828
|
values = values.tolist()
|
|
1828
1829
|
return {
|
|
1829
|
-
row: dict(zip(cols[start:stop], values[start:stop]))
|
|
1830
|
+
row: dict(zip(cols[start:stop], values[start:stop], strict=True))
|
|
1830
1831
|
for row, (start, stop) in zip(
|
|
1831
1832
|
compressed_rows.tolist(),
|
|
1832
1833
|
np.lib.stride_tricks.sliding_window_view(indptr, 2).tolist(),
|
|
1834
|
+
strict=True,
|
|
1833
1835
|
)
|
|
1834
1836
|
}
|
|
1835
1837
|
# Alternative
|
|
@@ -3582,6 +3584,7 @@ class MatrixExpression(BaseExpression):
|
|
|
3582
3584
|
ndim = 2
|
|
3583
3585
|
output_type = Matrix
|
|
3584
3586
|
_is_transposed = False
|
|
3587
|
+
__networkx_backend__ = "graphblas"
|
|
3585
3588
|
__networkx_plugin__ = "graphblas"
|
|
3586
3589
|
|
|
3587
3590
|
def __init__(
|
|
@@ -3723,6 +3726,7 @@ class MatrixIndexExpr(AmbiguousAssignOrExtract):
|
|
|
3723
3726
|
ndim = 2
|
|
3724
3727
|
output_type = Matrix
|
|
3725
3728
|
_is_transposed = False
|
|
3729
|
+
__networkx_backend__ = "graphblas"
|
|
3726
3730
|
__networkx_plugin__ = "graphblas"
|
|
3727
3731
|
|
|
3728
3732
|
def __init__(self, parent, resolved_indexes, nrows, ncols):
|
|
@@ -3823,6 +3827,7 @@ class TransposedMatrix:
|
|
|
3823
3827
|
ndim = 2
|
|
3824
3828
|
_is_scalar = False
|
|
3825
3829
|
_is_transposed = True
|
|
3830
|
+
__networkx_backend__ = "graphblas"
|
|
3826
3831
|
__networkx_plugin__ = "graphblas"
|
|
3827
3832
|
|
|
3828
3833
|
def __init__(self, matrix):
|
|
@@ -251,8 +251,7 @@ class TypedOpBase:
|
|
|
251
251
|
|
|
252
252
|
def __repr__(self):
|
|
253
253
|
classname = self.opclass.lower()
|
|
254
|
-
|
|
255
|
-
classname = classname[:-2]
|
|
254
|
+
classname = classname.removesuffix("op")
|
|
256
255
|
dtype2 = "" if self._type2 is None else f", {self._type2.name}"
|
|
257
256
|
return f"{classname}.{self.name}[{self.type.name}{dtype2}]"
|
|
258
257
|
|
|
@@ -165,7 +165,7 @@ class Scalar(BaseType):
|
|
|
165
165
|
return self.__int__
|
|
166
166
|
raise AttributeError("Scalar object only has `__index__` for integral dtypes")
|
|
167
167
|
|
|
168
|
-
def __array__(self, dtype=None):
|
|
168
|
+
def __array__(self, dtype=None, *, copy=None):
|
|
169
169
|
if dtype is None:
|
|
170
170
|
dtype = self.dtype.np_type
|
|
171
171
|
return np.array(self.value, dtype=dtype)
|
|
@@ -99,7 +99,7 @@ class BaseConfig(MutableMapping):
|
|
|
99
99
|
return {reverse_bitwise[val]}
|
|
100
100
|
rv = set()
|
|
101
101
|
for k, v in self._bitwise[key].items():
|
|
102
|
-
if isinstance(k, str) and val & v and
|
|
102
|
+
if isinstance(k, str) and val & v and (v).bit_count() == 1:
|
|
103
103
|
rv.add(k)
|
|
104
104
|
return rv
|
|
105
105
|
if is_bool:
|