[Numpy-discussion] Scalar-ndarray arguments passed to not_equal
Friedrich Romstedt
friedrichromstedt at gmail.com
Thu Feb 4 05:34:31 EST 2010
Hi,
I'm just coding a package for uncertain arrays using the accelerated
numpy functionality intensively. I'm sorry, but I have to give some
background information first. The package provides a class
upy.undarray, which holds the nominal value and the uncertainty
information. It has methods __add__(other), __radd__(other), ...,
__eq__(other), __ne__(other), which accept both upy.undarrays and all
other values suitable for coercion, thus also native numpy.ndarrays.
But because numpy treats in the statement:
result = numpyarray * upyarray
upyarray as a scalar, because it's not an numpy.ndarray, I have to
overload the numpy arithmetics by own objects by using
numpy.set_numeric_ops(add = ..., ..., equal = equal, not_equal =
not_equal). The arguments are defined by the module (it will be
clearifiied below).
Because numpy.add etc. are ufuncs exhibiting attributes, I wrote a
class to wrap them:
class ufuncWrap:
"""Wraps numpy ufuncs. Behaves like the original, with the exception
that __call__() will be overloaded."""
def __init__(self, ufunc, overload):
"""UFUNC is the ufunc to be wrapped. OVERLOAD is the name (string)
of the undarray method to be used in overloading __call__()."""
self.ufunc = ufunc
self.overload = overload
def __call__(self, a, b, *args, **kwargs):
"""When B is an undarray, call B.overload(a), else .ufunc(a, b)."""
if isinstance(b, undarray):
return getattr(b, self.overload)(a)
else:
return self.ufunc(a, b, *args, **kwargs)
def __getattr__(self, attr):
"""Return getattr(.ufunc, ATTR)."""
return getattr(self.ufunc, attr)
I only have to wrap binary operators.
Then, e.g.:
class Equal(ufuncWrap):
def __init__(self):
ufuncWrap.__init__(self, numpy.equal, '__eq__')
equal = Equal()
This works as expected.
But this approach fails (in first iteration) for a similar class
NotEqual. I have let the module output the arguments passed to
ufuncWrap.__call__(), and I found that the statement:
result = (numpyarray != upyarray)
with:
numpyarray = numpy.asarray([1.0])
upyarray = upy.ndarray([2.0], error = [0.1])
is passed on to NotEqual.__call__() as the arguments:
a = a numpy-array array([1.0])
b = a numpy-array array(shape = (), dtype = numpy.object), which is a
scalar array holding the upy.ndarray instance passed to !=.
I can work around the exhbited behaviour by:
class NotEqual(ufuncWrap):
def __init__(self):
ufuncWrap.__init__(self, numpy.not_equal, '__ne__')
def __call__(self, a, b, *args, **kwargs):
# numpy's calling mechanism of not_equal() seems to have a bug,
# such that b is always a numpy.ndarray. When b should be an undarray,
# it is a numpy.ndarray(dtype = numpy.object, shape = ()) ...
# Make the call also compatible with future, bug-fixed versions.
if isinstance(b, numpy.ndarray):
if b.ndim == 0:
# Implement some conversion from scalar array to stored object.
b = b.sum()
return ufuncWrap.__call__(self, a, b, *args, **kwargs)
What is the reason for the behaviour observed?
I'm using numpy 1.4.0 with Python 2.5.
Friedrich
More information about the NumPy-Discussion
mailing list