python-graphblas 2023.12.0__py3-none-any.whl → 2025.2.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.
Files changed (61) hide show
  1. graphblas/agg/__init__.py +2 -1
  2. graphblas/binary/numpy.py +1 -0
  3. graphblas/core/automethods.py +1 -5
  4. graphblas/core/base.py +1 -1
  5. graphblas/core/dtypes.py +16 -6
  6. graphblas/core/expr.py +4 -4
  7. graphblas/core/formatting.py +1 -1
  8. graphblas/core/infix.py +1 -2
  9. graphblas/core/matrix.py +51 -106
  10. graphblas/core/operator/base.py +3 -3
  11. graphblas/core/operator/binary.py +2 -0
  12. graphblas/core/operator/indexunary.py +2 -0
  13. graphblas/core/operator/monoid.py +2 -0
  14. graphblas/core/operator/select.py +2 -0
  15. graphblas/core/operator/semiring.py +2 -0
  16. graphblas/core/operator/unary.py +2 -0
  17. graphblas/core/operator/utils.py +1 -0
  18. graphblas/core/scalar.py +12 -1
  19. graphblas/core/ss/__init__.py +3 -1
  20. graphblas/core/ss/binary.py +1 -0
  21. graphblas/core/ss/config.py +1 -1
  22. graphblas/core/ss/descriptor.py +1 -0
  23. graphblas/core/ss/indexunary.py +1 -0
  24. graphblas/core/ss/matrix.py +90 -64
  25. graphblas/core/ss/select.py +1 -0
  26. graphblas/core/ss/unary.py +1 -0
  27. graphblas/core/ss/vector.py +61 -30
  28. graphblas/core/utils.py +18 -6
  29. graphblas/core/vector.py +31 -72
  30. graphblas/exceptions.py +11 -3
  31. graphblas/io/__init__.py +0 -1
  32. graphblas/io/_awkward.py +1 -0
  33. graphblas/io/_matrixmarket.py +2 -0
  34. graphblas/io/_networkx.py +6 -2
  35. graphblas/io/_scipy.py +1 -0
  36. graphblas/io/_sparse.py +1 -0
  37. graphblas/monoid/numpy.py +1 -0
  38. graphblas/select/__init__.py +4 -11
  39. graphblas/semiring/numpy.py +1 -0
  40. graphblas/ss/_core.py +2 -4
  41. graphblas/tests/conftest.py +18 -6
  42. graphblas/tests/test_descriptor.py +1 -2
  43. graphblas/tests/test_dtype.py +9 -1
  44. graphblas/tests/test_infix.py +1 -1
  45. graphblas/tests/test_io.py +1 -12
  46. graphblas/tests/test_matrix.py +13 -21
  47. graphblas/tests/test_numpyops.py +10 -0
  48. graphblas/tests/test_op.py +0 -2
  49. graphblas/tests/test_scalar.py +5 -1
  50. graphblas/tests/test_ssjit.py +49 -3
  51. graphblas/tests/test_vector.py +16 -14
  52. graphblas/unary/numpy.py +1 -0
  53. graphblas/viz.py +2 -0
  54. {python_graphblas-2023.12.0.dist-info → python_graphblas-2025.2.0.dist-info}/METADATA +82 -43
  55. python_graphblas-2025.2.0.dist-info/RECORD +107 -0
  56. {python_graphblas-2023.12.0.dist-info → python_graphblas-2025.2.0.dist-info}/WHEEL +1 -1
  57. graphblas/core/agg.py +0 -17
  58. graphblas/io/_numpy.py +0 -104
  59. python_graphblas-2023.12.0.dist-info/RECORD +0 -109
  60. {python_graphblas-2023.12.0.dist-info → python_graphblas-2025.2.0.dist-info}/LICENSE +0 -0
  61. {python_graphblas-2023.12.0.dist-info → python_graphblas-2025.2.0.dist-info}/top_level.txt +0 -0
graphblas/agg/__init__.py CHANGED
@@ -73,7 +73,8 @@ Custom recipes (specific to SuiteSparse:GraphBLAS):
73
73
  # - bxnor monoid: even bits
74
74
  # - bnor monoid: odd bits
75
75
  """
76
- # All items are dynamically added by classes in core/agg.py
76
+
77
+ # All items are dynamically added by classes in core/operator/agg.py
77
78
  # This module acts as a container of Aggregator instances
78
79
  _deprecated = {}
79
80
 
graphblas/binary/numpy.py CHANGED
@@ -5,6 +5,7 @@ See list of numpy ufuncs supported by numpy here:
5
5
  https://numba.readthedocs.io/en/stable/reference/numpysupported.html#math-operations
6
6
 
7
7
  """
8
+
8
9
  import numpy as _np
9
10
 
10
11
  from .. import _STANDARD_OPERATOR_NAMES
@@ -7,6 +7,7 @@ To automatically create the functions, run:
7
7
  $ python -m graphblas.core.automethods
8
8
 
