diff --git a/docs/generated/sparse.COO.all.rst b/docs/generated/sparse.COO.all.rst new file mode 100644 index 00000000..f79e99c4 --- /dev/null +++ b/docs/generated/sparse.COO.all.rst @@ -0,0 +1,6 @@ +COO.all +======= + +.. currentmodule:: sparse + +.. automethod:: COO.all \ No newline at end of file diff --git a/docs/generated/sparse.COO.any.rst b/docs/generated/sparse.COO.any.rst new file mode 100644 index 00000000..1bdad68c --- /dev/null +++ b/docs/generated/sparse.COO.any.rst @@ -0,0 +1,6 @@ +COO.any +======= + +.. currentmodule:: sparse + +.. automethod:: COO.any \ No newline at end of file diff --git a/docs/generated/sparse.COO.rst b/docs/generated/sparse.COO.rst index d0a1c9f2..cdd16d4e 100644 --- a/docs/generated/sparse.COO.rst +++ b/docs/generated/sparse.COO.rst @@ -40,10 +40,13 @@ COO :toctree: COO.reduce + COO.sum - COO.max - COO.min COO.prod + COO.min + COO.max + COO.any + COO.all .. rubric:: :ref:`Converting to other formats ` .. autosummary:: diff --git a/sparse/coo/core.py b/sparse/coo/core.py index 1ec395be..881a721f 100644 --- a/sparse/coo/core.py +++ b/sparse/coo/core.py @@ -811,6 +811,114 @@ def max(self, axis=None, keepdims=False, out=None): """ return np.maximum.reduce(self, out=out, axis=axis, keepdims=keepdims) + def any(self, axis=None, keepdims=False, out=None): + """ + See if any values along array are ``True``. Uses all axes by default. + + Parameters + ---------- + axis : Union[int, Iterable[int]], optional + The axes along which to minimize. Uses all axes by default. + keepdims : bool, optional + Whether or not to keep the dimensions of the original array. + + Returns + ------- + COO + The reduced output sparse array. + + See Also + -------- + :obj:`numpy.all` : Equivalent numpy function. + + Notes + ----- + * This function internally calls :obj:`COO.sum_duplicates` to bring the array into + canonical form. + * The :code:`out` parameter is provided just for compatibility with Numpy and + isn't actually supported. + + Examples + -------- + You can use :obj:`COO.min` to minimize an array across any dimension. + + >>> x = np.array([[False, False], + ... [False, True ], + ... [True, False], + ... [True, True ]]) + >>> s = COO.from_numpy(x) + >>> s2 = s.any(axis=1) + >>> s2.todense() # doctest: +SKIP + array([False, True, True, True]) + + You can also use the :code:`keepdims` argument to keep the dimensions after the + minimization. + + >>> s3 = s.any(axis=1, keepdims=True) + >>> s3.shape + (4, 1) + + By default, this reduces the array down to one number, minimizing along all axes. + + >>> s.any() + True + """ + return np.logical_or.reduce(self, out=out, axis=axis, keepdims=keepdims) + + def all(self, axis=None, keepdims=False, out=None): + """ + See if all values in an array are ``True``. Uses all axes by default. + + Parameters + ---------- + axis : Union[int, Iterable[int]], optional + The axes along which to minimize. Uses all axes by default. + keepdims : bool, optional + Whether or not to keep the dimensions of the original array. + + Returns + ------- + COO + The reduced output sparse array. + + See Also + -------- + :obj:`numpy.all` : Equivalent numpy function. + + Notes + ----- + * This function internally calls :obj:`COO.sum_duplicates` to bring the array into + canonical form. + * The :code:`out` parameter is provided just for compatibility with Numpy and + isn't actually supported. + + Examples + -------- + You can use :obj:`COO.min` to minimize an array across any dimension. + + >>> x = np.array([[False, False], + ... [False, True ], + ... [True, False], + ... [True, True ]]) + >>> s = COO.from_numpy(x) + >>> s2 = s.all(axis=1) + >>> s2.todense() # doctest: +SKIP + array([False, False, False, True]) + + You can also use the :code:`keepdims` argument to keep the dimensions after the + minimization. + + >>> s3 = s.all(axis=1, keepdims=True) + >>> s3.shape + (4, 1) + + By default, this reduces the array down to one boolean, minimizing along all axes. + + >>> s.all() + False + """ + return np.logical_and.reduce(self, out=out, axis=axis, keepdims=keepdims) + def min(self, axis=None, keepdims=False, out=None): """ Minimize along the given axes. Uses all axes by default. @@ -865,7 +973,7 @@ def min(self, axis=None, keepdims=False, out=None): >>> s3.shape (5, 1) - By default, this reduces the array down to one number, minimizing along all axes. + By default, this reduces the array down to one boolean, minimizing along all axes. >>> s.min() 0 diff --git a/sparse/tests/test_coo.py b/sparse/tests/test_coo.py index abca2806..ac3bf4fd 100644 --- a/sparse/tests/test_coo.py +++ b/sparse/tests/test_coo.py @@ -27,6 +27,20 @@ def test_reductions(reduction, axis, keepdims, kwargs, eqkwargs): assert_eq(xx, yy, **eqkwargs) +@pytest.mark.parametrize('reduction,kwargs,eqkwargs', [ + ('any', {}, {}), + ('all', {}, {}), +]) +@pytest.mark.parametrize('axis', [None, 0, 1, 2, (0, 2), -3, (1, -1)]) +@pytest.mark.parametrize('keepdims', [True, False]) +def test_reductions_bool(reduction, axis, keepdims, kwargs, eqkwargs): + x = sparse.random((2, 3, 4), density=.25).astype(bool) + y = x.todense() + xx = getattr(x, reduction)(axis=axis, keepdims=keepdims, **kwargs) + yy = getattr(y, reduction)(axis=axis, keepdims=keepdims, **kwargs) + assert_eq(xx, yy, **eqkwargs) + + @pytest.mark.parametrize('reduction,kwargs,eqkwargs', [ (np.max, {}, {}), (np.sum, {}, {}), @@ -433,25 +447,25 @@ def test_trinary_broadcasting(shapes, func): @pytest.mark.parametrize('shapes, func', [ ([ - (2,), - (3, 2), - (4, 3, 2), - ], lambda x, y, z: (x + y) * z), + (2,), + (3, 2), + (4, 3, 2), + ], lambda x, y, z: (x + y) * z), ([ - (3,), - (2, 3), - (2, 2, 3), - ], lambda x, y, z: x * (y + z)), + (3,), + (2, 3), + (2, 2, 3), + ], lambda x, y, z: x * (y + z)), ([ - (2,), - (2, 2), - (2, 2, 2), - ], lambda x, y, z: x * y * z), + (2,), + (2, 2), + (2, 2, 2), + ], lambda x, y, z: x * y * z), ([ - (4,), - (4, 4), - (4, 4, 4), - ], lambda x, y, z: x + y + z), + (4,), + (4, 4), + (4, 4, 4), + ], lambda x, y, z: x + y + z), ]) @pytest.mark.parametrize('value', [ np.nan,