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

Skip to content

Commit 9e80d17

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

File tree

4 files changed

+222
-14
lines changed

4 files changed

+222
-14
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
`numpy.fft` deprecations for n-D transforms with ``None`` values in arguments
2+
-----------------------------------------------------------------------------
3+
4+
Using `numpy.fft.fftn`, `numpy.fft.ifftn`, `numpy.fft.rfftn`,
5+
`numpy.fft.irfftn`, `numpy.fft.fft2` or `numpy.fft.ifft2` with the ``s``
6+
parameter set to a value that is not ``None`` and the ``axes`` parameter set
7+
to ``None`` has been deprecated, in line with the array API standard.
8+
To retain current behaviour, pass a sequence [0, ..., k-1] to ``axes`` for
9+
an array of dimension k.
10+
11+
Furthermore, passing an array to ``s`` which contains ``None`` values is
12+
deprecated as the parameter is documented to accept a sequence of integers
13+
in both the NumPy docs and the array API specification. To use the default
14+
behaviour of the corresponding 1-D transform, pass the value matching
15+
the default for its ``n`` parameter. To use the default behaviour for every
16+
axis, the ``s`` argument can be omitted.
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: 8000 172 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 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,37 @@ 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+
765+
.. deprecated:: 2.0
766+
767+
`s` must contain only ``int``s, not ``None`` values. ``None``
768+
values currently mean that the default value for ``n`` is used
769+
in the corresponding 1-D transform, but this behaviour is
770+
deprecated.
771+
736772
axes : sequence of ints, optional
737773
Axes over which to compute the FFT. If not given, the last ``len(s)``
738774
axes are used, or all axes if `s` is also not specified.
739775
Repeated indices in `axes` means that the transform over that axis is
740776
performed multiple times.
777+
778+
.. deprecated:: 2.0
779+
780+
If `s` is specified, the corresponding `axes` to be transformed
781+
must be explicitly specified too.
782+
741783
norm : {"backward", "ortho", "forward"}, optional
742784
.. versionadded:: 1.10.0
743785
@@ -842,14 +884,37 @@ def ifftn(a, s=None, axes=None, norm=None):
842884
(``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.).
843885
This corresponds to ``n`` for ``ifft(x, n)``.
844886
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.
887+
the input is cropped. If it is larger, the input is padded with zeros.
888+
889+
.. versionchanged:: 2.0
890+
891+
If it is ``-1``, the whole input is used (no padding/trimming).
892+
893+
If `s` is not given, the shape of the input along the axes specified
894+
by `axes` is used. See notes for issue on `ifft` zero padding.
895+
896+
.. deprecated:: 2.0
897+
898+
If `s` is not ``None``, `axes` must not be ``None`` either.
899+
900+
.. deprecated:: 2.0
901+
902+
`s` must contain only ``int``s, not ``None`` values. ``None``
903+
values currently mean that the default value for ``n`` is used
904+
in the corresponding 1-D transform, but this behaviour is
905+
deprecated.
906+
848907
axes : sequence of ints, optional
849908
Axes over which to compute the IFFT. If not given, the last ``len(s)``
850909
axes are used, or all axes if `s` is also not specified.
851910
Repeated indices in `axes` means that the inverse transform over that
852911
axis is performed multiple times.
912+
913+
.. deprecated:: 2.0
914+
915+
If `s` is specified, the corresponding `axes` to be transformed
916+
must be explicitly specified too.
917+
853918
norm : {"backward", "ortho", "forward"}, optional
854919
.. versionadded:: 1.10.0
855920
@@ -937,14 +1002,37 @@ def fft2(a, s=None, axes=(-2, -1), norm=None):
9371002
(``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.).
9381003
This corresponds to ``n`` for ``fft(x, n)``.
9391004
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
1005+
the input is cropped. If it is larger, the input is padded with zeros.
1006+
1007+
.. versionchanged:: 2.0
1008+
1009+
If it is ``-1``, the whole input is used (no padding/trimming).
1010+
1011+
If `s` is not given, the shape of the input along the axes specified
9421012
by `axes` is used.
1013+
1014+
.. deprecated:: 2.0
1015+
1016+
If `s` is not ``None``, `axes` must not be ``None`` either.
1017+
1018+
.. deprecated:: 2.0
1019+
1020+
`s` must contain only ``int``s, not ``None`` values. ``None``
1021+
values currently mean that the default value for ``n`` is used
1022+
in the corresponding 1-D transform, but this behaviour is
1023+
deprecated.
1024+
9431025
axes : sequence of ints, optional
9441026
Axes over which to compute the FFT. If not given, the last two
9451027
axes are used. A repeated index in `axes` means the transform over
9461028
that axis is performed multiple times. A one-element sequence means
9471029
that a one-dimensional FFT is performed.
1030+
1031+
.. deprecated:: 2.0
1032+
1033+
If `s` is specified, the corresponding `axes` to be transformed
1034+
must be explicitly specified too.
1035+
9481036
norm : {"backward", "ortho", "forward"}, optional
9491037
.. versionadded:: 1.10.0
9501038
@@ -1040,14 +1128,37 @@ def ifft2(a, s=None, axes=(-2, -1), norm=None):
10401128
Shape (length of each axis) of the output (``s[0]`` refers to axis 0,
10411129
``s[1]`` to axis 1, etc.). This corresponds to `n` for ``ifft(x, n)``.
10421130
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
1131+
the input is cropped. If it is larger, the input is padded with zeros.
1132+
1133+
.. versionchanged:: 2.0
1134+
1135+
If it is ``-1``, the whole input is used (no padding/trimming).
1136+
1137+
If `s` is not given, the shape of the input along the axes specified
10451138
by `axes` is used. See notes for issue on `ifft` zero padding.
1139+
1140+
.. deprecated:: 2.0
1141+
1142+
If `s` is not ``None``, `axes` must not be ``None`` either.
1143+
1144+
.. deprecated:: 2.0
1145+
1146+
`s` must contain only ``int``s, not ``None`` values. ``None``
1147+
values currently mean that the default value for ``n`` is used
1148+
in the corresponding 1-D transform, but this behaviour is
1149+
deprecated.
1150+
10461151
axes : sequence of ints, optional
10471152
Axes over which to compute the FFT. If not given, the last two
10481153
axes are used. A repeated index in `axes` means the transform over
10491154
that axis is performed multiple times. A one-element sequence means
10501155
that a one-dimensional FFT is performed.
1156+
1157+
.. deprecated:: 2.0
1158+
1159+
If `s` is specified, the corresponding `axes` to be transformed
1160+
must be explicitly specified too.
1161+
10511162
norm : {"backward", "ortho", "forward"}, optional
10521163
.. versionadded:: 1.10.0
10531164
@@ -1128,12 +1239,35 @@ def rfftn(a, s=None, axes=None, norm=None):
11281239
The final element of `s` corresponds to `n` for ``rfft(x, n)``, while
11291240
for the remaining axes, it corresponds to `n` for ``fft(x, n)``.
11301241
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
1242+
the input is cropped. If it is larger, the input is padded with zeros.
1243+
1244+
.. versionchanged:: 2.0
1245+
1246+
If it is ``-1``, the whole input is used (no padding/trimming).
1247+
1248+
If `s` is not given, the shape of the input along the axes specified
11331249
by `axes` is used.
1250+
1251+
.. deprecated:: 2.0
1252+
1253+
If `s` is not ``None``, `axes` must not be ``None`` either.
1254+
1255+
.. deprecated:: 2.0
1256+
1257+
`s` must contain only ``int``s, not ``None`` values. ``None``
1258+
values currently mean that the default value for ``n`` is used
1259+
in the corresponding 1-D transform, but this behaviour is
1260+
deprecated.
1261+
11341262
axes : sequence of ints, optional
11351263
Axes over which to compute the FFT. If not given, the last ``len(s)``
11361264
axes are used, or all axes if `s` is also not specified.
1265+
1266+
.. deprecated:: 2.0
1267+
1268+
If `s` is specified, the corresponding `axes` to be transformed
1269+
must be explicitly specified too.
1270+
11371271
norm : {"backward", "ortho", "forward"}, optional
11381272
.. versionadded:: 1.10.0
11391273
@@ -1284,14 +1418,38 @@ def irfftn(a, s=None, axes=None, norm=None):
12841418
where ``s[-1]//2+1`` points of the input are used.
12851419
Along any axis, if the shape indicated by `s` is smaller than that of
12861420
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
1421+
with zeros.
1422+
1423+
.. versionchanged:: 2.0
1424+
1425+
If it is ``-1``, the whole input is used (no padding/trimming).
1426+
1427+
If `s` is not given, the shape of the input along the axes
12881428
specified by axes is used. Except for the last axis which is taken to
12891429
be ``2*(m-1)`` where ``m`` is the length of the input along that axis.
1430+
1431+
.. deprecated:: 2.0
1432+
1433+
If `s` is not ``None``, `axes` must not be ``None`` either.
1434+
1435+
.. deprecated:: 2.0
1436+
1437+
`s` must contain only ``int``s, not ``None`` values. ``None``
1438+
values currently mean that the default value for ``n`` is used
1439+
in the corresponding 1-D transform, but this behaviour is
1440+
deprecated.
1441+
12901442
axes : sequence of ints, optional
12911443
Axes over which to compute the inverse FFT. If not given, the last
12921444
`len(s)` axes are used, or all axes if `s` is also not specified.
12931445
Repeated indices in `axes` means that the inverse transform over that
12941446
axis is performed multiple times.
1447+
1448+
.. deprecated:: 2.0
1449+
1450+
If `s` is specified, the corresponding `axes` to be transformed
1451+
must be explicitly specified too.
1452+
12951453
norm : {"backward", "ortho", "forward"}, optional
12961454
.. versionadded:: 1.10.0
12971455

