summaryrefslogtreecommitdiff
path: root/numpy/ma/core.py
diff options
context:
space:
mode:
authorpierregm <pierregm@localhost>2008-12-22 10:01:51 +0000
committerpierregm <pierregm@localhost>2008-12-22 10:01:51 +0000
commit934b27413ae9bd02fe40bafcf040a6f3fe0edff8 (patch)
treef8c40822f330dbc727ba3d6459fb1a880770fa2c /numpy/ma/core.py
parent13ad7269de41edb67b786bbeb7605c1702003e84 (diff)
downloadnumpy-934b27413ae9bd02fe40bafcf040a6f3fe0edff8.tar.gz
testutils:
assert_array_compare : make sure that the comparison is performed on ndarrays, and make sure we use the np version of the comparison function. core: * Try not to touch the data in unary/binary ufuncs, (including inplace)
Diffstat (limited to 'numpy/ma/core.py')
-rw-r--r--numpy/ma/core.py139
1 files changed, 90 insertions, 49 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index a3cda941d..6b4dc98e6 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -535,17 +535,20 @@ class _MaskedUnaryOperation:
# ... but np.putmask looks more efficient, despite the copy.
np.putmask(d1, dm, self.fill)
# Take care of the masked singletong first ...
- if not m.ndim and m:
+ if (not m.ndim) and m:
return masked
- # Get the result class .......................
- if isinstance(a, MaskedArray):
- subtype = type(a)
+ elif m is nomask:
+ result = self.f(d1, *args, **kwargs)
else:
- subtype = MaskedArray
- # Get the result as a view of the subtype ...
- result = self.f(d1, *args, **kwargs).view(subtype)
- # Fix the mask if we don't have a scalar
- if result.ndim > 0:
+ result = np.where(m, d1, self.f(d1, *args, **kwargs))
+ # If result is not a scalar
+ if result.ndim:
+ # Get the result subclass:
+ if isinstance(a, MaskedArray):
+ subtype = type(a)
+ else:
+ subtype = MaskedArray
+ result = result.view(subtype)
result._mask = m
result._update_from(a)
return result
@@ -584,19 +587,45 @@ class _MaskedBinaryOperation:
def __call__ (self, a, b, *args, **kwargs):
"Execute the call behavior."
m = mask_or(getmask(a), getmask(b))
- (d1, d2) = (get_data(a), get_data(b))
- result = self.f(d1, d2, *args, **kwargs).view(get_masked_subclass(a, b))
- if len(result.shape):
- if m is not nomask:
- result._mask = make_mask_none(result.shape)
- result._mask.flat = m
+ (da, db) = (getdata(a), getdata(b))
+ # Easy case: there's no mask...
+ if m is nomask:
+ result = self.f(da, db, *args, **kwargs)
+ # There are some masked elements: run only on the unmasked
+ else:
+ result = np.where(m, da, self.f(da, db, *args, **kwargs))
+ # Transforms to a (subclass of) MaskedArray if we don't have a scalar
+ if result.shape:
+ result = result.view(get_masked_subclass(a, b))
+ result._mask = make_mask_none(result.shape)
+ result._mask.flat = m
if isinstance(a, MaskedArray):
result._update_from(a)
if isinstance(b, MaskedArray):
result._update_from(b)
+ # ... or return masked if we have a scalar and the common mask is True
elif m:
return masked
return result
+#
+# result = self.f(d1, d2, *args, **kwargs).view(get_masked_subclass(a, b))
+# if len(result.shape):
+# if m is not nomask:
+# result._mask = make_mask_none(result.shape)
+# result._mask.flat = m
+# #!!!!!
+# # Force m to be at least 1D
+# m.shape = m.shape or (1,)
+# print "Resetting data"
+# result.data[m].flat = d1.flat
+# #!!!!!
+# if isinstance(a, MaskedArray):
+# result._update_from(a)
+# if isinstance(b, MaskedArray):
+# result._update_from(b)
+# elif m:
+# return masked
+# return result
def reduce(self, target, axis=0, dtype=None):
"""Reduce `target` along the given `axis`."""
@@ -639,11 +668,13 @@ class _MaskedBinaryOperation:
m = umath.logical_or.outer(ma, mb)
if (not m.ndim) and m:
return masked
- rcls = get_masked_subclass(a, b)
- # We could fill the arguments first, butis it useful ?
- # d = self.f.outer(filled(a, self.fillx), filled(b, self.filly)).view(rcls)
- d = self.f.outer(getdata(a), getdata(b)).view(rcls)
- if d.ndim > 0:
+ (da, db) = (getdata(a), getdata(b))
+ if m is nomask:
+ d = self.f.outer(da, db)
+ else:
+ d = np.where(m, da, self.f.outer(da, db))
+ if d.shape:
+ d = d.view(get_masked_subclass(a, b))
d._mask = m
return d
@@ -655,7 +686,7 @@ class _MaskedBinaryOperation:
if isinstance(target, MaskedArray):
tclass = type(target)
else:
- tclass = masked_array
+ tclass = MaskedArray
t = filled(target, self.filly)
return self.f.accumulate(t, axis).view(tclass)
@@ -664,7 +695,8 @@ class _MaskedBinaryOperation:
#..............................................................................
class _DomainedBinaryOperation:
- """Define binary operations that have a domain, like divide.
+ """
+ Define binary operations that have a domain, like divide.
They have no reduce, outer or accumulate.
@@ -689,25 +721,29 @@ class _DomainedBinaryOperation:
ufunc_domain[dbfunc] = domain
ufunc_fills[dbfunc] = (fillx, filly)
- def __call__(self, a, b):
+ def __call__(self, a, b, *args, **kwargs):
"Execute the call behavior."
ma = getmask(a)
mb = getmask(b)
- d1 = getdata(a)
- d2 = get_data(b)
- t = narray(self.domain(d1, d2), copy=False)
+ da = getdata(a)
+ db = getdata(b)
+ t = narray(self.domain(da, db), copy=False)
if t.any(None):
mb = mask_or(mb, t)
# The following line controls the domain filling
- if t.size == d2.size:
- d2 = np.where(t, self.filly, d2)
+ if t.size == db.size:
+ db = np.where(t, self.filly, db)
else:
- d2 = np.where(np.resize(t, d2.shape), self.filly, d2)
+ db = np.where(np.resize(t, db.shape), self.filly, db)
m = mask_or(ma, mb)
if (not m.ndim) and m:
return masked
- result = self.f(d1, d2).view(get_masked_subclass(a, b))
- if result.ndim > 0:
+ elif (m is nomask):
+ result = self.f(da, db, *args, **kwargs)
+ else:
+ result = np.where(m, da, self.f(da, db, *args, **kwargs))
+ if result.shape:
+ result = result.view(get_masked_subclass(a, b))
result._mask = m
if isinstance(a, MaskedArray):
result._update_from(a)
@@ -2243,32 +2279,33 @@ masked_%(name)s(data = %(data)s,
#............................................
def __iadd__(self, other):
"Add other to self in-place."
- ndarray.__iadd__(self._data, getdata(other))
m = getmask(other)
if self._mask is nomask:
self._mask = m
- elif m is not nomask:
- self._mask += m
+ else:
+ if m is not nomask:
+ self._mask += m
+ ndarray.__iadd__(self._data, np.where(self._mask, 0, getdata(other)))
return self
#....
def __isub__(self, other):
"Subtract other from self in-place."
- ndarray.__isub__(self._data, getdata(other))
m = getmask(other)
if self._mask is nomask:
self._mask = m
elif m is not nomask:
self._mask += m
+ ndarray.__isub__(self._data, np.where(self._mask, 0, getdata(other)))
return self
#....
def __imul__(self, other):
"Multiply self by other in-place."
- ndarray.__imul__(self._data, getdata(other))
m = getmask(other)
if self._mask is nomask:
self._mask = m
elif m is not nomask:
self._mask += m
+ ndarray.__imul__(self._data, np.where(self._mask, 1, getdata(other)))
return self
#....
def __idiv__(self, other):
@@ -2281,21 +2318,25 @@ masked_%(name)s(data = %(data)s,
if dom_mask.any():
(_, fval) = ufunc_fills[np.divide]
other_data = np.where(dom_mask, fval, other_data)
- ndarray.__idiv__(self._data, other_data)
- self._mask = mask_or(self._mask, new_mask)
+# self._mask = mask_or(self._mask, new_mask)
+ self._mask |= new_mask
+ ndarray.__idiv__(self._data, np.where(self._mask, 1, other_data))
return self
#...
def __ipow__(self, other):
"Raise self to the power other, in place"
- _data = self._data
other_data = getdata(other)
other_mask = getmask(other)
- ndarray.__ipow__(_data, other_data)
- invalid = np.logical_not(np.isfinite(_data))
+ ndarray.__ipow__(self._data, np.where(self._mask, 1, other_data))
+ invalid = np.logical_not(np.isfinite(self._data))
+ if invalid.any():
+ if self._mask is not nomask:
+ self._mask |= invalid
+ else:
+ self._mask = invalid
+ np.putmask(self._data, invalid, self.fill_value)
new_mask = mask_or(other_mask, invalid)
self._mask = mask_or(self._mask, new_mask)
- # The following line is potentially problematic, as we change _data...
- np.putmask(self._data, invalid, self.fill_value)
return self
#............................................
def __float__(self):
@@ -3848,22 +3889,22 @@ def power(a, b, third=None):
else:
basetype = MaskedArray
# Get the result and view it as a (subclass of) MaskedArray
- result = umath.power(fa, fb).view(basetype)
+ result = np.where(m, fa, umath.power(fa, fb)).view(basetype)
+ result._update_from(a)
# Find where we're in trouble w/ NaNs and Infs
invalid = np.logical_not(np.isfinite(result.view(ndarray)))
- # Retrieve some extra attributes if needed
- if isinstance(result, MaskedArray):
- result._update_from(a)
# Add the initial mask
if m is not nomask:
- if np.isscalar(result):
+ if not (result.ndim):
return masked
+ m |= invalid
result._mask = m
# Fix the invalid parts
if invalid.any():
if not result.ndim:
return masked
- result[invalid] = masked
+ elif result._mask is nomask:
+ result._mask = invalid
result._data[invalid] = result.fill_value
return result