Skip to content

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

Merged
merged 2 commits into from
Jan 8, 2019
Merged

BUG: Make pocketfft handle long doubles. #12685

merged 2 commits into from
Jan 8, 2019

Conversation

mreineck
Copy link
Contributor

@mreineck mreineck commented Jan 7, 2019

BUG: fix #12663

@mattip
Copy link
Member

mattip commented Jan 7, 2019

The shippable build died before testing. Can we restart it or do we need to close/open the PR?

Copy link
Contributor

@mhvk mhvk left a 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!

@@ -173,7 +173,7 @@ def fft(a, n=None, axis=-1, norm=None):

"""

a = asarray(a)
a = asarray(a).astype(complex, copy=False)
Copy link
Contributor

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, will adjust soon!

Copy link
Member

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.

Copy link
Contributor

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...

Copy link
Member

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?

Copy link
Contributor

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".

Copy link
Contributor Author

@mreineck mreineck Jan 7, 2019

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()?

Copy link
Contributor

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...

Copy link
Contributor Author

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.

@tylerjereddy
Copy link
Contributor

I restarted the Shippable build manually; looks like some connection issues for a subset of the Azure 32 bit jobs at the moment

@mattip
Copy link
Member

mattip commented Jan 7, 2019

Previous to merging pocketfft were we also downcasting longdouble to float64?

@mreineck
Copy link
Contributor Author

mreineck commented Jan 7, 2019

It must have happened somewhere; the C code only dealt with double precision, exactly as the current one.

@mreineck
Copy link
Contributor Author

mreineck commented Jan 7, 2019

I think that should do the trick.

@charris
Copy link
Member

charris commented Jan 7, 2019

The azure failures are because windows doesn't have 128 bit floats, and Linux 32 bit platforms have 96 bit floats instead. Instead of float128 you should try longdouble and clongdouble. I like to try all float types myself, so [dtype[c] for c in "efdgFDG"].

@charris charris changed the title BUG: fix #12663 BUG: Make pocketfft handle long doubles. Jan 7, 2019
tweak and add test

better fix

fix

cleanup, additional test

fix test
@mreineck
Copy link
Contributor Author

mreineck commented Jan 8, 2019

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)

Copy link
Member

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?

Copy link
Member

@eric-wieser eric-wieser Jan 8, 2019

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Member

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):
   ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@mreineck
Copy link
Contributor Author

mreineck commented Jan 8, 2019

While we are at it: should I remove all __future__ imports from the FFT sources, now that Python3 is mandatory?

@charris
Copy link
Member

charris commented Jan 8, 2019

should I remove all __future__ imports from the FFT sources

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.

@mattip
Copy link
Member

mattip commented Jan 8, 2019

LGTM.

@mhvk
Copy link
Contributor

mhvk commented Jan 8, 2019

LGTM too.

@mattip mattip merged commit 9405d2b into numpy:master Jan 8, 2019
@mattip
Copy link
Member

mattip commented Jan 8, 2019

Thanks @mreineck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

FFT transforms no longer handle float128 arrays
7 participants