-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
ENH: add norm=forward,backward
to numpy.fft functions
#16476
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
Changes from 1 commit
087f7d3
8fc777a
789646d
93d834b
5e5e9c5
da249db
7a15c22
ca0dd88
48a3ef0
2110457
4427019
aaa438e
8a86168
693c942
21964b9
29149da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
``norm=forward`` keyword option available for ``numpy.fft`` functions | ||
--------------------------------------------------------------------- | ||
Using the keyword argument option ``norm=forward`` has the direct transforms | ||
scaled by ``1/n`` and the inverse transforms unscaled (i.e. directly opposite | ||
to the default option ``norm=None``). | ||
``norm=backward``, ``forward`` keyword options for ``numpy.fft`` functions | ||
-------------------------------------------------------------------------- | ||
The keyword argument option ``norm=backward`` is added as an alias for ``None`` | ||
and acts as the default option; using it has the direct transforms unscaled | ||
and the inverse transforms scaled by ``1/n``. | ||
|
||
Using the new keyword argument option ``norm=forward`` has the direct | ||
transforms scaled by ``1/n`` and the inverse transforms unscaled (i.e. directly | ||
opposite to the default option ``norm=backward``). |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,13 +128,13 @@ | |
Normalization | ||
------------- | ||
|
||
The default normalization has the direct transforms unscaled and the inverse | ||
transforms are scaled by :math:`1/n`. It is possible to obtain unitary | ||
transforms by setting the keyword argument ``norm`` to ``"ortho"`` (default is | ||
`None`) so that both direct and inverse transforms will be scaled by | ||
:math:`1/\\sqrt{n}`. Finally, setting the keyword argument "norm" to | ||
The default normalization has the direct (forward) transforms unscaled and the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add "backward" here. Maybe also an initial sentence just about the fact that the argument refers to the pair/which direction is transformed. It reads a bit more difficult than feels necessary to me, but I think its fine to leave for later improvements. Its not easy to write easy to read docs... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok; added a commit with all review suggestions @seberg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, will merge once the tests run through (maybe minus the azure tests if they are acting up again). |
||
inverse (backward) transforms scaled by :math:`1/n`. It is possible to obtain | ||
unitary transforms by setting the keyword argument ``norm`` to ``"ortho"`` | ||
(default is ``"backward"``) so that both direct and inverse transforms are | ||
scaled by :math:`1/\\sqrt{n}`. Finally, setting the keyword argument "norm" to | ||
cval26 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``"forward"`` has the direct transforms scaled by :math:`1/n` and the inverse | ||
transforms unscaled (i.e. directly oppposite to the default option ``None``). | ||
transforms unscaled (i.e. directly oppposite to the default ``"backward"``). | ||
cval26 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Real and Hermitian transforms | ||
----------------------------- | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,20 +3,20 @@ | |||||||||
|
||||||||||
Routines in this module: | ||||||||||
|
||||||||||
fft(a, n=None, axis=-1, norm=None) | ||||||||||
ifft(a, n=None, axis=-1, norm=None) | ||||||||||
rfft(a, n=None, axis=-1, norm=None) | ||||||||||
irfft(a, n=None, axis=-1, norm=None) | ||||||||||
hfft(a, n=None, axis=-1, norm=None) | ||||||||||
ihfft(a, n=None, axis=-1, norm=None) | ||||||||||
fftn(a, s=None, axes=None, norm=None) | ||||||||||
ifftn(a, s=None, axes=None, norm=None) | ||||||||||
rfftn(a, s=None, axes=None, norm=None) | ||||||||||
irfftn(a, s=None, axes=None, norm=None) | ||||||||||
fft2(a, s=None, axes=(-2,-1), norm=None) | ||||||||||
ifft2(a, s=None, axes=(-2, -1), norm=None) | ||||||||||
rfft2(a, s=None, axes=(-2,-1), norm=None) | ||||||||||
irfft2(a, s=None, axes=(-2, -1), norm=None) | ||||||||||
fft(a, n=None, axis=-1, norm="backward") | ||||||||||
ifft(a, n=None, axis=-1, norm="backward") | ||||||||||
rfft(a, n=None, axis=-1, norm="backward") | ||||||||||
irfft(a, n=None, axis=-1, norm="backward") | ||||||||||
hfft(a, n=None, axis=-1, norm="backward") | ||||||||||
ihfft(a, n=None, axis=-1, norm="backward") | ||||||||||
fftn(a, s=None, axes=None, norm="backward") | ||||||||||
ifftn(a, s=None, axes=None, norm="backward") | ||||||||||
rfftn(a, s=None, axes=None, norm="backward") | ||||||||||
irfftn(a, s=None, axes=None, norm="backward") | ||||||||||
fft2(a, s=None, axes=(-2,-1), norm="backward") | ||||||||||
ifft2(a, s=None, axes=(-2, -1), norm="backward") | ||||||||||
rfft2(a, s=None, axes=(-2,-1), norm="backward") | ||||||||||
irfft2(a, s=None, axes=(-2, -1), norm="backward") | ||||||||||
|
||||||||||
i = inverse transform | ||||||||||
r = transform of purely real data | ||||||||||
|
@@ -85,8 +85,8 @@ def _go_forw(n, norm): | |||||||||
10000 td> | return sqrt(n) | |||||||||
elif norm == "forward": | ||||||||||
return n | ||||||||||
raise ValueError(f"Invalid norm value {norm}; should be \"backward\"\ | ||||||||||
(None), \"ortho\" or \"forward\".") | ||||||||||
raise ValueError(f'Invalid norm value {norm}; should be "backward",\ | ||||||||||
"ortho" or "forward".') | ||||||||||
|
||||||||||
|
||||||||||
def _go_back(n, norm): | ||||||||||
|
@@ -99,8 +99,17 @@ def _go_back(n, norm): | |||||||||
return sqrt(n) | ||||||||||
elif norm == "forward": | ||||||||||
return 1 | ||||||||||
raise ValueError(f"Invalid norm value {norm}; should be \"backward\"\ | ||||||||||
(None), \"ortho\" or \"forward\".") | ||||||||||
raise ValueError(f'Invalid norm value {norm}; should be "backward",\ | ||||||||||
"ortho" or "forward".') | ||||||||||
|
||||||||||
|
||||||||||
def _swap_direction(norm): | ||||||||||
try: | ||||||||||
return {"backward": "forward", None: "forward", | ||||||||||
"ortho": "ortho", "forward": "backward"}[norm] | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is micro-optimization, but I'd prefer a plain if-else over dict for simple cases like this... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. apart from how compact it is, I think this is superior to a plain if-else clause bcs it handles the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's wrong with this? if ...:
# do this
elif ...:
# do that
else:
raise ValueError(...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you move the dictionary into a module level constant, _SWAP_DIRECTION_MAP = {...}
def _swap_direction(norm):
try:
return _SWAP_DIRECTION_MAP[norm]
except KeyError:
raise ValueError("") There's not much in it though, a few 10s of nanoseconds at most I think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, Peter! Is it because this way we save time for the dict construction? Like I said this is micro optimization, that I was just curious why dict was preferred is all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in my reply I didn't mean that using an initially I was thinking of writing it with an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i've added a commit moving the dictionary into a module level constant to accelerate the lookup; it looks like our two options are: (1) use a let me know what you think; from the comments I understand that these are comparable in terms of performance @peterbell10 @leofang There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, if it's inside the function then the dict is reconstructed for every function call whereas the module level variable is constructed only once at import time. As for dict vs if-else in a more general sense. I have no strong feeling either way, both are not that much code and both can be quite readable. |
||||||||||
except KeyError: | ||||||||||
raise ValueError(f'Invalid norm value {norm}; should be "backward",\ | ||||||||||
"ortho" or "forward".') | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (The line continuation change also above) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||||||||||
|
||||||||||
|
||||||||||
def _fft_dispatcher(a, n=None, axis=None, norm=None): | ||||||||||
|
@@ -131,12 +140,11 @@ def fft(a, n=None, axis=-1, norm=None): | |||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
cval26 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). | ||||||||||
Default is "backward" (alias of None). | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be great to have 1-2 sentences here pointing out that the normalization signals where the normalization occurs in the fft-ifft pair. And/or just making this slightly longer to provide some of the info from the general docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
cval26 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
The "backward", "forward" options were added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -239,14 +247,14 @@ def ifft(a, n=None, axis=-1, norm=None): | |||||||||
axis : int, optional | ||||||||||
Axis over which to compute the inverse DFT. If not given, the last | ||||||||||
axis is used. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -321,14 +329,14 @@ def rfft(a, n=None, axis=-1, norm=None): | |||||||||
axis : int, optional | ||||||||||
Axis over which to compute the FFT. If not given, the last axis is | ||||||||||
used. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -421,14 +429,14 @@ def irfft(a, n=None, axis=-1, norm=None): | |||||||||
axis : int, optional | ||||||||||
Axis over which to compute the inverse FFT. If not given, the last | ||||||||||
axis is used. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -513,14 +521,14 @@ def hfft(a, n=None, axis=-1, norm=None): | |||||||||
axis : int, optional | ||||||||||
Axis over which to compute the FFT. If not given, the last | ||||||||||
axis is used. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -584,8 +592,8 @@ def hfft(a, n=None, axis=-1, norm=None): | |||||||||
a = asarray(a) | ||||||||||
if n is None: | ||||||||||
n = (a.shape[axis] - 1) * 2 | ||||||||||
output = irfft(conjugate(a), n, axis) | ||||||||||
output *= _go_back(n, norm) | ||||||||||
new_norm = _swap_direction(norm) | ||||||||||
output = irfft(conjugate(a), n, axis, norm=new_norm) | ||||||||||
return output | ||||||||||
cval26 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
|
||||||||||
|
@@ -607,14 +615,14 @@ def ihfft(a, n=None, axis=-1, norm=None): | |||||||||
axis : int, optional | ||||||||||
Axis over which to compute the inverse FFT. If not given, the last | ||||||||||
axis is used. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -649,8 +657,8 @@ def ihfft(a, n=None, axis=-1, norm=None): | |||||||||
a = asarray(a) | ||||||||||
if n is None: | ||||||||||
n = a.shape[axis] | ||||||||||
output = conjugate(rfft(a, n, axis)) | ||||||||||
output *= 1./_go_back(n, norm) | ||||||||||
new_norm = _swap_direction(norm) | ||||||||||
output = conjugate(rfft(a, n, axis, norm=new_norm)) | ||||||||||
return output | ||||||||||
|
||||||||||
|
||||||||||
|
@@ -713,14 +721,14 @@ def fftn(a, s=None, axes=None, norm=None): | |||||||||
axes are used, or all axes if `s` is also not specified. | ||||||||||
Repeated indices in `axes` means that the transform over that axis is | ||||||||||
performed multiple times. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -823,14 +831,14 @@ def ifftn(a, s=None, axes=None, norm=None): | |||||||||
axes are used, or all axes if `s` is also not specified. | ||||||||||
Repeated indices in `axes` means that the inverse transform over that | ||||||||||
axis is performed multiple times. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -916,14 +924,14 @@ def fft2(a, s=None, axes=(-2, -1), norm=None): | |||||||||
axes are used. A repeated index in `axes` means the transform over | ||||||||||
that axis is performed multiple times. A one-element sequence means | ||||||||||
that a one-dimensional FFT is performed. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -1017,14 +1025,14 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None): | |||||||||
axes are used. A repeated index in `axes` means the transform over | ||||||||||
that axis is performed multiple times. A one-element sequence means | ||||||||||
that a one-dimensional FFT is performed. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -1101,14 +1109,14 @@ def rfftn(a, s=None, axes=None, norm=None): | |||||||||
axes : sequence of ints, optional | ||||||||||
Axes over which to compute the FFT. If not given, the last ``len(s)`` | ||||||||||
axes are used, or all axes if `s` is also not specified. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -1183,14 +1191,14 @@ def rfft2(a, s=None, axes=(-2, -1), norm=None): | |||||||||
Shape of the FFT. | ||||||||||
axes : sequence of ints, optional | ||||||||||
Axes over which to compute the FFT. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -1246,14 +1254,14 @@ def irfftn(a, s=None, axes=None, norm=None): | |||||||||
`len(s)` axes are used, or all axes if `s` is also not specified. | ||||||||||
Repeated indices in `axes` means that the inverse transform over that | ||||||||||
axis is performed multiple times. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
@@ -1333,14 +1341,14 @@ def irfft2(a, s=None, axes=(-2, -1), norm=None): | |||||||||
axes : sequence of ints, optional | ||||||||||
The axes over which to compute the inverse fft. 57AE td> | ||||||||||
Default is the last two axes. | ||||||||||
norm : {None, "ortho", "forward"}, optional | ||||||||||
norm : {"backward", "ortho", "forward"}, optional | ||||||||||
.. versionadded:: 1.10.0 | ||||||||||
|
||||||||||
Normalization mode (see `numpy.fft`). Default is None. | ||||||||||
Normalization mode (see `numpy.fft`). Default is "backward". | ||||||||||
|
||||||||||
.. versionadded:: 1.20.0 | ||||||||||
|
||||||||||
The "forward" option was added. | ||||||||||
The "backward", "forward" values were added. | ||||||||||
|
||||||||||
Returns | ||||||||||
------- | ||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.