7

I am trying to subclass a numpy ndarray but I am not able to get right the operations with other numpy types such as masked array or matrix. It seems to me that the __array_priority__ is not being honored. As an example, I have created a dummy class that mimicks the important aspects:

import numpy as np

class C(np.ndarray):

    __array_priority__ = 15.0

    def __mul__(self, other):
        print("__mul__")
        return 42

    def __rmul__(self, other):
        print("__rmul__")
        return 42

Operations between my class and normal ndarray work as expected:

>>> c1 = C((3, 3))
>>> o1 = np.ones((3, 3))
>>> print(o1 * c1)
__mul__
42
>>> print(c1 * o1)
__rmul__
42 

But, when I try to operate with matrix (or masked arrays) the array priority is not respected.

>>> m = np.matrix((3, 3))
>>> print(c1 * m)
__mul__
42
>>> print(m * c1)
Traceback (most recent call last):
...
  File "/usr/lib64/python2.7/site-packages/numpy/matrixlib/defmatrix.py", line 330, in __mul__
    return N.dot(self, asmatrix(other))
ValueError: objects are not aligned

It seems to me that the way ufuncs are wrapped for matrix and masked arrays do not honor array priority. Is this the case? Is there a workaround?

Hernan
  • 5,811
  • 10
  • 51
  • 86
  • 1
    Actually, the error message is given because they are not aligned, since `np.matrix((3, 3))` is not the same as `np.asmatrix(np.ones((3, 3)))`. However, the problem still persists except that `m * c1` is the one that isn't working. – Gustav Larsson Jul 31 '13 at 01:42
  • @GustavLarsson Thanks for spotting that. I fixed it and added more info in the motivation. – Hernan Jul 31 '13 at 02:25

1 Answers1

2

One workaround is to subclass np.matrixib.defmatrix.matrix:

class C(np.matrixlib.defmatrix.matrix):

    __array_priority__ = 15.0

    def __mul__(self, other):
        print("__mul__")
        return 42

    def __rmul__(self, other):
        print("__rmul__")
        return 4

In this case the priority is also higher then a np.ndarray and your multiplication methods are always called.

As added in the comments, you can subclass from multiple classes in case you need interoperability:

class C(np.matrixlib.defmatrix.matrix, np.ndarray):
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • This works nicely, but my classes are better described by ndarray than matrix. Additionally, my class should interoperate with ndarray, matrix and masked darray. Is there a way to achieve this? – Hernan Jul 31 '13 at 20:17
  • Try using this approach and see if the interoperation is achieved, if not, you can subclass from more than one class, doing like: `class C(np.matrixlib.defmatrix.matrix, np.ndarray):`, for example... – Saullo G. P. Castro Jul 31 '13 at 20:18
  • I have redefined the class as `class C(np.matrixlib.defmatrix.matrix, np.ma.core.MaskedArray, np.ndarray):`. It is ugly but it seems to work, I still need more test cases. I am now trying to do the same for a class that wraps an array (without subclassing). Again, it works fine when multipliying by a ndarray but not for anything else. – Hernan Aug 04 '13 at 23:36
  • I think the solution for your case is doing the multiple subclassing when subclassing only from `np.matrixlib.defmatrix.matrix` does not work. – Saullo G. P. Castro Aug 05 '13 at 06:46