cxx11_tensor_fft.cpp File Reference
#include "main.h"
#include <Eigen/CXX11/Tensor>

Functions

template<int DataLayout>
static void test_fft_2D_golden ()
 
static void test_fft_complex_input_golden ()
 
static void test_fft_real_input_golden ()
 
template<int DataLayout, typename RealScalar , bool isComplexInput, int FFTResultType, int FFTDirection, int TensorRank>
static void test_fft_real_input_energy ()
 
template<typename RealScalar >
static void test_fft_non_power_of_2_round_trip (int exponent)
 
 EIGEN_DECLARE_TEST (cxx11_tensor_fft)
 

Function Documentation

◆ EIGEN_DECLARE_TEST()

EIGEN_DECLARE_TEST ( cxx11_tensor_fft  )
247  {
250 
251  test_fft_2D_golden<ColMajor>();
252  test_fft_2D_golden<RowMajor>();
253 
254  test_fft_real_input_energy<ColMajor, float, true, Eigen::BothParts, FFT_FORWARD, 1>();
255  test_fft_real_input_energy<ColMajor, double, true, Eigen::BothParts, FFT_FORWARD, 1>();
256  test_fft_real_input_energy<ColMajor, float, false, Eigen::BothParts, FFT_FORWARD, 1>();
257  test_fft_real_input_energy<ColMajor, double, false, Eigen::BothParts, FFT_FORWARD, 1>();
258 
259  test_fft_real_input_energy<ColMajor, float, true, Eigen::BothParts, FFT_FORWARD, 2>();
260  test_fft_real_input_energy<ColMajor, double, true, Eigen::BothParts, FFT_FORWARD, 2>();
261  test_fft_real_input_energy<ColMajor, float, false, Eigen::BothParts, FFT_FORWARD, 2>();
262  test_fft_real_input_energy<ColMajor, double, false, Eigen::BothParts, FFT_FORWARD, 2>();
263 
264  test_fft_real_input_energy<ColMajor, float, true, Eigen::BothParts, FFT_FORWARD, 3>();
265  test_fft_real_input_energy<ColMajor, double, true, Eigen::BothParts, FFT_FORWARD, 3>();
266  test_fft_real_input_energy<ColMajor, float, false, Eigen::BothParts, FFT_FORWARD, 3>();
267  test_fft_real_input_energy<ColMajor, double, false, Eigen::BothParts, FFT_FORWARD, 3>();
268 
269  test_fft_real_input_energy<ColMajor, float, true, Eigen::BothParts, FFT_FORWARD, 4>();
270  test_fft_real_input_energy<ColMajor, double, true, Eigen::BothParts, FFT_FORWARD, 4>();
271  test_fft_real_input_energy<ColMajor, float, false, Eigen::BothParts, FFT_FORWARD, 4>();
272  test_fft_real_input_energy<ColMajor, double, false, Eigen::BothParts, FFT_FORWARD, 4>();
273 
274  test_fft_real_input_energy<RowMajor, float, true, Eigen::BothParts, FFT_FORWARD, 1>();
275  test_fft_real_input_energy<RowMajor, double, true, Eigen::BothParts, FFT_FORWARD, 1>();
276  test_fft_real_input_energy<RowMajor, float, false, Eigen::BothParts, FFT_FORWARD, 1>();
277  test_fft_real_input_energy<RowMajor, double, false, Eigen::BothParts, FFT_FORWARD, 1>();
278 
279  test_fft_real_input_energy<RowMajor, float, true, Eigen::BothParts, FFT_FORWARD, 2>();
280  test_fft_real_input_energy<RowMajor, double, true, Eigen::BothParts, FFT_FORWARD, 2>();
281  test_fft_real_input_energy<RowMajor, float, false, Eigen::BothParts, FFT_FORWARD, 2>();
282  test_fft_real_input_energy<RowMajor, double, false, Eigen::BothParts, FFT_FORWARD, 2>();
283 
284  test_fft_real_input_energy<RowMajor, float, true, Eigen::BothParts, FFT_FORWARD, 3>();
285  test_fft_real_input_energy<RowMajor, double, true, Eigen::BothParts, FFT_FORWARD, 3>();
286  test_fft_real_input_energy<RowMajor, float, false, Eigen::BothParts, FFT_FORWARD, 3>();
287  test_fft_real_input_energy<RowMajor, double, false, Eigen::BothParts, FFT_FORWARD, 3>();
288 
289  test_fft_real_input_energy<RowMajor, float, true, Eigen::BothParts, FFT_FORWARD, 4>();
290  test_fft_real_input_energy<RowMajor, double, true, Eigen::BothParts, FFT_FORWARD, 4>();
291  test_fft_real_input_energy<RowMajor, float, false, Eigen::BothParts, FFT_FORWARD, 4>();
292  test_fft_real_input_energy<RowMajor, double, false, Eigen::BothParts, FFT_FORWARD, 4>();
293 
294  test_fft_non_power_of_2_round_trip<float>(7);
295  test_fft_non_power_of_2_round_trip<double>(7);
296 }
static void test_fft_real_input_golden()
Definition: cxx11_tensor_fft.cpp:115
static void test_fft_complex_input_golden()
Definition: cxx11_tensor_fft.cpp:58

