LCOV - code coverage report
Current view: top level - src/diagonalize - DiagonalizerLapackeEvd.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 26 33 78.8 %
Date: 2026-06-19 12:50:25 Functions: 10 12 83.3 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2024 PairInteraction Developers
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : #include "pairinteraction/diagonalize/DiagonalizerLapackeEvd.hpp"
       5             : 
       6             : #include "pairinteraction/enums/FloatType.hpp"
       7             : #include "pairinteraction/utils/eigen_assertion.hpp"
       8             : #include "pairinteraction/utils/eigen_compat.hpp"
       9             : 
      10             : #include <Eigen/Dense>
      11             : #include <cmath>
      12             : #include <fmt/core.h>
      13             : #include <fmt/format.h>
      14             : #include <spdlog/spdlog.h>
      15             : 
      16             : #ifdef WITH_MKL
      17             : #include <mkl.h>
      18             : #elif WITH_LAPACKE
      19             : #include <lapacke.h>
      20             : #endif
      21             : 
      22             : namespace pairinteraction {
      23             : #if defined(WITH_MKL) || defined(WITH_LAPACKE)
      24           0 : lapack_int evd(int matrix_layout, char jobz, char uplo, lapack_int n, float *a, lapack_int lda,
      25             :                float *w) {
      26           0 :     return LAPACKE_ssyevd(matrix_layout, jobz, uplo, n, a, lda, w);
      27             : };
      28             : 
      29           2 : lapack_int evd(int matrix_layout, char jobz, char uplo, lapack_int n, double *a, lapack_int lda,
      30             :                double *w) {
      31           2 :     return LAPACKE_dsyevd(matrix_layout, jobz, uplo, n, a, lda, w);
      32             : };
      33             : 
      34           2 : lapack_int evd(int matrix_layout, char jobz, char uplo, lapack_int n, lapack_complex_float *a,
      35             :                lapack_int lda, float *w) {
      36           2 :     return LAPACKE_cheevd(matrix_layout, jobz, uplo, n, a, lda, w);
      37             : };
      38             : 
      39           3 : lapack_int evd(int matrix_layout, char jobz, char uplo, lapack_int n, lapack_complex_double *a,
      40             :                lapack_int lda, double *w) {
      41           3 :     return LAPACKE_zheevd(matrix_layout, jobz, uplo, n, a, lda, w);
      42             : };
      43             : 
      44             : template <typename Scalar>
      45             : template <typename ScalarLim>
      46           7 : EigenSystemH<Scalar> DiagonalizerLapackeEvd<Scalar>::dispatch_eigh(
      47             :     const Eigen::SparseMatrix<Scalar, Eigen::RowMajor> &matrix, double rtol) const {
      48             :     using real_lim_t = typename traits::NumTraits<ScalarLim>::real_t;
      49           7 :     int dim = matrix.rows();
      50             : 
      51             :     // Subtract the mean of the diagonal elements from the diagonal
      52           7 :     real_t shift{};
      53           7 :     Eigen::MatrixX<ScalarLim> evecs = this->template subtract_mean<ScalarLim>(matrix, shift, rtol);
      54             : 
      55             :     // Diagonalize the shifted matrix
      56           7 :     char jobz = 'V'; // eigenvalues and eigenvectors are computed
      57           7 :     char uplo = 'U'; // full matrix is stored, upper is used
      58             : 
      59           7 :     Eigen::VectorX<real_lim_t> evals(dim);
      60           7 :     lapack_int info = evd(LAPACK_COL_MAJOR, jobz, uplo, dim, evecs.data(), dim, evals.data());
      61             : 
      62           7 :     if (info != 0) {
      63           0 :         if (info < 0) {
      64           0 :             throw std::invalid_argument(
      65             :                 fmt::format("Diagonalization error: Argument {} to the "
      66             :                             "lapacke_evd routine had an illegal value (the counting of the "
      67             :                             "arguments starts with one). For a documentation of lapacke_evd, see "
      68             :                             "https://www.intel.com/content/www/us/en/docs/onemkl/"
      69             :                             "developer-reference-c/2025-1/syevd.html.",
      70             :                             -info));
      71             :         }
      72           0 :         throw std::runtime_error(fmt::format(
      73             :             "Diagonalization error: The lapacke_evd routine failed with error code {}.", info));
      74             :     }
      75             : 
      76           7 :     return {evecs.sparseView(1, 0.5 * rtol / std::sqrt(dim)).template cast<Scalar>(),
      77           7 :             this->add_mean(evals, shift)};
      78          14 : }
      79             : 
      80             : template <typename Scalar>
      81           4 : DiagonalizerLapackeEvd<Scalar>::DiagonalizerLapackeEvd(FloatType float_type)
      82           4 :     : DiagonalizerInterface<Scalar>(float_type) {}
      83             : 
      84             : template <typename Scalar>
      85             : EigenSystemH<Scalar>
      86           7 : DiagonalizerLapackeEvd<Scalar>::eigh(const Eigen::SparseMatrix<Scalar, Eigen::RowMajor> &matrix,
      87             :                                      double rtol) const {
      88           7 :     switch (this->float_type) {
      89           2 :     case FloatType::FLOAT32:
      90           2 :         return dispatch_eigh<traits::restricted_t<Scalar, FloatType::FLOAT32>>(matrix, rtol);
      91           5 :     case FloatType::FLOAT64:
      92           5 :         return dispatch_eigh<traits::restricted_t<Scalar, FloatType::FLOAT64>>(matrix, rtol);
      93           0 :     default:
      94           0 :         throw std::invalid_argument("Unsupported floating point precision.");
      95             :     }
      96             : }
      97             : 
      98             : #else
      99             : 
     100             : template <typename Scalar>
     101             : DiagonalizerLapackeEvd<Scalar>::DiagonalizerLapackeEvd(FloatType float_type)
     102             :     : DiagonalizerInterface<Scalar>(float_type) {
     103             :     throw std::runtime_error("The lapacke_evd routine is not available in this build. Please use a "
     104             :                              "different diagonalizer.");
     105             : }
     106             : 
     107             : template <typename Scalar>
     108             : EigenSystemH<Scalar> DiagonalizerLapackeEvd<Scalar>::eigh(
     109             :     const Eigen::SparseMatrix<Scalar, Eigen::RowMajor> & /*matrix*/, double /*rtol*/) const {
     110             :     std::abort(); // can't happen because the constructor throws
     111             : }
     112             : 
     113             : #endif // WITH_MKL || WITH_LAPACKE
     114             : 
     115             : // Explicit instantiations
     116             : template class DiagonalizerLapackeEvd<double>;
     117             : template class DiagonalizerLapackeEvd<std::complex<double>>;
     118             : } // namespace pairinteraction

Generated by: LCOV version 1.16