-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
ENH: Added support for arrays with dtype=object
to np.isinf
, np.isnan
, np.isfinite
#10820
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
), | ||
'isfinite': | ||
Ufunc(1, 1, None, | ||
docstrings.get('numpy.core.umath.isfinite'), | ||
None, | ||
TD(inexact, out='?'), | ||
TD(noint, out='?'), |
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.
What happens if I have multiple overlapping TD
calls? e.g., if I hadn't deleted the line TD(inexact, out='?')
here.
@@ -1287,6 +1287,71 @@ def test_nan(): | |||
|
|||
assert_raises(TypeError, test_nan) | |||
|
|||
|
|||
class _CustomFloat(object): |
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.
If there is already an implementation of mocks like these somewhere, I would be happy to get rid of them.
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.
Can you use unittest.mock
?
numpy/core/src/umath/loops.c.src
Outdated
int v; | ||
|
||
UNARY_LOOP { | ||
PyObject *in1 = *(PyObject **)ip1; |
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 am almost 100% sure that I don't need to Py_INCREF(in1)
here or anywhere else, but I feel like someone should verify that since I do pass it to PyFloat_AsDouble
and PyComplex_AsCComplex
down the line.
numpy/core/src/umath/loops.c.src
Outdated
if (cplx.real == -1.0 && cplx.imag == 0.0 && PyErr_Occurred()) { | ||
PyErr_Format(PyExc_TypeError, "must be real or complex number, not %s", | ||
Py_TYPE(in1)->tp_name); | ||
break; |
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.
Does a corresponding Py_DECREF(in1)
need to go here? (see above)
numpy/core/src/umath/loops.c.src
Outdated
else { | ||
v = @func@(dbl) != 0; | ||
} | ||
*((npy_bool *)op1) = v; |
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.
Does a corresponding Py_DECREF(in1)
need to go here? (see above)
I think this would be a little cleaner via |
Nothing seemed worth adding to the docs of the functions themselves.
1787c1a
to
30928b5
Compare
@eric-wieser. I have moved the implementation to I added support for integers (objects implementing I've added a couple more comments to my code about concerns that I have with the correctness. |
doc/release/1.14.0-notes.rst
Outdated
@@ -347,6 +347,12 @@ in the c-api_ documentation and the example in how-to-extend_. | |||
|
|||
.. _c-api: https://github.com/numpy/numpy/blob/master/doc/source/reference/c-api.array.rst | |||
.. _how-to-extend: https://github.com/numpy/numpy/blob/master/doc/source/user/c-info.how-to-extend.rst | |||
Support for ``dtype=object`` in ``isinf``, ``isnan``, ``isfinite`` | |||
Support for ``dtype=object`` in ``isnan``, ``isinf``, ``isfinite`` |
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.
Rebase mistake
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.
Fixed
Note this duplicates #6320 - you might want to compare to the approach used there |
@@ -808,6 +808,7 @@ def english_upper(s): | |||
docstrings.get('numpy.core.umath.isnan'), | |||
None, | |||
TD(inexact, out='?'), |
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.
What happens if I have multiple overlapping TD calls? e.g., if this line read TD(noint, out='?'), making conflicting protoypes for dtype=object
?
if(i1 == NULL) { | ||
return NULL; | ||
} | ||
else { |
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 am almost 100% sure that I don't need to Py_INCREF(i1) here or anywhere else, but I feel like someone should verify that since I do pass it to PyFloat_AsDouble
, PyComplex_AsCComplex
, etc down the line.
Just because all my tests pass does not mean that the refcounting is done correctly here.
@@ -226,6 +226,84 @@ npy_ObjectLCM(PyObject *i1, PyObject *i2) | |||
return PyNumber_Absolute(tmp); | |||
} | |||
|
|||
/* Utility used to check if a number is an integer or has an __int__/__long__ method */ |
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.
An alternative implementation is suggested by https://stackoverflow.com/a/49562820/2988730. However, using PyNumber_Long
/PyNumber_Int
will allow converstion of strings and objects with just __trunc__
but no __float__
, which I don't think we want.
@eric-wieser I agree that this should defer to #6320. I especially like the part where the result is always I will leave this around for a bit longer to see if anyone can give me more pointers. In the meantime, I will go work on adding |
Sounds good to me. Maybe add loops for the integer types too. I think there's a dead PR for that somewhere too. |
@eric-wieser Let me know if you find it. That was one of the questions I had at the top. At least for the three functions that I have here, you don't even need a loop, just a boolean array of all ones. Is that something that ufuncs can easily support? |
You just write a loop that ignores its inputs and writes ones to the output. |
Still looking, but found a related one for bools: #12988 |
@madphysicist would you like to continue with this? The release note should be rewritten as a fragment in |
@mattip. Eventually. I'm going to have to re-familiarize myself with what I did here first. |
Closing. This has been around for quite a while and has not moved very far. Please reopen if you want to pursue the idea. |
The loops check if the object has a
__float__
or__complex__
method, then handle the object as usual. Preference is given to__float__
in all cases. This is a preliminary step to make sure I understand the basics of how to add to aufunc
, so please grade harshly! The next step will be addingdatetime
andtimedelta
support tonp.isfinite
, in preparation for adding support tonp.histogram
.Two questions arise:
isinite
,isinf
,isnan
not optimized to always returnTrue
regardless of the input data?a. Am I correct to assume that the values are actually cast to floating point before running through the normal loop?
b. Is there any desire to change this? Or conversely, any motivation not to?
isneginf
andisposinf
not ufuncs likeisinf
? There does not appear to be any major issue except a minor break in backwards compatibility where the second parameter would be renamed fromy
toout
.