-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
BUG Numpy ufunc binop fix for subclasses with __numpy_ufunc__ (closes #4815) #5748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
These changes only affect objects defining __numpy_ufunc__. Other objects use the __array_priority__ mechanism to decide whether NotImplemented should be returned or not. The binops previously returned NotImplemented even if other._r<op>__ is ndarray.__r<op>__, rather than trying to evaluate the result via ufuncs. This causes problems in binops of two objects that both subclass from ndarray and define __numpy_ufunc__. The solution added here makes the total logic as follows: def __binop__(self, other): if (hasattr(other, '__numpy_ufunc__') and not isinstance(other, self.__class__) and hasattr(other, '__rop__') and other.__class__.__rop__ is not self.__class__.__rop__): return NotImplemented return np.binop(self, other)
In particular, for a class S3(S2), where S2 defines __numpy_ufunc__, ensure that, e.g., S3() + S2() does *not* pass control to S2 if S2 and S3 share the same __radd__.
Can someone remind me what exactly is wrong with this? One possiblity is that the plain old ufunc fallback behaviour is just broken in general, like maybe we don't actually have a way to tell when the np.binop() call actually failed in a way that should trigger a I re-read the NEP, and it has (a) a made-up-example that doesn't mean much on its own, and (b) a argument that implementing That said, there is one very important specific place where we have to enable "bad" design, which is scipy.sparse's So I propose:
Ugly, isn't it :-). But simple, unabusable, and does the job! AFAICT the logic above ought to fix #4815, as well as (obviously) the scipy.sparse issues, and is at least possible for me to understand, which the current code / this PR doesn't seem to be. Even more obviously I'm surely missing something. What is it? |
@njsmith - I have to agree the rationale right now is opaque. Rereading your e-mail and the NEP example you linked to, I also think that in that context my original PR (#4815) actually has some merit, in that if one argues that having Still, from a larger perspective, it would seem up to the implementers of p.s. But don't let this detract from the fact that the introduction of |
BUG Numpy ufunc binop fix for subclasses with __numpy_ufunc__ (closes #4815)
Uh. I am unsure whether this patch is the correct solution, but strongly suspect it is not. |
@mhvk This is a fairly substantive addition, so it needs some documentation, both in |
@njsmith Alternatives welcome ;) I vaguely recall a proposal to add a dictionary to ndarray, which I think might allow us to define real left and right operators for ndarray. Longer term, I'd like to see both masks and units as part fo the basic array, but I think that means funding some people to work on dynd. Both extended types and priorites will alway suffer from the promotion/precedence problem. What I like about this solution is that it is isolated to the operators and is not very intrusive. |
Units as part of the basic array makes no sense architecturally, units Regarding the actual patch: What I dislike about the solution is that it I am really uncomfortable with releasing 1.10 with new numpy_ufunc On Tue, May 5, 2015 at 8:13 PM, Charles Harris notifications@github.com
Nathaniel J. Smith -- http://vorpus.org |
I think the complexity here is comes from subclassing ndarray. Essentially, we are redefining subclassing ndarray as private inheritance (c++) (component or implementation) rather than "real" subclassing/polymorphism. We could make that official with another attribute |
Mind, I'm willing to revert this if we can come to a better solution. |
My comment above is perhaps a better solution? I am also trying to write up an actual description of how we do dispatch for these methods currently in another window right now. (Surprise discovery so far: all of those weird cases where ufunc calls return |
@njsmith: let's recap: (i) numpy_ufunc is logically independent of |
This fix for #4815 includes the solution by @pv and a test case to guard against regression.