chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
file(
|
||||
GLOB TEST_OPS
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"test_*.py")
|
||||
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
|
||||
|
||||
foreach(TEST_OP ${TEST_OPS})
|
||||
py_test_modules(${TEST_OP} MODULES ${TEST_OP})
|
||||
endforeach()
|
||||
|
||||
set_pir_tests_properties()
|
||||
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
@@ -0,0 +1,168 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import enum
|
||||
from functools import partial
|
||||
|
||||
import numpy as np
|
||||
from numpy import asarray
|
||||
from numpy.fft._pocketfft import _cook_nd_args, _raw_fft, _raw_fftnd
|
||||
|
||||
|
||||
class NormMode(enum.Enum):
|
||||
none = 1
|
||||
by_sqrt_n = 2
|
||||
by_n = 3
|
||||
|
||||
|
||||
def _get_norm_mode(norm, forward):
|
||||
if np.lib.NumpyVersion(np.__version__) >= "2.0.0":
|
||||
return norm
|
||||
if norm == "ortho":
|
||||
return NormMode.by_sqrt_n
|
||||
if norm is None or norm == "backward":
|
||||
return NormMode.none if forward else NormMode.by_n
|
||||
return NormMode.by_n if forward else NormMode.none
|
||||
|
||||
|
||||
def _get_inv_norm(n, norm_mode):
|
||||
if np.lib.NumpyVersion(np.__version__) >= "2.0.0":
|
||||
return norm_mode
|
||||
assert isinstance(norm_mode, NormMode), f"invalid norm_type {norm_mode}"
|
||||
if norm_mode == NormMode.none:
|
||||
return 1.0
|
||||
if norm_mode == NormMode.by_sqrt_n:
|
||||
return np.sqrt(n)
|
||||
return n
|
||||
|
||||
|
||||
# 1d transforms
|
||||
def _fftc2c(a, n=None, axis=-1, norm=None, forward=None, out=None):
|
||||
a = asarray(a)
|
||||
if n is None:
|
||||
n = a.shape[axis]
|
||||
inv_norm = _get_inv_norm(n, norm)
|
||||
output = _raw_fft(a, n, axis, False, forward, inv_norm)
|
||||
return output
|
||||
|
||||
|
||||
def _fftr2c(a, n=None, axis=-1, norm=None, forward=None):
|
||||
a = asarray(a)
|
||||
if n is None:
|
||||
n = a.shape[axis]
|
||||
inv_norm = _get_inv_norm(n, norm)
|
||||
output = _raw_fft(a, n, axis, True, True, inv_norm)
|
||||
if not forward:
|
||||
output = output.conj()
|
||||
return output
|
||||
|
||||
|
||||
def _fftc2r(a, n=None, axis=-1, norm=None, forward=None):
|
||||
a = asarray(a)
|
||||
if n is None:
|
||||
n = (a.shape[axis] - 1) * 2
|
||||
inv_norm = _get_inv_norm(n, norm)
|
||||
output = _raw_fft(
|
||||
a.conj() if forward else a, n, axis, True, False, inv_norm
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
# general fft functors
|
||||
def _fft_c2c_nd(x, axes, norm_mode, forward):
|
||||
f = partial(_fftc2c, forward=forward)
|
||||
y = _raw_fftnd(x, s=None, axes=axes, function=f, norm=norm_mode)
|
||||
return y
|
||||
|
||||
|
||||
def _fft_r2c_nd(x, axes, norm_mode, forward, onesided):
|
||||
a = asarray(x)
|
||||
s, axes = _cook_nd_args(a, axes=axes)
|
||||
if onesided:
|
||||
a = _fftr2c(a, s[-1], axes[-1], norm_mode, forward)
|
||||
a = _fft_c2c_nd(a, axes[:-1], norm_mode, forward)
|
||||
else:
|
||||
a = _fft_c2c_nd(x, axes, norm_mode, forward)
|
||||
return a
|
||||
|
||||
|
||||
def _fft_c2r_nd(x, axes, norm_mode, forward, last_dim_size):
|
||||
a = asarray(x)
|
||||
s, axes = _cook_nd_args(a, axes=axes, invreal=1)
|
||||
if last_dim_size is not None:
|
||||
s[-1] = last_dim_size
|
||||
a = _fft_c2c_nd(a, axes[:-1], norm_mode, forward)
|
||||
a = _fftc2r(a, s[-1], axes[-1], norm_mode, forward)
|
||||
return a
|
||||
|
||||
|
||||
# kernels
|
||||
def fft_c2c(x, axes, normalization, forward):
|
||||
norm_mode = _get_norm_mode(normalization, forward)
|
||||
return _fft_c2c_nd(x, axes, norm_mode, forward)
|
||||
|
||||
|
||||
def fft_c2r(x, axes, normalization, forward, last_dim_size):
|
||||
norm_mode = _get_norm_mode(normalization, forward)
|
||||
return _fft_c2r_nd(x, axes, norm_mode, forward, last_dim_size)
|
||||
|
||||
|
||||
def fft_r2c(x, axes, normalization, forward, onesided):
|
||||
norm_mode = _get_norm_mode(normalization, forward)
|
||||
return _fft_r2c_nd(x, axes, norm_mode, forward, onesided)
|
||||
|
||||
|
||||
# backward kernel
|
||||
def fft_c2c_backward(dy, axes, normalization, forward):
|
||||
norm_mode = _get_norm_mode(normalization, forward)
|
||||
dx = _fft_c2c_nd(dy, axes, norm_mode, not forward)
|
||||
return dx
|
||||
|
||||
|
||||
def fft_r2c_backward(x, dy, axes, normalization, forward, onesided):
|
||||
a = dy
|
||||
if not onesided:
|
||||
a = fft_c2c_backward(a, axes, normalization, forward)
|
||||
else:
|
||||
pad_widths = [(0, 0)] * a.ndim
|
||||
last_axis = axes[-1]
|
||||
if last_axis < 0:
|
||||
last_axis += a.ndim
|
||||
last_dim_size = a.shape[last_axis]
|
||||
pad_widths[last_axis] = (0, x.shape[last_axis] - last_dim_size)
|
||||
a = np.pad(a, pad_width=pad_widths)
|
||||
a = fft_c2c_backward(a, axes, normalization, forward)
|
||||
return a.real
|
||||
|
||||
|
||||
def _fft_fill_conj_grad(x, axes, length_to_double):
|
||||
last_fft_axis = axes[-1]
|
||||
shape = x.shape
|
||||
for multi_index in np.ndindex(*shape):
|
||||
if (
|
||||
0 < multi_index[last_fft_axis]
|
||||
and multi_index[last_fft_axis] <= length_to_double
|
||||
):
|
||||
x[multi_index] *= 2
|
||||
return x
|
||||
|
||||
|
||||
def fft_c2r_backward(x, dy, axes, normalization, forward, last_dim_size):
|
||||
norm_mode = _get_norm_mode(normalization, forward)
|
||||
a = dy
|
||||
a = _fft_r2c_nd(dy, axes, norm_mode, not forward, True)
|
||||
last_fft_axis = axes[-1]
|
||||
length_to_double = dy.shape[last_fft_axis] - x.shape[last_fft_axis]
|
||||
a = _fft_fill_conj_grad(a, axes, length_to_double)
|
||||
return a
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,428 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import scipy.fft
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestFFTAliasBase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
np.random.seed(2025)
|
||||
self.places = [paddle.CPUPlace()]
|
||||
if paddle.is_compiled_with_cuda():
|
||||
self.places.append(paddle.CUDAPlace(0))
|
||||
|
||||
self.init_params()
|
||||
self.init_data()
|
||||
self.paddle_axis_arg = "axes" if self.is_nd_or_shift else "axis"
|
||||
|
||||
def init_params(self):
|
||||
self.shape = [2, 4, 6]
|
||||
self.test_dim_val = -1
|
||||
self.norm = "backward"
|
||||
self.dtype = "float32"
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
self.paddle_api = None
|
||||
self.scipy_api = None
|
||||
|
||||
def init_data(self):
|
||||
if self.is_real_input:
|
||||
self.np_x = np.random.rand(*self.shape).astype(self.dtype)
|
||||
else:
|
||||
real = np.random.rand(*self.shape).astype(self.dtype)
|
||||
imag = np.random.rand(*self.shape).astype(self.dtype)
|
||||
self.np_x = real + 1j * imag
|
||||
|
||||
def get_scipy_ref(self):
|
||||
kwargs = {"norm": self.norm}
|
||||
|
||||
if 'shift' in self.scipy_api.__name__:
|
||||
return self.scipy_api(self.np_x, axes=self.test_dim_val)
|
||||
|
||||
if self.is_nd_or_shift:
|
||||
kwargs["axes"] = self.test_dim_val
|
||||
else:
|
||||
kwargs["axis"] = self.test_dim_val
|
||||
|
||||
return self.scipy_api(self.np_x, **kwargs)
|
||||
|
||||
def test_dygraph_Compatibility(self):
|
||||
if self.paddle_api is None:
|
||||
return
|
||||
|
||||
paddle.disable_static()
|
||||
for place in self.places:
|
||||
paddle.set_device(place)
|
||||
|
||||
x = paddle.to_tensor(self.np_x)
|
||||
paddle_dygraph_out = []
|
||||
|
||||
# 1. Paddle Usage
|
||||
kw_std = {"x": x, self.paddle_axis_arg: self.test_dim_val}
|
||||
if 'shift' not in self.paddle_api.__name__:
|
||||
kw_std["norm"] = self.norm
|
||||
|
||||
out1 = self.paddle_api(**kw_std)
|
||||
paddle_dygraph_out.append(out1)
|
||||
|
||||
# 2. Alias Usage
|
||||
kw_alias = {"input": x, "dim": self.test_dim_val}
|
||||
if 'shift' not in self.paddle_api.__name__:
|
||||
kw_alias["norm"] = self.norm
|
||||
|
||||
out2 = self.paddle_api(**kw_alias)
|
||||
paddle_dygraph_out.append(out2)
|
||||
|
||||
# 3. Alias Usage with 'out' parameter (Skip for shift APIs)
|
||||
if 'shift' not in self.paddle_api.__name__:
|
||||
out_tensor = paddle.empty_like(out1)
|
||||
kw_out = {
|
||||
"input": x,
|
||||
"dim": self.test_dim_val,
|
||||
"out": out_tensor,
|
||||
"norm": self.norm,
|
||||
}
|
||||
|
||||
self.paddle_api(**kw_out)
|
||||
paddle_dygraph_out.append(out_tensor)
|
||||
|
||||
ref_out = self.get_scipy_ref()
|
||||
|
||||
for i, out in enumerate(paddle_dygraph_out):
|
||||
np.testing.assert_allclose(
|
||||
out.numpy(),
|
||||
ref_out,
|
||||
rtol=1e-05,
|
||||
atol=1e-08,
|
||||
err_msg=f"Dygraph mismatch case {i} (0=std, 1=alias, 2=out) for {self.paddle_api.__name__} on {place}",
|
||||
)
|
||||
paddle.enable_static()
|
||||
|
||||
def test_static_Compatibility(self):
|
||||
if self.paddle_api is None:
|
||||
return
|
||||
|
||||
paddle.enable_static()
|
||||
main = paddle.static.Program()
|
||||
startup = paddle.static.Program()
|
||||
|
||||
with paddle.base.program_guard(main, startup):
|
||||
x = paddle.static.data(
|
||||
name="x", shape=self.shape, dtype=self.np_x.dtype
|
||||
)
|
||||
|
||||
# 1. Paddle Usage
|
||||
kw_std = {"x": x, self.paddle_axis_arg: self.test_dim_val}
|
||||
if 'shift' not in self.paddle_api.__name__:
|
||||
kw_std["norm"] = self.norm
|
||||
out_std = self.paddle_api(**kw_std)
|
||||
|
||||
# 2. Alias Usage
|
||||
kw_alias = {"input": x, "dim": self.test_dim_val}
|
||||
if 'shift' not in self.paddle_api.__name__:
|
||||
kw_alias["norm"] = self.norm
|
||||
out_alias = self.paddle_api(**kw_alias)
|
||||
|
||||
ref_out = self.get_scipy_ref()
|
||||
|
||||
for place in self.places:
|
||||
exe = paddle.base.Executor(place)
|
||||
exe.run(startup)
|
||||
fetches = exe.run(
|
||||
main,
|
||||
feed={"x": self.np_x},
|
||||
fetch_list=[out_std, out_alias],
|
||||
)
|
||||
|
||||
np.testing.assert_allclose(
|
||||
fetches[0],
|
||||
ref_out,
|
||||
rtol=1e-05,
|
||||
atol=1e-08,
|
||||
err_msg=f"Static graph mismatch (Standard Args) for {self.paddle_api.__name__} on {place}",
|
||||
)
|
||||
|
||||
np.testing.assert_allclose(
|
||||
fetches[1],
|
||||
ref_out,
|
||||
rtol=1e-05,
|
||||
atol=1e-08,
|
||||
err_msg=f"Static graph mismatch (Alias Args) for {self.paddle_api.__name__} on {place}",
|
||||
)
|
||||
paddle.disable_static()
|
||||
|
||||
|
||||
class TestFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.fft
|
||||
self.scipy_api = scipy.fft.fft
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestIFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ifft
|
||||
self.scipy_api = scipy.fft.ifft
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestRFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.rfft
|
||||
self.scipy_api = scipy.fft.rfft
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestIRFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.irfft
|
||||
self.scipy_api = scipy.fft.irfft
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestHFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.hfft
|
||||
self.scipy_api = scipy.fft.hfft
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestIHFFT_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ihfft
|
||||
self.scipy_api = scipy.fft.ihfft
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = False
|
||||
|
||||
|
||||
class TestFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.fft2
|
||||
self.scipy_api = scipy.fft.fft2
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestIFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ifft2
|
||||
self.scipy_api = scipy.fft.ifft2
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestRFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.rfft2
|
||||
self.scipy_api = scipy.fft.rfft2
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestIRFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.irfft2
|
||||
self.scipy_api = scipy.fft.irfft2
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestHFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.hfft2
|
||||
self.scipy_api = scipy.fft.hfft2
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestIHFFT2_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ihfft2
|
||||
self.scipy_api = scipy.fft.ihfft2
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.fftn
|
||||
self.scipy_api = scipy.fft.fftn
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestIFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ifftn
|
||||
self.scipy_api = scipy.fft.ifftn
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestRFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.rfftn
|
||||
self.scipy_api = scipy.fft.rfftn
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestIRFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.irfftn
|
||||
self.scipy_api = scipy.fft.irfftn
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestHFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.hfftn
|
||||
self.scipy_api = scipy.fft.hfftn
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestIHFFTN_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ihfftn
|
||||
self.scipy_api = scipy.fft.ihfftn
|
||||
self.is_real_input = True
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1, 2)
|
||||
|
||||
|
||||
class TestFFTShift_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.fftshift
|
||||
self.scipy_api = scipy.fft.fftshift
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestIFFTShift_Alias(TestFFTAliasBase):
|
||||
def init_params(self):
|
||||
super().init_params()
|
||||
self.paddle_api = paddle.fft.ifftshift
|
||||
self.scipy_api = scipy.fft.ifftshift
|
||||
self.is_real_input = False
|
||||
self.is_nd_or_shift = True
|
||||
self.test_dim_val = (0, 1)
|
||||
|
||||
|
||||
class TestFftfreq(unittest.TestCase):
|
||||
def test_basic_usage(self):
|
||||
result = paddle.fft.fftfreq(n=10, d=1.0)
|
||||
self.assertEqual(result.shape, [10])
|
||||
|
||||
expected = paddle.to_tensor(
|
||||
[0.0, 0.1, 0.2, 0.3, 0.4, -0.5, -0.4, -0.3, -0.2, -0.1],
|
||||
dtype='float32',
|
||||
)
|
||||
self.assertTrue(paddle.allclose(result, expected))
|
||||
|
||||
def test_all_parameters(self):
|
||||
out = paddle.zeros([10], dtype='float32')
|
||||
|
||||
result = paddle.fft.fftfreq(
|
||||
n=10,
|
||||
d=2.0,
|
||||
dtype='float64',
|
||||
out=out,
|
||||
device='cpu',
|
||||
requires_grad=True,
|
||||
)
|
||||
|
||||
self.assertTrue(result.place.is_cpu_place())
|
||||
self.assertFalse(result.stop_gradient)
|
||||
self.assertEqual(result.dtype, paddle.float64)
|
||||
|
||||
expected = paddle.to_tensor(
|
||||
[0.0, 0.05, 0.1, 0.15, 0.2, -0.25, -0.2, -0.15, -0.1, -0.05],
|
||||
dtype='float64',
|
||||
)
|
||||
self.assertTrue(paddle.allclose(result, expected))
|
||||
|
||||
|
||||
class TestRfftfreq(unittest.TestCase):
|
||||
def test_basic_usage(self):
|
||||
result = paddle.fft.rfftfreq(n=10, d=1.0)
|
||||
self.assertEqual(result.shape, [6]) # 1 + n//2 = 6
|
||||
|
||||
expected = paddle.arange(0, 6) * (1.0 / (10 * 1.0))
|
||||
self.assertTrue(paddle.allclose(result, expected))
|
||||
|
||||
def test_all_parameters(self):
|
||||
out = paddle.zeros([6], dtype='float32')
|
||||
|
||||
result = paddle.fft.rfftfreq(
|
||||
n=10,
|
||||
d=2.0,
|
||||
dtype='float64',
|
||||
out=out,
|
||||
device='cpu',
|
||||
requires_grad=True,
|
||||
)
|
||||
self.assertTrue(result.place.is_cpu_place())
|
||||
self.assertFalse(result.stop_gradient)
|
||||
self.assertEqual(result.dtype, paddle.float64)
|
||||
|
||||
expected = paddle.arange(0, 6, dtype='float64') * (1.0 / (10 * 2.0))
|
||||
self.assertTrue(paddle.allclose(result, expected))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,318 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from op_test import OpTest
|
||||
|
||||
sys.path.append("../../fft")
|
||||
from spectral_op_np import fft_c2c, fft_c2r, fft_r2c
|
||||
|
||||
import paddle
|
||||
from paddle import _C_ops
|
||||
|
||||
paddle.enable_static()
|
||||
|
||||
TEST_CASE_NAME = 'test_case'
|
||||
|
||||
|
||||
def parameterize(attrs, input_values=None):
|
||||
if isinstance(attrs, str):
|
||||
attrs = [attrs]
|
||||
input_dicts = (
|
||||
attrs
|
||||
if input_values is None
|
||||
else [dict(zip(attrs, vals)) for vals in input_values]
|
||||
)
|
||||
|
||||
def decorator(base_class):
|
||||
test_class_module = sys.modules[base_class.__module__].__dict__
|
||||
for idx, input_dict in enumerate(input_dicts):
|
||||
test_class_dict = dict(base_class.__dict__)
|
||||
test_class_dict.update(input_dict)
|
||||
|
||||
name = class_name(base_class, idx, input_dict)
|
||||
|
||||
test_class_module[name] = type(name, (base_class,), test_class_dict)
|
||||
|
||||
for method_name in list(base_class.__dict__):
|
||||
if method_name.startswith("test"):
|
||||
delattr(base_class, method_name)
|
||||
return base_class
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def to_safe_name(s):
|
||||
return str(re.sub("[^a-zA-Z0-9_]+", "_", s))
|
||||
|
||||
|
||||
def class_name(cls, num, params_dict):
|
||||
suffix = to_safe_name(
|
||||
next((v for v in params_dict.values() if isinstance(v, str)), "")
|
||||
)
|
||||
if TEST_CASE_NAME in params_dict:
|
||||
suffix = to_safe_name(params_dict["test_case"])
|
||||
return "{}_{}{}".format(cls.__name__, num, suffix and "_" + suffix)
|
||||
|
||||
|
||||
def fft_c2c_python_api(x, axes, norm, forward):
|
||||
return _C_ops.fft_c2c(x, axes, norm, forward)
|
||||
|
||||
|
||||
def fft_r2c_python_api(x, axes, norm, forward, onesided):
|
||||
return _C_ops.fft_r2c(x, axes, norm, forward, onesided)
|
||||
|
||||
|
||||
def fft_c2r_python_api(x, axes, norm, forward, last_dim_size=0):
|
||||
return _C_ops.fft_c2r(x, axes, norm, forward, last_dim_size)
|
||||
|
||||
|
||||
@parameterize(
|
||||
(TEST_CASE_NAME, 'x', 'axes', 'norm', 'forward'),
|
||||
[
|
||||
(
|
||||
'test_axes_is_sqe_type',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
[0, 1],
|
||||
'forward',
|
||||
True,
|
||||
),
|
||||
(
|
||||
'test_axis_not_last',
|
||||
(
|
||||
np.random.random((4, 8, 4)) + 1j * np.random.random((4, 8, 4))
|
||||
).astype(np.complex128),
|
||||
(0, 1),
|
||||
"backward",
|
||||
False,
|
||||
),
|
||||
(
|
||||
'test_norm_forward',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(0,),
|
||||
"forward",
|
||||
False,
|
||||
),
|
||||
(
|
||||
'test_norm_backward',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(0,),
|
||||
"backward",
|
||||
True,
|
||||
),
|
||||
(
|
||||
'test_norm_ortho',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(1,),
|
||||
"ortho",
|
||||
True,
|
||||
),
|
||||
],
|
||||
)
|
||||
class TestFFTC2COp(OpTest):
|
||||
def setUp(self):
|
||||
self.op_type = "fft_c2c"
|
||||
self.dtype = self.x.dtype
|
||||
self.python_api = fft_c2c_python_api
|
||||
|
||||
out = fft_c2c(self.x, self.axes, self.norm, self.forward)
|
||||
|
||||
self.inputs = {'X': self.x}
|
||||
self.attrs = {
|
||||
'axes': self.axes,
|
||||
'normalization': self.norm,
|
||||
"forward": self.forward,
|
||||
}
|
||||
self.outputs = {'Out': out}
|
||||
|
||||
def test_check_output(self):
|
||||
self.check_output()
|
||||
|
||||
def test_check_grad(self):
|
||||
self.check_grad(
|
||||
["X"],
|
||||
"Out",
|
||||
)
|
||||
|
||||
|
||||
@parameterize(
|
||||
(TEST_CASE_NAME, 'x', 'axes', 'norm', 'forward', 'last_dim_size'),
|
||||
[
|
||||
(
|
||||
'test_axes_is_sqe_type',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
[0, 1],
|
||||
'forward',
|
||||
False,
|
||||
26,
|
||||
),
|
||||
(
|
||||
'test_axis_not_last',
|
||||
(
|
||||
np.random.random((4, 7, 4)) + 1j * np.random.random((4, 7, 4))
|
||||
).astype(np.complex128),
|
||||
(0, 1),
|
||||
"backward",
|
||||
False,
|
||||
None,
|
||||
),
|
||||
(
|
||||
'test_norm_forward',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(0,),
|
||||
"forward",
|
||||
False,
|
||||
22,
|
||||
),
|
||||
(
|
||||
'test_norm_backward',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(0,),
|
||||
"backward",
|
||||
False,
|
||||
22,
|
||||
),
|
||||
(
|
||||
'test_norm_ortho',
|
||||
(
|
||||
np.random.random((12, 14)) + 1j * np.random.random((12, 14))
|
||||
).astype(np.complex128),
|
||||
(1,),
|
||||
"ortho",
|
||||
True,
|
||||
26,
|
||||
),
|
||||
],
|
||||
)
|
||||
class TestFFTC2ROp(OpTest):
|
||||
def setUp(self):
|
||||
self.op_type = "fft_c2r"
|
||||
self.dtype = self.x.dtype
|
||||
self.python_api = fft_c2r_python_api
|
||||
|
||||
out = fft_c2r(
|
||||
self.x, self.axes, self.norm, self.forward, self.last_dim_size
|
||||
)
|
||||
|
||||
self.inputs = {'X': self.x}
|
||||
self.attrs = {
|
||||
"axes": self.axes,
|
||||
"normalization": self.norm,
|
||||
"forward": self.forward,
|
||||
"last_dim_size": self.last_dim_size,
|
||||
}
|
||||
self.outputs = {'Out': out}
|
||||
|
||||
def test_check_output(self):
|
||||
self.check_output()
|
||||
|
||||
def test_check_grad(self):
|
||||
self.check_grad(
|
||||
["X"],
|
||||
"Out",
|
||||
)
|
||||
|
||||
|
||||
@parameterize(
|
||||
(TEST_CASE_NAME, 'x', 'axes', 'norm', 'forward', 'onesided'),
|
||||
[
|
||||
(
|
||||
'test_axes_is_sqe_type',
|
||||
np.random.randn(12, 18).astype(np.float64),
|
||||
(0, 1),
|
||||
'forward',
|
||||
True,
|
||||
True,
|
||||
),
|
||||
(
|
||||
'test_axis_not_last',
|
||||
np.random.randn(4, 8, 4).astype(np.float64),
|
||||
(0, 1),
|
||||
"backward",
|
||||
False,
|
||||
False,
|
||||
),
|
||||
(
|
||||
'test_norm_forward',
|
||||
np.random.randn(12, 18).astype(np.float64),
|
||||
(0, 1),
|
||||
"forward",
|
||||
False,
|
||||
False,
|
||||
),
|
||||
(
|
||||
'test_norm_backward',
|
||||
np.random.randn(12, 18).astype(np.float64),
|
||||
(0,),
|
||||
"backward",
|
||||
True,
|
||||
False,
|
||||
),
|
||||
(
|
||||
'test_norm_ortho',
|
||||
np.random.randn(12, 18).astype(np.float64),
|
||||
(1,),
|
||||
"ortho",
|
||||
True,
|
||||
False,
|
||||
),
|
||||
],
|
||||
)
|
||||
class TestFFTR2COp(OpTest):
|
||||
def setUp(self):
|
||||
self.op_type = "fft_r2c"
|
||||
self.dtype = self.x.dtype
|
||||
self.python_api = fft_r2c_python_api
|
||||
|
||||
out = fft_r2c(self.x, self.axes, self.norm, self.forward, self.onesided)
|
||||
|
||||
self.inputs = {'X': self.x}
|
||||
self.attrs = {
|
||||
'axes': self.axes,
|
||||
'normalization': self.norm,
|
||||
"forward": self.forward,
|
||||
'onesided': self.onesided,
|
||||
}
|
||||
self.outputs = {'Out': out}
|
||||
|
||||
def test_check_output(self):
|
||||
self.check_output()
|
||||
|
||||
def test_check_grad(self):
|
||||
self.check_grad(
|
||||
["X"],
|
||||
"Out",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user