[Numpy-discussion] Scalar-ndarray arguments passed to not_equal

Friedrich Romstedt friedrichromstedt@gmail....
Thu Feb 4 04:34:31 CST 2010


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)
			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)


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.


More information about the NumPy-Discussion mailing list