From 00423dc55f22878f9359c346df6226bea4445186 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 19 Jan 2018 01:28:25 +0100 Subject: [PATCH 1/9] Add tests for scipy spmatrices from the left. --- requirements.txt | 2 +- sparse/coo.py | 115 ++++----------------------------------- sparse/tests/test_coo.py | 14 +++++ 3 files changed, 25 insertions(+), 106 deletions(-) diff --git a/requirements.txt b/requirements.txt index df1123ff..f1802810 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -numpy +numpy >= 1.13 scipy >= 0.19 six diff --git a/sparse/coo.py b/sparse/coo.py index f0b5f0b1..cb509ed7 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -7,6 +7,7 @@ import numpy as np import scipy.sparse +from numpy.lib.mixins import NDArrayOperatorsMixin from .slicing import normalize_index from .utils import _zero_of_dtype @@ -20,7 +21,7 @@ pass -class COO(object): +class COO(NDArrayOperatorsMixin): """ A sparse multidimensional array. @@ -1221,6 +1222,10 @@ def __rmatmul__(self, other): return NotImplemented def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + out = kwargs.pop('out', None) + if out is not None: + return NotImplemented + if method == '__call__': return COO._elemwise(ufunc, *inputs, **kwargs) elif method == 'reduce': @@ -1522,105 +1527,6 @@ def sum_duplicates(self): self.coords = coords self.has_duplicates = False - def __add__(self, other): - return self.elemwise(operator.add, other) - - def __radd__(self, other): - return self.elemwise(_reverse_self_other(operator.add), other) - - def __neg__(self): - return self.elemwise(operator.neg) - - def __sub__(self, other): - return self.elemwise(operator.sub, other) - - def __rsub__(self, other): - return self.elemwise(_reverse_self_other(operator.sub), other) - - def __mul__(self, other): - return self.elemwise(operator.mul, other) - - def __rmul__(self, other): - return self.elemwise(_reverse_self_other(operator.mul), other) - - def __truediv__(self, other): - return self.elemwise(operator.truediv, other) - - def __rtruediv__(self, other): - return self.elemwise(_reverse_self_other(operator.truediv), other) - - def __floordiv__(self, other): - return self.elemwise(operator.floordiv, other) - - def __rfloordiv__(self, other): - return self.elemwise(_reverse_self_other(operator.floordiv), other) - - __div__ = __truediv__ - __rdiv__ = __rtruediv__ - - def __pow__(self, other): - return self.elemwise(operator.pow, other) - - def __rpow__(self, other): - return self.elemwise(_reverse_self_other(operator.pow), other) - - def __mod__(self, other): - return self.elemwise(operator.mod, other) - - def __rmod__(self, other): - return self.elemwise(_reverse_self_other(operator.mod), other) - - def __and__(self, other): - return self.elemwise(operator.and_, other) - - def __rand__(self, other): - return self.elemwise(_reverse_self_other(operator.and_), other) - - def __xor__(self, other): - return self.elemwise(operator.xor, other) - - def __rxor__(self, other): - return self.elemwise(_reverse_self_other(operator.xor), other) - - def __or__(self, other): - return self.elemwise(operator.or_, other) - - def __ror__(self, other): - return self.elemwise(_reverse_self_other(operator.or_), other) - - def __invert__(self): - return self.elemwise(operator.invert) - - def __gt__(self, other): - return self.elemwise(operator.gt, other) - - def __ge__(self, other): - return self.elemwise(operator.ge, other) - - def __lt__(self, other): - return self.elemwise(operator.lt, other) - - def __le__(self, other): - return self.elemwise(operator.le, other) - - def __eq__(self, other): - return self.elemwise(operator.eq, other) - - def __ne__(self, other): - return self.elemwise(operator.ne, other) - - def __lshift__(self, other): - return self.elemwise(operator.lshift, other) - - def __rlshift__(self, other): - return self.elemwise(_reverse_self_other(operator.lshift), other) - - def __rshift__(self, other): - return self.elemwise(operator.rshift, other) - - def __rrshift__(self, other): - return self.elemwise(_reverse_self_other(operator.rshift), other) - @staticmethod def _elemwise(func, *args, **kwargs): if len(args) == 0: @@ -1628,7 +1534,7 @@ def _elemwise(func, *args, **kwargs): self = args[0] if isinstance(self, scipy.sparse.spmatrix): - self = COO.from_numpy(self) + self = COO.from_scipy_sparse(self) elif np.isscalar(self) or (isinstance(self, np.ndarray) and self.ndim == 0): func = partial(func, self) @@ -1712,7 +1618,7 @@ def broadcast_to(self, shape): return COO(coords, data, shape=result_shape, has_duplicates=self.has_duplicates, sorted=self.sorted) - def __abs__(self): + def abs(self): """ Calculate the absolute value element-wise. @@ -1722,8 +1628,6 @@ def __abs__(self): """ return self.elemwise(abs) - abs = __abs__ - def exp(self, out=None): """ Calculate the exponential of all elements in the array. @@ -2464,7 +2368,8 @@ def _elemwise_binary(func, self, other, *args, **kwargs): self_zero = _zero_of_dtype(self.dtype) other_zero = _zero_of_dtype(other.dtype) - func_zero = _zero_of_dtype(func(self_zero, other_zero, *args, **kwargs).dtype) + func_value = func(self_zero, other_zero, *args, **kwargs) + func_zero = _zero_of_dtype(np.dtype(func_value)) if check and func(self_zero, other_zero, *args, **kwargs) != func_zero: raise ValueError("Performing this operation would produce " "a dense result: %s" % str(func)) diff --git a/sparse/tests/test_coo.py b/sparse/tests/test_coo.py index f5883d70..28772976 100644 --- a/sparse/tests/test_coo.py +++ b/sparse/tests/test_coo.py @@ -256,6 +256,20 @@ def test_op_scipy_sparse(func): assert_eq(func(x, y), func(xs, ys)) +@pytest.mark.parametrize('func', [ + operator.mul, operator.add, operator.sub, operator.gt, + operator.lt, operator.ne +]) +def test_op_scipy_sparse_left(func): + ys = sparse.random((3, 4), density=0.5) + x = sparse.random((3, 4), density=0.5).todense() + + xs = scipy.sparse.csr_matrix(x) + y = ys.todense() + + assert_eq(func(x, y), func(xs, ys)) + + @pytest.mark.parametrize('func, scalar', [ (operator.mul, 5), (operator.add, 0), From 08e559b251e5b78bb4a73bf7a7dc18e336479840 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 19 Jan 2018 01:37:18 +0100 Subject: [PATCH 2/9] Fix failing tests. --- sparse/tests/test_coo.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sparse/tests/test_coo.py b/sparse/tests/test_coo.py index 28772976..b6a2fa44 100644 --- a/sparse/tests/test_coo.py +++ b/sparse/tests/test_coo.py @@ -257,8 +257,12 @@ def test_op_scipy_sparse(func): @pytest.mark.parametrize('func', [ - operator.mul, operator.add, operator.sub, operator.gt, - operator.lt, operator.ne + operator.mul, + operator.add, + operator.sub, + pytest.mark.xfail(operator.gt, reason='Scipy sparse doesn\'t support this yet.'), + pytest.mark.xfail(operator.lt, reason='Scipy sparse doesn\'t support this yet.'), + pytest.mark.xfail(operator.ne, reason='Scipy sparse doesn\'t support this yet.'), ]) def test_op_scipy_sparse_left(func): ys = sparse.random((3, 4), density=0.5) From e36bc8c0329a8b121bee6d3d295d901ac5c08fc6 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 19 Jan 2018 10:11:38 +0100 Subject: [PATCH 3/9] Update docs. --- docs/generated/sparse.COO.rst | 2 +- docs/user_manual/operations.rst | 2 +- docs/user_manual/operations/elemwise.rst | 7 ++-- .../operations/{basic.rst => operators.rst} | 28 +++++++++++++--- sparse/coo.py | 15 +++++---- sparse/tests/test_coo.py | 32 ------------------- 6 files changed, 38 insertions(+), 48 deletions(-) rename docs/user_manual/operations/{basic.rst => operators.rst} (79%) diff --git a/docs/generated/sparse.COO.rst b/docs/generated/sparse.COO.rst index 86b12545..078b2846 100644 --- a/docs/generated/sparse.COO.rst +++ b/docs/generated/sparse.COO.rst @@ -6,7 +6,7 @@ COO .. autoclass:: COO .. note:: - :obj:`COO` objects also support :doc:`operators <../user_manual/operations/basic>` + :obj:`COO` objects also support :doc:`operators <../user_manual/operations/operators>` and :doc:`indexing <../user_manual/operations/indexing>` .. rubric:: Attributes diff --git a/docs/user_manual/operations.rst b/docs/user_manual/operations.rst index 3794a698..82f98c08 100644 --- a/docs/user_manual/operations.rst +++ b/docs/user_manual/operations.rst @@ -8,7 +8,7 @@ common operations `_ .. toctree:: :maxdepth: 2 - operations/basic + operations/operators operations/elemwise operations/reductions operations/indexing diff --git a/docs/user_manual/operations/elemwise.rst b/docs/user_manual/operations/elemwise.rst index b0c2a3f9..b54e26fa 100644 --- a/docs/user_manual/operations/elemwise.rst +++ b/docs/user_manual/operations/elemwise.rst @@ -26,14 +26,15 @@ However, the following are all unsupported and will raise a :obj:`ValueError`: np.log(x) Notice that you can apply any unary or binary :obj:`numpy.ufunc` to :obj:`COO` -arrays, :obj:`scipy.sparse.spmatrix` objects and scalars and it will work so -long as the result is not dense. +arrays, and :obj:`numpy.ndarray` objects and scalars and it will work so +long as the result is not dense. When applying to :obj:`numpy.ndarray` objects, +we check that operating on the array with zero would always produce a zero. :obj:`COO.elemwise` ------------------- This function allows you to apply any arbitrary unary or binary function where the first object is :obj:`COO`, and the second is a scalar, :obj:`COO`, or -a :obj:`scipy.sparse.spmatrix`. For example, the following will add two +a :obj:`numpy.ndarray`. For example, the following will add two :obj:`COO` objects: .. code-block:: python diff --git a/docs/user_manual/operations/basic.rst b/docs/user_manual/operations/operators.rst similarity index 79% rename from docs/user_manual/operations/basic.rst rename to docs/user_manual/operations/operators.rst index c47913f3..47c4c635 100644 --- a/docs/user_manual/operations/basic.rst +++ b/docs/user_manual/operations/operators.rst @@ -1,9 +1,9 @@ .. currentmodule:: sparse -Basic Operations -================ +Operators +========= :obj:`COO` objects can have a number of operators applied to them. They support -operations with scalars, :obj:`scipy.sparse.spmatrix` objects, and other +operations with scalars, :obj:`numpy.ndarray` objects, and other :obj:`COO` objects. For example, to get the sum of two :obj:`COO` objects, you would do the following: @@ -53,6 +53,26 @@ If densification is needed, it must be explicit. In other words, you must call :obj:`COO.todense` on the :obj:`COO` object. If both operands are :obj:`COO`, both must be densified. +Operations with :obj:`numpy.ndarray` +------------------------------------ +Certain operations with :obj:`numpy.ndarray` are also supported. For example, +the following are all allowed if :code:`x` is a :obj:`numpy.ndarray` and +:code:`(x == 0).all()` evaluates to :code:`True`: + +.. code-block:: python + + x + y + x - y + +The following is true so long as there are no infinities or NaNs in :code:`x`: + +.. code-block:: python + + x * y + +In general, if operating on the :code:`numpy.ndarray` with a zero would produce +all-zeros then the operation is supported. + Broadcasting ------------ All binary operators support :obj:`broadcasting `. @@ -67,7 +87,7 @@ will raise a :obj:`ValueError`. Full List of Operators ---------------------- Here, :code:`x` and :code:`y` can be :obj:`COO` arrays, -:obj:`scipy.sparse.spmatrix` objects or scalars, keeping in mind :ref:`auto +:obj:`numpy.ndarray` objects or scalars, keeping in mind :ref:`auto densification rules `. The following operators are supported: * Basic algebraic operations diff --git a/sparse/coo.py b/sparse/coo.py index cb509ed7..f1b3e3f6 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -1533,10 +1533,8 @@ def _elemwise(func, *args, **kwargs): return func() self = args[0] - if isinstance(self, scipy.sparse.spmatrix): - self = COO.from_scipy_sparse(self) - elif np.isscalar(self) or (isinstance(self, np.ndarray) - and self.ndim == 0): + if np.isscalar(self) or (isinstance(self, np.ndarray) + and self.ndim == 0): func = partial(func, self) other = args[1] if isinstance(other, scipy.sparse.spmatrix): @@ -1547,8 +1545,6 @@ def _elemwise(func, *args, **kwargs): return _elemwise_unary(func, self, *args[1:], **kwargs) else: other = args[1] - if isinstance(other, scipy.sparse.spmatrix): - other = COO.from_scipy_sparse(other) if isinstance(other, COO) or isinstance(other, np.ndarray): return _elemwise_binary(func, self, other, *args[2:], **kwargs) @@ -1565,7 +1561,7 @@ def elemwise(self, func, *args, **kwargs): The function to apply to one or two arguments. args : tuple, optional The extra arguments to pass to the function. If :code:`args[0]` is a COO object, - a scipy.sparse.spmatrix or a scalar; the function will be treated as a binary + or a scalar; the function will be treated as a binary function. Otherwise, it will be treated as a unary function. kwargs : dict, optional The kwargs to pass to the function. @@ -1584,6 +1580,11 @@ def elemwise(self, func, *args, **kwargs): -------- :obj:`numpy.ufunc` : A similar Numpy construct. Note that any :code:`ufunc` can be used as the :code:`func` input to this function. + + Notes + ----- + In the future, this function may support functions of more than two arguments. Therefore, + it is best to pass in any additional arguments as keyword arguments. """ return COO._elemwise(func, self, *args, **kwargs) diff --git a/sparse/tests/test_coo.py b/sparse/tests/test_coo.py index b6a2fa44..d270af42 100644 --- a/sparse/tests/test_coo.py +++ b/sparse/tests/test_coo.py @@ -242,38 +242,6 @@ def test_auto_densification_fails(func): func(xs, ys) -@pytest.mark.parametrize('func', [ - operator.mul, operator.add, operator.sub, operator.gt, - operator.lt, operator.ne -]) -def test_op_scipy_sparse(func): - xs = sparse.random((3, 4), density=0.5) - y = sparse.random((3, 4), density=0.5).todense() - - ys = scipy.sparse.csr_matrix(y) - x = xs.todense() - - assert_eq(func(x, y), func(xs, ys)) - - -@pytest.mark.parametrize('func', [ - operator.mul, - operator.add, - operator.sub, - pytest.mark.xfail(operator.gt, reason='Scipy sparse doesn\'t support this yet.'), - pytest.mark.xfail(operator.lt, reason='Scipy sparse doesn\'t support this yet.'), - pytest.mark.xfail(operator.ne, reason='Scipy sparse doesn\'t support this yet.'), -]) -def test_op_scipy_sparse_left(func): - ys = sparse.random((3, 4), density=0.5) - x = sparse.random((3, 4), density=0.5).todense() - - xs = scipy.sparse.csr_matrix(x) - y = ys.todense() - - assert_eq(func(x, y), func(xs, ys)) - - @pytest.mark.parametrize('func, scalar', [ (operator.mul, 5), (operator.add, 0), From e38f548ecff90fe2e016eff0b7540de1a00b0eb4 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 19 Jan 2018 10:18:36 +0100 Subject: [PATCH 4/9] Add back pure Python abs support. --- sparse/coo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sparse/coo.py b/sparse/coo.py index f1b3e3f6..ef92b17d 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -1629,6 +1629,8 @@ def abs(self): """ return self.elemwise(abs) + __abs__ = abs + def exp(self, out=None): """ Calculate the exponential of all elements in the array. From 3951ac5b2537b185e643704081f4b94678c612f6 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Tue, 23 Jan 2018 16:13:50 +0100 Subject: [PATCH 5/9] Drop Scipy op support --- sparse/coo.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sparse/coo.py b/sparse/coo.py index ef92b17d..f7978ea4 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -1537,8 +1537,6 @@ def _elemwise(func, *args, **kwargs): and self.ndim == 0): func = partial(func, self) other = args[1] - if isinstance(other, scipy.sparse.spmatrix): - other = COO.from_scipy_sparse(other) return _elemwise_unary(func, other, *args[2:], **kwargs) if len(args) == 1: From 4809648c894c6ac2bc6df84d0b5921c5f3690f0f Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Thu, 25 Jan 2018 13:45:03 +0100 Subject: [PATCH 6/9] Add Scipy sparse support back. --- sparse/coo.py | 12 ++++++++---- sparse/tests/test_coo.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/sparse/coo.py b/sparse/coo.py index f7978ea4..22b048c8 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -1539,11 +1539,17 @@ def _elemwise(func, *args, **kwargs): other = args[1] return _elemwise_unary(func, other, *args[2:], **kwargs) + if isinstance(self, scipy.sparse.spmatrix): + self = COO.from_scipy_sparse(self) + if len(args) == 1: return _elemwise_unary(func, self, *args[1:], **kwargs) else: other = args[1] + if isinstance(other, scipy.sparse.spmatrix): + other = COO.from_scipy_sparse(other) + if isinstance(other, COO) or isinstance(other, np.ndarray): return _elemwise_binary(func, self, other, *args[2:], **kwargs) else: @@ -1625,9 +1631,7 @@ def abs(self): -------- :obj:`numpy.absolute` : NumPy equivalent ufunc. """ - return self.elemwise(abs) - - __abs__ = abs + return self.elemwise(np.abs) def exp(self, out=None): """ @@ -1909,7 +1913,7 @@ def astype(self, dtype, out=None): actually supported. """ assert out is None - return self.elemwise(np.ndarray.astype, dtype) + return self.elemwise(np.ndarray.astype, dtype=dtype) def maybe_densify(self, max_size=1000, min_density=0.25): """ diff --git a/sparse/tests/test_coo.py b/sparse/tests/test_coo.py index d270af42..ae3889ca 100644 --- a/sparse/tests/test_coo.py +++ b/sparse/tests/test_coo.py @@ -894,6 +894,38 @@ def test_scipy_sparse_interaction(scipy_format): assert_eq(sp, coo) +@pytest.mark.parametrize('func', [ + operator.mul, operator.add, operator.sub, operator.gt, + operator.lt, operator.ne +]) +def test_op_scipy_sparse(func): + xs = sparse.random((3, 4), density=0.5) + y = sparse.random((3, 4), density=0.5).todense() + + ys = scipy.sparse.csr_matrix(y) + x = xs.todense() + + assert_eq(func(x, y), func(xs, ys)) + + +@pytest.mark.parametrize('func', [ + operator.add, + operator.sub, + pytest.mark.xfail(operator.mul, reason='Scipy sparse auto-densifies in this case.'), + pytest.mark.xfail(operator.gt, reason='Scipy sparse doesn\'t support this yet.'), + pytest.mark.xfail(operator.lt, reason='Scipy sparse doesn\'t support this yet.'), + pytest.mark.xfail(operator.ne, reason='Scipy sparse doesn\'t support this yet.'), +]) +def test_op_scipy_sparse_left(func): + ys = sparse.random((3, 4), density=0.5) + x = sparse.random((3, 4), density=0.5).todense() + + xs = scipy.sparse.csr_matrix(x) + y = ys.todense() + + assert_eq(func(x, y), func(xs, ys)) + + def test_cache_csr(): x = sparse.random((10, 5), density=0.5).todense() s = COO(x, cache=True) From 5ccdbaa93113e87c07e270478cc75944d8dda487 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Thu, 25 Jan 2018 16:41:22 +0100 Subject: [PATCH 7/9] Update docs. --- docs/user_manual/operations/operators.rst | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/user_manual/operations/operators.rst b/docs/user_manual/operations/operators.rst index 47c4c635..1372854b 100644 --- a/docs/user_manual/operations/operators.rst +++ b/docs/user_manual/operations/operators.rst @@ -73,6 +73,26 @@ The following is true so long as there are no infinities or NaNs in :code:`x`: In general, if operating on the :code:`numpy.ndarray` with a zero would produce all-zeros then the operation is supported. +Operations with :obj:`scipy.sparse.spmatrix` +-------------------------------------------- +Certain operations with :obj:`scipy.sparse.spmatrix` are also supported. +For example, the following are all allowed if :code:`y` is a :obj:`scipy.sparse.spmatrix`: + +.. code-block:: python + + x + y + x - y + x * y + x > y + x < y + +In general, if operating on a :code:`scipy.sparse.spmatrix` is the same as operating +on :obj:`COO`, as long as it is to the right of the operator. + +.. note:: Results are not guaranteed if :code:`x` is a :obj:`scipy.sparse.spmatrix`. + For this reason, we recommend that all Scipy sparse matrices should be explicitly + converted to :obj:`COO` before any operations. + Broadcasting ------------ All binary operators support :obj:`broadcasting `. @@ -88,7 +108,8 @@ Full List of Operators ---------------------- Here, :code:`x` and :code:`y` can be :obj:`COO` arrays, :obj:`numpy.ndarray` objects or scalars, keeping in mind :ref:`auto -densification rules `. The following operators are supported: +densification rules `. In addition, :code:`y` can also +be a :obj:`scipy.sparse.spmatrix` The following operators are supported: * Basic algebraic operations @@ -119,3 +140,5 @@ densification rules `. The following operators are supported * :obj:`operator.lshift` (:code:`x << y`) * :obj:`operator.rshift` (:code:`x >> y`) + +.. note:: In-place operators are not supported at this time. From 3a92642fbe4db2779829c0c5c8511235efdf095c Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 26 Jan 2018 21:33:03 +0100 Subject: [PATCH 8/9] Remove most .ufunc calls since Numpy doesn't have them. --- sparse/coo.py | 255 -------------------------------------------------- 1 file changed, 255 deletions(-) diff --git a/sparse/coo.py b/sparse/coo.py index 22b048c8..4a56ce05 100644 --- a/sparse/coo.py +++ b/sparse/coo.py @@ -1623,202 +1623,6 @@ def broadcast_to(self, shape): return COO(coords, data, shape=result_shape, has_duplicates=self.has_duplicates, sorted=self.sorted) - def abs(self): - """ - Calculate the absolute value element-wise. - - See also - -------- - :obj:`numpy.absolute` : NumPy equivalent ufunc. - """ - return self.elemwise(np.abs) - - def exp(self, out=None): - """ - Calculate the exponential of all elements in the array. - - See also - -------- - :obj:`numpy.exp` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.exp) - - def expm1(self, out=None): - """ - Calculate :code:`exp(x) - 1` for all elements in the array. - - See also - -------- - scipy.sparse.coo_matrix.expm1 : SciPy sparse equivalent function - :obj:`numpy.expm1` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.expm1) - - def log1p(self, out=None): - """ - Return the natural logarithm of one plus the input array, element-wise. - - Calculates :code:`log(1 + x)`. - - See also - -------- - scipy.sparse.coo_matrix.log1p : SciPy sparse equivalent function - :obj:`numpy.log1p` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.log1p) - - def sin(self, out=None): - """ - Trigonometric sine, element-wise. - - See also - -------- - scipy.sparse.coo_matrix.sin : SciPy sparse equivalent function - :obj:`numpy.sin` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.sin) - - def sinh(self, out=None): - """ - Hyperbolic sine, element-wise. - - See also - -------- - scipy.sparse.coo_matrix.sinh : SciPy sparse equivalent function - :obj:`numpy.sinh` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.sinh) - - def tan(self, out=None): - """ - Compute tangent element-wise. - - See also - -------- - scipy.sparse.coo_matrix.tan : SciPy sparse equivalent function - :obj:`numpy.tan` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - """ - assert out is None - return self.elemwise(np.tan) - - def tanh(self, out=None): - """ - Compute hyperbolic tangent element-wise. - - See also - -------- - scipy.sparse.coo_matrix.tanh : SciPy sparse equivalent function - :obj:`numpy.tanh` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.tanh) - - def sqrt(self, out=None): - """ - Return the positive square-root of an array, element-wise. - - See also - -------- - scipy.sparse.coo_matrix.sqrt : SciPy sparse equivalent function - :obj:`numpy.sqrt` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.sqrt) - - def ceil(self, out=None): - """ - Return the ceiling of the input, element-wise. - - See also - -------- - scipy.sparse.coo_matrix.ceil : SciPy sparse equivalent function - :obj:`numpy.ceil` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.ceil) - - def floor(self, out=None): - """ - Return the floor of the input, element-wise. - - See also - -------- - scipy.sparse.coo_matrix.floor : SciPy sparse equivalent function - :obj:`numpy.floor` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.floor) - def round(self, decimals=0, out=None): """ Evenly round to the given number of decimals. @@ -1837,65 +1641,6 @@ def round(self, decimals=0, out=None): assert out is None return self.elemwise(np.round, decimals) - def rint(self, out=None): - """ - Round elements of the array to the nearest integer. - - See also - -------- - scipy.sparse.coo_matrix.rint : SciPy sparse equivalent function - :obj:`numpy.rint` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.rint) - - def conj(self, out=None): - """ - Return the complex conjugate, element-wise. - - See also - -------- - conjugate : Equivalent function - scipy.sparse.coo_matrix.conj : SciPy sparse equivalent function - :obj:`numpy.conj` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.conj) - - def conjugate(self, out=None): - """ - Return the complex conjugate, element-wise. - - See also - -------- - conj : Equivalent function - scipy.sparse.coo_matrix.conjugate : SciPy sparse equivalent function - :obj:`numpy.conj` : NumPy equivalent ufunc. - :obj:`COO.elemwise`: Apply an arbitrary element-wise function to one or two - arguments. - - Notes - ----- - The :code:`out` parameter is provided just for compatibility with Numpy and isn't - actually supported. - """ - assert out is None - return self.elemwise(np.conjugate) - def astype(self, dtype, out=None): """ Copy of the array, cast to a specified type. From 316022d6d927234185277046313e43a003ea5eca Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Fri, 26 Jan 2018 21:45:11 +0100 Subject: [PATCH 9/9] Update docs. --- docs/generated/sparse.COO.abs.rst | 6 ----- docs/generated/sparse.COO.ceil.rst | 6 ----- docs/generated/sparse.COO.conj.rst | 6 ----- docs/generated/sparse.COO.conjugate.rst | 6 ----- docs/generated/sparse.COO.exp.rst | 6 ----- docs/generated/sparse.COO.expm1.rst | 6 ----- docs/generated/sparse.COO.floor.rst | 6 ----- docs/generated/sparse.COO.log1p.rst | 6 ----- docs/generated/sparse.COO.rint.rst | 6 ----- docs/generated/sparse.COO.rst | 14 ------------ docs/generated/sparse.COO.sin.rst | 6 ----- docs/generated/sparse.COO.sinh.rst | 6 ----- docs/generated/sparse.COO.sqrt.rst | 6 ----- docs/generated/sparse.COO.tan.rst | 6 ----- docs/generated/sparse.COO.tanh.rst | 6 ----- docs/user_manual/operations/elemwise.rst | 29 ++++-------------------- 16 files changed, 4 insertions(+), 123 deletions(-) delete mode 100644 docs/generated/sparse.COO.abs.rst delete mode 100644 docs/generated/sparse.COO.ceil.rst delete mode 100644 docs/generated/sparse.COO.conj.rst delete mode 100644 docs/generated/sparse.COO.conjugate.rst delete mode 100644 docs/generated/sparse.COO.exp.rst delete mode 100644 docs/generated/sparse.COO.expm1.rst delete mode 100644 docs/generated/sparse.COO.floor.rst delete mode 100644 docs/generated/sparse.COO.log1p.rst delete mode 100644 docs/generated/sparse.COO.rint.rst delete mode 100644 docs/generated/sparse.COO.sin.rst delete mode 100644 docs/generated/sparse.COO.sinh.rst delete mode 100644 docs/generated/sparse.COO.sqrt.rst delete mode 100644 docs/generated/sparse.COO.tan.rst delete mode 100644 docs/generated/sparse.COO.tanh.rst diff --git a/docs/generated/sparse.COO.abs.rst b/docs/generated/sparse.COO.abs.rst deleted file mode 100644 index 7bfba439..00000000 --- a/docs/generated/sparse.COO.abs.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.abs -======== - -.. currentmodule:: sparse - -.. automethod:: COO.abs \ No newline at end of file diff --git a/docs/generated/sparse.COO.ceil.rst b/docs/generated/sparse.COO.ceil.rst deleted file mode 100644 index e999de48..00000000 --- a/docs/generated/sparse.COO.ceil.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.ceil -========= - -.. currentmodule:: sparse - -.. automethod:: COO.ceil \ No newline at end of file diff --git a/docs/generated/sparse.COO.conj.rst b/docs/generated/sparse.COO.conj.rst deleted file mode 100644 index 39a963af..00000000 --- a/docs/generated/sparse.COO.conj.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.conj -========= - -.. currentmodule:: sparse - -.. automethod:: COO.conj \ No newline at end of file diff --git a/docs/generated/sparse.COO.conjugate.rst b/docs/generated/sparse.COO.conjugate.rst deleted file mode 100644 index 476903c1..00000000 --- a/docs/generated/sparse.COO.conjugate.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.conjugate -============== - -.. currentmodule:: sparse - -.. automethod:: COO.conjugate \ No newline at end of file diff --git a/docs/generated/sparse.COO.exp.rst b/docs/generated/sparse.COO.exp.rst deleted file mode 100644 index 7a6067ef..00000000 --- a/docs/generated/sparse.COO.exp.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.exp -======== - -.. currentmodule:: sparse - -.. automethod:: COO.exp \ No newline at end of file diff --git a/docs/generated/sparse.COO.expm1.rst b/docs/generated/sparse.COO.expm1.rst deleted file mode 100644 index 46717d78..00000000 --- a/docs/generated/sparse.COO.expm1.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.expm1 -========== - -.. currentmodule:: sparse - -.. automethod:: COO.expm1 \ No newline at end of file diff --git a/docs/generated/sparse.COO.floor.rst b/docs/generated/sparse.COO.floor.rst deleted file mode 100644 index 7ff8a946..00000000 --- a/docs/generated/sparse.COO.floor.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.floor -========== - -.. currentmodule:: sparse - -.. automethod:: COO.floor \ No newline at end of file diff --git a/docs/generated/sparse.COO.log1p.rst b/docs/generated/sparse.COO.log1p.rst deleted file mode 100644 index ec27f8e4..00000000 --- a/docs/generated/sparse.COO.log1p.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.log1p -========== - -.. currentmodule:: sparse - -.. automethod:: COO.log1p \ No newline at end of file diff --git a/docs/generated/sparse.COO.rint.rst b/docs/generated/sparse.COO.rint.rst deleted file mode 100644 index 4302f0d4..00000000 --- a/docs/generated/sparse.COO.rint.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.rint -========= - -.. currentmodule:: sparse - -.. automethod:: COO.rint \ No newline at end of file diff --git a/docs/generated/sparse.COO.rst b/docs/generated/sparse.COO.rst index 078b2846..2da5bcf3 100644 --- a/docs/generated/sparse.COO.rst +++ b/docs/generated/sparse.COO.rst @@ -33,22 +33,8 @@ COO :toctree: COO.elemwise - COO.abs COO.astype - COO.ceil - COO.conj - COO.conjugate - COO.exp - COO.expm1 - COO.floor - COO.log1p - COO.rint COO.round - COO.sin - COO.sinh - COO.sqrt - COO.tan - COO.tanh .. rubric:: :doc:`Reductions <../user_manual/operations/reductions>` .. autosummary:: diff --git a/docs/generated/sparse.COO.sin.rst b/docs/generated/sparse.COO.sin.rst deleted file mode 100644 index 2c00972b..00000000 --- a/docs/generated/sparse.COO.sin.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.sin -======== - -.. currentmodule:: sparse - -.. automethod:: COO.sin \ No newline at end of file diff --git a/docs/generated/sparse.COO.sinh.rst b/docs/generated/sparse.COO.sinh.rst deleted file mode 100644 index e3d5b7f0..00000000 --- a/docs/generated/sparse.COO.sinh.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.sinh -========= - -.. currentmodule:: sparse - -.. automethod:: COO.sinh \ No newline at end of file diff --git a/docs/generated/sparse.COO.sqrt.rst b/docs/generated/sparse.COO.sqrt.rst deleted file mode 100644 index 10a8ccb2..00000000 --- a/docs/generated/sparse.COO.sqrt.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.sqrt -========= - -.. currentmodule:: sparse - -.. automethod:: COO.sqrt \ No newline at end of file diff --git a/docs/generated/sparse.COO.tan.rst b/docs/generated/sparse.COO.tan.rst deleted file mode 100644 index f91eb510..00000000 --- a/docs/generated/sparse.COO.tan.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.tan -======== - -.. currentmodule:: sparse - -.. automethod:: COO.tan \ No newline at end of file diff --git a/docs/generated/sparse.COO.tanh.rst b/docs/generated/sparse.COO.tanh.rst deleted file mode 100644 index db166d9a..00000000 --- a/docs/generated/sparse.COO.tanh.rst +++ /dev/null @@ -1,6 +0,0 @@ -COO\.tanh -========= - -.. currentmodule:: sparse - -.. automethod:: COO.tanh \ No newline at end of file diff --git a/docs/user_manual/operations/elemwise.rst b/docs/user_manual/operations/elemwise.rst index b54e26fa..a1f2127f 100644 --- a/docs/user_manual/operations/elemwise.rst +++ b/docs/user_manual/operations/elemwise.rst @@ -10,18 +10,18 @@ To illustrate, the following are all possible, and will produce another .. code-block:: python - x.abs() + np.abs(x) np.sin(x) np.sqrt(x) - x.conj() - x.expm1() + np.conj(x) + np.expm1(x) np.log1p(x) However, the following are all unsupported and will raise a :obj:`ValueError`: .. code-block:: python - x.exp() + np.exp(x) np.cos(x) np.log(x) @@ -41,24 +41,3 @@ a :obj:`numpy.ndarray`. For example, the following will add two x.elemwise(np.add, y) -Partial List of Supported :obj:`numpy.ufunc` s ----------------------------------------------- -Although any unary or binary :obj:`numpy.ufunc` should work if the result is -not dense, when calling in the form :code:`x.func()`, the following operations -are supported: - -* :obj:`COO.abs` -* :obj:`COO.expm1` -* :obj:`COO.log1p` -* :obj:`COO.sin` -* :obj:`COO.sinh` -* :obj:`COO.tan` -* :obj:`COO.tanh` -* :obj:`COO.sqrt` -* :obj:`COO.ceil` -* :obj:`COO.floor` -* :obj:`COO.round` -* :obj:`COO.rint` -* :obj:`COO.conj` -* :obj:`COO.conjugate` -* :obj:`COO.astype`