Browse files

Merge pull request #451 from larsmans/sparse-min-max

ENH: sparse: min and max methods for CSR & CSC & COO
  • Loading branch information...
2 parents 608b418 + 3807b6d commit 2619f0ca030b2bcf630ddd9a33f48c588cf4fcea @pv pv committed Mar 11, 2013
Showing with 100 additions and 10 deletions.
  1. +2 −2 scipy/sparse/bsr.py
  2. +2 −2 scipy/sparse/compressed.py
  3. +2 −2 scipy/sparse/coo.py
  4. +43 −0 scipy/sparse/data.py
  5. +51 −4 scipy/sparse/tests/test_base.py
View
4 scipy/sparse/bsr.py
@@ -10,15 +10,15 @@
import numpy as np
-from .data import _data_matrix
+from .data import _data_matrix, _minmax_mixin
from .compressed import _cs_matrix
from .base import isspmatrix, _formats
from .sputils import isshape, getdtype, to_native, upcast
from . import sparsetools
from .sparsetools import bsr_matvec, bsr_matvecs, csr_matmat_pass1, \
bsr_matmat_pass2, bsr_transpose, bsr_sort_indices
-class bsr_matrix(_cs_matrix):
+class bsr_matrix(_cs_matrix, _minmax_mixin):
"""Block Sparse Row matrix
This can be instantiated in several ways:
View
4 scipy/sparse/compressed.py
@@ -10,13 +10,13 @@
from scipy.lib.six.moves import xrange
from .base import spmatrix, isspmatrix, SparseEfficiencyWarning
-from .data import _data_matrix
+from .data import _data_matrix, _minmax_mixin
from . import sparsetools
from .sputils import upcast, upcast_char, to_native, isdense, isshape, \
getdtype, isscalarlike, isintlike
-class _cs_matrix(_data_matrix):
+class _cs_matrix(_data_matrix, _minmax_mixin):
"""base matrix class for compressed row and column oriented matrices"""
def __init__(self, arg1, shape=None, dtype=None, copy=False):
View
4 scipy/sparse/coo.py
@@ -13,10 +13,10 @@
from .sparsetools import coo_tocsr, coo_todense, coo_matvec
from .base import isspmatrix
-from .data import _data_matrix
+from .data import _data_matrix, _minmax_mixin
from .sputils import upcast, upcast_char, to_native, isshape, getdtype, isintlike
-class coo_matrix(_data_matrix):
+class coo_matrix(_data_matrix, _minmax_mixin):
"""
A sparse matrix in COOrdinate format.
View
43 scipy/sparse/data.py
@@ -92,3 +92,46 @@ def method(self):
return method
setattr(_data_matrix, name, _create_method(npfunc))
+
+
+class _minmax_mixin(object):
+ """Mixin for min and max methods.
+
+ These are not implemented for dia_matrix, hence the separate class.
+ """
+
+ def max(self):
+ """Maximum of the elements of this matrix.
+
+ This takes all elements into account, not just the non-zero ones.
+
+ Returns
+ -------
+ amax : self.dtype
+ Maximum element.
+ """
+ zero = self.dtype.type(0)
+ if self.nnz == 0:
+ return zero
+ mx = np.max(self.data)
+ if self.nnz != np.product(self.shape):
+ mx = max(zero, mx)
+ return mx
+
+ def min(self):
+ """Minimum of the elements of this matrix.
+
+ This takes all elements into account, not just the non-zero ones.
+
+ Returns
+ -------
+ amin : self.dtype
+ Minimum element.
+ """
+ zero = self.dtype.type(0)
+ if self.nnz == 0:
+ return zero
+ mn = np.min(self.data)
+ if self.nnz != np.product(self.shape):
+ mn = min(zero, mn)
+ return mn
View
55 scipy/sparse/tests/test_base.py
@@ -1410,6 +1410,49 @@ def test_mu(self):
assert_equal(S1.dtype,D1.dtype)
+class _TestMinMax(object):
+ def test_minmax(self):
+ for dtype in [np.float32, np.float64, np.int32, np.int64]:
+ D = np.arange(20, dtype=dtype).reshape(5,4)
+
+ X = self.spmatrix(D)
+ assert_equal(X.min(), 0)
+ assert_equal(X.max(), 19)
+ assert_equal(X.min().dtype, dtype)
+ assert_equal(X.max().dtype, dtype)
+
+ D *= -1
+ X = self.spmatrix(D)
+ assert_equal(X.min(), -19)
+ assert_equal(X.max(), 0)
+
+ D += 5
+ X = self.spmatrix(D)
+ assert_equal(X.min(), -14)
+ assert_equal(X.max(), 5)
+
+ # try a fully dense matrix
+ X = self.spmatrix(np.arange(1, 10).reshape(3, 3))
+ assert_equal(X.min(), 1)
+ assert_equal(X.min().dtype, X.dtype)
+
+ X = -X
+ assert_equal(X.max(), -1)
+
+ # and a fully sparse matrix
+ Z = self.spmatrix(np.zeros(1))
+ assert_equal(Z.min(), 0)
+ assert_equal(Z.max(), 0)
+ assert_equal(Z.max().dtype, Z.dtype)
+
+ # another test
+ D = np.arange(20, dtype=float).reshape(5,4)
+ D[0:2, :] = 0
+ X = self.spmatrix(D)
+ assert_equal(X.min(), 0)
+ assert_equal(X.max(), 19)
+
+
#------------------------------------------------------------------------------
# Tailored base class for generic tests
#------------------------------------------------------------------------------
@@ -1443,7 +1486,8 @@ def wrapper(*a, **kw):
def sparse_test_class(getset=True, slicing=True, slicing_assign=True,
fancy_indexing=True, fancy_assign=True,
- fancy_multidim_indexing=True, fancy_multidim_assign=True):
+ fancy_multidim_indexing=True, fancy_multidim_assign=True,
+ minmax=True):
"""
Construct a base class, optionally converting some of the tests in
the suite to check that the feature is not implemented.
@@ -1462,6 +1506,7 @@ def sparse_test_class(getset=True, slicing=True, slicing_assign=True,
fancy_indexing and fancy_multidim_indexing),
_possibly_unimplemented(_TestFancyMultidimAssign,
fancy_multidim_assign and fancy_assign),
+ _possibly_unimplemented(_TestMinMax, minmax),
TestCase)
# check that test names do not clash
@@ -1738,7 +1783,8 @@ def test_slicing_3(self):
class TestDOK(sparse_test_class(slicing=False,
slicing_assign=False,
fancy_indexing=False,
- fancy_assign=False)):
+ fancy_assign=False,
+ minmax=False)):
spmatrix = dok_matrix
def test_mult(self):
@@ -1873,7 +1919,7 @@ def test_fancy_assign_slice(self):
def test_fancy_indexing_multidim_set(self):
pass
-class TestLIL(sparse_test_class()):
+class TestLIL(sparse_test_class(minmax=False)):
spmatrix = lil_matrix
def test_dot(self):
@@ -2034,7 +2080,8 @@ def test_constructor4(self):
class TestDIA(sparse_test_class(getset=False, slicing=False, slicing_assign=False,
- fancy_indexing=False, fancy_assign=False)):
+ fancy_indexing=False, fancy_assign=False,
+ minmax=False)):
spmatrix = dia_matrix
def test_constructor1(self):

0 comments on commit 2619f0c

Please sign in to comment.