8000 API: adjust nD fft `s` param to array API · numpy/numpy@72b7d19 · GitHub
[go: up one dir, main page]

Skip to content

Commit 72b7d19

Browse files
committed
API: adjust nD fft s param to array API
1 parent 284a2f0 commit 72b7d19

File tree

4 files changed

+143
-14
lines changed

4 files changed

+143
-14
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
`numpy.fft` deprecations for n-D transforms with ``None`` values in arguments
2+
-------------------------------------------------------------------------
3+
4+
`numpy.fft.fftn`, `numpy.fft.ifftn`, `numpy.fft.rfftn` and `numpy.fft.irfftn`
5+
are deprecated in line with the following part of the array API
6+
specification: "If ``s`` is not ``None``, ``axes`` must not be ``None``".
7+
Furthermore, passing an array to ``s`` which contains ``None`` values is
8+
deprecated as the parameter is documented to accept a sequence of integers
9+
in both the NumPy docs and the array API specification.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
`numpy.fft` n-D transforms allow ``s[i] == -1``
2+
-----------------------------------------------
3+
4+
`numpy.fft.fftn`, `numpy.fft.ifftn`, `numpy.fft.rfftn`, `numpy.fft.irfftn`,
5+
`numpy.fft.fft2`, and `numpy.fft.ifft2` now use the whole input array along
6+
the axis ``i`` if ``s[i] == -1``, in line with the array API specification.

numpy/fft/_pocketfft.py

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
'irfftn', 'rfft2', 'irfft2', 'fft2', 'ifft2', 'fftn', 'ifftn']
3232

3333
import functools
34+
import warnings
3435

3536
from numpy.lib.array_utils import normalize_axis_index
3637
from numpy._core import asarray, zeros, swapaxes, conjugate, take, sqrt
@@ -681,20 +682,38 @@ def ihfft(a, n=None, axis=-1, norm=None):
681682

682683
def _cook_nd_args(a, s=None, axes=None, invreal=0):
683684
if s is None:
684-
shapeless = 1
685+
shapeless = True
685686
if axes is None:
686687
s = list(a.shape)
687688
else:
688689
s = take(a.shape, axes)
689690
else:
690-
shapeless = 0
691+
shapeless = False
691692
s = list(s)
692693
if axes is None:
694+
if not shapeless:
695+
msg = ("`axes` should not be `None` if `s` is not `None` "
696+
"(Deprecated in NumPy 2.0). In a future version of NumPy, "
697+
"this will raise an error 8000 and `s[i]` will correspond to "
698+
"the size along the transformed axis specified by "
699+
"`axes[i]`. To retain current behaviour, pass a sequence "
700+
"[0, ..., k-1] to `axes` for an array of dimension k.")
701+
warnings.warn(msg, DeprecationWarning, stacklevel=3)
693702
axes = list(range(-len(s), 0))
694703
if len(s) != len(axes):
695704
raise ValueError("Shape and axes have different lengths.")
696705
if invreal and shapeless:
697706
s[-1] = (a.shape[axes[-1]] - 1) * 2
707+
if None in s:
708+
msg = ("Passing an array containing `None` values to `s` is "
709+
"deprecated in NumPy 2.0 and will raise an error in "
710+
"a future version of NumPy. To use the default behaviour "
711+
"of the corresponding 1-D transform, pass the value matching "
712+
"the default for its `n` parameter. To use the default "
713+
"behaviour for every axis, the `s` argument can be omitted.")
714+
warnings.warn(msg, DeprecationWarning, stacklevel=3)
715+
# use the whole input array along axis `i` if `s[i] == -1`
716+
s = [a.shape[_a] if _s == -1 else _s for _s, _a in zip(s, axes)]
698717
return s, axes
699718

700719