References test_fft_complex_input_golden(), and test_fft_real_input_golden().

◆ test_fft_2D_golden()

template<int DataLayout>
static void test_fft_2D_golden ( )
static
16  {
17  Tensor<float, 2, DataLayout> input(2, 3);
18  input(0, 0) = 1;
19  input(0, 1) = 2;
20  input(0, 2) = 3;
21  input(1, 0) = 4;
22  input(1, 1) = 5;
23  input(1, 2) = 6;
24 
26  fft[0] = 0;
27  fft[1] = 1;
28 
29  Tensor<std::complex<float>, 2, DataLayout> output = input.template fft<Eigen::BothParts, Eigen::FFT_FORWARD>(fft);
30 
31  std::complex<float> output_golden[6]; // in ColMajor order
32  output_golden[0] = std::complex<float>(21, 0);
33  output_golden[1] = std::complex<float>(-9, 0);
34  output_golden[2] = std::complex<float>(-3, 1.73205);
35  output_golden[3] = std::complex<float>(0, 0);
36  output_golden[4] = std::complex<float>(-3, -1.73205);
37  output_golden[5] = std::complex<float>(0, 0);
38 
39  std::complex<float> c_offset = std::complex<float>(1.0, 1.0);
40 
41  if (DataLayout == ColMajor) {
42  VERIFY_IS_APPROX(output(0) + c_offset, output_golden[0] + c_offset);
43  VERIFY_IS_APPROX(output(1) + c_offset, output_golden[1] + c_offset);
44  VERIFY_IS_APPROX(output(2) + c_offset, output_golden[2] + c_offset);
45  VERIFY_IS_APPROX(output(3) + c_offset, output_golden[3] + c_offset);
46  VERIFY_IS_APPROX(output(4) + c_offset, output_golden[4] + c_offset);
47  VERIFY_IS_APPROX(output(5) + c_offset, output_golden[5] + c_offset);
48  } else {
49  VERIFY_IS_APPROX(output(0) + c_offset, output_golden[0] + c_offset);
50  VERIFY_IS_APPROX(output(1) + c_offset, output_golden[2] + c_offset);
51  VERIFY_IS_APPROX(output(2) + c_offset, output_golden[4] + c_offset);
52  VERIFY_IS_APPROX(output(3) + c_offset, output_golden[1] + c_offset);
53  VERIFY_IS_APPROX(output(4) + c_offset, output_golden[3] + c_offset);
54  VERIFY_IS_APPROX(output(5) + c_offset, output_golden[5] + c_offset);
55  }
56 }
The tensor class.
Definition: Tensor.h:68
static const int DataLayout
Definition: cxx11_tensor_image_patch_sycl.cpp:24
@ ColMajor
Definition: Constants.h:318
#define VERIFY_IS_APPROX(a, b)
Definition: integer_types.cpp:13
std::array< T, N > array
Definition: EmulateArray.h:231
void output(std::ostream &outfile, const unsigned &nplot)
Overload output function.
Definition: overloaded_element_body.h:490

