Skip to content

[EXPERIMENTAL] Add "onchange" hook #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
36 changes: 35 additions & 1 deletion graphblas/_ss/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ def build_diag(self, vector, k=0):
vector = self._parent._expect_type(
vector, gb.Vector, within="ss.build_diag", argname="vector"
)
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
call("GxB_Matrix_diag", [self._parent, vector, _as_scalar(k, INT64, is_cscalar=True), None])

def split(self, chunks, *, name=None):
Expand Down Expand Up @@ -544,6 +546,8 @@ def concat(self, tiles):
graphblas.ss.concat
"""
tiles, m, n, is_matrix = _concat_mn(tiles, is_matrix=True)
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
self._concat(tiles, m, n)

def build_scalar(self, rows, columns, value):
Expand All @@ -564,6 +568,8 @@ def build_scalar(self, rows, columns, value):
f"`rows` and `columns` lengths must match: {rows.size}, {columns.size}"
)
scalar = _as_scalar(value, self._parent.dtype, is_cscalar=False) # pragma: is_grbscalar
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
call(
"GxB_Matrix_build_Scalar",
[
Expand Down Expand Up @@ -897,8 +903,12 @@ def _export(self, format=None, *, sort=False, give_ownership=False, raw=False, m
format = f"{self.format[:-1]}r"
elif format == "columnwise":
format = f"{self.format[:-1]}c"
if give_ownership or format == "coo":
if format == "coo":
parent = self._parent
elif give_ownership:
parent = self._parent
if parent._hooks is not None and "onchange" in parent._hooks:
parent._hooks["onchange"](self)
else:
parent = self._parent.dup(name=f"M_{method}")
dtype = parent.dtype.np_type
Expand Down Expand Up @@ -1388,6 +1398,8 @@ def pack_csr(

See `Matrix.ss.import_csr` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_csr(
indptr=indptr,
values=values,
Expand Down Expand Up @@ -1561,6 +1573,8 @@ def pack_csc(

See `Matrix.ss.import_csc` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_csc(
indptr=indptr,
values=values,
Expand Down Expand Up @@ -1744,6 +1758,8 @@ def pack_hypercsr(

See `Matrix.ss.import_hypercsr` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_hypercsr(
rows=rows,
indptr=indptr,
Expand Down Expand Up @@ -1938,6 +1954,8 @@ def pack_hypercsc(

See `Matrix.ss.import_hypercsc` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_hypercsc(
cols=cols,
indptr=indptr,
Expand Down Expand Up @@ -2126,6 +2144,8 @@ def pack_bitmapr(

See `Matrix.ss.import_bitmapr` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_bitmapr(
bitmap=bitmap,
values=values,
Expand Down Expand Up @@ -2302,6 +2322,8 @@ def pack_bitmapc(

See `Matrix.ss.import_bitmapc` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_bitmapc(
bitmap=bitmap,
values=values,
Expand Down Expand Up @@ -2467,6 +2489,8 @@ def pack_fullr(

See `Matrix.ss.import_fullr` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_fullr(
values=values,
is_iso=is_iso,
Expand Down Expand Up @@ -2614,6 +2638,8 @@ def pack_fullc(

See `Matrix.ss.import_fullc` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_fullc(
values=values,
is_iso=is_iso,
Expand Down Expand Up @@ -2765,6 +2791,8 @@ def pack_coo(

See `Matrix.ss.import_coo` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_coo(
nrows=self._parent._nrows,
ncols=self._parent._ncols,
Expand Down Expand Up @@ -2943,6 +2971,8 @@ def pack_coor(

See `Matrix.ss.import_coor` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_coor(
rows=rows,
cols=cols,
Expand Down Expand Up @@ -3096,6 +3126,8 @@ def pack_cooc(

See `Matrix.ss.import_cooc` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_cooc(
ncols=self._parent._ncols,
rows=rows,
Expand Down Expand Up @@ -3284,6 +3316,8 @@ def pack_any(

See `Matrix.ss.import_any` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_any(
values=values,
is_iso=is_iso,
Expand Down
16 changes: 16 additions & 0 deletions graphblas/_ss/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ def build_diag(self, matrix, k=0):
# Transpose descriptor doesn't do anything, so use the parent
k = -k
matrix = matrix._matrix
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
call("GxB_Vector_diag", [self._parent, matrix, _as_scalar(k, INT64, is_cscalar=True), None])

def split(self, chunks, *, name=None):
Expand Down Expand Up @@ -253,6 +255,8 @@ def concat(self, tiles):
graphblas.ss.concat
"""
tiles, m, n, is_matrix = _concat_mn(tiles, is_matrix=False)
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
self._concat(tiles, m)

