2

What is the simplest way to make numpy's dot() method use my object's __rmatmul__ method?

The issue is easily demonstrated with scipy.sparse:

import numpy as np
from scipy import sparse

A = np.array([[1, 2], [3, 4]]) 
B = sparse.diags([1, 2])

BA = B.dot(A)          # Works fine
AB = B.__rmatmul__(A)  # Works: This is what I want to happen
AB = B.T.dot(A.T).T    # Works but not simple
AB = A @ B             # Preferred way for Python 3.5+
AB = A.dot(B)          # This is what people do, but it gives very non-intuitive results

The desired result here is B.__rmatmul__(A) but I do not want users used to using numpy.dot to get tripped up when the reasonable expression A.dot(B) returns a 2x2 array where each element is a sparse matrix (a copy of B):

>>> AB
array([[<2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements (1 diagonals) in DIAgonal format>,
        <2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements (1 diagonals) in DIAgonal format>],
       [<2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements (1 diagonals) in DIAgonal format>,
        <2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements (1 diagonals) in DIAgonal format>]], dtype=object)

If I am writing my own "sparse" class, how can I get numpy to use my objects __rmatmul__ function? From the answer here, it seems like the only solution might be to make my object a subclass of np.ndarray, but this seems way too complicated (and may still fail since I doubt I can provide sensible view-like access to a sparse array).

(The particular application I would like to use is a custom sparse representation of an array as a sum over dyads, but the details are not important.)

References

This issue has been pointed out several times, and the result explained in terms of the behaviour of numpy.dot(), but the solutions are all workarounds. None answer this question.

People running into this issue:

Ugly workarounds:

(Update)

I think in Python 3.5 and above it is clear that one should used the notation A @ B instead of dot(). The question still remains for earlier versions of python, but is less relevant.

mforbes
  • 7,062
  • 3
  • 16
  • 21
  • The problem is that `A.dot` isn't an operator. It does a naive `np.array(B)`, instead of using `B.A` or deferring to B's own method. – hpaulj Apr 27 '19 at 12:37
  • Even using `A @ B`, a complete answer will need to discuss [`__array_priority__`](https://www.numpy.org/devdocs/user/c-info.beyond-basics.html?highlight=__array_priority__#the-array-priority-attribute). – mforbes Apr 27 '19 at 19:36
  • @mforbes Did you ever workout how to do this? – Tom McLean Sep 07 '22 at 14:42
  • 1
    @TomMcLean No, but I have not looked at this for a while. The situation might be better now. – mforbes Sep 27 '22 at 20:17

0 Answers0