numerics 0.1.0
Loading...
Searching...
No Matches
fft.cpp
Go to the documentation of this file.
1#include "spectral/fft.hpp"
2#include "backends/seq/impl.hpp"
5#ifdef NUMERICS_HAS_STD_SIMD
7#endif
8#include <stdexcept>
9
10namespace num {
11namespace spectral {
12
13// -- One-shot dispatch --------------------------------------------------------
14
15void fft(const CVector& in, CVector& out, FFTBackend b) {
16 if (out.size() != in.size())
17 throw std::invalid_argument("fft: in and out must have the same size");
18#ifdef NUMERICS_HAS_FFTW
19 if (b == FFTBackend::fftw) {
20 backends::fftw::fft(in, out);
21 return;
22 }
23#endif
24#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
25 if (b == FFTBackend::simd) {
26 backends::opt::fft(in, out);
27 return;
28 }
29#endif
30#ifdef NUMERICS_HAS_STD_SIMD
31 if (b == FFTBackend::stdsimd) {
32 backends::stdsimd::fft(in, out);
33 return;
34 }
35#endif
36 // seq is the fallback for simd/stdsimd on unsupported platforms
37 backends::seq::fft(in, out);
38}
39
40void ifft(const CVector& in, CVector& out, FFTBackend b) {
41 if (out.size() != in.size())
42 throw std::invalid_argument("ifft: in and out must have the same size");
43#ifdef NUMERICS_HAS_FFTW
44 if (b == FFTBackend::fftw) {
45 backends::fftw::ifft(in, out);
46 return;
47 }
48#endif
49#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
50 if (b == FFTBackend::simd) {
51 backends::opt::ifft(in, out);
52 return;
53 }
54#endif
55#ifdef NUMERICS_HAS_STD_SIMD
56 if (b == FFTBackend::stdsimd) {
57 backends::stdsimd::ifft(in, out);
58 return;
59 }
60#endif
61 backends::seq::ifft(in, out);
62}
63
64void rfft(const Vector& in, CVector& out, FFTBackend b) {
65 if (static_cast<int>(out.size()) != static_cast<int>(in.size()) / 2 + 1)
66 throw std::invalid_argument("rfft: out must have size n/2+1");
67#ifdef NUMERICS_HAS_FFTW
68 if (b == FFTBackend::fftw) {
69 backends::fftw::rfft(in, out);
70 return;
71 }
72#endif
73#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
74 if (b == FFTBackend::simd) {
75 backends::opt::rfft(in, out);
76 return;
77 }
78#endif
79#ifdef NUMERICS_HAS_STD_SIMD
80 if (b == FFTBackend::stdsimd) {
81 backends::stdsimd::rfft(in, out);
82 return;
83 }
84#endif
85 backends::seq::rfft(in, out);
86}
87
88void irfft(const CVector& in, int n, Vector& out, FFTBackend b) {
89 if (static_cast<int>(in.size()) != n / 2 + 1)
90 throw std::invalid_argument("irfft: in must have size n/2+1");
91 if (static_cast<int>(out.size()) != n)
92 throw std::invalid_argument("irfft: out must have size n");
93#ifdef NUMERICS_HAS_FFTW
94 if (b == FFTBackend::fftw) {
95 backends::fftw::irfft(in, n, out);
96 return;
97 }
98#endif
99#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
100 if (b == FFTBackend::simd) {
101 backends::opt::irfft(in, n, out);
102 return;
103 }
104#endif
105#ifdef NUMERICS_HAS_STD_SIMD
106 if (b == FFTBackend::stdsimd) {
107 backends::stdsimd::irfft(in, n, out);
108 return;
109 }
110#endif
111 backends::seq::irfft(in, n, out);
112}
113
114// -- FFTPlan ------------------------------------------------------------------
115
116FFTPlan::FFTPlan(int n, bool forward, FFTBackend b)
117 : n_(n)
118 , backend_(b) {
119#ifdef NUMERICS_HAS_FFTW
120 if (b == FFTBackend::fftw) {
121 impl_ = new backends::fftw::FFTPlanImpl(n, forward);
122 return;
123 }
124#endif
125#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
126 if (b == FFTBackend::simd) {
127 impl_ = new backends::opt::FFTPlanImpl(n, !forward);
128 return;
129 }
130#endif
131#ifdef NUMERICS_HAS_STD_SIMD
132 if (b == FFTBackend::stdsimd) {
133 impl_ = new backends::stdsimd::FFTPlanImpl(n, !forward);
134 return;
135 }
136#endif
137 impl_ = new backends::seq::FFTPlanImpl(n, !forward);
138}
139
141#ifdef NUMERICS_HAS_FFTW
142 if (backend_ == FFTBackend::fftw) {
143 delete static_cast<backends::fftw::FFTPlanImpl*>(impl_);
144 return;
145 }
146#endif
147#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
148 if (backend_ == FFTBackend::simd) {
149 delete static_cast<backends::opt::FFTPlanImpl*>(impl_);
150 return;
151 }
152#endif
153#ifdef NUMERICS_HAS_STD_SIMD
154 if (backend_ == FFTBackend::stdsimd) {
155 delete static_cast<backends::stdsimd::FFTPlanImpl*>(impl_);
156 return;
157 }
158#endif
159 delete static_cast<backends::seq::FFTPlanImpl*>(impl_);
160}
161
162void FFTPlan::execute(const CVector& in, CVector& out) const {
163 if (static_cast<int>(in.size()) != n_ || static_cast<int>(out.size()) != n_)
164 throw std::invalid_argument("FFTPlan::execute: size mismatch");
165#ifdef NUMERICS_HAS_FFTW
166 if (backend_ == FFTBackend::fftw) {
167 static_cast<backends::fftw::FFTPlanImpl*>(impl_)->execute(in, out);
168 return;
169 }
170#endif
171#if defined(NUMERICS_HAS_AVX2) || defined(NUMERICS_HAS_NEON)
172 if (backend_ == FFTBackend::simd) {
173 for (idx i = 0; i < static_cast<idx>(n_); ++i)
174 out[i] = in[i];
175 static_cast<backends::opt::FFTPlanImpl*>(impl_)->execute(out);
176 return;
177 }
178#endif
179#ifdef NUMERICS_HAS_STD_SIMD
180 if (backend_ == FFTBackend::stdsimd) {
181 for (idx i = 0; i < static_cast<idx>(n_); ++i)
182 out[i] = in[i];
183 static_cast<backends::stdsimd::FFTPlanImpl*>(impl_)->execute(out);
184 return;
185 }
186#endif
187 for (idx i = 0; i < static_cast<idx>(n_); ++i)
188 out[i] = in[i];
189 static_cast<backends::seq::FFTPlanImpl*>(impl_)->execute(out);
190}
191
192} // namespace spectral
193} // namespace num
Dense vector with optional GPU storage, templated over scalar type T.
Definition vector.hpp:24
constexpr idx size() const noexcept
Definition vector.hpp:80
FFTPlan(int n, bool forward=true, FFTBackend b=default_fft_backend)
Definition fft.cpp:116
void execute(const CVector &in, CVector &out) const
Definition fft.cpp:162
FFT interface with backend dispatch.
void irfft(const num::CVector &in, int n, num::Vector &out)
Definition impl.hpp:206
void ifft(const num::CVector &in, num::CVector &out)
Definition impl.hpp:187
void fft(const num::CVector &in, num::CVector &out)
Definition impl.hpp:179
void rfft(const num::Vector &in, num::CVector &out)
Definition impl.hpp:195
void ifft(const num::CVector &in, num::CVector &out)
Definition impl.hpp:54
void rfft(const num::Vector &in, num::CVector &out)
Definition impl.hpp:60
void irfft(const num::CVector &in, int n, num::Vector &out)
Definition impl.hpp:70
void fft(const num::CVector &in, num::CVector &out)
Definition impl.hpp:48
void ifft(const CVector &in, CVector &out, FFTBackend b=default_fft_backend)
Inverse complex DFT (unnormalised: result = n * true_inverse).
Definition fft.cpp:40
void fft(const CVector &in, CVector &out, FFTBackend b=default_fft_backend)
Forward complex DFT. out must be pre-allocated to in.size().
Definition fft.cpp:15
FFTBackend
Selects which backend handles an FFT operation.
Definition fft.hpp:29
void irfft(const CVector &in, int n, Vector &out, FFTBackend b=default_fft_backend)
Complex-to-real inverse DFT (unnormalised).
Definition fft.cpp:88
void rfft(const Vector &in, CVector &out, FFTBackend b=default_fft_backend)
Real-to-complex forward DFT. out must be pre-allocated to n/2+1.
Definition fft.cpp:64
std::size_t idx
Definition types.hpp:11
FFTW3 backend wrappers. Only included by src/spectral/fft.cpp.
Handwritten AVX2 / NEON butterfly for the FFT.
std::experimental::simd butterfly for FFT.
Precomputed twiddle factors + SIMD butterfly execution.
Definition impl.hpp:140