| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2021 Erik Schultheis <erik.schultheis@aalto.fi> |
| // |
| // 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/. |
| |
| #ifndef EIGEN_LAPACKE_HELPERS_H |
| #define EIGEN_LAPACKE_HELPERS_H |
| |
| // IWYU pragma: private |
| #include "./InternalHeaderCheck.h" |
| |
| #ifdef EIGEN_USE_MKL |
| #include "mkl_lapacke.h" |
| #else |
| #include "lapacke.h" |
| #endif |
| |
| namespace Eigen { |
| namespace internal { |
| /** |
| * \internal |
| * \brief Implementation details and helper functions for the lapacke glue code. |
| */ |
| namespace lapacke_helpers { |
| |
| // --------------------------------------------------------------------------------------------------------------------- |
| // Translation from Eigen to Lapacke for types and constants |
| // --------------------------------------------------------------------------------------------------------------------- |
| |
| // For complex numbers, the types in Eigen and Lapacke are different, but layout compatible. |
| template<typename Scalar> |
| struct translate_type_imp; |
| template<> |
| struct translate_type_imp<float> { |
| using type = float; |
| }; |
| template<> |
| struct translate_type_imp<double> { |
| using type = double; |
| }; |
| template<> |
| struct translate_type_imp<std::complex<double>> { |
| using type = lapack_complex_double; |
| }; |
| template<> |
| struct translate_type_imp<std::complex<float>> { |
| using type = lapack_complex_float; |
| }; |
| |
| /// Given an Eigen types, this is defined to be the corresponding, layout-compatible lapack type |
| template<typename Scalar> |
| using translated_type = typename translate_type_imp<Scalar>::type; |
| |
| /// These functions convert their arguments from Eigen to Lapack types |
| /// This function performs conversion for any of the translations defined above. |
| template<typename Source, typename Target=translated_type<Source>> |
| EIGEN_ALWAYS_INLINE auto to_lapack(Source value) { return static_cast<Target>(value); } |
| |
| /// This function performs conversions for pointer types corresponding to the translations abovce. |
| /// This is valid because the translations are between layout-compatible types. |
| template<typename Source, typename Target=translated_type<Source>> |
| EIGEN_ALWAYS_INLINE auto to_lapack(Source *value) { return reinterpret_cast<Target*>(value); } |
| |
| /// This function converts the Eigen Index to a lapack index, with possible range checks |
| /// \sa internal::convert_index |
| EIGEN_ALWAYS_INLINE lapack_int to_lapack(Index index) { |
| return convert_index<lapack_int>(index); |
| } |
| |
| /// translates storage order of the given Eigen object to the corresponding lapack constant |
| template<typename Derived> |
| EIGEN_ALWAYS_INLINE EIGEN_CONSTEXPR lapack_int lapack_storage_of(const EigenBase<Derived> &) { |
| return Derived::IsRowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; |
| } |
| |
| // --------------------------------------------------------------------------------------------------------------------- |
| // Automatic generation of low-level wrappers |
| // --------------------------------------------------------------------------------------------------------------------- |
| |
| /*! |
| * \internal |
| * \brief Helper type to facilitate the wrapping of raw LAPACKE functions for different types into a single, overloaded C++ function. |
| * This is achieved in combination with \r EIGEN_MAKE_LAPACKE_WRAPPER |
| * \details This implementation works by providing an overloaded call function that just forwards its arguments to the |
| * underlying lapack function. Each of these overloads is enabled only if the call is actually well formed. |
| * Because these lapack functions take pointers to the underlying scalar type as arguments, even though the actual Scalars |
| * would be implicitly convertible, the pointers are not and therefore only a single overload can be valid at the same time. |
| * Thus, despite all functions taking fully generic `Args&&... args` as arguments, there is never any ambiguity. |
| */ |
| template<typename DoubleFn, typename SingleFn, typename DoubleCpxFn, typename SingleCpxFn> |
| struct WrappingHelper { |
| // The naming of double, single, double complex and single complex is purely for readability |
| // and doesn't actually affect the workings of this class. In principle, the arguments can |
| // be supplied in any permuted order. |
| DoubleFn double_; SingleFn single_; DoubleCpxFn double_cpx_; SingleCpxFn single_cpx_; |
| |
| template<typename... Args> |
| auto call(Args&&... args) -> decltype(double_(std::forward<Args>(args)...)) { |
| return double_(std::forward<Args>(args)...); |
| } |
| |
| template<typename... Args> |
| auto call(Args&&... args) -> decltype(single_(std::forward<Args>(args)...)){ |
| return single_(std::forward<Args>(args)...); |
| } |
| |
| template<typename... Args> |
| auto call(Args&&... args) -> decltype(double_cpx_(std::forward<Args>(args)...)){ |
| return double_cpx_(std::forward<Args>(args)...); |
| } |
| |
| template<typename... Args> |
| auto call(Args&&... args) -> decltype(single_cpx_(std::forward<Args>(args)...)){ |
| return single_cpx_(std::forward<Args>(args)...); |
| } |
| }; |
| |
| /** \internal Helper function that generates a `WrappingHelper` object with the given function pointers and |
| * invokes its `call` method, thus selecting one of the overloads. |
| * \sa EIGEN_MAKE_LAPACKE_WRAPPER |
| */ |
| template<typename DoubleFn, typename SingleFn, typename DoubleCpxFn, typename SingleCpxFn, typename... Args> |
| EIGEN_ALWAYS_INLINE auto call_wrapper(DoubleFn df, SingleFn sf, DoubleCpxFn dcf, SingleCpxFn scf, Args&&... args) { |
| WrappingHelper<DoubleFn, SingleFn, DoubleCpxFn, SingleCpxFn> helper{df, sf, dcf, scf}; |
| return helper.call(std::forward<Args>(args)...); |
| } |
| |
| /** |
| * \internal |
| * Generates a new function `Function` that dispatches to the corresponding LAPACKE_? prefixed functions. |
| * \sa WrappingHelper |
| */ |
| #define EIGEN_MAKE_LAPACKE_WRAPPER(FUNCTION) \ |
| template<typename... Args> \ |
| EIGEN_ALWAYS_INLINE auto FUNCTION(Args&&... args) { return call_wrapper(LAPACKE_d##FUNCTION, LAPACKE_s##FUNCTION, LAPACKE_z##FUNCTION, LAPACKE_c##FUNCTION, std::forward<Args>(args)...); } |
| |
| // Now with this macro and the helper wrappers, we can generate the dispatch for all the lapacke functions that are |
| // used in Eigen. |
| // We define these here instead of in the files where they are used because this allows us to #undef the macro again |
| // right here |
| EIGEN_MAKE_LAPACKE_WRAPPER(potrf) |
| EIGEN_MAKE_LAPACKE_WRAPPER(getrf) |
| EIGEN_MAKE_LAPACKE_WRAPPER(geqrf) |
| EIGEN_MAKE_LAPACKE_WRAPPER(gesdd) |
| |
| #undef EIGEN_MAKE_LAPACKE_WRAPPER |
| } |
| } |
| } |
| |
| #endif // EIGEN_LAPACKE_HELPERS_H |