From c0aea2f72a4ae1fcaee1f770e76595837aa50d56 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Fri, 15 Apr 2022 23:44:18 -0500 Subject: [PATCH 1/6] Add `x.reposition` to "shift" values around. Fixes #180 --- graphblas/_automethods.py | 5 ++++ graphblas/infix.py | 2 ++ graphblas/matrix.py | 47 ++++++++++++++++++++++++++++++++++ graphblas/tests/test_matrix.py | 24 +++++++++++++++++ graphblas/tests/test_vector.py | 21 +++++++++++++++ graphblas/vector.py | 31 ++++++++++++++++++++++ setup.cfg | 1 + 7 files changed, 131 insertions(+) diff --git a/graphblas/_automethods.py b/graphblas/_automethods.py index fc3c95ccd..793ae24b4 100644 --- a/graphblas/_automethods.py +++ b/graphblas/_automethods.py @@ -230,6 +230,10 @@ def reduce_scalar(self): return self._get_value("reduce_scalar") +def reposition(self): + return self._get_value("reposition") + + def select(self): return self._get_value("select") @@ -353,6 +357,7 @@ def __ixor__(self, other): "ewise_add", "ewise_mult", "ewise_union", + "reposition", "select", "ss", "to_values", diff --git a/graphblas/infix.py b/graphblas/infix.py index 06ae6c1cf..1c1003a5d 100644 --- a/graphblas/infix.py +++ b/graphblas/infix.py @@ -89,6 +89,7 @@ def shape(self): nvals = wrapdoc(Vector.nvals)(property(_automethods.nvals)) outer = wrapdoc(Vector.outer)(property(_automethods.outer)) reduce = wrapdoc(Vector.reduce)(property(_automethods.reduce)) + reposition = wrapdoc(Vector.reposition)(property(_automethods.reposition)) select = wrapdoc(Vector.select)(property(_automethods.select)) ss = wrapdoc(Vector.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Vector.to_pygraphblas)(property(_automethods.to_pygraphblas)) @@ -206,6 +207,7 @@ def shape(self): reduce_columnwise = wrapdoc(Matrix.reduce_columnwise)(property(_automethods.reduce_columnwise)) reduce_rowwise = wrapdoc(Matrix.reduce_rowwise)(property(_automethods.reduce_rowwise)) reduce_scalar = wrapdoc(Matrix.reduce_scalar)(property(_automethods.reduce_scalar)) + reposition = wrapdoc(Matrix.reposition)(property(_automethods.reposition)) select = wrapdoc(Matrix.select)(property(_automethods.select)) ss = wrapdoc(Matrix.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Matrix.to_pygraphblas)(property(_automethods.to_pygraphblas)) diff --git a/graphblas/matrix.py b/graphblas/matrix.py index d24ae62dc..264f700cb 100644 --- a/graphblas/matrix.py +++ b/graphblas/matrix.py @@ -917,6 +917,51 @@ def reduce_scalar(self, op=monoid.plus, *, allow_empty=True): is_cscalar=not allow_empty, ) + # Unofficial methods + def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name=None): + """Return a new Matrix with the values repositioned by row_offset and column_offset. + + Positive offset moves values to the right (or down), negative to the left (or up). + Values repositioned outside of the new Matrix are dropped (i.e., they don't wrap around). + + Parameters + ---------- + row_offset : int + column_offset : int + nrows : int, optional + The nrows of the new Matrix. If not specified, same nrows as input Matrix. + ncols : int, optional + The ncols of the new Matrix. If not specified, same ncols as input Matrix. + name : str, optional + Name of the new Matrix. + + """ + if nrows is None: + nrows = self._nrows + if ncols is None: + ncols = self._ncols + row_offset = int(row_offset) + if row_offset < 0: + row_start = -row_offset + row_stop = row_start + nrows + else: + row_start = 0 + row_stop = max(0, nrows - row_offset) + col_offset = int(column_offset) + if col_offset < 0: + col_start = -col_offset + col_stop = col_start + ncols + else: + col_start = 0 + col_stop = max(0, ncols - col_offset) + chunk = self[row_start:row_stop, col_start:col_stop].new(name="M_repositioning") + rv = Matrix(self.dtype, nrows, ncols, name=name) + rv[ + row_start + row_offset : row_start + row_offset + chunk._nrows, + col_start + col_offset : col_start + col_offset + chunk._ncols, + ] = chunk + return rv + ################################## # Extract and Assign index methods ################################## @@ -1474,6 +1519,7 @@ def shape(self): reduce_columnwise = wrapdoc(Matrix.reduce_columnwise)(property(_automethods.reduce_columnwise)) reduce_rowwise = wrapdoc(Matrix.reduce_rowwise)(property(_automethods.reduce_rowwise)) reduce_scalar = wrapdoc(Matrix.reduce_scalar)(property(_automethods.reduce_scalar)) + reposition = wrapdoc(Matrix.reposition)(property(_automethods.reposition)) select = wrapdoc(Matrix.select)(property(_automethods.select)) ss = wrapdoc(Matrix.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Matrix.to_pygraphblas)(property(_automethods.to_pygraphblas)) @@ -1553,6 +1599,7 @@ def shape(self): reduce_columnwise = wrapdoc(Matrix.reduce_columnwise)(property(_automethods.reduce_columnwise)) reduce_rowwise = wrapdoc(Matrix.reduce_rowwise)(property(_automethods.reduce_rowwise)) reduce_scalar = wrapdoc(Matrix.reduce_scalar)(property(_automethods.reduce_scalar)) + reposition = wrapdoc(Matrix.reposition)(property(_automethods.reposition)) select = wrapdoc(Matrix.select)(property(_automethods.select)) ss = wrapdoc(Matrix.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Matrix.to_pygraphblas)(property(_automethods.to_pygraphblas)) diff --git a/graphblas/tests/test_matrix.py b/graphblas/tests/test_matrix.py index 084a56534..4136f735b 100644 --- a/graphblas/tests/test_matrix.py +++ b/graphblas/tests/test_matrix.py @@ -3284,3 +3284,27 @@ def test_udt(): info = A.ss.export("coor") result = A.ss.import_any(**info) assert result.isequal(A) + + +def test_reposition(A): + rows, cols, values = A.to_values() + rows = rows.astype(int) + cols = cols.astype(int) + + def get_expected(row_offset, col_offset, nrows, ncols): + r = rows + row_offset + c = cols + col_offset + mask = (r >= 0) & (r < nrows) & (c >= 0) & (c < ncols) + return Matrix.from_values(r[mask], c[mask], values[mask], nrows=nrows, ncols=ncols) + + for row_offset in range(-A.nrows - 2, A.nrows + 3, 3): + for col_offset in range(-A.ncols - 2, A.ncols + 3, 3): + result = A.reposition(row_offset, col_offset) + expected = get_expected(row_offset, col_offset, A.nrows, A.ncols) + assert result.isequal(expected) + result = A.reposition(row_offset, col_offset, nrows=3, ncols=10) + expected = get_expected(row_offset, col_offset, 3, 10) + assert result.isequal(expected) + result = A.reposition(row_offset, col_offset, nrows=10, ncols=3) + expected = get_expected(row_offset, col_offset, 10, 3) + assert result.isequal(expected) diff --git a/graphblas/tests/test_vector.py b/graphblas/tests/test_vector.py index 54a467886..3d3dda41a 100644 --- a/graphblas/tests/test_vector.py +++ b/graphblas/tests/test_vector.py @@ -1959,3 +1959,24 @@ def test_ewise_union_infix(): op(v & w, 5, left_default=10, right_default=20) with pytest.raises(TypeError): op(v, w, left_default=10, right_default=20) + + +def test_reposition(v): + indices, values = v.to_values() + indices = indices.astype(int) + + def get_expected(offset, size): + ind = indices + offset + mask = (ind >= 0) & (ind < size) + return Vector.from_values(ind[mask], values[mask], size=size) + + for offset in range(-v.size - 2, v.size + 3): + result = v.reposition(offset) + expected = get_expected(offset, v.size) + assert result.isequal(expected) + result = v.reposition(offset, size=3) + expected = get_expected(offset, 3) + assert result.isequal(expected) + result = v.reposition(offset, size=10) + expected = get_expected(offset, 10) + assert result.isequal(expected) diff --git a/graphblas/vector.py b/graphblas/vector.py index 7ecbe92cf..1e862d6d0 100644 --- a/graphblas/vector.py +++ b/graphblas/vector.py @@ -837,6 +837,35 @@ def outer(self, other, op=binary.times): ) return expr + def reposition(self, offset, *, size=None, name=None): + """Return a new Vector with the values repositioned by offset. + + Positive offset moves values to the right, negative to the left. + Values repositioned outside of the new Vector are dropped (i.e., they don't wrap around). + + Parameters + ---------- + offset : int + size : int, optional + The size of the new Vector. If not specified, same size as input Vector. + name : str, optional + Name of the new Vector. + + """ + if size is None: + size = self._size + offset = int(offset) + if offset < 0: + start = -offset + stop = start + size + else: + start = 0 + stop = max(0, size - offset) + chunk = self[start:stop].new(name="v_repositioning") + rv = Vector(self.dtype, size, name=name) + rv[start + offset : start + offset + chunk._size] = chunk + return rv + ################################## # Extract and Assign index methods ################################## @@ -1112,6 +1141,7 @@ def shape(self): nvals = wrapdoc(Vector.nvals)(property(_automethods.nvals)) outer = wrapdoc(Vector.outer)(property(_automethods.outer)) reduce = wrapdoc(Vector.reduce)(property(_automethods.reduce)) + reposition = wrapdoc(Vector.reposition)(property(_automethods.reposition)) select = wrapdoc(Vector.select)(property(_automethods.select)) ss = wrapdoc(Vector.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Vector.to_pygraphblas)(property(_automethods.to_pygraphblas)) @@ -1183,6 +1213,7 @@ def shape(self): nvals = wrapdoc(Vector.nvals)(property(_automethods.nvals)) outer = wrapdoc(Vector.outer)(property(_automethods.outer)) reduce = wrapdoc(Vector.reduce)(property(_automethods.reduce)) + reposition = wrapdoc(Vector.reposition)(property(_automethods.reposition)) select = wrapdoc(Vector.select)(property(_automethods.select)) ss = wrapdoc(Vector.ss)(property(_automethods.ss)) to_pygraphblas = wrapdoc(Vector.to_pygraphblas)(property(_automethods.to_pygraphblas)) diff --git a/setup.cfg b/setup.cfg index a9809b694..ad7d5fc09 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,6 +3,7 @@ test=pytest [flake8] max-line-length = 100 +inline-quotes = " exclude = versioneer.py, graphblas/tests/test_formatting.py, From 46b3d19eb82edbaed2cb3740b9a2b3000d3e4e11 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Sat, 16 Apr 2022 00:35:49 -0500 Subject: [PATCH 2/6] Reposition for transposed matrices --- graphblas/matrix.py | 18 ++++++++++---- graphblas/tests/test_matrix.py | 43 +++++++++++++++++++++++----------- graphblas/tests/test_scalar.py | 14 +++++++++-- graphblas/tests/test_vector.py | 14 +++++++++-- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/graphblas/matrix.py b/graphblas/matrix.py index 264f700cb..c7181a274 100644 --- a/graphblas/matrix.py +++ b/graphblas/matrix.py @@ -954,12 +954,19 @@ def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name= else: col_start = 0 col_stop = max(0, ncols - col_offset) - chunk = self[row_start:row_stop, col_start:col_stop].new(name="M_repositioning") rv = Matrix(self.dtype, nrows, ncols, name=name) - rv[ - row_start + row_offset : row_start + row_offset + chunk._nrows, - col_start + col_offset : col_start + col_offset + chunk._ncols, - ] = chunk + if self._is_transposed: + chunk = self._matrix[col_start:col_stop, row_start:row_stop].new(name="M_repositioning") + rv[ + row_start + row_offset : row_start + row_offset + chunk._ncols, + col_start + col_offset : col_start + col_offset + chunk._nrows, + ] = chunk.T + else: + chunk = self[row_start:row_stop, col_start:col_stop].new(name="M_repositioning") + rv[ + row_start + row_offset : row_start + row_offset + chunk._nrows, + col_start + col_offset : col_start + col_offset + chunk._ncols, + ] = chunk return rv ################################## @@ -1707,6 +1714,7 @@ def _name_html(self): reduce_rowwise = Matrix.reduce_rowwise reduce_columnwise = Matrix.reduce_columnwise reduce_scalar = Matrix.reduce_scalar + reposition = Matrix.reposition # Operator sugar __or__ = Matrix.__or__ diff --git a/graphblas/tests/test_matrix.py b/graphblas/tests/test_matrix.py index 4136f735b..abdf1d0b0 100644 --- a/graphblas/tests/test_matrix.py +++ b/graphblas/tests/test_matrix.py @@ -2602,7 +2602,12 @@ def test_expr_is_like_matrix(A): "resize", "update", } - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Matrix. You may need to " + "add an entry to `matrix` or `matrix_vector` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) assert attrs - infix_attrs == expected # TransposedMatrix is used differently than other expressions, # so maybe it shouldn't support everything. @@ -2638,7 +2643,12 @@ def test_index_expr_is_like_matrix(A): "from_values", "resize", } - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Matrix. You may need to " + "add an entry to `matrix` or `matrix_vector` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) def test_flatten(A): @@ -3291,20 +3301,25 @@ def test_reposition(A): rows = rows.astype(int) cols = cols.astype(int) - def get_expected(row_offset, col_offset, nrows, ncols): - r = rows + row_offset - c = cols + col_offset + def get_expected(row_offset, col_offset, nrows, ncols, is_transposed): + r = rows + c = cols + if is_transposed: + r, c = c, r + r = r + row_offset + c = c + col_offset mask = (r >= 0) & (r < nrows) & (c >= 0) & (c < ncols) return Matrix.from_values(r[mask], c[mask], values[mask], nrows=nrows, ncols=ncols) for row_offset in range(-A.nrows - 2, A.nrows + 3, 3): for col_offset in range(-A.ncols - 2, A.ncols + 3, 3): - result = A.reposition(row_offset, col_offset) - expected = get_expected(row_offset, col_offset, A.nrows, A.ncols) - assert result.isequal(expected) - result = A.reposition(row_offset, col_offset, nrows=3, ncols=10) - expected = get_expected(row_offset, col_offset, 3, 10) - assert result.isequal(expected) - result = A.reposition(row_offset, col_offset, nrows=10, ncols=3) - expected = get_expected(row_offset, col_offset, 10, 3) - assert result.isequal(expected) + for M in [A, A.T]: + result = M.reposition(row_offset, col_offset) + expected = get_expected(row_offset, col_offset, M.nrows, M.ncols, M._is_transposed) + assert result.isequal(expected) + result = M.reposition(row_offset, col_offset, nrows=3, ncols=10) + expected = get_expected(row_offset, col_offset, 3, 10, M._is_transposed) + assert result.isequal(expected) + result = M.reposition(row_offset, col_offset, nrows=10, ncols=3) + expected = get_expected(row_offset, col_offset, 10, 3, M._is_transposed) + assert result.isequal(expected) diff --git a/graphblas/tests/test_scalar.py b/graphblas/tests/test_scalar.py index 1baa1f7a0..2c4ef88c6 100644 --- a/graphblas/tests/test_scalar.py +++ b/graphblas/tests/test_scalar.py @@ -328,7 +328,12 @@ def test_expr_is_like_scalar(s): } if s.is_cscalar: expected.add("_empty") - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Scalar. You may need to " + "add an entry to `scalar` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) assert attrs - infix_attrs == expected @@ -354,7 +359,12 @@ def test_index_expr_is_like_scalar(s): } if s.is_cscalar: expected.add("_empty") - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Scalar. You may need to " + "add an entry to `scalar` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) def test_ndim(s): diff --git a/graphblas/tests/test_vector.py b/graphblas/tests/test_vector.py index 3d3dda41a..ff58384e3 100644 --- a/graphblas/tests/test_vector.py +++ b/graphblas/tests/test_vector.py @@ -1405,7 +1405,12 @@ def test_expr_is_like_vector(v): "resize", "update", } - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Vector. You may need to " + "add an entry to `vector` or `matrix_vector` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) assert attrs - infix_attrs == expected @@ -1434,7 +1439,12 @@ def test_index_expr_is_like_vector(v): "from_values", "resize", } - assert attrs - expr_attrs == expected + assert attrs - expr_attrs == expected, ( + "If you see this message, you probably added a method to Vector. You may need to " + "add an entry to `vector` or `matrix_vector` set in `graphblas._automethods.py` " + "and then run `python -m graphblas._automethods`. If you're messing with infix " + "methods, then you may need to run `python -m graphblas._infixmethods`." + ) def test_random(v): From ea506abf234b7f2f29f90f920a880c4810e3bc3f Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Sat, 16 Apr 2022 00:41:34 -0500 Subject: [PATCH 3/6] Add a note to the docstrings --- graphblas/matrix.py | 2 ++ graphblas/vector.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/graphblas/matrix.py b/graphblas/matrix.py index c7181a274..29c506606 100644 --- a/graphblas/matrix.py +++ b/graphblas/matrix.py @@ -924,6 +924,8 @@ def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name= Positive offset moves values to the right (or down), negative to the left (or up). Values repositioned outside of the new Matrix are dropped (i.e., they don't wrap around). + This is not a standard GraphBLAS method. This is implemented with an extract and assign. + Parameters ---------- row_offset : int diff --git a/graphblas/vector.py b/graphblas/vector.py index 1e862d6d0..ed4c677e0 100644 --- a/graphblas/vector.py +++ b/graphblas/vector.py @@ -843,6 +843,8 @@ def reposition(self, offset, *, size=None, name=None): Positive offset moves values to the right, negative to the left. Values repositioned outside of the new Vector are dropped (i.e., they don't wrap around). + This is not a standard GraphBLAS method. This is implemented with an extract and assign. + Parameters ---------- offset : int From 1645af3b7cc572d49f3da983284b1221101b94ec Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Sat, 16 Apr 2022 17:58:02 -0500 Subject: [PATCH 4/6] Have `reposition` return an expression --- graphblas/base.py | 9 +++++++- graphblas/matrix.py | 38 ++++++++++++++++++++-------------- graphblas/tests/test_matrix.py | 24 ++++++++++++++++++--- graphblas/tests/test_vector.py | 6 +++--- graphblas/vector.py | 21 ++++++++++++------- 5 files changed, 69 insertions(+), 29 deletions(-) diff --git a/graphblas/base.py b/graphblas/base.py index 37df02a6f..42a7c0cda 100644 --- a/graphblas/base.py +++ b/graphblas/base.py @@ -423,10 +423,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") - if expr.op is not None and expr.op.opclass == "Aggregator": + elif expr.op is not None and expr.op.opclass == "Aggregator": updater = self(mask=mask, accum=accum, replace=replace) expr.op._new(updater, expr) return + elif expr.cfunc_name is None: # Custom recipe + updater = self(mask=mask, accum=accum, replace=replace) + expr.args[0](updater, *expr.args[1]) + return # Normalize mask and separate out complement and structural flags if mask is None: @@ -573,6 +577,9 @@ def _new(self, dtype, mask, name, **kwargs): if self.op is not None and self.op.opclass == "Aggregator": updater = output(mask=mask) self.op._new(updater, self) + elif self.cfunc_name is None: # Custom recipe + updater = output if mask is None else output(mask=mask) + self.args[0](updater, *self.args[1]) elif mask is None: output.update(self) else: diff --git a/graphblas/matrix.py b/graphblas/matrix.py index 29c506606..d782deb41 100644 --- a/graphblas/matrix.py +++ b/graphblas/matrix.py @@ -1,5 +1,6 @@ import itertools import warnings +from operator import setitem import numpy as np @@ -918,8 +919,8 @@ def reduce_scalar(self, op=monoid.plus, *, allow_empty=True): ) # Unofficial methods - def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name=None): - """Return a new Matrix with the values repositioned by row_offset and column_offset. + def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None): + """Reposition values by adding `row_offset` and `column_offset` to the indices. Positive offset moves values to the right (or down), negative to the left (or up). Values repositioned outside of the new Matrix are dropped (i.e., they don't wrap around). @@ -934,14 +935,16 @@ def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name= The nrows of the new Matrix. If not specified, same nrows as input Matrix. ncols : int, optional The ncols of the new Matrix. If not specified, same ncols as input Matrix. - name : str, optional - Name of the new Matrix. """ if nrows is None: nrows = self._nrows + else: + nrows = int(nrows) if ncols is None: ncols = self._ncols + else: + ncols = int(ncols) row_offset = int(row_offset) if row_offset < 0: row_start = -row_offset @@ -956,20 +959,25 @@ def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None, name= else: col_start = 0 col_stop = max(0, ncols - col_offset) - rv = Matrix(self.dtype, nrows, ncols, name=name) if self._is_transposed: - chunk = self._matrix[col_start:col_stop, row_start:row_stop].new(name="M_repositioning") - rv[ - row_start + row_offset : row_start + row_offset + chunk._ncols, - col_start + col_offset : col_start + col_offset + chunk._nrows, - ] = chunk.T + chunk = ( + self._matrix[col_start:col_stop, row_start:row_stop].new(name="M_repositioning").T + ) else: chunk = self[row_start:row_stop, col_start:col_stop].new(name="M_repositioning") - rv[ - row_start + row_offset : row_start + row_offset + chunk._nrows, - col_start + col_offset : col_start + col_offset + chunk._ncols, - ] = chunk - return rv + indices = ( + slice(row_start + row_offset, row_start + row_offset + chunk._nrows), + slice(col_start + col_offset, col_start + col_offset + chunk._ncols), + ) + return MatrixExpression( + "reposition", + None, + [setitem, (indices, chunk), self], # [func, args, expr_arg0, expr_arg1, ...] + expr_repr="{2.name}.reposition(%d, %d)" % (row_offset, column_offset), + nrows=nrows, + ncols=ncols, + dtype=self.dtype, + ) ################################## # Extract and Assign index methods diff --git a/graphblas/tests/test_matrix.py b/graphblas/tests/test_matrix.py index abdf1d0b0..5f9cf306f 100644 --- a/graphblas/tests/test_matrix.py +++ b/graphblas/tests/test_matrix.py @@ -3314,12 +3314,30 @@ def get_expected(row_offset, col_offset, nrows, ncols, is_transposed): for row_offset in range(-A.nrows - 2, A.nrows + 3, 3): for col_offset in range(-A.ncols - 2, A.ncols + 3, 3): for M in [A, A.T]: - result = M.reposition(row_offset, col_offset) + result = M.reposition(row_offset, col_offset).new() expected = get_expected(row_offset, col_offset, M.nrows, M.ncols, M._is_transposed) assert result.isequal(expected) - result = M.reposition(row_offset, col_offset, nrows=3, ncols=10) + result = M.reposition(row_offset, col_offset, nrows=3, ncols=10).new() expected = get_expected(row_offset, col_offset, 3, 10, M._is_transposed) assert result.isequal(expected) - result = M.reposition(row_offset, col_offset, nrows=10, ncols=3) + result = M.reposition(row_offset, col_offset, nrows=10, ncols=3).new() expected = get_expected(row_offset, col_offset, 10, 3, M._is_transposed) assert result.isequal(expected) + + result = A.reposition(3, 1).new(mask=A.S) + expected = Matrix.from_values([3, 4, 6], [2, 5, 3], [2, 8, 3], nrows=A.nrows, ncols=A.ncols) + assert result.isequal(expected) + + result(A.S, binary.plus) << A.reposition(3, 1) + expected *= 2 + assert result.isequal(expected) + + result = A.T.reposition(-1, 1).new(mask=A.S) + expected = Matrix.from_values( + [0, 1, 1, 3, 4, 5], [1, 4, 6, 2, 5, 2], [2, 3, 1, 8, 7, 4], nrows=A.ncols, ncols=A.nrows + ) + assert result.isequal(expected) + + result(A.S, binary.plus) << A.T.reposition(-1, 1) + expected *= 2 + assert result.isequal(expected) diff --git a/graphblas/tests/test_vector.py b/graphblas/tests/test_vector.py index ff58384e3..10f514106 100644 --- a/graphblas/tests/test_vector.py +++ b/graphblas/tests/test_vector.py @@ -1981,12 +1981,12 @@ def get_expected(offset, size): return Vector.from_values(ind[mask], values[mask], size=size) for offset in range(-v.size - 2, v.size + 3): - result = v.reposition(offset) + result = v.reposition(offset).new() expected = get_expected(offset, v.size) assert result.isequal(expected) - result = v.reposition(offset, size=3) + result = v.reposition(offset, size=3).new() expected = get_expected(offset, 3) assert result.isequal(expected) - result = v.reposition(offset, size=10) + result = v.reposition(offset, size=10).new() expected = get_expected(offset, 10) assert result.isequal(expected) diff --git a/graphblas/vector.py b/graphblas/vector.py index ed4c677e0..1be3aeb51 100644 --- a/graphblas/vector.py +++ b/graphblas/vector.py @@ -1,5 +1,6 @@ import itertools import warnings +from operator import setitem import numpy as np @@ -837,8 +838,8 @@ def outer(self, other, op=binary.times): ) return expr - def reposition(self, offset, *, size=None, name=None): - """Return a new Vector with the values repositioned by offset. + def reposition(self, offset, *, size=None): + """Reposition the values by adding `offset` to the indices. Positive offset moves values to the right, negative to the left. Values repositioned outside of the new Vector are dropped (i.e., they don't wrap around). @@ -850,12 +851,12 @@ def reposition(self, offset, *, size=None, name=None): offset : int size : int, optional The size of the new Vector. If not specified, same size as input Vector. - name : str, optional - Name of the new Vector. """ if size is None: size = self._size + else: + size = int(size) offset = int(offset) if offset < 0: start = -offset @@ -864,9 +865,15 @@ def reposition(self, offset, *, size=None, name=None): start = 0 stop = max(0, size - offset) chunk = self[start:stop].new(name="v_repositioning") - rv = Vector(self.dtype, size, name=name) - rv[start + offset : start + offset + chunk._size] = chunk - return rv + indices = slice(start + offset, start + offset + chunk._size) + return VectorExpression( + "reposition", + None, + [setitem, (indices, chunk), self], # [func, args, expr_arg0, expr_arg1, ...] + expr_repr="{2.name}.reposition(%d)" % offset, + size=size, + dtype=self.dtype, + ) ################################## # Extract and Assign index methods From 73c7dc2ef7e15dc602507489a93250d03fb214c9 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Sat, 16 Apr 2022 21:40:57 -0500 Subject: [PATCH 5/6] Add recipes for broadcasting and make them more efficient with masks. --- graphblas/base.py | 15 ++++--- graphblas/matrix.py | 72 ++++++++++++++++++++++++------ graphblas/tests/test_vector.py | 8 ++++ graphblas/vector.py | 81 ++++++++++++++++++++++++++-------- 4 files changed, 136 insertions(+), 40 deletions(-) diff --git a/graphblas/base.py b/graphblas/base.py index 42a7c0cda..359dbf779 100644 --- a/graphblas/base.py +++ b/graphblas/base.py @@ -429,7 +429,7 @@ def _update(self, expr, mask=None, accum=None, replace=False, input_mask=None): return elif expr.cfunc_name is None: # Custom recipe updater = self(mask=mask, accum=accum, replace=replace) - expr.args[0](updater, *expr.args[1]) + expr.args[-2](updater, *expr.args[-1]) return # Normalize mask and separate out complement and structural flags @@ -544,9 +544,9 @@ def __init__( self.bt = bt self.op = op if expr_repr is None: - if len(args) == 1: + if len(args) == 1 or cfunc_name is None and len(args) == 3: expr_repr = "{0.name}.{method_name}({op})" - elif len(args) == 2: + elif len(args) == 2 or cfunc_name is None and len(args) == 4: expr_repr = "{0.name}.{method_name}({1.name}, op={op})" else: # pragma: no cover raise ValueError(f"No default expr_repr for len(args) == {len(args)}") @@ -578,8 +578,7 @@ def _new(self, dtype, mask, name, **kwargs): updater = output(mask=mask) self.op._new(updater, self) elif self.cfunc_name is None: # Custom recipe - updater = output if mask is None else output(mask=mask) - self.args[0](updater, *self.args[1]) + self.args[-2](output(mask=mask), *self.args[-1]) elif mask is None: output.update(self) else: @@ -590,13 +589,15 @@ def _new(self, dtype, mask, name, **kwargs): dup = new def _format_expr(self): - return self.expr_repr.format(*self.args, method_name=self.method_name, op=self.op) + args = self.args[:-2] if self.cfunc_name is None else self.args + return self.expr_repr.format(*args, method_name=self.method_name, op=self.op) def _format_expr_html(self): expr_repr = self.expr_repr.replace(".name", "._name_html").replace( "._expr_name", "._expr_name_html" ) - return expr_repr.format(*self.args, method_name=self.method_name, op=self.op) + args = self.args[:-2] if self.cfunc_name is None else self.args + return expr_repr.format(*args, method_name=self.method_name, op=self.op) _expect_type = _expect_type _expect_op = _expect_op diff --git a/graphblas/matrix.py b/graphblas/matrix.py index d782deb41..922e4ad6f 100644 --- a/graphblas/matrix.py +++ b/graphblas/matrix.py @@ -1,6 +1,5 @@ import itertools import warnings -from operator import setitem import numpy as np @@ -27,6 +26,29 @@ ffi_new = ffi.new +# Custom recipes +def _m_add_v(updater, left, right, op): + full = Vector(right.dtype, left._nrows, name="v_full") + full[:] = 0 + temp = full.outer(right, binary.second).new(name="M_temp", mask=updater.kwargs.get("mask")) + updater << left.ewise_add(temp, op, require_monoid=False) + + +def _m_mult_v(updater, left, right, op): + updater << left.mxm(right.diag(name="M_temp"), get_semiring(monoid.any, op)) + + +def _m_union_v(updater, left, right, left_default, right_default, op): + full = Vector(right.dtype, left._nrows, name="v_full") + full[:] = 0 + temp = full.outer(right, binary.second).new(name="M_temp", mask=updater.kwargs.get("mask")) + updater << left.ewise_union(temp, op, left_default=left_default, right_default=right_default) + + +def _reposition(updater, indices, chunk): + updater[indices] = chunk + + class Matrix(BaseType): """ GraphBLAS Sparse Matrix @@ -478,17 +500,20 @@ def ewise_add(self, other, op=monoid.plus, *, require_monoid=True): self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if other.ndim == 1: # Broadcast rowwise from the right - # Can we do `C(M.S) << plus(A | v)` -> `C(M.S) << plus(any_second(M @ v.diag()) | A)`? if self._ncols != other._size: - # Check this before we compute a possibly large matrix below raise DimensionMismatch( "Dimensions not compatible for broadcasting Vector from the right " f"to rows of Matrix in {method_name}. Matrix.ncols (={self._ncols}) " f"must equal Vector.size (={other._size})." ) - full = Vector(other.dtype, self._nrows, name="v_full") - full[:] = 0 - other = full.outer(other, binary.second).new(name="M_temp") + return MatrixExpression( + method_name, + None, + [self, other, _m_add_v, (self, other, op)], # [*expr_args, func, args] + nrows=self._nrows, + ncols=self._ncols, + op=op, + ) expr = MatrixExpression( method_name, f"GrB_Matrix_eWiseAdd_{op.opclass}", @@ -516,7 +541,21 @@ def ewise_mult(self, other, op=binary.times): # Per the spec, op may be a semiring, but this is weird, so don't. self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if other.ndim == 1: - return self.mxm(other.diag(name="M_temp"), get_semiring(monoid.any, op)) + # Broadcast rowwise from the right + if self._ncols != other._size: + raise DimensionMismatch( + "Dimensions not compatible for broadcasting Vector from the right " + f"to rows of Matrix in {method_name}. Matrix.ncols (={self._ncols}) " + f"must equal Vector.size (={other._size})." + ) + return MatrixExpression( + method_name, + None, + [self, other, _m_mult_v, (self, other, op)], # [*expr_args, func, args] + nrows=self._nrows, + ncols=self._ncols, + op=op, + ) expr = MatrixExpression( method_name, f"GrB_Matrix_eWiseMult_{op.opclass}", @@ -585,19 +624,24 @@ def ewise_union(self, other, op, left_default, right_default): self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if op.opclass == "Monoid": op = op.binaryop + expr_repr = "{0.name}.{method_name}({2.name}, {op}, {1._expr_name}, {3._expr_name})" if other.ndim == 1: # Broadcast rowwise from the right - # Can we do `C(M.S) << plus(A | v)` -> `C(M.S) << plus(any_second(M @ v.diag()) | A)`? if self._ncols != other._size: - # Check this before we compute a possibly large matrix below raise DimensionMismatch( "Dimensions not compatible for broadcasting Vector from the right " f"to rows of Matrix in {method_name}. Matrix.ncols (={self._ncols}) " f"must equal Vector.size (={other._size})." ) - full = Vector(other.dtype, self._nrows, name="v_full") - full[:] = 0 - other = full.outer(other, binary.second).new(name="M_temp") + return MatrixExpression( + method_name, + None, + [self, left, other, right, _m_union_v, (self, other, left, right, op)], + expr_repr=expr_repr, + nrows=self._nrows, + ncols=self._ncols, + op=op, + ) expr = MatrixExpression( method_name, "GxB_Matrix_eWiseUnion", @@ -605,7 +649,7 @@ def ewise_union(self, other, op, left_default, right_default): op=op, at=self._is_transposed, bt=other._is_transposed, - expr_repr="{0.name}.{method_name}({2.name}, {op}, {1._expr_name}, {3._expr_name})", + expr_repr=expr_repr, ) if self.shape != other.shape: expr.new(name="") # incompatible shape; raise now @@ -972,7 +1016,7 @@ def reposition(self, row_offset, column_offset, *, nrows=None, ncols=None): return MatrixExpression( "reposition", None, - [setitem, (indices, chunk), self], # [func, args, expr_arg0, expr_arg1, ...] + [self, _reposition, (indices, chunk)], # [*expr_args, func, args] expr_repr="{2.name}.reposition(%d, %d)" % (row_offset, column_offset), nrows=nrows, ncols=ncols, diff --git a/graphblas/tests/test_vector.py b/graphblas/tests/test_vector.py index 10f514106..e360caa46 100644 --- a/graphblas/tests/test_vector.py +++ b/graphblas/tests/test_vector.py @@ -1902,6 +1902,10 @@ def test_broadcasting(A, v): assert result.isequal(expected) result = binary.plus(v | A).new() assert result.isequal(expected) + # use mask + result(A.S, replace=True) << binary.plus(v | A) + expected(A.S, replace=True) << expected + assert result.isequal(expected) expected = semiring.any_plus(v.diag() @ A).new() result = v.ewise_mult(A, monoid.plus).new() @@ -1924,6 +1928,10 @@ def test_broadcasting(A, v): result = A.dup() result += v assert result.isequal(expected) + # use mask + result(A.S, replace=True) << binary.plus(A | v) + expected(A.S, replace=True) << expected + assert result.isequal(expected) expected = semiring.any_plus(A @ v.diag()).new() result = A.ewise_mult(v, monoid.plus).new() diff --git a/graphblas/vector.py b/graphblas/vector.py index 1be3aeb51..eb91abd15 100644 --- a/graphblas/vector.py +++ b/graphblas/vector.py @@ -1,6 +1,5 @@ import itertools import warnings -from operator import setitem import numpy as np @@ -26,6 +25,29 @@ ffi_new = ffi.new +# Custom recipes +def _v_add_m(updater, left, right, op): + full = Vector(left.dtype, right._ncols, name="v_full") + full[:] = 0 + temp = left.outer(full, binary.first).new(name="M_temp", mask=updater.kwargs.get("mask")) + updater << temp.ewise_add(right, op, require_monoid=False) + + +def _v_mult_m(updater, left, right, op): + updater << left.diag(name="M_temp").mxm(right, get_semiring(monoid.any, op)) + + +def _v_union_m(updater, left, right, left_default, right_default, op): + full = Vector(left.dtype, right._ncols, name="v_full") + full[:] = 0 + temp = left.outer(full, binary.first).new(name="M_temp", mask=updater.kwargs.get("mask")) + updater << temp.ewise_union(right, op, left_default=left_default, right_default=right_default) + + +def _reposition(updater, indices, chunk): + updater[indices] = chunk + + class Vector(BaseType): """ GraphBLAS Sparse Vector @@ -423,7 +445,7 @@ def ewise_add(self, other, op=monoid.plus, *, require_monoid=True): performing any operation. In the case of `gt`, the non-empty value is cast to a boolean. For these reasons, users are required to be explicit when choosing this surprising behavior. """ - from .matrix import Matrix, TransposedMatrix + from .matrix import Matrix, MatrixExpression, TransposedMatrix method_name = "ewise_add" other = self._expect_type( @@ -444,7 +466,6 @@ def ewise_add(self, other, op=monoid.plus, *, require_monoid=True): self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if other.ndim == 2: # Broadcast columnwise from the left - # Can we do `C(M.S) << plus(v | A)` -> `C(M.S) << plus(any_first(v.diag() @ M) | A)`? if other._nrows != self._size: # Check this before we compute a possibly large matrix below raise DimensionMismatch( @@ -452,10 +473,14 @@ def ewise_add(self, other, op=monoid.plus, *, require_monoid=True): f"to columns of Matrix in {method_name}. Matrix.nrows (={other._nrows}) " f"must equal Vector.size (={self._size})." ) - full = Vector(self.dtype, other._ncols, name="v_full") - full[:] = 0 - temp = self.outer(full, binary.first).new(name="M_temp") - return temp.ewise_add(other, op, require_monoid=False) + return MatrixExpression( + method_name, + None, + [self, other, _v_add_m, (self, other, op)], + nrows=other._nrows, + ncols=other._ncols, + op=op, + ) expr = VectorExpression( method_name, f"GrB_Vector_eWiseAdd_{op.opclass}", @@ -473,7 +498,7 @@ def ewise_mult(self, other, op=binary.times): Result will contain the intersection of indices from both Vectors Default op is binary.times """ - from .matrix import Matrix, TransposedMatrix + from .matrix import Matrix, MatrixExpression, TransposedMatrix method_name = "ewise_mult" other = self._expect_type( @@ -483,7 +508,21 @@ def ewise_mult(self, other, op=binary.times): # Per the spec, op may be a semiring, but this is weird, so don't. self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if other.ndim == 2: - return self.diag(name="M_temp").mxm(other, get_semiring(monoid.any, op)) + # Broadcast columnwise from the left + if other._nrows != self._size: + raise DimensionMismatch( + "Dimensions not compatible for broadcasting Vector from the left " + f"to columns of Matrix in {method_name}. Matrix.nrows (={other._nrows}) " + f"must equal Vector.size (={self._size})." + ) + return MatrixExpression( + method_name, + None, + [self, other, _v_mult_m, (self, other, op)], + nrows=other._nrows, + ncols=other._ncols, + op=op, + ) expr = VectorExpression( method_name, f"GrB_Vector_eWiseMult_{op.opclass}", @@ -507,7 +546,7 @@ def ewise_union(self, other, op, left_default, right_default): ``op`` should be a BinaryOp or Monoid. """ # SS, SuiteSparse-specific: eWiseUnion - from .matrix import Matrix, TransposedMatrix + from .matrix import Matrix, MatrixExpression, TransposedMatrix method_name = "ewise_union" other = self._expect_type( @@ -552,26 +591,30 @@ def ewise_union(self, other, op, left_default, right_default): self._expect_op(op, ("BinaryOp", "Monoid"), within=method_name, argname="op") if op.opclass == "Monoid": op = op.binaryop + expr_repr = "{0.name}.{method_name}({2.name}, {op}, {1._expr_name}, {3._expr_name})" if other.ndim == 2: # Broadcast columnwise from the left - # Can we do `C(M.S) << plus(v | A)` -> `C(M.S) << plus(any_first(v.diag() @ M) | A)`? if other._nrows != self._size: - # Check this before we compute a possibly large matrix below raise DimensionMismatch( "Dimensions not compatible for broadcasting Vector from the left " f"to columns of Matrix in {method_name}. Matrix.nrows (={other._nrows}) " f"must equal Vector.size (={self._size})." ) - full = Vector(self.dtype, other._ncols, name="v_full") - full[:] = 0 - temp = self.outer(full, binary.first).new(name="M_temp") - return temp.ewise_union(other, op, left_default, right_default) + return MatrixExpression( + method_name, + None, + [self, left, other, right, _v_union_m, (self, other, left, right, op)], + expr_repr=expr_repr, + nrows=other._nrows, + ncols=other._ncols, + op=op, + ) expr = VectorExpression( method_name, "GxB_Vector_eWiseUnion", [self, left, other, right], op=op, - expr_repr="{0.name}.{method_name}({2.name}, {op}, {1._expr_name}, {3._expr_name})", + expr_repr=expr_repr, ) if self._size != other._size: expr.new(name="") # incompatible shape; raise now @@ -869,8 +912,8 @@ def reposition(self, offset, *, size=None): return VectorExpression( "reposition", None, - [setitem, (indices, chunk), self], # [func, args, expr_arg0, expr_arg1, ...] - expr_repr="{2.name}.reposition(%d)" % offset, + [self, _reposition, (indices, chunk)], # [*expr_args, func, args] + expr_repr="{0.name}.reposition(%d)" % offset, size=size, dtype=self.dtype, ) From a0f756dcfdb885e300e61f85de95144a7201a384 Mon Sep 17 00:00:00 2001 From: Erik Welch Date: Sat, 16 Apr 2022 22:38:16 -0500 Subject: [PATCH 6/6] Rerender notebooks whose outputs were wrong after renaming the project. Also, don't report missing coverage on things that will be super-hard to cover. This will help us be less annoyed when trying to keep other parts covered. --- graphblas/__init__.py | 8 +- graphblas/formatting.py | 6 +- graphblas/operator.py | 2 +- .../Connected Components -- FastSV.ipynb | 215 ++++--- notebooks/Operators.ipynb | 128 ++-- notebooks/repr_demo.ipynb | 557 ++++++++++++++++-- 6 files changed, 702 insertions(+), 214 deletions(-) diff --git a/graphblas/__init__.py b/graphblas/__init__.py index 6b39bfe1f..34a64dd0d 100644 --- a/graphblas/__init__.py +++ b/graphblas/__init__.py @@ -186,7 +186,7 @@ def find_spec(self, fullname, path, target=None): if fullname in _NEEDS_OPERATOR and "operator" not in globals(): _load("operator") name = fullname[7:] # Trim "graphblas." - if name in globals(): + if name in globals(): # pragma: no cover # Make sure we execute the module only once module = globals()[name] spec = module.__spec__ @@ -195,14 +195,14 @@ def find_spec(self, fullname, path, target=None): class _SkipLoad(_Loader): - def __init__(self, module, orig_loader): + def __init__(self, module, orig_loader): # pragma: no cover self.module = module self.orig_loader = orig_loader - def create_module(self, spec): + def create_module(self, spec): # pragma: no cover return self.module - def exec_module(self, module): + def exec_module(self, module): # pragma: no cover # Don't execute the module, but restore the original loader module.__spec__.loader = self.orig_loader diff --git a/graphblas/formatting.py b/graphblas/formatting.py index be1cb6cec..2979b0d7d 100644 --- a/graphblas/formatting.py +++ b/graphblas/formatting.py @@ -109,7 +109,7 @@ def _update_matrix_dataframe(df, matrix, rows, row_offset, columns, column_offse if type(matrix) is TransposedMatrix: parent = matrix._matrix submatrix = Matrix(parent.dtype, parent._nrows, parent._ncols, name="") - if parent._nvals > 0: + if parent._nvals > 0: # pragma: no branch # Get val to support iso-valued matrices val = parent.reduce_scalar(monoid.any, allow_empty=False).new(name="") submatrix(parent.S)[columns, rows] = val @@ -257,7 +257,7 @@ def _get_matrix_dataframe(matrix, max_rows, min_rows, max_columns, *, mask=None) if min(nonzero._nvals, num_rows) > 2 * df.count().sum(): rows, cols, vals = nonzero.ss.head(num_rows, sort=True) if mask.complement: - if not vals.flags.writeable: + if not vals.flags.writeable: # pragma: no branch vals = vals.copy() vals[:] = 0 df = pd.DataFrame({"row": rows, "col": cols, "val": vals}) @@ -307,7 +307,7 @@ def _get_vector_dataframe(vector, max_rows, min_rows, max_columns, *, mask=None) if min(nonzero._nvals, num_rows) > 2 * df.count().sum(): indices, vals = nonzero.ss.head(num_rows, sort=True) if mask.complement: - if not vals.flags.writeable: + if not vals.flags.writeable: # pragma: no branch vals = vals.copy() vals[:] = 0 df = pd.DataFrame({"index": indices, "val": vals}) diff --git a/graphblas/operator.py b/graphblas/operator.py index 187ed7d0b..c34b9f513 100644 --- a/graphblas/operator.py +++ b/graphblas/operator.py @@ -1556,7 +1556,7 @@ def binary_wrapper(z_ptr, x_ptr, y_ptr): # pragma: no cover if ret_type is not dtype and ret_type is not dtype2: if ret_type.gb_obj is dtype.gb_obj: ret_type = dtype - elif ret_type.gb_obj is dtype2.gb_obj: + elif ret_type.gb_obj is dtype2.gb_obj: # pragma: no cover ret_type = dtype2 binary_wrapper, wrapper_sig = _get_udt_wrapper(numba_func, ret_type, dtype, dtype2) diff --git a/notebooks/Connected Components -- FastSV.ipynb b/notebooks/Connected Components -- FastSV.ipynb index 2e4abe271..dcb0c8b86 100644 --- a/notebooks/Connected Components -- FastSV.ipynb +++ b/notebooks/Connected Components -- FastSV.ipynb @@ -103,9 +103,20 @@ "tags": [] }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_20958/1209887720.py:2: DeprecationWarning: \n", + "\n", + "The scipy.sparse array containers will be used instead of matrices\n", + "in Networkx 3.0. Use `from_scipy_sparse_array` instead.\n", + " G = nx.convert_matrix.from_scipy_sparse_matrix(A)\n" + ] + }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -234,7 +245,7 @@ "
A
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -245,7 +256,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
221212INT32INT64bitmapr (iso)
\n", @@ -468,9 +479,9 @@ "
" ], "text/plain": [ - "\"A\" nvals nrows ncols dtype format\n", - "graphblas.Matrix 22 12 12 INT32 bitmapr (iso)\n", - "--------------------------------------------------------\n", + "\"A\" nvals nrows ncols dtype format\n", + "gb.Matrix 22 12 12 INT64 bitmapr (iso)\n", + "----------------------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", "0 1 1 1 \n", "1 1 1 \n", @@ -515,7 +526,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -686,7 +697,7 @@ "
parents
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -753,9 +764,9 @@ "" ], "text/plain": [ - "\"parents\" nvals size dtype format\n", - "graphblas.Vector 0 12 UINT32 sparse\n", - "------------------------------------------\n", + "\"parents\" nvals size dtype format\n", + "gb.Vector 0 12 UINT32 sparse\n", + "--------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " " ] @@ -870,7 +881,7 @@ "
modified?
\n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -937,9 +948,9 @@ "" ], "text/plain": [ - "\"modified?\" nvals size dtype format\n", - "graphblas.Vector 0 12 BOOL sparse\n", - "-----------------------------------------\n", + "\"modified?\" nvals size dtype format\n", + "gb.Vector 0 12 BOOL sparse\n", + "---------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " " ] @@ -1072,7 +1083,7 @@ "
parents
\n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1139,9 +1150,9 @@ "" ], "text/plain": [ - "\"parents\" nvals size dtype format\n", - "graphblas.Vector 12 12 UINT32 full\n", - "------------------------------------------\n", + "\"parents\" nvals size dtype format\n", + "gb.Vector 12 12 UINT32 full\n", + "--------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " 0 1 2 3 4 5 6 7 8 9 10 11" ] @@ -1276,7 +1287,7 @@ "
Minimum grandparent
\n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1344,7 +1355,7 @@ ], "text/plain": [ "\"Minimum grandparent\" nvals size dtype format\n", - "graphblas.Vector 12 12 UINT32 full\n", + "gb.Vector 12 12 UINT32 full\n", "--------------------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " 0 0 0 0 2 2 6 6 6 9 9 9" @@ -1620,7 +1631,7 @@ "
modified?
\n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1687,9 +1698,9 @@ "" ], "text/plain": [ - "\"modified?\" nvals size dtype format\n", - "graphblas.Vector 12 12 BOOL full\n", - "-----------------------------------------\n", + "\"modified?\" nvals size dtype format\n", + "gb.Vector 12 12 BOOL full\n", + "---------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " False True True True True True False True True False True True" ] @@ -1724,7 +1735,7 @@ "
changed?
\n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1737,8 +1748,8 @@ "" ], "text/plain": [ - "\"changed?\" value dtype\n", - "graphblas.Scalar True BOOL" + "\"changed?\" value dtype\n", + "gb.Scalar True BOOL" ] }, "execution_count": 23, @@ -1952,7 +1963,7 @@ "
parents
\n", "
graphblas.Scalar
gb.Scalar
value
dtype
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1961,7 +1972,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
1212INT32INT64full
\n", @@ -2019,9 +2030,9 @@ "
" ], "text/plain": [ - "\"parents\" nvals size dtype format\n", - "graphblas.Vector 12 12 INT32 full\n", - "-----------------------------------------\n", + "\"parents\" nvals size dtype format\n", + "gb.Vector 12 12 INT64 full\n", + "-------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", " 0 0 0 0 0 0 6 6 6 9 9 9" ] @@ -2063,7 +2074,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -2145,7 +2156,7 @@ { "data": { "text/plain": [ - "array([10, 3, 2, 11, 4, 6, 7, 5, 8, 0, 1, 9])" + "array([ 6, 1, 7, 4, 0, 9, 10, 3, 8, 5, 2, 11])" ] }, "execution_count": 30, @@ -2323,7 +2334,7 @@ "
P
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2334,7 +2345,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
121212INT32INT64csr (iso)
\n", @@ -2380,19 +2391,19 @@ " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", " \n", - " 1\n", " \n", " \n", " \n", " 1\n", " \n", + " 1\n", " \n", " \n", - " 1\n", " \n", " \n", " \n", @@ -2406,12 +2417,12 @@ " 2\n", " \n", " \n", - " 1\n", " \n", " \n", " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2423,6 +2434,7 @@ " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2430,15 +2442,14 @@ " \n", " \n", " \n", - " 1\n", " \n", " \n", " 4\n", + " 1\n", " \n", " \n", " \n", " \n", - " 1\n", " \n", " \n", " \n", @@ -2455,10 +2466,10 @@ " \n", " \n", " \n", - " 1\n", " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2471,10 +2482,10 @@ " \n", " \n", " \n", - " 1\n", " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2482,9 +2493,9 @@ " \n", " \n", " \n", + " 1\n", " \n", " \n", - " 1\n", " \n", " \n", " \n", @@ -2509,12 +2520,12 @@ " \n", " \n", " 9\n", - " 1\n", " \n", " \n", " \n", " \n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2525,8 +2536,8 @@ " \n", " 10\n", " \n", - " 1\n", " \n", + " 1\n", " \n", " \n", " \n", @@ -2548,31 +2559,31 @@ " \n", " \n", " \n", - " 1\n", " \n", " \n", + " 1\n", " \n", " \n", "\n", "
" ], "text/plain": [ - "\"P\" nvals nrows ncols dtype format\n", - "graphblas.Matrix 12 12 12 INT32 csr (iso)\n", - "----------------------------------------------------\n", + "\"P\" nvals nrows ncols dtype format\n", + "gb.Matrix 12 12 12 INT64 csr (iso)\n", + "------------------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", - "0 1 \n", - "1 1 \n", - "2 1 \n", - "3 1\n", - "4 1 \n", - "5 1 \n", - "6 1 \n", - "7 1 \n", + "0 1 \n", + "1 1 \n", + "2 1 \n", + "3 1 \n", + "4 1 \n", + "5 1 \n", + "6 1 \n", + "7 1 \n", "8 1 \n", - "9 1 \n", - "10 1 \n", - "11 1 " + "9 1 \n", + "10 1 \n", + "11 1" ] }, "execution_count": 32, @@ -2641,9 +2652,20 @@ "tags": [] }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_20958/873994875.py:2: DeprecationWarning: \n", + "\n", + "The scipy.sparse array containers will be used instead of matrices\n", + "in Networkx 3.0. Use `from_scipy_sparse_array` instead.\n", + " G_perm = nx.convert_matrix.from_scipy_sparse_matrix(A_sci)\n" + ] + }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -2760,7 +2782,7 @@ "
parents
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2769,7 +2791,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
1212INT32INT64full
\n", @@ -2812,14 +2834,14 @@ " 0\n", " 0\n", " 2\n", - " 2\n", - " 2\n", - " 5\n", - " 2\n", - " 5\n", - " 5\n", + " 3\n", " 0\n", " 2\n", + " 0\n", + " 0\n", + " 3\n", + " 0\n", + " 3\n", " 2\n", " \n", " \n", @@ -2827,11 +2849,11 @@ "
" ], "text/plain": [ - "\"parents\" nvals size dtype format\n", - "graphblas.Vector 12 12 INT32 full\n", - "-----------------------------------------\n", + "\"parents\" nvals size dtype format\n", + "gb.Vector 12 12 INT64 full\n", + "-------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", - " 0 0 2 2 2 5 2 5 5 0 2 2" + " 0 0 2 3 0 2 0 0 3 0 3 2" ] }, "execution_count": 35, @@ -2973,7 +2995,7 @@ { "data": { "text/plain": [ - "array([ 7, 1, 10, 4, 11, 0, 8, 5, 6, 3, 9, 2])" + "array([ 8, 1, 7, 2, 9, 11, 5, 3, 4, 0, 6, 10])" ] }, "execution_count": 40, @@ -3042,9 +3064,20 @@ "tags": [] }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_20958/2236542675.py:2: DeprecationWarning: \n", + "\n", + "The scipy.sparse array containers will be used instead of matrices\n", + "in Networkx 3.0. Use `from_scipy_sparse_array` instead.\n", + " G_perm2 = nx.convert_matrix.from_scipy_sparse_matrix(AAA_sci)\n" + ] + }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -3153,7 +3186,7 @@ "
parents
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3162,7 +3195,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
1212INT32INT64full
\n", @@ -3203,28 +3236,28 @@ " \n", " \n", " 0\n", - " 1\n", - " 2\n", - " 1\n", - " 2\n", " 0\n", - " 0\n", - " 1\n", - " 2\n", " 2\n", + " 0\n", " 2\n", + " 0\n", " 2\n", + " 7\n", + " 0\n", + " 0\n", + " 7\n", + " 7\n", " \n", " \n", "\n", "
" ], "text/plain": [ - "\"parents\" nvals size dtype format\n", - "graphblas.Vector 12 12 INT32 full\n", - "-----------------------------------------\n", + "\"parents\" nvals size dtype format\n", + "gb.Vector 12 12 INT64 full\n", + "-------------------------------------\n", " 0 1 2 3 4 5 6 7 8 9 10 11\n", - " 0 1 2 1 2 0 0 1 2 2 2 2" + " 0 0 2 0 2 0 2 7 0 0 7 7" ] }, "execution_count": 44, @@ -3300,7 +3333,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/notebooks/Operators.ipynb b/notebooks/Operators.ipynb index c2b77fffd..170bf96bb 100644 --- a/notebooks/Operators.ipynb +++ b/notebooks/Operators.ipynb @@ -233,19 +233,19 @@ { "data": { "text/plain": [ - "{'FC32': 'FC32',\n", - " 'FC64': 'FC64',\n", - " 'BOOL': 'BOOL',\n", - " 'FP32': 'FP32',\n", - " 'FP64': 'FP64',\n", - " 'INT16': 'INT16',\n", - " 'INT32': 'INT32',\n", - " 'INT64': 'INT64',\n", - " 'INT8': 'INT8',\n", - " 'UINT16': 'UINT16',\n", - " 'UINT32': 'UINT32',\n", - " 'UINT64': 'UINT64',\n", - " 'UINT8': 'UINT8'}" + "{FC32: FC32,\n", + " FC64: FC64,\n", + " BOOL: BOOL,\n", + " FP32: FP32,\n", + " FP64: FP64,\n", + " INT16: INT16,\n", + " INT32: INT32,\n", + " INT64: INT64,\n", + " INT8: INT8,\n", + " UINT16: UINT16,\n", + " UINT32: UINT32,\n", + " UINT64: UINT64,\n", + " UINT8: UINT8}" ] }, "execution_count": 11, @@ -329,7 +329,7 @@ { "data": { "text/plain": [ - "'INT64'" + "INT64" ] }, "execution_count": 14, @@ -350,7 +350,7 @@ { "data": { "text/plain": [ - "'INT64'" + "INT64" ] }, "execution_count": 15, @@ -434,7 +434,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 19, @@ -578,19 +578,19 @@ { "data": { "text/plain": [ - "{'FC32': 'FC32',\n", - " 'FC64': 'FC64',\n", - " 'FP32': 'FP32',\n", - " 'FP64': 'FP64',\n", - " 'BOOL': 'FP32',\n", - " 'INT8': 'FP32',\n", - " 'INT16': 'FP32',\n", - " 'UINT8': 'FP32',\n", - " 'UINT16': 'FP32',\n", - " 'INT32': 'FP64',\n", - " 'INT64': 'FP64',\n", - " 'UINT32': 'FP64',\n", - " 'UINT64': 'FP64'}" + "{FC32: FC32,\n", + " FC64: FC64,\n", + " FP32: FP32,\n", + " FP64: FP64,\n", + " BOOL: FP32,\n", + " INT8: FP32,\n", + " INT16: FP32,\n", + " UINT8: FP32,\n", + " UINT16: FP32,\n", + " INT32: FP64,\n", + " INT64: FP64,\n", + " UINT32: FP64,\n", + " UINT64: FP64}" ] }, "execution_count": 25, @@ -700,18 +700,18 @@ { "data": { "text/plain": [ - "{'FC32': 'FC32',\n", - " 'FC64': 'FC64',\n", - " 'FP32': 'FP32',\n", - " 'FP64': 'FP64',\n", - " 'INT16': 'INT16',\n", - " 'INT32': 'INT32',\n", - " 'INT64': 'INT64',\n", - " 'INT8': 'INT8',\n", - " 'UINT16': 'UINT16',\n", - " 'UINT32': 'UINT32',\n", - " 'UINT64': 'UINT64',\n", - " 'UINT8': 'UINT8'}" + "{FC32: FC32,\n", + " FC64: FC64,\n", + " FP32: FP32,\n", + " FP64: FP64,\n", + " INT16: INT16,\n", + " INT32: INT32,\n", + " INT64: INT64,\n", + " INT8: INT8,\n", + " UINT16: UINT16,\n", + " UINT32: UINT32,\n", + " UINT64: UINT64,\n", + " UINT8: UINT8}" ] }, "execution_count": 30, @@ -732,18 +732,18 @@ { "data": { "text/plain": [ - "{'FC32': 0j,\n", - " 'FC64': 0j,\n", - " 'FP32': 0.0,\n", - " 'FP64': 0.0,\n", - " 'INT16': 0,\n", - " 'INT32': 0,\n", - " 'INT64': 0,\n", - " 'INT8': 0,\n", - " 'UINT16': 0,\n", - " 'UINT32': 0,\n", - " 'UINT64': 0,\n", - " 'UINT8': 0}" + "{FC32: 0j,\n", + " FC64: 0j,\n", + " FP32: 0.0,\n", + " FP64: 0.0,\n", + " INT16: 0,\n", + " INT32: 0,\n", + " INT64: 0,\n", + " INT8: 0,\n", + " UINT16: 0,\n", + " UINT32: 0,\n", + " UINT64: 0,\n", + " UINT8: 0}" ] }, "execution_count": 31, @@ -910,16 +910,16 @@ { "data": { "text/plain": [ - "{'FP32': 'FP32',\n", - " 'FP64': 'FP64',\n", - " 'INT16': 'INT16',\n", - " 'INT32': 'INT32',\n", - " 'INT64': 'INT64',\n", - " 'INT8': 'INT8',\n", - " 'UINT16': 'UINT16',\n", - " 'UINT32': 'UINT32',\n", - " 'UINT64': 'UINT64',\n", - " 'UINT8': 'UINT8'}" + "{FP32: FP32,\n", + " FP64: FP64,\n", + " INT16: INT16,\n", + " INT32: INT32,\n", + " INT64: INT64,\n", + " INT8: INT8,\n", + " UINT16: UINT16,\n", + " UINT32: UINT32,\n", + " UINT64: UINT64,\n", + " UINT8: UINT8}" ] }, "execution_count": 37, @@ -1127,7 +1127,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/notebooks/repr_demo.ipynb b/notebooks/repr_demo.ipynb index dedd7046c..5a85828c6 100644 --- a/notebooks/repr_demo.ipynb +++ b/notebooks/repr_demo.ipynb @@ -107,15 +107,17 @@ "
v0
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
format
35INT64bitmap
\n", "
\n", @@ -158,9 +160,9 @@ "
" ], "text/plain": [ - "\"v_0\" nvals size dtype\n", - "graphblas.Vector 3 5 INT64\n", - "---------------------------------\n", + "\"v_0\" nvals size dtype format\n", + "gb.Vector 3 5 INT64 bitmap\n", + "-------------------------------------\n", " 0 1 2 3 4\n", " 0 1 2" ] @@ -265,15 +267,17 @@ "
vhuge
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
format
29007199254740992INT64sparse
\n", "
\n", @@ -348,9 +352,9 @@ "
" ], "text/plain": [ - "\"v_huge\" nvals size dtype\n", - "graphblas.Vector 2 9007199254740992 INT64\n", - "---------------------------------------------\n", + "\"v_huge\" nvals size dtype format\n", + "gb.Vector 2 9007199254740992 INT64 sparse\n", + "-------------------------------------------------\n", " 0 1 2 3 \\\n", " 0 \n", "\n", @@ -466,17 +470,19 @@ "
M0
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
dtype
format
445INT64bitmapr
\n", "
\n", @@ -543,9 +549,9 @@ "
" ], "text/plain": [ - "\"M_0\" nvals nrows ncols dtype\n", - "graphblas.Matrix 4 4 5 INT64\n", - "-----------------------------------------\n", + "\"M_0\" nvals nrows ncols dtype format\n", + "gb.Matrix 4 4 5 INT64 bitmapr\n", + "----------------------------------------------\n", " 0 1 2 3 4\n", "0 \n", "1 0 2 \n", @@ -646,17 +652,19 @@ "
M0.T
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.TransposedMatrix
gb.TransposedMatrix
nvals
nrows
ncols
dtype
format
454INT64bitmapc
\n", "
\n", @@ -725,9 +733,9 @@ "
" ], "text/plain": [ - "\"M_0.T\" nvals nrows ncols dtype\n", - "graphblas.TransposedMatrix 4 5 4 INT64\n", - "---------------------------------------------------\n", + "\"M_0.T\" nvals nrows ncols dtype format\n", + "gb.TransposedMatrix 4 5 4 INT64 bitmapc\n", + "--------------------------------------------------------\n", " 0 1 2 3\n", "0 0 \n", "1 1\n", @@ -839,17 +847,19 @@ " \n", "
StructuralMask\n",
        "of\n",
-       "graphblas.Matrix
\n", + "gb.Matrix\n", "
nvals
\n", "
nrows
\n", "
ncols
\n", "
dtype
\n", + "
format
\n", " \n", " \n", " 4\n", " 4\n", " 5\n", " INT64\n", + " bitmapr\n", " \n", "\n", "\n", @@ -916,10 +926,10 @@ "" ], "text/plain": [ - "\"M_0.S\" nvals nrows ncols dtype\n", - "StructuralMask \n", - "of graphblas.Matrix 4 4 5 INT64\n", - "--------------------------------------------\n", + "\"M_0.S\" nvals nrows ncols dtype format\n", + "StructuralMask\n", + "of gb.Matrix 4 4 5 INT64 bitmapr\n", + "---------------------------------------------------\n", " 0 1 2 3 4\n", "0 \n", "1 1 1 \n", @@ -1021,17 +1031,19 @@ " \n", "
ComplementedValueMask\n",
        "of\n",
-       "graphblas.Matrix
\n", + "gb.Matrix\n", "
nvals
\n", "
nrows
\n", "
ncols
\n", "
dtype
\n", + "
format
\n", " \n", " \n", " 4\n", " 4\n", " 5\n", " INT64\n", + " bitmapr\n", " \n", "\n", "\n", @@ -1098,10 +1110,10 @@ "" ], "text/plain": [ - "\"~M_0.V\" nvals nrows ncols dtype\n", + "\"~M_0.V\" nvals nrows ncols dtype format\n", "ComplementedValueMask\n", - "of graphblas.Matrix 4 4 5 INT64\n", - "-------------------------------------------------\n", + "of gb.Matrix 4 4 5 INT64 bitmapr\n", + "----------------------------------------------------------\n", " 0 1 2 3 4\n", "0 \n", "1 1 0 \n", @@ -1133,7 +1145,7 @@ { "data": { "text/html": [ - "
graphblas.VectorExpression:
\n", + "
gb.VectorExpression:
\n", "\n", " \n", " \n", @@ -1218,20 +1230,22 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
M0
\n", + "
M0
\n", "
M0.mxv(v0, op=semiring.plus_times[INT64])
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
dtype
format
445INT64bitmapr
\n", "
\n", @@ -1367,18 +1381,20 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
v0
\n", + "
v0
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
format
35INT64bitmap
\n", "
\n", @@ -1418,12 +1434,141 @@ " \n", " \n", "\n", + "

\n", + "\n", + "
Result
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gb.Vector
nvals
size
dtype
format
24INT64bitmap
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123
26
\n", "
Do expr.new() or other << expr to calculate the expression.
" ], "text/plain": [ - "graphblas.VectorExpression size dtype\n", + "gb.VectorExpression size dtype\n", "M_0.mxv(v_0, op=semiring.plus_times[INT64]) 4 INT64\n", "\n", + "\"Result\" nvals size dtype format\n", + "gb.Vector 2 4 INT64 bitmap\n", + "-------------------------------------\n", + " 0 1 2 3\n", + " 2 6\n", + "\n", "Do expr.new() or other << expr to calculate the expression." ] }, @@ -1444,7 +1589,7 @@ { "data": { "text/html": [ - "
graphblas.MatrixExpression:
\n", + "
gb.MatrixExpression:
\n", "\n", " \n", " \n", @@ -1531,20 +1676,22 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
M0
\n", + "
M0
\n", "
M0.mxm(M0.T, op=semiring.min_plus[INT64])
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
dtype
format
445INT64bitmapr
\n", "
\n", @@ -1680,20 +1827,22 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
M0.T
\n", + "
M0.T
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.TransposedMatrix
gb.TransposedMatrix
nvals
nrows
ncols
dtype
format
454INT64bitmapc
\n", "
\n", @@ -1759,12 +1908,167 @@ " \n", " \n", "\n", + "

\n", + "\n", + "
Result
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gb.Matrix
nvals
nrows
ncols
dtype
format
244INT64bitmapr
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123
0
10
2
32
\n", "
Do expr.new() or other << expr to calculate the expression.
" ], "text/plain": [ - "graphblas.MatrixExpression nrows ncols dtype\n", + "gb.MatrixExpression nrows ncols dtype\n", "M_0.mxm(M_0.T, op=semiring.min_plus[INT64]) 4 4 INT64\n", "\n", + "\"Result\" nvals nrows ncols dtype format\n", + "gb.Matrix 2 4 4 INT64 bitmapr\n", + "----------------------------------------------\n", + " 0 1 2 3\n", + "0 \n", + "1 0 \n", + "2 \n", + "3 2\n", + "\n", "Do expr.new() or other << expr to calculate the expression." ] }, @@ -1785,7 +2089,7 @@ { "data": { "text/html": [ - "
graphblas.VectorExpression:
\n", + "
gb.VectorExpression:
\n", "\n", " \n", " \n", @@ -1870,18 +2174,20 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
v0
\n", + "
v0
\n", "
v0.apply(binary.times[INT64], right=10)
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Vector
gb.Vector
nvals
size
dtype
format
35INT64bitmap
\n", "
\n", @@ -1921,10 +2227,10 @@ " \n", " \n", "\n", - "
10
\n", + "
\n", "\n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1934,12 +2240,143 @@ " \n", "
graphblas.Scalar
gb.Scalar
value
dtype
\n", "
\n", - "
Do expr.new() or other << expr to calculate the expression." + "
\n", + "\n", + "
Result
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gb.Vector
nvals
size
dtype
format
35INT64bitmap
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01234
01020
\n", + "
Do expr.new() or other << expr to calculate the expression." ], "text/plain": [ - "graphblas.VectorExpression size dtype\n", + "gb.VectorExpression size dtype\n", "v_0.apply(binary.times[INT64], right=10) 5 INT64\n", "\n", + "\"Result\" nvals size dtype format\n", + "gb.Vector 3 5 INT64 bitmap\n", + "-------------------------------------\n", + " 0 1 2 3 4\n", + " 0 10 20\n", + "\n", "Do expr.new() or other << expr to calculate the expression." ] }, @@ -1960,7 +2397,7 @@ { "data": { "text/html": [ - "
graphblas.ScalarExpression:
\n", + "
gb.ScalarExpression:
\n", "\n", " \n", " \n", @@ -2043,20 +2480,22 @@ " padding-bottom: 0px;\n", "}\n", "\n", - "
M0
\n", + "
M0
\n", "
M0.reduce_scalar(monoid.plus[INT64])
\n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", "
graphblas.Matrix
gb.Matrix
nvals
nrows
ncols
dtype
format
445INT64bitmapr
\n", "
\n", @@ -2120,12 +2559,28 @@ " \n", " \n", "\n", - "
Do expr.new() or other << expr to calculate the expression." + "
Result
\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gb.Scalar
value
dtype
6INT64
\n", + "
\n", + "
Do expr.new() or other << expr to calculate the expression." ], "text/plain": [ - "graphblas.ScalarExpression dtype\n", + "gb.ScalarExpression dtype\n", "M_0.reduce_scalar(monoid.plus[INT64]) INT64\n", "\n", + "\"Result\" value dtype\n", + "gb.Scalar 6 INT64\n", + "\n", "Do expr.new() or other << expr to calculate the expression." ] }, @@ -2148,7 +2603,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -2162,7 +2617,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.9.12" } }, "nbformat": 4,