Skip to content

Commit

Permalink
Merge pull request #451 from larsmans/sparse-min-max
Browse files Browse the repository at this point in the history
ENH: sparse: min and max methods for CSR & CSC & COO
  • Loading branch information
pv committed Mar 11, 2013
2 parents 608b418 + 3807b6d commit 2619f0c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 10 deletions.
4 changes: 2 additions & 2 deletions scipy/sparse/bsr.py
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions scipy/sparse/compressed.py
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions scipy/sparse/coo.py
Expand Up @@ -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.
Expand Down
43 changes: 43 additions & 0 deletions scipy/sparse/data.py
Expand Up @@ -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
55 changes: 51 additions & 4 deletions scipy/sparse/tests/test_base.py
Expand Up @@ -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
#------------------------------------------------------------------------------
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit 2619f0c

Please sign in to comment.