References Eigen::ColMajor, DataLayout, output(), and VERIFY_IS_APPROX.

◆ test_fft_complex_input_golden()

static void test_fft_complex_input_golden ( )
static
58  {
60  input(0) = std::complex<float>(1, 1);
61  input(1) = std::complex<float>(2, 2);
62  input(2) = std::complex<float>(3, 3);
63  input(3) = std::complex<float>(4, 4);
64  input(4) = std::complex<float>(5, 5);
65 
67  fft[0] = 0;
68 
69  Tensor<std::complex<float>, 1, ColMajor> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
70  Tensor<std::complex<float>, 1, ColMajor> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
71 
72  Tensor<float, 1, ColMajor> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
73  Tensor<float, 1, ColMajor> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
74 
75  Tensor<float, 1, ColMajor> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
76  Tensor<float, 1, ColMajor> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
77 
78  VERIFY_IS_EQUAL(forward_output_both_parts.dimension(0), input.dimension(0));
79  VERIFY_IS_EQUAL(reverse_output_both_parts.dimension(0), input.dimension(0));
80 
81  VERIFY_IS_EQUAL(forward_output_real_part.dimension(0), input.dimension(0));
82  VERIFY_IS_EQUAL(reverse_output_real_part.dimension(0), input.dimension(0));
83 
84  VERIFY_IS_EQUAL(forward_output_imag_part.dimension(0), input.dimension(0));
85  VERIFY_IS_EQUAL(reverse_output_imag_part.dimension(0), input.dimension(0));
86 
87  std::complex<float> forward_golden_result[5];
88  std::complex<float> reverse_golden_result[5];
89 
90  forward_golden_result[0] = std::complex<float>(15.000000000000000, +15.000000000000000);
91  forward_golden_result[1] = std::complex<float>(-5.940954801177935, +0.940954801177934);
92  forward_golden_result[2] = std::complex<float>(-3.312299240582266, -1.687700759417735);
93  forward_golden_result[3] = std::complex<float>(-1.687700759417735, -3.312299240582266);
94  forward_golden_result[4] = std::complex<float>(0.940954801177934, -5.940954801177935);
95 
96  reverse_golden_result[0] = std::complex<float>(3.000000000000000, +3.000000000000000);
97  reverse_golden_result[1] = std::complex<float>(0.188190960235587, -1.188190960235587);
98  reverse_golden_result[2] = std::complex<float>(-0.337540151883547, -0.662459848116453);
99  reverse_golden_result[3] = std::complex<float>(-0.662459848116453, -0.337540151883547);
100  reverse_golden_result[4] = std::complex<float>(-1.188190960235587, +0.188190960235587);
101 
102  for (int i = 0; i < 5; ++i) {
103  VERIFY_IS_APPROX(forward_output_both_parts(i), forward_golden_result[i]);
104  VERIFY_IS_APPROX(forward_output_real_part(i), forward_golden_result[i].real());
105  VERIFY_IS_APPROX(forward_output_imag_part(i), forward_golden_result[i].imag());
106  }
107 
108  for (int i = 0; i < 5; ++i) {
109  VERIFY_IS_APPROX(reverse_output_both_parts(i), reverse_golden_result[i]);
110  VERIFY_IS_APPROX(reverse_output_real_part(i), reverse_golden_result[i].real());
111  VERIFY_IS_APPROX(reverse_output_imag_part(i), reverse_golden_result[i].imag());
112  }
113 }
AnnoyingScalar imag(const AnnoyingScalar &)
Definition: AnnoyingScalar.h:132
int i
Definition: BiCGSTAB_step_by_step.cpp:9
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const
Definition: Tensor.h:99
float real
Definition: datatypes.h:10
#define VERIFY_IS_EQUAL(a, b)
Definition: main.h:367
@ FFT_FORWARD
Definition: TensorForwardDeclarations.h:170
@ FFT_REVERSE
Definition: TensorForwardDeclarations.h:170
@ ImagPart
Definition: TensorForwardDeclarations.h:168
@ BothParts
Definition: TensorForwardDeclarations.h:168
@ RealPart
Definition: TensorForwardDeclarations.h:168

