-
-
Notifications
You must be signed in to change notification settings - Fork 11.2k
BUG: Make pocketfft handle long doubles. #12685
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
The shippable build died before testing. Can we restart it or do we need to close/open the PR? |
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 be even easier (see in-line comment). Do add a test as well!
numpy/fft/pocketfft.py
Outdated
@@ -173,7 +173,7 @@ def fft(a, n=None, axis=-1, norm=None): | |||
|
|||
""" | |||
|
|||
a = asarray(a) | |||
a = asarray(a).astype(complex, copy=False) |
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.
To get the dtype more directly just do asarray(a, dtype=complex)
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.
Thanks, will adjust soon!
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 actually need to cast to complex
here if the data is already float64
? It would be worth enumerating in the issue description exactly which types currently fail, so we can work out which casts are actually necessary.
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.
Ah, yes, since the pocketfft
code runs on either standard double of complex, I think you actually do need asarray
first (to ensure we know the dtype
) and then an astype
, but like:
a = asarray(a)
# Cast to either standard double or standard complex
a = a.astype(complex if a.dtype.kind == 'c' else float)
Probably good to make this a little helper function...
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 pocketfft support float32
without casting here?
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.
https://github.com/scipy/scipy/blob/v1.2.0/scipy/interpolate/_bsplines.py#L33
This or similar incantation occurs several times in scipy, and every time the sentiment is "annoyingly, there's no numpy function for it".
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 think I'm only now beginning to understand the real problem here ...
What exactly does
TypeError: Cannot cast array data from dtype('float128') to dtype('complex128') according to the rule 'safe'
mean? So far I thought the code was complaining that it couldn't convert a float type to a complex one, but actually it seems to be about the loss of precision.
If that assumption is correct, we only have to do a cast if the input has 128bit precision. Everything else will be handled automatically by the existing code.
Is there a way to allow "unsafe" casting in PyArray_ContiguousFromObject()
and PyArray_CopyFromObject()
?
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.
complex128
has float64
real and imaginary, hence it cannot be safely cast indeed. Passing on astype(..., casting='unsafe')
should solve it.
Sorry, really should have thought of that before...
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.
The problem is that I currently do all the hard work (making sure that the input is contiguous and of the proper type) in the C part. If I cannot ask for unsafe casting there, this may lead to duplicated work, which I'd like to avoid. But if the C interface does not have the facility, I'll move this to Python.
I restarted the Shippable build manually; looks like some connection issues for a subset of the Azure 32 bit jobs at the moment |
Previous to merging pocketfft were we also downcasting |
It must have happened somewhere; the C code only dealt with double precision, exactly as the current one. |
I think that should do the trick. |
The azure failures are because windows doesn't have 128 bit floats, and Linux 32 bit platforms have 96 bit floats instead. Instead of |
Good to go? |
x = random(30).astype(np.dtype(c)) | ||
assert_array_almost_equal(np.fft.ifft(np.fft.fft(x)), x) | ||
assert_array_almost_equal(np.fft.irfft(np.fft.rfft(x)), x) | ||
|
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.
Is there a reason you didn't use 'efdgFDG'
which is all the float types?
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.
Also, may as well use pytest.mark.parametrize
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'm not using the "FDG" types because that would mean calling a real-valued FFT with a complex-valued input, which really makes no sense (and it produces a warning as expected).
I can add "e", if you like.
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'm sorry, I don't have the time right now to learn how pytest
works.
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.
@pytest.mark.parametrize("dtype", [np.half, np.single, np.double, np.longdouble])
def test_something(dtype):
...
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.
Thanks!
While we are at it: should I remove all |
No. We are postponing the big Python 2.7 cleanup till the end of the year just to keep backports as simple as we can for the LTS 1.16. |
LGTM. |
LGTM too. |
Thanks @mreineck |
BUG: fix #12663