// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include // IWYU pragma: private #include "./InternalHeaderCheck.h" #include #include namespace Eigen { namespace internal { namespace imklfft { #define RUN_OR_ASSERT(EXPR, ERROR_MSG) \ { \ MKL_LONG status = (EXPR); \ eigen_assert(status == DFTI_NO_ERROR && (ERROR_MSG)); \ }; inline MKL_Complex16* complex_cast(const std::complex* p) { return const_cast(reinterpret_cast(p)); } inline MKL_Complex8* complex_cast(const std::complex* p) { return const_cast(reinterpret_cast(p)); } /* * Parameters: * precision: enum, Precision of the transform: DFTI_SINGLE or DFTI_DOUBLE. * forward_domain: enum, Forward domain of the transform: DFTI_COMPLEX or * DFTI_REAL. dimension: MKL_LONG Dimension of the transform. sizes: MKL_LONG if * dimension = 1.Length of the transform for a one-dimensional transform. sizes: * Array of type MKL_LONG otherwise. Lengths of each dimension for a * multi-dimensional transform. */ inline void configure_descriptor(std::shared_ptr& handl, enum DFTI_CONFIG_VALUE precision, enum DFTI_CONFIG_VALUE forward_domain, MKL_LONG dimension, MKL_LONG* sizes) { eigen_assert(dimension == 1 || dimension == 2 && "Transformation dimension must be less than 3."); DFTI_DESCRIPTOR_HANDLE res = nullptr; if (dimension == 1) { RUN_OR_ASSERT(DftiCreateDescriptor(&res, precision, forward_domain, dimension, *sizes), "DftiCreateDescriptor failed.") handl.reset(res, [](DFTI_DESCRIPTOR_HANDLE handle) { DftiFreeDescriptor(&handle); }); if (forward_domain == DFTI_REAL) { // Set CCE storage RUN_OR_ASSERT(DftiSetValue(handl.get(), DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX), "DftiSetValue failed.") } } else { RUN_OR_ASSERT(DftiCreateDescriptor(&res, precision, DFTI_COMPLEX, dimension, sizes), "DftiCreateDescriptor failed.") handl.reset(res, [](DFTI_DESCRIPTOR_HANDLE handle) { DftiFreeDescriptor(&handle); }); } RUN_OR_ASSERT(DftiSetValue(handl.get(), DFTI_PLACEMENT, DFTI_NOT_INPLACE), "DftiSetValue failed.") RUN_OR_ASSERT(DftiCommitDescriptor(handl.get()), "DftiCommitDescriptor failed.") } template struct plan {}; template <> struct plan { typedef float scalar_type; typedef MKL_Complex8 complex_type; std::shared_ptr m_plan; plan() = default; enum DFTI_CONFIG_VALUE precision = DFTI_SINGLE; inline void forward(complex_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_COMPLEX, 1, &nfft); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse(complex_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_COMPLEX, 1, &nfft); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } inline void forward(complex_type* dst, scalar_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_REAL, 1, &nfft); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse(scalar_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_REAL, 1, &nfft); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } inline void forward2(complex_type* dst, complex_type* src, int n0, int n1) { if (m_plan == 0) { MKL_LONG sizes[2] = {n0, n1}; configure_descriptor(m_plan, precision, DFTI_COMPLEX, 2, sizes); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse2(complex_type* dst, complex_type* src, int n0, int n1) { if (m_plan == 0) { MKL_LONG sizes[2] = {n0, n1}; configure_descriptor(m_plan, precision, DFTI_COMPLEX, 2, sizes); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } }; template <> struct plan { typedef double scalar_type; typedef MKL_Complex16 complex_type; std::shared_ptr m_plan; plan() = default; enum DFTI_CONFIG_VALUE precision = DFTI_DOUBLE; inline void forward(complex_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_COMPLEX, 1, &nfft); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse(complex_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_COMPLEX, 1, &nfft); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } inline void forward(complex_type* dst, scalar_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_REAL, 1, &nfft); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse(scalar_type* dst, complex_type* src, MKL_LONG nfft) { if (m_plan == 0) { configure_descriptor(m_plan, precision, DFTI_REAL, 1, &nfft); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } inline void forward2(complex_type* dst, complex_type* src, int n0, int n1) { if (m_plan == 0) { MKL_LONG sizes[2] = {n0, n1}; configure_descriptor(m_plan, precision, DFTI_COMPLEX, 2, sizes); } RUN_OR_ASSERT(DftiComputeForward(m_plan.get(), src, dst), "DftiComputeForward failed.") } inline void inverse2(complex_type* dst, complex_type* src, int n0, int n1) { if (m_plan == 0) { MKL_LONG sizes[2] = {n0, n1}; configure_descriptor(m_plan, precision, DFTI_COMPLEX, 2, sizes); } RUN_OR_ASSERT(DftiComputeBackward(m_plan.get(), src, dst), "DftiComputeBackward failed.") } }; template struct imklfft_impl { typedef Scalar_ Scalar; typedef std::complex Complex; inline void clear() { m_plans.clear(); } // complex-to-complex forward FFT inline void fwd(Complex* dst, const Complex* src, int nfft) { MKL_LONG size = nfft; get_plan(nfft, dst, src).forward(complex_cast(dst), complex_cast(src), size); } // real-to-complex forward FFT inline void fwd(Complex* dst, const Scalar* src, int nfft) { MKL_LONG size = nfft; get_plan(nfft, dst, src).forward(complex_cast(dst), const_cast(src), nfft); } // 2-d complex-to-complex inline void fwd2(Complex* dst, const Complex* src, int n0, int n1) { get_plan(n0, n1, dst, src).forward2(complex_cast(dst), complex_cast(src), n0, n1); } // inverse complex-to-complex inline void inv(Complex* dst, const Complex* src, int nfft) { MKL_LONG size = nfft; get_plan(nfft, dst, src).inverse(complex_cast(dst), complex_cast(src), nfft); } // half-complex to scalar inline void inv(Scalar* dst, const Complex* src, int nfft) { MKL_LONG size = nfft; get_plan(nfft, dst, src).inverse(const_cast(dst), complex_cast(src), nfft); } // 2-d complex-to-complex inline void inv2(Complex* dst, const Complex* src, int n0, int n1) { get_plan(n0, n1, dst, src).inverse2(complex_cast(dst), complex_cast(src), n0, n1); } private: std::map> m_plans; inline plan& get_plan(int nfft, void* dst, const void* src) { int inplace = dst == src ? 1 : 0; int aligned = ((reinterpret_cast(src) & 15) | (reinterpret_cast(dst) & 15)) == 0 ? 1 : 0; int64_t key = ((nfft << 2) | (inplace << 1) | aligned) << 1; // Create element if key does not exist. return m_plans[key]; } inline plan& get_plan(int n0, int n1, void* dst, const void* src) { int inplace = (dst == src) ? 1 : 0; int aligned = ((reinterpret_cast(src) & 15) | (reinterpret_cast(dst) & 15)) == 0 ? 1 : 0; int64_t key = (((((int64_t)n0) << 31) | (n1 << 2) | (inplace << 1) | aligned) << 1) + 1; // Create element if key does not exist. return m_plans[key]; } }; #undef RUN_OR_ASSERT } // namespace imklfft } // namespace internal } // namespace Eigen