numpy/fft/tests/test_pocketfft.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,34 @@ 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+
np.fft.fft2, np.fft.ifft2])
205+
def test_s_negative_1(self, op):
206+
x = np.arange(100).reshape(10, 10)
207+
# should use the whole input array along the first axis
208+
assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5)
209+
210+
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
211+
np.fft.rfftn, np.fft.irfftn])
212+
def test_s_axes_none(self, op):
213+
x = np.arange(100).reshape(10, 10)
214+
with pytest.warns(match='`axes` should not be `None` if `s`'):
215+
op(x, s=(-1, 5))
216+
217+
@pytest.mark.parametrize("op", [np.fft.fft2, np.fft.ifft2])
218+
def test_s_axes_none_2D(self, op):
219+
x = np.arange(100).reshape(10, 10)
220+
with pytest.warns(match='`axes` should not be `None` if `s`'):
221+
op(x, s=(-1, 5), axes=None)
222+
223+
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
224+
np.fft.rfftn, np.fft.irfftn,
225+
np.fft.fft2, np.fft.ifft2])
226+
def test_s_contains_none(self, op):
227+
x = random((30, 20, 10))
228+
with pytest.warns(match='array containing `None` values to `s`'):
229+
op(x, s=(10, None, 10), axes=(0, 1, 2))
230+
203231
def test_all_1d_norm_preserving(self):
204232
# verify that round-trip transforms are norm-preserving
205233
x = random(30)

0 commit comments

Comments
 (0)
0