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)