References Eigen::BothParts, Eigen::ColMajor, Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), Eigen::FFT_FORWARD, Eigen::FFT_REVERSE, i, imag(), Eigen::ImagPart, Eigen::RealPart, VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

Referenced by EIGEN_DECLARE_TEST().

◆ test_fft_non_power_of_2_round_trip()

template<typename RealScalar >
static void test_fft_non_power_of_2_round_trip ( int  exponent)
static
223  {
224  int n = (1 << exponent) + 1;
225 
226  Eigen::DSizes<ptrdiff_t, 1> dimensions;
227  dimensions[0] = n;
228  const DSizes<ptrdiff_t, 1> arr = dimensions;
230 
231  input.resize(arr);
232  input.setRandom();
233 
234  array<int, 1> fft;
235  fft[0] = 0;
236 
237  Tensor<std::complex<RealScalar>, 1, ColMajor> forward = input.template fft<BothParts, FFT_FORWARD>(fft);
238 
239  Tensor<RealScalar, 1, ColMajor, ptrdiff_t> output = forward.template fft<RealPart, FFT_REVERSE>(fft);
240 
241  for (int i = 0; i < n; ++i) {
242  RealScalar tol = test_precision<RealScalar>() * (std::abs(input[i]) + std::abs(output[i]) + 1);
244  }
245 }
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & setRandom()
Definition: TensorBase.h:1049
EIGEN_DEVICE_FUNC void resize(Index firstDimension, IndexTypes... otherDimensions)
Definition: Tensor.h:296
#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b)
Definition: main.h:373
Definition: TensorDimensions.h:161