def build_scalar(self, indices, value):
Expand All @@ -268,6 +272,8 @@ def build_scalar(self, indices, value):
"""
indices = ints_to_numpy_buffer(indices, np.uint64, name="indices")
scalar = _as_scalar(value, self._parent.dtype, is_cscalar=False) # pragma: is_grbscalar
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
call(
"GxB_Vector_build_Scalar",
[
Expand Down Expand Up @@ -464,6 +470,8 @@ def unpack(self, format=None, *, sort=False, raw=False):
def _export(self, format=None, *, sort=False, give_ownership=False, raw=False, method):
if give_ownership:
parent = self._parent
if parent._hooks is not None and "onchange" in parent._hooks:
parent._hooks["onchange"](self)
else:
parent = self._parent.dup(name=f"v_{method}")
dtype = parent.dtype.np_type
Expand Down Expand Up @@ -680,6 +688,8 @@ def pack_any(

See `Vector.ss.import_any` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_any(
values=values,
is_iso=is_iso,
Expand Down Expand Up @@ -860,6 +870,8 @@ def pack_sparse(

See `Vector.ss.import_sparse` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_sparse(
indices=indices,
values=values,
Expand Down Expand Up @@ -1027,6 +1039,8 @@ def pack_bitmap(

See `Vector.ss.import_bitmap` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_bitmap(
bitmap=bitmap,
values=values,
Expand Down Expand Up @@ -1188,6 +1202,8 @@ def pack_full(

See `Vector.ss.import_full` documentation for more details.
"""
if self._parent._hooks is not None and "onchange" in self._parent._hooks:
self._parent._hooks["onchange"](self)
return self._import_full(
values=values,
is_iso=is_iso,
Expand Down
11 changes: 10 additions & 1 deletion graphblas/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ def _update(self, expr, mask=None, accum=None, replace=False, input_mask=None):
"Scalar accumulation with extract element"
"--such as `s(accum=accum) << v[0]`--is not supported"
)
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
expr.parent._extract_element(
expr.resolved_indexes, self.dtype, is_cscalar=self._is_cscalar, result=self
)
Expand Down Expand Up @@ -396,8 +398,9 @@ def _update(self, expr, mask=None, accum=None, replace=False, input_mask=None):
if type(expr) is Scalar:
scalar = expr
else:
dtype = self.dtype if self.dtype._is_udt else None
try:
scalar = Scalar.from_value(expr, is_cscalar=None, name="")
scalar = Scalar.from_value(expr, dtype, is_cscalar=None, name="")
except TypeError:
raise TypeError(
"Assignment value must be a valid expression type, not "
Expand All @@ -422,10 +425,14 @@ def _update(self, expr, mask=None, accum=None, replace=False, input_mask=None):
if input_mask is not None:
raise TypeError("`input_mask` argument may only be used for extract")
elif expr.op is not None and expr.op.opclass == "Aggregator":
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
updater = self(mask=mask, accum=accum, replace=replace)
expr.op._new(updater, expr)
return
elif expr.cfunc_name is None: # Custom recipe
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
updater = self(mask=mask, accum=accum, replace=replace)
expr.args[-2](updater, *expr.args[-1])
return
Expand Down Expand Up @@ -474,6 +481,8 @@ def _update(self, expr, mask=None, accum=None, replace=False, input_mask=None):
args.append(expr.op)
args.extend(expr.args)
args.append(desc)
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
# Make the GraphBLAS call
call(cfunc_name, args)
if self._is_scalar:
Expand Down
4 changes: 4 additions & 0 deletions graphblas/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ def __getitem__(self, keys):

def _setitem(self, resolved_indexes, obj, *, is_submask):
# Occurs when user calls C(params)[index] = expr
if self.parent._hooks is not None and "onchange" in self.parent._hooks:
self.parent._hooks["onchange"](self)
if resolved_indexes.is_single_element and not self.kwargs:
# Fast path using assignElement
self.parent._assign_element(resolved_indexes, obj)
Expand All @@ -427,6 +429,8 @@ def __delitem__(self, keys):
if self.parent._is_scalar:
raise TypeError("Indexing not supported for Scalars")
resolved_indexes = IndexerResolver(self.parent, keys)
if self.parent._hooks is not None and "onchange" in self.parent._hooks:
self.parent._hooks["onchange"](self)
if resolved_indexes.is_single_element:
self.parent._delete_element(resolved_indexes)
else:
Expand Down
10 changes: 9 additions & 1 deletion graphblas/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Matrix(BaseType):
High-level wrapper around GrB_Matrix type
"""

__slots__ = "_nrows", "_ncols", "_parent", "ss"
__slots__ = "_nrows", "_ncols", "_parent", "_hooks", "ss"
ndim = 2
_is_transposed = False
_name_counter = itertools.count()
Expand All @@ -78,6 +78,7 @@ def __new__(cls, dtype=FP64, nrows=0, ncols=0, *, name=None):
self._nrows = nrows.value
self._ncols = ncols.value
self._parent = None
self._hooks = None
self.ss = ss(self)
return self

Expand All @@ -90,6 +91,7 @@ def _from_obj(cls, gb_obj, dtype, nrows, ncols, *, parent=None, name=None):
self._nrows = nrows
self._ncols = ncols
self._parent = parent
self._hooks = None if parent is None else parent._hooks
self.ss = ss(self)
return self

Expand Down Expand Up @@ -271,11 +273,15 @@ def T(self):
return TransposedMatrix(self)

def clear(self):
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
call("GrB_Matrix_clear", [self])

def resize(self, nrows, ncols):
nrows = _as_scalar(nrows, _INDEX, is_cscalar=True)
ncols = _as_scalar(ncols, _INDEX, is_cscalar=True)
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
call("GrB_Matrix_resize", [self, nrows, ncols])
self._nrows = nrows.value
self._ncols = ncols.value
Expand Down Expand Up @@ -325,6 +331,8 @@ def build(self, rows, columns, values, *, dup_op=None, clear=False, nrows=None,
f"`rows` and `columns` and `values` lengths must match: "
f"{rows.size}, {columns.size}, {values.size}"
)
if self._hooks is not None and "onchange" in self._hooks:
self._hooks["onchange"](self)
if clear:
self.clear()
if nrows is not None or ncols is not None:
Expand Down
Loading