Skip to content

Conversation

@peterbell10
Copy link
Member

@peterbell10 peterbell10 commented May 31, 2019

Closes #10175

Enhancements

  • Support for long double transforms
  • Multi-threading using OpenMP (disabled for now)
  • NumPy-like real to complex rffts including n-dimensional transforms rfftn
  • Orthonormal transforms (norm = 'ortho')
  • Bluestein's algorithm
  • GIL is released during transforms

Issues

  • The build definitions don't select the extra_compile_args based on the compiler which would be needed to compile with OpenMP in a portable way.
  • FFTPACK optimized for the case when real sequences were passed to fft which is missing from pocketfft currently.
  • Normalization factors are only passed to c++ with double precision, even for long double transforms.
  • This adds a build time dependency on pybind11 and I'm not sure if it is required at run-time as well.
  • Docstrings need to be written
  • The pocketfft backend is passing all of the numpy.fft tests and most of the scipy.fftpack tests after some modifications. I have 1 remaining failure locally which is a precision difference for float32 transforms. Needs investigation.

Open questions

@rgommers rgommers added enhancement A new feature or improvement scipy.fft labels May 31, 2019
@rgommers
Copy link
Member

Thanks @peterbell10, great start!

I created a new scipy.fft label for the new submodule.

For all the things that need significant discussion and deciding, I suggest to create separate issues. And keep the list in this PR as the "master issue". Otherwise things will get unwieldy. Suggestion of separate issues:

  • OpenMP portability and build config (incl pybind11).
  • what functions to include in the new module (e.g. hfft)
  • multithreading behavior
  • overwrite_x

@peterbell10
Copy link
Member Author

Thanks @rgommers, that's a good idea.

@peterbell10
Copy link
Member Author

Regarding the failing test, single precision fftpack tests were marked as xfail so fftpack failed for the same test case. Investigating it shows that pocketfft is in fact more accurate than fftpack.

Max abs diff fft:      2.99796178049074e-06
Max abs diff fftpack:  3.06302563664315e-06
Max rel diff fft:      4.73642558242986e-05
Max rel diff fftpack:  2.63469637785951e-04

I've given single precision variants slightly more tolerance so the test should be passing now.

@peterbell10 peterbell10 force-pushed the scipy-fft branch 2 times, most recently from 3bffa16 to 550f389 Compare June 4, 2019 15:36
@peterbell10
Copy link
Member Author

I've had a look through the pybind11 repo and the only python code is either tests or the get_include functionality. That, combined with the fact that there is nothing else linked in; I'm now reasonably confident that it's only a build-time dependency.

@peterbell10
Copy link
Member Author

Also, I'm planning to base a lot of the documentation off the numpy fft docs as they seemed to be slightly more consistent. I hope that's not a problem.

@rgommers
Copy link
Member

rgommers commented Jun 4, 2019

Also, I'm planning to base a lot of the documentation off the numpy fft docs as they seemed to be slightly more consistent. I hope that's not a problem.

Definitely not, please borrow whatever is helpful!

@peterbell10
Copy link
Member Author

I'm struggling to get the documentation to build correctly. The scipy.fft module docstring gives me a numpydoc error, despite it being very similar to every other module docstring

Unknown section Fast Fourier Transforms (ffts) in the docstring of <module 'scipy.fft'[...]

which comes from this section heading in the docstring, which is exactly the same as for fftpack

Fast Fourier Transforms (FFTs)
==============================

If I remove the section headings entirely, the module summary builds. However, there are no .rst files for the fft module in doc/source/generated so the functions aren't documented anywhere. I assume I need to tell the generator about the fft module somewhere but I can't see where the generator is.

Any help would be appreciated.

@rgommers
Copy link
Member

rgommers commented Jun 5, 2019

Unknown section

Hmm, that error is normally for function docstrings. Perhaps numpydoc gets itself confused and is parsing a module docstring as function docstring. Could be because scipy.fft used to be a function and you didn't do a clean rebuild?

@peterbell10
Copy link
Member Author

peterbell10 commented Jun 5, 2019

CircleCI should be doing a clean build and it's happening on there as well.

Edit: I just tried removing all reference to numpy.fft.fft from the scipy __init__.py and still get the same error.

@peterbell10
Copy link
Member Author

It looks like the root cause is that isinstance(scipy.fft, Callable)==True, so numpydoc is treating it like a function.

@peterbell10
Copy link
Member Author

peterbell10 commented Jun 6, 2019

I've added a workaround for sphinx documenting scipy.fft as a function and the numpydoc error is gone. However, the function documentation still isn't being generated.

