From 3fdf1883369c5cd40ad7022ad46a629f2284a7a3 Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Sun, 22 Mar 2015 21:15:59 -0400 Subject: [PATCH 1/4] BUG: Implemented MaskedArray.dot MaskedArray used to inherit ndarray.dot which ignored masks in the operands. Fixes issue #5185. --- numpy/ma/core.py | 16 ++++++++++++++++ numpy/ma/extras.py | 8 +------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 79924351c065..964636595240 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -4522,6 +4522,22 @@ def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None): return D.astype(dtype).filled(0).sum(axis=None, out=out) trace.__doc__ = ndarray.trace.__doc__ + def dot(self, other, out=None): + am = ~getmaskarray(self) + bm = ~getmaskarray(other) + if out is None: + d = np.dot(filled(self, 0), filled(other, 0)) + m = ~np.dot(am, bm) + return masked_array(d, mask=m) + d = self.filled(0).dot(other.filled(0), out) + if out.mask.shape != d.shape: + out._mask = numpy.empty(d.shape, MaskType) + np.dot(am, bm, out._mask) + np.logical_not(out._mask, out._mask) + return out + dot.__doc__ = ndarray.dot.__doc__ + + def sum(self, axis=None, dtype=None, out=None): """ Return the sum of the array elements over the given axis. diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py index 6d812964d820..d389099ae0c4 100644 --- a/numpy/ma/extras.py +++ b/numpy/ma/extras.py @@ -1047,13 +1047,7 @@ def dot(a, b, strict=False): if strict and (a.ndim == 2) and (b.ndim == 2): a = mask_rows(a) b = mask_cols(b) - # - d = np.dot(filled(a, 0), filled(b, 0)) - # - am = (~getmaskarray(a)) - bm = (~getmaskarray(b)) - m = ~np.dot(am, bm) - return masked_array(d, mask=m) + return a.dot(b) #####-------------------------------------------------------------------------- #---- --- arraysetops --- From 2383bd624992e4ea3e1b9d56f128ccf5d1a9eb5a Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Sun, 29 Mar 2015 14:00:31 -0400 Subject: [PATCH 2/4] Fixed out!=None case, added tests. --- numpy/ma/core.py | 2 +- numpy/ma/tests/test_core.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 964636595240..f3ae45a557e0 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -4529,7 +4529,7 @@ def dot(self, other, out=None): d = np.dot(filled(self, 0), filled(other, 0)) m = ~np.dot(am, bm) return masked_array(d, mask=m) - d = self.filled(0).dot(other.filled(0), out) + d = self.filled(0).dot(other.filled(0), out._data) if out.mask.shape != d.shape: out._mask = numpy.empty(d.shape, MaskType) np.dot(am, bm, out._mask) diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 1d4462306520..e67889f374b8 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -2982,6 +2982,30 @@ def test_trace(self): X.trace() - sum(mXdiag.mask * X.diagonal(), axis=0)) + def test_dot(self): + # Tests dot on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + fx = mx.filled(0) + r = mx.dot(mx) + assert_almost_equal(r.filled(0), fx.dot(fx)) + self.assertIs(r.mask, nomask) + + fX = mX.filled(0) + r = mX.dot(mX) + assert_almost_equal(r.filled(0), fX.dot(fX)) + self.assertTrue(r.mask[1,3]) + r1 = empty_like(r) + mX.dot(mX, r1) + assert_almost_equal(r, r1) + + mYY = mXX.swapaxes(-1, -2) + fXX, fYY = mXX.filled(0), mYY.filled(0) + r = mXX.dot(mYY) + assert_almost_equal(r.filled(0), fXX.dot(fYY)) + r1 = empty_like(r) + mXX.dot(mYY, r1) + assert_almost_equal(r, r1) + def test_varstd(self): # Tests var & std on MaskedArrays. (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d From 188ed4f314354f8e2f35937d205da5cd4ca1c175 Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Sun, 29 Mar 2015 14:45:52 -0400 Subject: [PATCH 3/4] Made dot return proper type. --- numpy/ma/core.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index f3ae45a557e0..51e9f0f28a12 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -4528,7 +4528,11 @@ def dot(self, other, out=None): if out is None: d = np.dot(filled(self, 0), filled(other, 0)) m = ~np.dot(am, bm) - return masked_array(d, mask=m) + if d.ndim == 0: + d = np.asarray(d) + r = d.view(get_masked_subclass(self, other)) + r.__setmask__(m) + return r d = self.filled(0).dot(other.filled(0), out._data) if out.mask.shape != d.shape: out._mask = numpy.empty(d.shape, MaskType) From bf8d3329d43bf534e45cb8182a6d712138566cdc Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Mon, 30 Mar 2015 13:39:22 -0400 Subject: [PATCH 4/4] Use Python 2.6 compatible assertions in tests. --- numpy/ma/tests/test_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index e67889f374b8..807fc0ba6d5e 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -2988,12 +2988,12 @@ def test_dot(self): fx = mx.filled(0) r = mx.dot(mx) assert_almost_equal(r.filled(0), fx.dot(fx)) - self.assertIs(r.mask, nomask) + assert_(r.mask is nomask) fX = mX.filled(0) r = mX.dot(mX) assert_almost_equal(r.filled(0), fX.dot(fX)) - self.assertTrue(r.mask[1,3]) + assert_(r.mask[1,3]) r1 = empty_like(r) mX.dot(mX, r1) assert_almost_equal(r, r1)