9
9
  """
10
+
10
11
  from .. import config
11
12
 
12
13
 
@@ -281,10 +282,6 @@ def to_edgelist(self):
281
282
  return self._get_value("to_edgelist")
282
283
 
283
284
 
284
- def to_values(self):
285
- return self._get_value("to_values")
286
-
287
-
288
285
  def value(self):
289
286
  return self._get_value("value")
290
287
 
@@ -398,7 +395,6 @@ def _main():
398
395
  "ss",
399
396
  "to_coo",
400
397
  "to_dense",
401
- "to_values",
402
398
  }
403
399
  vector = {
404
400
  "_as_matrix",
graphblas/core/base.py CHANGED
@@ -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."
graphblas/core/dtypes.py CHANGED
@@ -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 = np.lib.format.safe_eval(f"[{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
- if backend == "suitesparse":
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()
@@ -375,8 +386,7 @@ def lookup_dtype(key, value=None):
375
386
 
376
387
 
377
388
  def unify(type1, type2, *, is_left_scalar=False, is_right_scalar=False):
378
- """
379
- Returns a type that can hold both type1 and type2.
389
+ """Returns a type that can hold both type1 and type2.
380
390
 
381
391
  For example:
382
392
  unify(INT32, INT64) -> INT64
@@ -430,7 +440,7 @@ def _dtype_to_string(dtype):
430
440
  np_type = dtype.np_type
431
441
  s = str(np_type)
432
442
  try:
433
- if np.dtype(np.lib.format.safe_eval(s)) == np_type: # pragma: no branch (safety)
443
+ if np.dtype(literal_eval(s)) == np_type: # pragma: no branch (safety)
434
444
  return s
435
445
  except Exception:
436
446
  pass
@@ -449,5 +459,5 @@ def _string_to_dtype(s):
449
459
  return lookup_dtype(s)
450
460
  except Exception:
451
461
  pass
452
- np_type = np.dtype(np.lib.format.safe_eval(s))
462
+ np_type = np.dtype(literal_eval(s))
453
463
  return lookup_dtype(np_type)
graphblas/core/expr.py CHANGED
@@ -147,13 +147,13 @@ class IndexerResolver:
147
147
  return self.indices[0]._py_index()
148
148
 
149
149
  def parse_indices(self, indices, shape):
150
- """
151
- Returns
150
+ """Returns
152
151
  -------
153
152
  [(rows, rowsize), (cols, colsize)] for Matrix
154
153
  [(idx, idx_size)] for Vector
155
154
 
156
155
  Within each tuple, if the index is of type int, the size will be None
156
+
157
157
  """
158
158
  if len(shape) == 1:
159
159
  if type(indices) is tuple:
@@ -312,8 +312,8 @@ class AmbiguousAssignOrExtract:
312
312
  Updater(self.parent, opts=opts)._setitem(self.resolved_indexes, expr, is_submask=False)
313
313
 
314
314
  def new(self, dtype=None, *, mask=None, input_mask=None, name=None, **opts):
315
- """
316
- Force extraction of the indexes into a new object
315
+ """Force extraction of the indexes into a new object.
316
+
317
317
  dtype and mask are the only controllable parameters.
318
318
  """
319
319
  if input_mask is not None:
@@ -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))
graphblas/core/infix.py CHANGED
@@ -236,7 +236,6 @@ class VectorInfixExpr(InfixExprBase):
236
236
  to_coo = wrapdoc(Vector.to_coo)(property(automethods.to_coo))
237
237
  to_dense = wrapdoc(Vector.to_dense)(property(automethods.to_dense))
238
238
  to_dict = wrapdoc(Vector.to_dict)(property(automethods.to_dict))
239
- to_values = wrapdoc(Vector.to_values)(property(automethods.to_values))
240
239
  vxm = wrapdoc(Vector.vxm)(property(automethods.vxm))
241
240
  wait = wrapdoc(Vector.wait)(property(automethods.wait))
242
241
  # These raise exceptions
@@ -317,6 +316,7 @@ class MatrixInfixExpr(InfixExprBase):
317
316
  ndim = 2
318
317
  output_type = MatrixExpression
319
318
  _is_transposed = False
319
+ __networkx_backend__ = "graphblas"
320
320
  __networkx_plugin__ = "graphblas"
321
321
 
322
322
  def __init__(self, left, right):
@@ -396,7 +396,6 @@ class MatrixInfixExpr(InfixExprBase):
396
396
  to_dense = wrapdoc(Matrix.to_dense)(property(automethods.to_dense))
397
397
  to_dicts = wrapdoc(Matrix.to_dicts)(property(automethods.to_dicts))
398
398
  to_edgelist = wrapdoc(Matrix.to_edgelist)(property(automethods.to_edgelist))
399
- to_values = wrapdoc(Matrix.to_values)(property(automethods.to_values))
400
399
  wait = wrapdoc(Matrix.wait)(property(automethods.wait))
401
400
  # These raise exceptions
402
401
  __array__ = Matrix.__array__