@@ -730,14 +749,30 @@ def fftn(a, s=None, axes=None, norm=None):
730749
(``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.).
731750
This corresponds to ``n`` for ``fft(x, n)``.
732751
Along any axis, if the given shape is smaller than that of the input,
733-
the input is cropped. If it is larger, the input is padded with zeros.
734-
if `s` is not given, the shape of the input along the axes specified
752+
the input is cropped. If it is larger, the input is padded with zeros.
753+
754+
.. versionchanged:: 2.0
755+
756+
If it is ``-1``, the whole input is used (no padding/trimming).
757+
758+
If `s` is not given, the shape of the input along the axes specified
735759
by `axes` is used.
760+
761+
.. deprecated:: 2.0
762+
763+
If `s` is not ``None``, `axes` must not be ``None`` either.
764+
736765
axes : sequence of ints, optional
737766
Axes over which to compute the FFT. If not given, the last ``len(s)``
738767
axes are used, or all axes if `s` is also not specified.
739768
Repeated indices in `axes` means that the transform over that axis is
740769
performed multiple times.
770+
771+
.. deprecated:: 2.0
772+
773+
If `s` is specified, the corresponding `axes` to be transformed
774+
must be explicitly specified too.
775+
741776
norm : {"backward", "ortho", "forward"}, optional
742777
.. versionadded:: 1.10.0
743778
@@ -842,14 +877,30 @@ def ifftn(a, s=None, axes=None, norm=None):
842877
(``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.).
843878
This corresponds to ``n`` for ``ifft(x, n)``.
844879
Along any axis, if the given shape is smaller than that of the input,
845-
the input is cropped. If it is larger, the input is padded with zeros.
846-
if `s` is not given, the shape of the input along the axes specified
847-
by `axes` is used. See notes for issue on `ifft` zero padding.
880+
the input is cropped. If it is larger, the input is padded with zeros.
881+
882+
.. versionchanged:: 2.0
883+
884+
If it is ``-1``, the whole input is used (no padding/trimming).
885+
886+
If `s` is not given, the shape of the input along the axes specified
887+
by `axes` is used. See notes for issue on `ifft` zero padding.
888+
889+
.. deprecated:: 2.0
890+
891+
If `s` is not ``None``, `axes` must not be ``None`` either.
892+
848893
axes : sequence of ints, optional
849894
Axes over which to compute the IFFT. If not given, the last ``len(s)``
850895
axes are used, or all axes if `s` is also not specified.
851896
Repeated indices in `axes` means that the inverse transform over that
852897
axis is performed multiple times.
898+
899+
.. deprecated:: 2.0
900+
901+
If `s` is specified, the corresponding `axes` to be transformed
902+
must be explicitly specified too.
903+
853904
norm : {"backward", "ortho", "forward"}, optional
854905
.. versionadded:: 1.10.0
855906
@@ -937,8 +988,13 @@ def fft2(a, s=None, axes=(-2, -1), norm=None):
937988
(``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.).
938989
This corresponds to ``n`` for ``fft(x, n)``.
939990
Along each axis, if the given shape is smaller than that of the input,
940-
the input is cropped. If it is larger, the input is padded with zeros.
941-
if `s` is not given, the shape of the input along the axes specified
991+
the input is cropped. If it is larger, the input is padded with zeros.
992+
993+
.. versionchanged:: 2.0
994+
995+
If it is ``-1``, the whole input is used (no padding/trimming).
996+
997+
If `s` is not given, the shape of the input along the axes specified
942998
by `axes` is used.
943999
axes : sequence of ints, optional
9441000
Axes over which to compute the FFT. If not given, the last two
@@ -1040,8 +1096,13 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None):
10401096
Shape (length of each axis) of the output (``s[0]`` refers to axis 0,
10411097
``s[1]`` to axis 1, etc.). This corresponds to `n` for ``ifft(x, n)``.
10421098
Along each axis, if the given shape is smaller than that of the input,
1043-
the input is cropped. If it is larger, the input is padded with zeros.
1044-
if `s` is not given, the shape of the input along the axes specified
1099+
the input is cropped. If it is larger, the input is padded with zeros.
1100+
1101+
.. versionchanged:: 2.0
1102+
1103+
If it is ``-1``, the whole input is used (no padding/trimming).
1104+
1105+
If `s` is not given, the shape of the input along the axes specified
10451106
by `axes` is used. See notes for issue on `ifft` zero padding.
10461107
axes : sequence of ints, optional
10471108
Axes over which to compute the FFT. If not given, the last two
@@ -1128,12 +1189,28 @@ def rfftn(a, s=None, axes=None, norm=None):
11281189
The final element of `s` corresponds to `n` for ``rfft(x, n)``, while
11291190
for the remaining axes, it corresponds to `n` for ``fft(x, n)``.
11301191
Along any axis, if the given shape is smaller than that of the input,
1131-
the input is cropped. If it is larger, the input is padded with zeros.
1132-
if `s` is not given, the shape of the input along the axes specified
1192+
the input is cropped. If it is larger, the input is padded with zeros.
1193+
1194+
.. versionchanged:: 2.0
1195+
1196+
If it is ``-1``, the whole input is used (no padding/trimming).
1197+
1198+
If `s` is not given, the shape of the input along the axes specified
11331199
by `axes` is used.
1200+
1201+
.. deprecated:: 2.0
1202+
1203+
If `s` is not ``None``, `axes` must not be ``None`` either.
1204+
11341205
axes : sequence of ints, optional
11351206
Axes over which to compute the FFT. If not given, the last ``len(s)``
11361207
axes are used, or all axes if `s` is also not specified.
1208+
1209+
.. deprecated:: 2.0
1210+
1211+
If `s` is specified, the corresponding `axes` to be transformed
1212+
must be explicitly specified too.
1213+
11371214
norm : {"backward", "ortho", "forward"}, optional
11381215
.. versionadded:: 1.10.0
11391216
@@ -1284,14 +1361,31 @@ def irfftn(a, s=None, axes=None, norm=None):
12841361
where ``s[-1]//2+1`` points of the input are used.
12851362
Along any axis, if the shape indicated by `s` is smaller than that of
12861363
the input, the input is cropped. If it is larger, the input is padded
1287-
with zeros. If `s` is not given, the shape of the input along the axes
1364+
with zeros.
1365+
1366+
.. versionchanged:: 2.0
1367+
1368+
If it is ``-1``, the whole input is used (no padding/trimming).
1369+
1370+
If `s` is not given, the shape of the input along the axes
12881371
specified by axes is used. Except for the last axis which is taken to
12891372
be ``2*(m-1)`` where ``m`` is the length of the input along that axis.
1373+
1374+
.. deprecated:: 2.0
1375+
1376+
If `s` is not ``None``, `axes` must not be ``None`` either.
1377+
12901378
axes : sequence of ints, optional
12911379
Axes over which to compute the inverse FFT. If not given, the last
12921380
`len(s)` axes are used, or all axes if `s` is also not specified.
12931381
Repeated indices in `axes` means that the inverse transform over that
12941382
axis is performed multiple times.
1383+
1384+
.. deprecated:: 2.0
1385+
1386+
If `s` is specified, the corresponding `axes` to be transformed
1387+
must be explicitly specified too.
1388+
12951389
norm : {"backward", "ortho", "forward"}, optional
12961390
.. versionadded:: 1.10.0
12971391

numpy/fft/tests/test_pocketfft.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,26 @@ def test_axes(self, op):
200200
tr_op = np.transpose(op(x, axes=a), a)
201201
assert_allclose(op_tr, tr_op, atol=1e-6)
202202

203+
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn])
204+
def test_s_negative_1(self, op):
205+
x = np.arange(100).reshape(10, 10)
206+
# should use the whole input array along the first axis
207+
assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5)
208+
209+
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
210+
np.fft.rfftn, np.fft.irfftn])
211+
def test_s_axes_none(self, op):
212+
x = np.arange(100).reshape(10, 10)
213+
with pytest.warns(match='`axes` should not be `None` if `s`'):
214+
op(x, s=(-1, 5))
215+
216+
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
217+
np.fft.rfftn, np.fft.irfftn])
218+
def test_s_contains_none(self, op):
219+
x = random((30, 20, 10))
220+
with pytest.warns(match='array containing `None` values to `s`'):
221+
op(x, s=(10, None, 10), axes=(0, 1, 2))
222+
203223
def test_all_1d_norm_preserving(self):
204224
# verify that round-trip transforms are norm-preserving
205225
x = random(30)

0 commit comments

Comments
 (0)
0