11#ifndef EIGEN_FFT_FFTW_IMPL_H
12#define EIGEN_FFT_FFTW_IMPL_H
15#include "./InternalHeaderCheck.h"
33inline T *fftw_cast(
const T *p) {
34 return const_cast<T *
>(p);
37inline fftw_complex *fftw_cast(
const std::complex<double> *p) {
38 return const_cast<fftw_complex *
>(
reinterpret_cast<const fftw_complex *
>(p));
41inline fftwf_complex *fftw_cast(
const std::complex<float> *p) {
42 return const_cast<fftwf_complex *
>(
reinterpret_cast<const fftwf_complex *
>(p));
45inline fftwl_complex *fftw_cast(
const std::complex<long double> *p) {
46 return const_cast<fftwl_complex *
>(
reinterpret_cast<const fftwl_complex *
>(p));
61#if EIGEN_HAS_ATTRIBUTE(visibility) && !EIGEN_OS_WIN
62#define EIGEN_FFTW_PLANNER_MUTEX_VISIBILITY __attribute__((visibility("default")))
64#define EIGEN_FFTW_PLANNER_MUTEX_VISIBILITY
67template <
typename Dummy =
void>
68struct fftw_planner_lock {
69 static EIGEN_FFTW_PLANNER_MUTEX_VISIBILITY std::mutex mutex;
71template <
typename Dummy>
72EIGEN_FFTW_PLANNER_MUTEX_VISIBILITY std::mutex fftw_planner_lock<Dummy>::mutex;
74inline std::mutex &fftw_planner_mutex() {
return fftw_planner_lock<>::mutex; }
76template <
typename PlanFactory>
77inline decltype(
auto) fftw_make_plan(PlanFactory factory) {
78 std::lock_guard<std::mutex> lock(fftw_planner_mutex());
86struct fftw_plan<float> {
87 typedef float scalar_type;
88 typedef fftwf_complex complex_type;
89 std::shared_ptr<fftwf_plan_s> m_plan;
90 fftw_plan() =
default;
92 void set_plan(fftwf_plan p) {
93 m_plan.reset(p, [](fftwf_plan plan) {
94 std::lock_guard<std::mutex> lock(fftw_planner_mutex());
95 fftwf_destroy_plan(plan);
98 inline void fwd(complex_type *dst, complex_type *src,
int nfft) {
100 set_plan(fftw_make_plan(
101 [&] {
return fftwf_plan_dft_1d(nfft, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
102 fftwf_execute_dft(m_plan.get(), src, dst);
104 inline void inv(complex_type *dst, complex_type *src,
int nfft) {
106 set_plan(fftw_make_plan(
107 [&] {
return fftwf_plan_dft_1d(nfft, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
108 fftwf_execute_dft(m_plan.get(), src, dst);
110 inline void fwd(complex_type *dst, scalar_type *src,
int nfft) {
113 fftw_make_plan([&] {
return fftwf_plan_dft_r2c_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
114 fftwf_execute_dft_r2c(m_plan.get(), src, dst);
116 inline void inv(scalar_type *dst, complex_type *src,
int nfft) {
119 fftw_make_plan([&] {
return fftwf_plan_dft_c2r_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
120 fftwf_execute_dft_c2r(m_plan.get(), src, dst);
123 inline void fwd2(complex_type *dst, complex_type *src,
int n0,
int n1) {
125 set_plan(fftw_make_plan(
126 [&] {
return fftwf_plan_dft_2d(n0, n1, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
127 fftwf_execute_dft(m_plan.get(), src, dst);
129 inline void inv2(complex_type *dst, complex_type *src,
int n0,
int n1) {
131 set_plan(fftw_make_plan(
132 [&] {
return fftwf_plan_dft_2d(n0, n1, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
133 fftwf_execute_dft(m_plan.get(), src, dst);
137struct fftw_plan<double> {
138 typedef double scalar_type;
139 typedef fftw_complex complex_type;
140 std::shared_ptr<fftw_plan_s> m_plan;
141 fftw_plan() =
default;
143 void set_plan(::fftw_plan p) {
144 m_plan.reset(p, [](::fftw_plan plan) {
145 std::lock_guard<std::mutex> lock(fftw_planner_mutex());
146 fftw_destroy_plan(plan);
149 inline void fwd(complex_type *dst, complex_type *src,
int nfft) {
151 set_plan(fftw_make_plan(
152 [&] {
return fftw_plan_dft_1d(nfft, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
153 fftw_execute_dft(m_plan.get(), src, dst);
155 inline void inv(complex_type *dst, complex_type *src,
int nfft) {
157 set_plan(fftw_make_plan(
158 [&] {
return fftw_plan_dft_1d(nfft, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
159 fftw_execute_dft(m_plan.get(), src, dst);
161 inline void fwd(complex_type *dst, scalar_type *src,
int nfft) {
164 fftw_make_plan([&] {
return fftw_plan_dft_r2c_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
165 fftw_execute_dft_r2c(m_plan.get(), src, dst);
167 inline void inv(scalar_type *dst, complex_type *src,
int nfft) {
170 fftw_make_plan([&] {
return fftw_plan_dft_c2r_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
171 fftw_execute_dft_c2r(m_plan.get(), src, dst);
173 inline void fwd2(complex_type *dst, complex_type *src,
int n0,
int n1) {
175 set_plan(fftw_make_plan(
176 [&] {
return fftw_plan_dft_2d(n0, n1, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
177 fftw_execute_dft(m_plan.get(), src, dst);
179 inline void inv2(complex_type *dst, complex_type *src,
int n0,
int n1) {
181 set_plan(fftw_make_plan(
182 [&] {
return fftw_plan_dft_2d(n0, n1, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
183 fftw_execute_dft(m_plan.get(), src, dst);
187struct fftw_plan<long double> {
188 typedef long double scalar_type;
189 typedef fftwl_complex complex_type;
190 std::shared_ptr<fftwl_plan_s> m_plan;
191 fftw_plan() =
default;
193 void set_plan(fftwl_plan p) {
194 m_plan.reset(p, [](fftwl_plan plan) {
195 std::lock_guard<std::mutex> lock(fftw_planner_mutex());
196 fftwl_destroy_plan(plan);
199 inline void fwd(complex_type *dst, complex_type *src,
int nfft) {
201 set_plan(fftw_make_plan(
202 [&] {
return fftwl_plan_dft_1d(nfft, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
203 fftwl_execute_dft(m_plan.get(), src, dst);
205 inline void inv(complex_type *dst, complex_type *src,
int nfft) {
207 set_plan(fftw_make_plan(
208 [&] {
return fftwl_plan_dft_1d(nfft, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
209 fftwl_execute_dft(m_plan.get(), src, dst);
211 inline void fwd(complex_type *dst, scalar_type *src,
int nfft) {
214 fftw_make_plan([&] {
return fftwl_plan_dft_r2c_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
215 fftwl_execute_dft_r2c(m_plan.get(), src, dst);
217 inline void inv(scalar_type *dst, complex_type *src,
int nfft) {
220 fftw_make_plan([&] {
return fftwl_plan_dft_c2r_1d(nfft, src, dst, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
221 fftwl_execute_dft_c2r(m_plan.get(), src, dst);
223 inline void fwd2(complex_type *dst, complex_type *src,
int n0,
int n1) {
225 set_plan(fftw_make_plan(
226 [&] {
return fftwl_plan_dft_2d(n0, n1, src, dst, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
227 fftwl_execute_dft(m_plan.get(), src, dst);
229 inline void inv2(complex_type *dst, complex_type *src,
int n0,
int n1) {
231 set_plan(fftw_make_plan(
232 [&] {
return fftwl_plan_dft_2d(n0, n1, src, dst, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); }));
233 fftwl_execute_dft(m_plan.get(), src, dst);
237template <
typename Scalar_>
239 typedef Scalar_ Scalar;
240 typedef std::complex<Scalar> Complex;
242 inline void clear() { m_plans.clear(); }
245 inline void fwd(Complex *dst,
const Complex *src,
int nfft) {
246 get_plan(nfft,
false,
false, dst, src).fwd(fftw_cast(dst), fftw_cast(src), nfft);
250 inline void fwd(Complex *dst,
const Scalar *src,
int nfft) {
251 get_plan(nfft,
false,
true, dst, src).fwd(fftw_cast(dst), fftw_cast(src), nfft);
255 inline void fwd2(Complex *dst,
const Complex *src,
int n0,
int n1) {
256 get_plan(n0, n1,
false,
false, dst, src).fwd2(fftw_cast(dst), fftw_cast(src), n0, n1);
260 inline void inv(Complex *dst,
const Complex *src,
int nfft) {
261 get_plan(nfft,
true,
false, dst, src).inv(fftw_cast(dst), fftw_cast(src), nfft);
265 inline void inv(Scalar *dst,
const Complex *src,
int nfft) {
266 get_plan(nfft,
true,
true, dst, src).inv(fftw_cast(dst), fftw_cast(src), nfft);
270 inline void inv2(Complex *dst,
const Complex *src,
int n0,
int n1) {
271 get_plan(n0, n1,
true,
false, dst, src).inv2(fftw_cast(dst), fftw_cast(src), n0, n1);
275 typedef fftw_plan<Scalar> PlanData;
277 typedef Eigen::numext::int64_t int64_t;
279 typedef std::map<int64_t, PlanData> PlanMap;
287 static int64_t plan_flags(
bool inverse,
bool real_io,
void *dst,
const void *src) {
288 bool inplace = (dst == src);
289 bool aligned = ((
reinterpret_cast<size_t>(src) & 15) | (
reinterpret_cast<size_t>(dst) & 15)) == 0;
290 return (inverse << 3) | (real_io << 2) | (inplace << 1) | aligned;
293 inline PlanData &get_plan(
int nfft,
bool inverse,
bool real_io,
void *dst,
const void *src) {
294 int64_t key = ((nfft << 4) | plan_flags(inverse, real_io, dst, src)) << 1;
298 inline PlanData &get_plan(
int n0,
int n1,
bool inverse,
bool real_io,
void *dst,
const void *src) {
299 int64_t key = (((((int64_t)n0) << 31) | (n1 << 4) | plan_flags(inverse, real_io, dst, src)) << 1) + 1;
Namespace containing all symbols from the Eigen library.