-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: preserve subclasses in ufunc.outer #8662
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
Good ol'
Seems we need a |
This is great! I was worried this might not go through It would probably good to test the subclass-with-method explicitly, but sadly the current state of testing is not all that great (there are some tests with subclasses in p.s. If you have any ideas for |
Ok, what should this code do? >>> x = np.matrix([[1, 2, 3]])
>>> np.add.outer(x, x)
array([[[[2, 3, 4]],
[[3, 4, 5]],
[[4, 5, 6]]]]) Right now, it returns an object of shape >>> np.add.outer(x, x)
matrix([[2, 4, 6]]) Do we really need to special case a pure-python subclass in the C code to make this work? Or can we kill this class of bugs forever by allowing |
I just looked at the failures and noticed the same thing -- and, no, one doesn't need to patch the C code, but I fear this means
So, I think in (Definitely needs more thought...). |
p.s. It would be nice for |
It already does. All
I don't think that'd help - the problem is that |
OK, I understand the path now. I guess there are only two real solutions:
In favour of (1) is that matrices are semi-deprecated anyway, now thought to have been a bad idea (and, really, to not have stacks of matrices is itself quite deadly). And it is nice to have other subclasses just work as expected. In favour of (2) is that somebody out there may count on |
I don't think
|
@eric-wieser - |
@mhvk: So, interesting question about
Does this execute both print statements, or just the first? To me, it seems desirable that both are executed. Maybe merging this pr after the |
I just checked and currently it will just go through the "not handled" clause. This is probably the best behaviour -- for ndarray subclasses, by passing on to |
Not without this patch they don't, as |
But presumably subclasses have already discarded their subclass nature in their |
I guess I'm envisaging an array with a custom Right now, the user is forced to reimplement the entirety of |
I don't quite see the problem: with |
Restarting tests against the latest head, since they've moved around a bunch in the last year |
6d3eaf7
to
126bd86
Compare
I got the tests to pass locally by preserving the old behavior for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would need to add unit tests even if reviewers could stomach this approach.
numpy/core/src/umath/ufunc_object.c
Outdated
@@ -5396,6 +5396,8 @@ ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) | |||
PyArrayObject *ap1 = NULL, *ap2 = NULL, *ap_new = NULL; | |||
PyObject *new_args, *tmp; | |||
PyObject *shape1, *shape2, *newshape; | |||
PyObject *numpy = PyImport_ImportModule("numpy"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't imagine this will help performance any for ufunc method--though these kinds of imports are littered throughout NumPy source
numpy/core/src/umath/ufunc_object.c
Outdated
@@ -5428,7 +5430,12 @@ ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) | |||
if (tmp == NULL) { | |||
return NULL; | |||
} | |||
ap1 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0); | |||
if (PyObject_IsInstance(tmp, numpy_matrix)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also spent some time looking at ways to probe for attributes unique to np.matrix
, in the hopes of keeping this check confined to the C level as much as possible.
Those with more matrix experience may have a better idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care enough about matrix
subclasses to do the IsInstance
rather than a direct type check? (Assuming the latter is fast also for pure python classes.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems wrong. Why are we special-casing matrix
, which we want to deprecate anyway, deep inside the ufunc machinery? Matrix is no more special than any other ndarray subclass, and should be using a protocol to avoid getting here in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because if matrix isn't handled specially somehow, it will create a behavior change here. Trying to implement a correct __array_ufunc__
for a deprecated type is probably not worth the time vs just hacking around it until it can be removed.
Does this actually fix the linked issue?
|
Just to note that the black hole imaging software used matrices in places. |
I don't understand--do you have a specific question? Yes, I ran the 3 lines of code in the linked issue to verify the fix, and I suspect Eric did on the original change too. Adding tests eventually can solidify things. |
* use an instance check to avoid complications with the matrix subclass * add unit test for allowing subclass passthrough in ufunc.outer
126bd86
to
e043bb9
Compare
I revised with an attempt at Eric's caching suggestion & a first draft of a possible unit test. I didn't switch to a stricter matrix type check as per Marten's comment yet, is that the direction the majority wants? |
I think this is good enough. Will merge soon unless someone objects |
Thanks Eric |
npy_cache_import( | ||
"numpy", | ||
"matrix", | ||
&_numpy_matrix); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing null check after this runs
Previously this was forcing to ndarray. Fixes #8661