I've also been trying to update the setup.py to conditionally add --std=c++11 for gcc-like compilers. The correct way to do this seems to be providing a custom build_ext class but there doesn't seem to be a standard way to update cmdclass in the numpy.distutils Configuration object.

@peterbell10 peterbell10 marked this pull request as ready for review June 6, 2019 13:37
@larsoner
Copy link
Member

Okay the FFT people appear to be happy and no other complaints, in it goes. Thanks @peterbell10 !

@larsoner larsoner merged commit 8b45c7e into scipy:master Jun 24, 2019
@WarrenWeckesser
Copy link
Member

This adds a build time dependency on pybind11 and I'm not sure if it is required at run-time as well.

This should be documented in INSTALL.rst.txt.

Kai-Striega added a commit to Kai-Striega/scipy that referenced this pull request Jun 25, 2019
The addition of the scipy.fft module [1] adds pybind11 as an additional
build time dependency. This has already been documented in
INSTALL.rst.txt [2] but not in HACKING.rst.txt. This commit adds
pybind11 to the required dependencies.

[1] scipy#10238
[2] scipy#10348

def rfft2(x, shape=None, axes=(-2,-1), norm=None, overwrite_x=False):
"""
2-D dicsrete Fourier transform of a real sequence
Copy link
Member

Choose a reason for hiding this comment

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

"discrete" typo


def irfft2(x, shape=None, axes=(-2,-1), norm=None, overwrite_x=False):
"""
2-D dicsrete inverse Fourier transform of a real sequence
Copy link
Member

Choose a reason for hiding this comment

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

"discrete" typo

return pfft.ifftn(tmp, axes, norm, overwrite_x, _default_workers)

def rfftn(x, shape=None, axes=None, norm=None, overwrite_x=False):
"""Return multi-dimentional discrete Fourier transform of real input"""
Copy link
Member

Choose a reason for hiding this comment

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

"multi-dimentional" typo


def rfft(x, n=None, axis=-1, norm=None, overwrite_x=False):
"""
Discrete Fourier transform of a real sequence.
Copy link
Member

@endolith endolith Jun 28, 2019

Choose a reason for hiding this comment

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

I guess these docstrings will be expanded to the same level of detail as the old ones in a different PR?

Copy link
Member Author

@peterbell10 peterbell10 Jun 28, 2019

Choose a reason for hiding this comment

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

The user-facing API is in scipy/fft/_basic.py which has the full docstrings.

Copy link
Member Author

Choose a reason for hiding this comment

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

See the rendered docs

@peterbell10
Copy link
Member Author

I've added a release note to the wiki page:
https://github.com/scipy/scipy/wiki/Release-note-entries-for-SciPy-1.4.0#scipyfft-added

@rgommers
Copy link
Member

That looks great, thanks Peter

@WarrenWeckesser
Copy link
Member

I was about to update some old code to use scipy.fft instead of scipy.fftpack, but I see that scipy.fft doesn't have a replacement for scipy.fftpack.diff. Was there ever a plan to add diff (or something similar) to scipy.fft? Or is something equivalent already available somewhere else?

@mreineck
Copy link
Contributor

I vaguely remember that we discussed that at the time and think we agreed that no replacement was needed, since diff was not documented and not used. That said, it should be easy to add as a post-processing step, correct?

@WarrenWeckesser
Copy link
Member

The docstring that I linked to is not complete, but I wouldn't say the function was not documented. It is definitely part of the public API. It might not be widely used, but:

Having said all that, apparently this is the first time someone has asked about the "missing" functions, so I guess the demand isn't really that high. Certainly the method is widely used, but I suspect the existence of the function is not well known. If you understand the method, it is not hard to implement, but I wouldn't call our current implementation trivial:

tmp = asarray(x)
if order == 0:
return tmp
if iscomplexobj(tmp):
return diff(tmp.real,order,period)+1j*diff(tmp.imag,order,period)
if period is not None:
c = 2*pi/period
else:
c = 1.0
n = len(x)
omega = _cache.get((n,order,c))
if omega is None:
if len(_cache) > 20:
while _cache:
_cache.popitem()
def kernel(k,order=order,c=c):
if k:
return pow(c*k,order)
return 0
omega = convolve.init_convolution_kernel(n,kernel,d=order,
zero_nyquist=1)
_cache[(n,order,c)] = omega
overwrite_x = _datacopied(tmp, x)
return convolve.convolve(tmp,omega,swap_real_imag=order % 2,
overwrite_x=overwrite_x)

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

Labels

enhancement A new feature or improvement scipy.fft

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use pypocketfft as FFT backend?

10 participants