python-graphblas 2023.5.0__py3-none-any.whl → 2023.7.0__py3-none-any.whl
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.
- graphblas/agg/__init__.py +4 -4
- graphblas/binary/ss.py +3 -0
- graphblas/core/agg.py +2 -2
- graphblas/core/automethods.py +1 -1
- graphblas/core/base.py +3 -3
- graphblas/core/descriptor.py +1 -0
- graphblas/{dtypes.py → core/dtypes.py} +99 -109
- graphblas/core/expr.py +1 -1
- graphblas/core/mask.py +5 -5
- graphblas/core/matrix.py +18 -18
- graphblas/core/operator/base.py +1 -1
- graphblas/core/operator/binary.py +3 -3
- graphblas/core/operator/indexunary.py +4 -3
- graphblas/core/operator/semiring.py +2 -2
- graphblas/core/operator/unary.py +3 -3
- graphblas/core/recorder.py +1 -1
- graphblas/core/scalar.py +1 -1
- graphblas/core/ss/__init__.py +3 -0
- graphblas/core/ss/binary.py +72 -0
- graphblas/core/ss/config.py +46 -11
- graphblas/core/ss/context.py +146 -0
- graphblas/core/ss/descriptor.py +21 -9
- graphblas/core/ss/dtypes.py +88 -0
- graphblas/core/ss/indexunary.py +77 -0
- graphblas/core/ss/matrix.py +84 -83
- graphblas/core/ss/select.py +45 -0
- graphblas/core/ss/unary.py +62 -0
- graphblas/core/ss/vector.py +38 -37
- graphblas/core/utils.py +14 -12
- graphblas/core/vector.py +14 -11
- graphblas/dtypes/__init__.py +43 -0
- graphblas/dtypes/ss.py +1 -0
- graphblas/indexunary/__init__.py +13 -1
- graphblas/indexunary/ss.py +6 -0
- graphblas/io/_awkward.py +58 -52
- graphblas/io/_matrixmarket.py +12 -3
- graphblas/io/_numpy.py +6 -6
- graphblas/monoid/__init__.py +13 -1
- graphblas/monoid/ss.py +5 -0
- graphblas/op/ss.py +2 -0
- graphblas/select/__init__.py +19 -7
- graphblas/select/ss.py +6 -0
- graphblas/semiring/ss.py +2 -0
- graphblas/ss/__init__.py +5 -1
- graphblas/ss/_core.py +67 -13
- graphblas/tests/conftest.py +33 -6
- graphblas/tests/test_core.py +4 -1
- graphblas/tests/test_dtype.py +23 -6
- graphblas/tests/test_io.py +21 -5
- graphblas/tests/test_matrix.py +1 -1
- graphblas/tests/test_op.py +14 -2
- graphblas/tests/test_ssjit.py +269 -0
- graphblas/tests/test_vector.py +12 -5
- graphblas/unary/ss.py +3 -0
- graphblas/viz.py +4 -5
- {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/LICENSE +1 -1
- {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/METADATA +25 -8
- python_graphblas-2023.7.0.dist-info/RECORD +110 -0
- python_graphblas-2023.5.0.dist-info/RECORD +0 -98
- {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/WHEEL +0 -0
- {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/top_level.txt +0 -0
graphblas/agg/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""``graphblas.agg`` is an experimental module for exploring Aggregators.
|
|
2
2
|
|
|
3
3
|
Aggregators may be used in reduce methods:
|
|
4
4
|
- Matrix.reduce_rowwise
|
|
@@ -59,9 +59,9 @@ Custom recipes (specific to SuiteSparse:GraphBLAS):
|
|
|
59
59
|
- ss.argmax
|
|
60
60
|
|
|
61
61
|
.. deprecated:: 2023.1.0
|
|
62
|
-
Aggregators
|
|
63
|
-
deprecated in the
|
|
64
|
-
instead such as
|
|
62
|
+
Aggregators ``first``, ``last``, ``first_index``, ``last_index``, ``argmin``, and ``argmax``
|
|
63
|
+
are deprecated in the ``agg`` namespace such as ``agg.first``. Use them from ``agg.ss``
|
|
64
|
+
namespace instead such as ``agg.ss.first``. Will be removed in version 2023.9.0 or later.
|
|
65
65
|
|
|
66
66
|
# Possible aggregators:
|
|
67
67
|
# - absolute_deviation, sum(abs(x - mean(x))), sum_absminus(x, mean(x))
|
graphblas/binary/ss.py
CHANGED
graphblas/core/agg.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""graphblas.core.agg namespace is deprecated; please use graphblas.core.operator.agg instead.
|
|
2
2
|
|
|
3
3
|
.. deprecated:: 2023.3.0
|
|
4
|
-
|
|
5
|
-
Use
|
|
4
|
+
``graphblas.core.agg`` will be removed in a future release.
|
|
5
|
+
Use ``graphblas.core.operator.agg`` instead.
|
|
6
6
|
Will be removed in version 2023.11.0 or later.
|
|
7
7
|
|
|
8
8
|
"""
|
graphblas/core/automethods.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Define functions to use as property methods on expressions.
|
|
2
2
|
|
|
3
|
-
These will automatically compute the value and avoid the need for
|
|
3
|
+
These will automatically compute the value and avoid the need for ``.new()``.
|
|
4
4
|
|
|
5
5
|
To automatically create the functions, run:
|
|
6
6
|
|
graphblas/core/base.py
CHANGED
|
@@ -348,7 +348,7 @@ class BaseType:
|
|
|
348
348
|
return
|
|
349
349
|
if opts:
|
|
350
350
|
# Ignore opts for now
|
|
351
|
-
descriptor_lookup(**opts)
|
|
351
|
+
desc = descriptor_lookup(**opts)
|
|
352
352
|
self.value = expr
|
|
353
353
|
return
|
|
354
354
|
|
|
@@ -371,7 +371,7 @@ class BaseType:
|
|
|
371
371
|
else:
|
|
372
372
|
if opts:
|
|
373
373
|
# Ignore opts for now
|
|
374
|
-
descriptor_lookup(**opts)
|
|
374
|
+
desc = descriptor_lookup(**opts)
|
|
375
375
|
self.value = expr
|
|
376
376
|
return
|
|
377
377
|
else:
|
|
@@ -571,7 +571,7 @@ class BaseExpression:
|
|
|
571
571
|
):
|
|
572
572
|
if opts:
|
|
573
573
|
# Ignore opts for now
|
|
574
|
-
descriptor_lookup(**opts)
|
|
574
|
+
desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
|
|
575
575
|
if self._is_scalar and self._value._is_cscalar != is_cscalar:
|
|
576
576
|
return self._value.dup(is_cscalar=is_cscalar, name=name)
|
|
577
577
|
rv = self._value
|
graphblas/core/descriptor.py
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import warnings
|
|
1
|
+
import warnings
|
|
2
2
|
|
|
3
|
-
import numpy as
|
|
4
|
-
from numpy import
|
|
5
|
-
from numpy import promote_types as _promote_types
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy import promote_types, result_type
|
|
6
5
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from .core import _has_numba
|
|
10
|
-
from .core import ffi as _ffi
|
|
11
|
-
from .core import lib as _lib
|
|
6
|
+
from .. import backend, dtypes
|
|
7
|
+
from ..core import NULL, _has_numba, ffi, lib
|
|
12
8
|
|
|
13
9
|
if _has_numba:
|
|
14
|
-
import numba
|
|
10
|
+
import numba
|
|
15
11
|
|
|
16
12
|
# Default assumption unless FC32/FC64 are found in lib
|
|
17
|
-
_supports_complex = hasattr(
|
|
13
|
+
_supports_complex = hasattr(lib, "GrB_FC64") or hasattr(lib, "GxB_FC64")
|
|
18
14
|
|
|
19
15
|
|
|
20
16
|
class DataType:
|
|
@@ -26,7 +22,7 @@ class DataType:
|
|
|
26
22
|
self.gb_name = gb_name
|
|
27
23
|
self.c_type = c_type
|
|
28
24
|
self.numba_type = numba_type
|
|
29
|
-
self.np_type =
|
|
25
|
+
self.np_type = np.dtype(np_type) if np_type is not None else None
|
|
30
26
|
|
|
31
27
|
def __repr__(self):
|
|
32
28
|
return self.name
|
|
@@ -62,7 +58,7 @@ class DataType:
|
|
|
62
58
|
|
|
63
59
|
@property
|
|
64
60
|
def _is_anonymous(self):
|
|
65
|
-
return
|
|
61
|
+
return getattr(dtypes, self.name, None) is not self
|
|
66
62
|
|
|
67
63
|
@property
|
|
68
64
|
def _is_udt(self):
|
|
@@ -80,27 +76,29 @@ class DataType:
|
|
|
80
76
|
def register_new(name, dtype):
|
|
81
77
|
if not name.isidentifier():
|
|
82
78
|
raise ValueError(f"`name` argument must be a valid Python identifier; got: {name!r}")
|
|
83
|
-
if name in _registry or name
|
|
79
|
+
if name in _registry or hasattr(dtypes, name):
|
|
84
80
|
raise ValueError(f"{name!r} name for dtype is unavailable")
|
|
85
81
|
rv = register_anonymous(dtype, name)
|
|
86
82
|
_registry[name] = rv
|
|
87
|
-
|
|
83
|
+
setattr(dtypes, name, rv)
|
|
88
84
|
return rv
|
|
89
85
|
|
|
90
86
|
|
|
91
87
|
def register_anonymous(dtype, name=None):
|
|
92
88
|
try:
|
|
93
|
-
dtype =
|
|
89
|
+
dtype = np.dtype(dtype)
|
|
94
90
|
except TypeError:
|
|
95
91
|
if isinstance(dtype, dict):
|
|
96
92
|
# Allow dtypes such as `{'x': int, 'y': float}` for convenience
|
|
97
|
-
dtype =
|
|
93
|
+
dtype = np.dtype(
|
|
94
|
+
[(key, lookup_dtype(val).np_type) for key, val in dtype.items()], align=True
|
|
95
|
+
)
|
|
98
96
|
elif isinstance(dtype, str) and "[" in dtype and dtype.endswith("]"):
|
|
99
97
|
# Allow dtypes such as `"INT64[3, 4]"` for convenience
|
|
100
98
|
base_dtype, shape = dtype.split("[", 1)
|
|
101
99
|
base_dtype = lookup_dtype(base_dtype)
|
|
102
|
-
shape =
|
|
103
|
-
dtype =
|
|
100
|
+
shape = np.lib.format.safe_eval(f"[{shape}")
|
|
101
|
+
dtype = np.dtype((base_dtype.np_type, shape))
|
|
104
102
|
else:
|
|
105
103
|
raise
|
|
106
104
|
if dtype in _registry:
|
|
@@ -114,36 +112,36 @@ def register_anonymous(dtype, name=None):
|
|
|
114
112
|
if dtype.hasobject:
|
|
115
113
|
raise ValueError("dtype must not allow Python objects")
|
|
116
114
|
|
|
117
|
-
from
|
|
115
|
+
from ..exceptions import check_status_carg
|
|
118
116
|
|
|
119
|
-
gb_obj =
|
|
117
|
+
gb_obj = ffi.new("GrB_Type*")
|
|
120
118
|
if backend == "suitesparse":
|
|
121
119
|
# We name this so that we can serialize and deserialize UDTs
|
|
122
120
|
# We don't yet have C definitions
|
|
123
121
|
np_repr = _dtype_to_string(dtype).encode()
|
|
124
|
-
if len(np_repr) >
|
|
122
|
+
if len(np_repr) > lib.GxB_MAX_NAME_LEN:
|
|
125
123
|
msg = (
|
|
126
124
|
f"UDT repr is too large to serialize ({len(repr(dtype).encode())} > "
|
|
127
|
-
f"{
|
|
125
|
+
f"{lib.GxB_MAX_NAME_LEN})."
|
|
128
126
|
)
|
|
129
127
|
if name is not None:
|
|
130
|
-
np_repr = name.encode()[:
|
|
128
|
+
np_repr = name.encode()[: lib.GxB_MAX_NAME_LEN]
|
|
131
129
|
else:
|
|
132
|
-
np_repr = np_repr[:
|
|
133
|
-
|
|
130
|
+
np_repr = np_repr[: lib.GxB_MAX_NAME_LEN]
|
|
131
|
+
warnings.warn(
|
|
134
132
|
f"{msg}. It will use the following name, "
|
|
135
133
|
f"and the dtype may need to be specified when deserializing: {np_repr}",
|
|
136
134
|
stacklevel=2,
|
|
137
135
|
)
|
|
138
|
-
status =
|
|
136
|
+
status = lib.GxB_Type_new(gb_obj, dtype.itemsize, np_repr, NULL)
|
|
139
137
|
else:
|
|
140
|
-
status =
|
|
138
|
+
status = lib.GrB_Type_new(gb_obj, dtype.itemsize)
|
|
141
139
|
check_status_carg(status, "Type", gb_obj[0])
|
|
142
140
|
|
|
143
141
|
# For now, let's use "opaque" unsigned bytes for the c type.
|
|
144
142
|
if name is None:
|
|
145
143
|
name = _default_name(dtype)
|
|
146
|
-
numba_type =
|
|
144
|
+
numba_type = numba.typeof(dtype).dtype if _has_numba else None
|
|
147
145
|
rv = DataType(name, gb_obj, None, f"uint8_t[{dtype.itemsize}]", numba_type, dtype)
|
|
148
146
|
_registry[gb_obj] = rv
|
|
149
147
|
_registry[dtype] = rv
|
|
@@ -155,153 +153,153 @@ def register_anonymous(dtype, name=None):
|
|
|
155
153
|
|
|
156
154
|
BOOL = DataType(
|
|
157
155
|
"BOOL",
|
|
158
|
-
|
|
156
|
+
lib.GrB_BOOL,
|
|
159
157
|
"GrB_BOOL",
|
|
160
158
|
"_Bool",
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
numba.types.bool_ if _has_numba else None,
|
|
160
|
+
np.bool_,
|
|
163
161
|
)
|
|
164
162
|
INT8 = DataType(
|
|
165
|
-
"INT8",
|
|
163
|
+
"INT8", lib.GrB_INT8, "GrB_INT8", "int8_t", numba.types.int8 if _has_numba else None, np.int8
|
|
166
164
|
)
|
|
167
165
|
UINT8 = DataType(
|
|
168
166
|
"UINT8",
|
|
169
|
-
|
|
167
|
+
lib.GrB_UINT8,
|
|
170
168
|
"GrB_UINT8",
|
|
171
169
|
"uint8_t",
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
numba.types.uint8 if _has_numba else None,
|
|
171
|
+
np.uint8,
|
|
174
172
|
)
|
|
175
173
|
INT16 = DataType(
|
|
176
174
|
"INT16",
|
|
177
|
-
|
|
175
|
+
lib.GrB_INT16,
|
|
178
176
|
"GrB_INT16",
|
|
179
177
|
"int16_t",
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
numba.types.int16 if _has_numba else None,
|
|
179
|
+
np.int16,
|
|
182
180
|
)
|
|
183
181
|
UINT16 = DataType(
|
|
184
182
|
"UINT16",
|
|
185
|
-
|
|
183
|
+
lib.GrB_UINT16,
|
|
186
184
|
"GrB_UINT16",
|
|
187
185
|
"uint16_t",
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
numba.types.uint16 if _has_numba else None,
|
|
187
|
+
np.uint16,
|
|
190
188
|
)
|
|
191
189
|
INT32 = DataType(
|
|
192
190
|
"INT32",
|
|
193
|
-
|
|
191
|
+
lib.GrB_INT32,
|
|
194
192
|
"GrB_INT32",
|
|
195
193
|
"int32_t",
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
numba.types.int32 if _has_numba else None,
|
|
195
|
+
np.int32,
|
|
198
196
|
)
|
|
199
197
|
UINT32 = DataType(
|
|
200
198
|
"UINT32",
|
|
201
|
-
|
|
199
|
+
lib.GrB_UINT32,
|
|
202
200
|
"GrB_UINT32",
|
|
203
201
|
"uint32_t",
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
numba.types.uint32 if _has_numba else None,
|
|
203
|
+
np.uint32,
|
|
206
204
|
)
|
|
207
205
|
INT64 = DataType(
|
|
208
206
|
"INT64",
|
|
209
|
-
|
|
207
|
+
lib.GrB_INT64,
|
|
210
208
|
"GrB_INT64",
|
|
211
209
|
"int64_t",
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
numba.types.int64 if _has_numba else None,
|
|
211
|
+
np.int64,
|
|
214
212
|
)
|
|
215
213
|
# _Index (like UINT64) is for internal use only and shouldn't be exposed to the user
|
|
216
214
|
_INDEX = DataType(
|
|
217
215
|
"UINT64",
|
|
218
|
-
|
|
216
|
+
lib.GrB_UINT64,
|
|
219
217
|
"GrB_Index",
|
|
220
218
|
"GrB_Index",
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
numba.types.uint64 if _has_numba else None,
|
|
220
|
+
np.uint64,
|
|
223
221
|
)
|
|
224
222
|
UINT64 = DataType(
|
|
225
223
|
"UINT64",
|
|
226
|
-
|
|
224
|
+
lib.GrB_UINT64,
|
|
227
225
|
"GrB_UINT64",
|
|
228
226
|
"uint64_t",
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
numba.types.uint64 if _has_numba else None,
|
|
228
|
+
np.uint64,
|
|
231
229
|
)
|
|
232
230
|
FP32 = DataType(
|
|
233
231
|
"FP32",
|
|
234
|
-
|
|
232
|
+
lib.GrB_FP32,
|
|
235
233
|
"GrB_FP32",
|
|
236
234
|
"float",
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
numba.types.float32 if _has_numba else None,
|
|
236
|
+
np.float32,
|
|
239
237
|
)
|
|
240
238
|
FP64 = DataType(
|
|
241
239
|
"FP64",
|
|
242
|
-
|
|
240
|
+
lib.GrB_FP64,
|
|
243
241
|
"GrB_FP64",
|
|
244
242
|
"double",
|
|
245
|
-
|
|
246
|
-
|
|
243
|
+
numba.types.float64 if _has_numba else None,
|
|
244
|
+
np.float64,
|
|
247
245
|
)
|
|
248
246
|
|
|
249
|
-
if _supports_complex and hasattr(
|
|
247
|
+
if _supports_complex and hasattr(lib, "GxB_FC32"):
|
|
250
248
|
FC32 = DataType(
|
|
251
249
|
"FC32",
|
|
252
|
-
|
|
250
|
+
lib.GxB_FC32,
|
|
253
251
|
"GxB_FC32",
|
|
254
252
|
"float _Complex",
|
|
255
|
-
|
|
256
|
-
|
|
253
|
+
numba.types.complex64 if _has_numba else None,
|
|
254
|
+
np.complex64,
|
|
257
255
|
)
|
|
258
|
-
if _supports_complex and hasattr(
|
|
256
|
+
if _supports_complex and hasattr(lib, "GrB_FC32"): # pragma: no cover (unused)
|
|
259
257
|
FC32 = DataType(
|
|
260
258
|
"FC32",
|
|
261
|
-
|
|
259
|
+
lib.GrB_FC32,
|
|
262
260
|
"GrB_FC32",
|
|
263
261
|
"float _Complex",
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
numba.types.complex64 if _has_numba else None,
|
|
263
|
+
np.complex64,
|
|
266
264
|
)
|
|
267
|
-
if _supports_complex and hasattr(
|
|
265
|
+
if _supports_complex and hasattr(lib, "GxB_FC64"):
|
|
268
266
|
FC64 = DataType(
|
|
269
267
|
"FC64",
|
|
270
|
-
|
|
268
|
+
lib.GxB_FC64,
|
|
271
269
|
"GxB_FC64",
|
|
272
270
|
"double _Complex",
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
numba.types.complex128 if _has_numba else None,
|
|
272
|
+
np.complex128,
|
|
275
273
|
)
|
|
276
|
-
if _supports_complex and hasattr(
|
|
274
|
+
if _supports_complex and hasattr(lib, "GrB_FC64"): # pragma: no cover (unused)
|
|
277
275
|
FC64 = DataType(
|
|
278
276
|
"FC64",
|
|
279
|
-
|
|
277
|
+
lib.GrB_FC64,
|
|
280
278
|
"GrB_FC64",
|
|
281
279
|
"double _Complex",
|
|
282
|
-
|
|
283
|
-
|
|
280
|
+
numba.types.complex128 if _has_numba else None,
|
|
281
|
+
np.complex128,
|
|
284
282
|
)
|
|
285
283
|
|
|
286
284
|
# Used for testing user-defined functions
|
|
287
285
|
_sample_values = {
|
|
288
|
-
INT8:
|
|
289
|
-
UINT8:
|
|
290
|
-
INT16:
|
|
291
|
-
UINT16:
|
|
292
|
-
INT32:
|
|
293
|
-
UINT32:
|
|
294
|
-
INT64:
|
|
295
|
-
UINT64:
|
|
296
|
-
FP32:
|
|
297
|
-
FP64:
|
|
298
|
-
BOOL:
|
|
286
|
+
INT8: np.int8(1),
|
|
287
|
+
UINT8: np.uint8(1),
|
|
288
|
+
INT16: np.int16(1),
|
|
289
|
+
UINT16: np.uint16(1),
|
|
290
|
+
INT32: np.int32(1),
|
|
291
|
+
UINT32: np.uint32(1),
|
|
292
|
+
INT64: np.int64(1),
|
|
293
|
+
UINT64: np.uint64(1),
|
|
294
|
+
FP32: np.float32(0.5),
|
|
295
|
+
FP64: np.float64(0.5),
|
|
296
|
+
BOOL: np.bool_(True),
|
|
299
297
|
}
|
|
300
298
|
if _supports_complex:
|
|
301
299
|
_sample_values.update(
|
|
302
300
|
{
|
|
303
|
-
FC32:
|
|
304
|
-
FC64:
|
|
301
|
+
FC32: np.complex64(complex(0, 0.5)),
|
|
302
|
+
FC64: np.complex128(complex(0, 0.5)),
|
|
305
303
|
}
|
|
306
304
|
)
|
|
307
305
|
|
|
@@ -389,19 +387,11 @@ def unify(type1, type2, *, is_left_scalar=False, is_right_scalar=False):
|
|
|
389
387
|
if type1 is type2:
|
|
390
388
|
return type1
|
|
391
389
|
if is_left_scalar:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
elif
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
else:
|
|
398
|
-
scalar_types = []
|
|
399
|
-
array_types = [type1.np_type]
|
|
400
|
-
if is_right_scalar:
|
|
401
|
-
scalar_types.append(type2.np_type)
|
|
402
|
-
else:
|
|
403
|
-
array_types.append(type2.np_type)
|
|
404
|
-
return lookup_dtype(_find_common_type(array_types, scalar_types))
|
|
390
|
+
if not is_right_scalar:
|
|
391
|
+
return lookup_dtype(result_type(np.array(0, type1.np_type), type2.np_type))
|
|
392
|
+
elif is_right_scalar:
|
|
393
|
+
return lookup_dtype(result_type(type1.np_type, np.array(0, type2.np_type)))
|
|
394
|
+
return lookup_dtype(promote_types(type1.np_type, type2.np_type))
|
|
405
395
|
|
|
406
396
|
|
|
407
397
|
def _default_name(dtype):
|
|
@@ -431,7 +421,7 @@ def _dtype_to_string(dtype):
|
|
|
431
421
|
>>> dtype == new_dtype
|
|
432
422
|
True
|
|
433
423
|
"""
|
|
434
|
-
if isinstance(dtype,
|
|
424
|
+
if isinstance(dtype, np.dtype) and dtype not in _registry:
|
|
435
425
|
np_type = dtype
|
|
436
426
|
else:
|
|
437
427
|
dtype = lookup_dtype(dtype)
|
|
@@ -440,11 +430,11 @@ def _dtype_to_string(dtype):
|
|
|
440
430
|
np_type = dtype.np_type
|
|
441
431
|
s = str(np_type)
|
|
442
432
|
try:
|
|
443
|
-
if
|
|
433
|
+
if np.dtype(np.lib.format.safe_eval(s)) == np_type: # pragma: no branch (safety)
|
|
444
434
|
return s
|
|
445
435
|
except Exception:
|
|
446
436
|
pass
|
|
447
|
-
if
|
|
437
|
+
if np.dtype(np_type.str) != np_type: # pragma: no cover (safety)
|
|
448
438
|
raise ValueError(f"Unable to reliably convert dtype to string and back: {dtype}")
|
|
449
439
|
return repr(np_type.str)
|
|
450
440
|
|
|
@@ -459,5 +449,5 @@ def _string_to_dtype(s):
|
|
|
459
449
|
return lookup_dtype(s)
|
|
460
450
|
except Exception:
|
|
461
451
|
pass
|
|
462
|
-
np_type =
|
|
452
|
+
np_type = np.dtype(np.lib.format.safe_eval(s))
|
|
463
453
|
return lookup_dtype(np_type)
|
graphblas/core/expr.py
CHANGED
|
@@ -421,7 +421,7 @@ class Updater:
|
|
|
421
421
|
# Fast path using assignElement
|
|
422
422
|
if self.opts:
|
|
423
423
|
# Ignore opts for now
|
|
424
|
-
descriptor_lookup(**self.opts)
|
|
424
|
+
desc = descriptor_lookup(**self.opts) # noqa: F841 (keep desc in scope for context)
|
|
425
425
|
self.parent._assign_element(resolved_indexes, obj)
|
|
426
426
|
else:
|
|
427
427
|
mask = self.kwargs.get("mask")
|
graphblas/core/mask.py
CHANGED
|
@@ -35,7 +35,7 @@ class Mask:
|
|
|
35
35
|
"""Return a new object with True values determined by the mask(s).
|
|
36
36
|
|
|
37
37
|
By default, the result is True wherever the mask(s) would have been applied,
|
|
38
|
-
and empty otherwise. If
|
|
38
|
+
and empty otherwise. If ``complement`` is True, then these are switched:
|
|
39
39
|
the result is empty where the mask(s) would have been applied, and True otherwise.
|
|
40
40
|
|
|
41
41
|
In other words, these are equivalent if complement is False (and mask keyword is None):
|
|
@@ -48,14 +48,14 @@ class Mask:
|
|
|
48
48
|
>>> C(self) << expr
|
|
49
49
|
>>> C(~result.S) << expr # equivalent when complement is True
|
|
50
50
|
|
|
51
|
-
This can also efficiently merge two masks by using the
|
|
51
|
+
This can also efficiently merge two masks by using the ``mask=`` argument.
|
|
52
52
|
This is equivalent to the following (but uses more efficient recipes):
|
|
53
53
|
|
|
54
54
|
>>> val = Matrix(...)
|
|
55
55
|
>>> val(self) << True
|
|
56
56
|
>>> val(mask, replace=True) << val
|
|
57
57
|
|
|
58
|
-
If
|
|
58
|
+
If ``complement=`` argument is True, then the *complement* will be returned.
|
|
59
59
|
This is equivalent to the following (but uses more efficient recipes):
|
|
60
60
|
|
|
61
61
|
>>> val = Matrix(...)
|
|
@@ -83,7 +83,7 @@ class Mask:
|
|
|
83
83
|
def __and__(self, other, **opts):
|
|
84
84
|
"""Return the intersection of two masks as a new mask.
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
``new_mask = mask1 & mask2`` is equivalent to the following:
|
|
87
87
|
|
|
88
88
|
>>> val = Matrix(bool, nrows, ncols)
|
|
89
89
|
>>> val(mask1) << True
|
|
@@ -109,7 +109,7 @@ class Mask:
|
|
|
109
109
|
def __or__(self, other, **opts):
|
|
110
110
|
"""Return the union of two masks as a new mask.
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
``new_mask = mask1 | mask2`` is equivalent to the following:
|
|
113
113
|
|
|
114
114
|
>>> val = Matrix(bool, nrows, ncols)
|
|
115
115
|
>>> val(mask1) << True
|
graphblas/core/matrix.py
CHANGED
|
@@ -355,7 +355,7 @@ class Matrix(BaseType):
|
|
|
355
355
|
Returns
|
|
356
356
|
-------
|
|
357
357
|
bool
|
|
358
|
-
Whether all values of the Matrix are close to the values in
|
|
358
|
+
Whether all values of the Matrix are close to the values in ``other``.
|
|
359
359
|
"""
|
|
360
360
|
other = self._expect_type(
|
|
361
361
|
other, (Matrix, TransposedMatrix), within="isclose", argname="other"
|
|
@@ -448,19 +448,19 @@ class Matrix(BaseType):
|
|
|
448
448
|
corresponding to the COO format of the Matrix.
|
|
449
449
|
|
|
450
450
|
.. deprecated:: 2022.11.0
|
|
451
|
-
|
|
452
|
-
Use
|
|
451
|
+
``Matrix.to_values`` will be removed in a future release.
|
|
452
|
+
Use ``Matrix.to_coo`` instead. Will be removed in version 2023.9.0 or later
|
|
453
453
|
|
|
454
454
|
Parameters
|
|
455
455
|
----------
|
|
456
456
|
dtype :
|
|
457
457
|
Requested dtype for the output values array.
|
|
458
458
|
rows : bool, default=True
|
|
459
|
-
Whether to return rows; will return
|
|
460
|
-
columns
|
|
461
|
-
Whether to return columns; will return
|
|
459
|
+
Whether to return rows; will return ``None`` for rows if ``False``
|
|
460
|
+
columns : bool, default=True
|
|
461
|
+
Whether to return columns; will return ``None`` for columns if ``False``
|
|
462
462
|
values : bool, default=True
|
|
463
|
-
Whether to return values; will return
|
|
463
|
+
Whether to return values; will return ``None`` for values if ``False``
|
|
464
464
|
sort : bool, default=True
|
|
465
465
|
Whether to require sorted indices.
|
|
466
466
|
If internally stored rowwise, the sorting will be first by rows, then by column.
|
|
@@ -488,11 +488,11 @@ class Matrix(BaseType):
|
|
|
488
488
|
dtype :
|
|
489
489
|
Requested dtype for the output values array.
|
|
490
490
|
rows : bool, default=True
|
|
491
|
-
Whether to return rows; will return
|
|
491
|
+
Whether to return rows; will return ``None`` for rows if ``False``
|
|
492
492
|
columns :bool, default=True
|
|
493
|
-
Whether to return columns; will return
|
|
493
|
+
Whether to return columns; will return ``None`` for columns if ``False``
|
|
494
494
|
values : bool, default=True
|
|
495
|
-
Whether to return values; will return
|
|
495
|
+
Whether to return values; will return ``None`` for values if ``False``
|
|
496
496
|
sort : bool, default=True
|
|
497
497
|
Whether to require sorted indices.
|
|
498
498
|
If internally stored rowwise, the sorting will be first by rows, then by column.
|
|
@@ -559,7 +559,7 @@ class Matrix(BaseType):
|
|
|
559
559
|
dtype :
|
|
560
560
|
Requested dtype for the output values array.
|
|
561
561
|
values : bool, default=True
|
|
562
|
-
Whether to return values; will return
|
|
562
|
+
Whether to return values; will return ``None`` for values if ``False``
|
|
563
563
|
sort : bool, default=True
|
|
564
564
|
Whether to require sorted indices.
|
|
565
565
|
If internally stored rowwise, the sorting will be first by rows, then by column.
|
|
@@ -585,7 +585,7 @@ class Matrix(BaseType):
|
|
|
585
585
|
The typical use case is to create a new Matrix and insert values
|
|
586
586
|
at the same time using :meth:`from_coo`.
|
|
587
587
|
|
|
588
|
-
All the arguments are used identically in :meth:`from_coo`, except for
|
|
588
|
+
All the arguments are used identically in :meth:`from_coo`, except for ``clear``, which
|
|
589
589
|
indicates whether to clear the Matrix prior to adding the new values.
|
|
590
590
|
"""
|
|
591
591
|
# TODO: accept `dtype` keyword to match the dtype of `values`?
|
|
@@ -665,7 +665,7 @@ class Matrix(BaseType):
|
|
|
665
665
|
else:
|
|
666
666
|
if opts:
|
|
667
667
|
# Ignore opts for now
|
|
668
|
-
descriptor_lookup(**opts)
|
|
668
|
+
desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
|
|
669
669
|
new_mat = ffi_new("GrB_Matrix*")
|
|
670
670
|
rv = Matrix._from_obj(new_mat, self.dtype, self._nrows, self._ncols, name=name)
|
|
671
671
|
call("GrB_Matrix_dup", [_Pointer(rv), self])
|
|
@@ -781,8 +781,8 @@ class Matrix(BaseType):
|
|
|
781
781
|
"""Create a new Matrix from row and column indices and values.
|
|
782
782
|
|
|
783
783
|
.. deprecated:: 2022.11.0
|
|
784
|
-
|
|
785
|
-
Use
|
|
784
|
+
``Matrix.from_values`` will be removed in a future release.
|
|
785
|
+
Use ``Matrix.from_coo`` instead. Will be removed in version 2023.9.0 or later
|
|
786
786
|
|
|
787
787
|
Parameters
|
|
788
788
|
----------
|
|
@@ -1086,7 +1086,7 @@ class Matrix(BaseType):
|
|
|
1086
1086
|
Parameters
|
|
1087
1087
|
----------
|
|
1088
1088
|
indptr : list or np.ndarray
|
|
1089
|
-
Pointers for each row into col_indices and values;
|
|
1089
|
+
Pointers for each row into col_indices and values; ``indptr.size == nrows + 1``.
|
|
1090
1090
|
col_indices : list or np.ndarray
|
|
1091
1091
|
Column indices.
|
|
1092
1092
|
values : list or np.ndarray or scalar, default 1.0
|
|
@@ -1133,7 +1133,7 @@ class Matrix(BaseType):
|
|
|
1133
1133
|
Parameters
|
|
1134
1134
|
----------
|
|
1135
1135
|
indptr : list or np.ndarray
|
|
1136
|
-
Pointers for each column into row_indices and values;
|
|
1136
|
+
Pointers for each column into row_indices and values; ``indptr.size == ncols + 1``.
|
|
1137
1137
|
col_indices : list or np.ndarray
|
|
1138
1138
|
Column indices.
|
|
1139
1139
|
values : list or np.ndarray or scalar, default 1.0
|
|
@@ -2707,7 +2707,7 @@ class Matrix(BaseType):
|
|
|
2707
2707
|
result = Scalar(dtype, is_cscalar=is_cscalar, name=name)
|
|
2708
2708
|
if opts:
|
|
2709
2709
|
# Ignore opts for now
|
|
2710
|
-
descriptor_lookup(**opts)
|
|
2710
|
+
desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
|
|
2711
2711
|
if is_cscalar:
|
|
2712
2712
|
dtype_name = "UDT" if dtype._is_udt else dtype.name
|
|
2713
2713
|
if (
|
graphblas/core/operator/base.py
CHANGED
|
@@ -398,7 +398,7 @@ class OpBase:
|
|
|
398
398
|
def _initialize(cls, include_in_ops=True):
|
|
399
399
|
"""
|
|
400
400
|
include_in_ops determines whether the operators are included in the
|
|
401
|
-
|
|
401
|
+
``gb.ops`` namespace in addition to the defined module.
|
|
402
402
|
"""
|
|
403
403
|
if cls._initialized: # pragma: no cover (safety)
|
|
404
404
|
return
|