References abs(), Eigen::ColMajor, i, n, output(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::resize(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX_OR_LESS_THAN.

◆ test_fft_real_input_energy()

template<int DataLayout, typename RealScalar , bool isComplexInput, int FFTResultType, int FFTDirection, int TensorRank>
static void test_fft_real_input_energy ( )
static
176  {
178  ptrdiff_t total_size = 1;
179  for (int i = 0; i < TensorRank; ++i) {
180  dimensions[i] = rand() % 20 + 1;
181  total_size *= dimensions[i];
182  }
183  const DSizes<ptrdiff_t, TensorRank> arr = dimensions;
184 
185  typedef std::conditional_t<isComplexInput == true, std::complex<RealScalar>, RealScalar> InputScalar;
186 
188  input.resize(arr);
189  input.setRandom();
190 
192  for (int i = 0; i < TensorRank; ++i) {
193  fft[i] = i;
194  }
195 
196  typedef std::conditional_t<FFTResultType == Eigen::BothParts, std::complex<RealScalar>, RealScalar> OutputScalar;
198  output = input.template fft<FFTResultType, FFTDirection>(fft);
199 
200  for (int i = 0; i < TensorRank; ++i) {
201  VERIFY_IS_EQUAL(output.dimension(i), input.dimension(i));
202  }
203 
204  RealScalar energy_original = 0.0;
205  RealScalar energy_after_fft = 0.0;
206 
207  for (int i = 0; i < total_size; ++i) {
208  energy_original += numext::abs2(input(i));
209  }
210 
211  for (int i = 0; i < total_size; ++i) {
212  energy_after_fft += numext::abs2(output(i));
213  }
214 
215  if (FFTDirection == FFT_FORWARD) {
216  VERIFY_IS_APPROX(energy_original, energy_after_fft / total_size);
217  } else {
218  VERIFY_IS_APPROX(energy_original, energy_after_fft * total_size);
219  }
220 }
EIGEN_DEVICE_FUNC bool abs2(bool x)
Definition: MathFunctions.h:1102
FFTDirection
Definition: TensorForwardDeclarations.h:170

References Eigen::numext::abs2(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), Eigen::FFT_FORWARD, i, output(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::resize(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_fft_real_input_golden()

static void test_fft_real_input_golden ( )
static
115  {
117  input(0) = 1.0;
118  input(1) = 2.0;
119  input(2) = 3.0;
120  input(3) = 4.0;
121  input(4) = 5.0;
122 
124  fft[0] = 0;
125 
126  Tensor<std::complex<float>, 1, ColMajor> forward_output_both_parts = input.fft<BothParts, FFT_FORWARD>(fft);
127  Tensor<std::complex<float>, 1, ColMajor> reverse_output_both_parts = input.fft<BothParts, FFT_REVERSE>(fft);
128 
129  Tensor<float, 1, ColMajor> forward_output_real_part = input.fft<RealPart, FFT_FORWARD>(fft);
130  Tensor<float, 1, ColMajor> reverse_output_real_part = input.fft<RealPart, FFT_REVERSE>(fft);
131 
132  Tensor<float, 1, ColMajor> forward_output_imag_part = input.fft<ImagPart, FFT_FORWARD>(fft);
133  Tensor<float, 1, ColMajor> reverse_output_imag_part = input.fft<ImagPart, FFT_REVERSE>(fft);
134 
135  VERIFY_IS_EQUAL(forward_output_both_parts.dimension(0), input.dimension(0));
136  VERIFY_IS_EQUAL(reverse_output_both_parts.dimension(0), input.dimension(0));
137 
138  VERIFY_IS_EQUAL(forward_output_real_part.dimension(0), input.dimension(0));
139  VERIFY_IS_EQUAL(reverse_output_real_part.dimension(0), input.dimension(0));
140 
141  VERIFY_IS_EQUAL(forward_output_imag_part.dimension(0), input.dimension(0));
142  VERIFY_IS_EQUAL(reverse_output_imag_part.dimension(0), input.dimension(0));
143 
144  std::complex<float> forward_golden_result[5];
145  std::complex<float> reverse_golden_result[5];
146 
147  forward_golden_result[0] = std::complex<float>(15, 0);
148  forward_golden_result[1] = std::complex<float>(-2.5, +3.44095480117793);
149  forward_golden_result[2] = std::complex<float>(-2.5, +0.81229924058227);
150  forward_golden_result[3] = std::complex<float>(-2.5, -0.81229924058227);
151  forward_golden_result[4] = std::complex<float>(-2.5, -3.44095480117793);
152 
153  reverse_golden_result[0] = std::complex<float>(3.0, 0);
154  reverse_golden_result[1] = std::complex<float>(-0.5, -0.688190960235587);
155  reverse_golden_result[2] = std::complex<float>(-0.5, -0.162459848116453);
156  reverse_golden_result[3] = std::complex<float>(-0.5, +0.162459848116453);
157  reverse_golden_result[4] = std::complex<float>(-0.5, +0.688190960235587);
158 
159  std::complex<float> c_offset(1.0, 1.0);
160  float r_offset = 1.0;
161 
162  for (int i = 0; i < 5; ++i) {
163  VERIFY_IS_APPROX(forward_output_both_parts(i) + c_offset, forward_golden_result[i] + c_offset);
164  VERIFY_IS_APPROX(forward_output_real_part(i) + r_offset, forward_golden_result[i].real() + r_offset);
165  VERIFY_IS_APPROX(forward_output_imag_part(i) + r_offset, forward_golden_result[i].imag() + r_offset);
166  }
167 
168  for (int i = 0; i < 5; ++i) {
169  VERIFY_IS_APPROX(reverse_output_both_parts(i) + c_offset, reverse_golden_result[i] + c_offset);
170  VERIFY_IS_APPROX(reverse_output_real_part(i) + r_offset, reverse_golden_result[i].real() + r_offset);
171  VERIFY_IS_APPROX(reverse_output_imag_part(i) + r_offset, reverse_golden_result[i].imag() + r_offset);
172  }
173 }

References Eigen::BothParts, Eigen::ColMajor, Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), Eigen::FFT_FORWARD, Eigen::FFT_REVERSE, i, imag(), Eigen::ImagPart, Eigen::RealPart, VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

Referenced by EIGEN_DECLARE_TEST().