LCOV - code coverage report
Current view: top level - src/utils - tensor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 38 39 97.4 %
Date: 2025-06-06 09:03:14 Functions: 2 4 50.0 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2025 Pairinteraction Developers
       2             : // SPDX-License-Identifier: LGPL-3.0-or-later
       3             : 
       4             : #include "pairinteraction/utils/tensor.hpp"
       5             : 
       6             : #include "pairinteraction/basis/BasisPair.hpp"
       7             : #include "pairinteraction/utils/eigen_assertion.hpp"
       8             : #include "pairinteraction/utils/traits.hpp"
       9             : 
      10             : #include <Eigen/SparseCore>
      11             : #include <algorithm>
      12             : #include <limits>
      13             : #include <memory>
      14             : #include <oneapi/tbb.h>
      15             : 
      16             : namespace pairinteraction::utils {
      17             : 
      18             : template <typename Scalar>
      19             : Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
      20          38 : calculate_tensor_product(const std::shared_ptr<const BasisPair<Scalar>> &basis_initial,
      21             :                          const std::shared_ptr<const BasisPair<Scalar>> &basis_final,
      22             :                          const Eigen::SparseMatrix<Scalar, Eigen::RowMajor> &matrix1,
      23             :                          const Eigen::SparseMatrix<Scalar, Eigen::RowMajor> &matrix2) {
      24          38 :     oneapi::tbb::concurrent_vector<Eigen::Triplet<Scalar>> triplets;
      25             : 
      26             :     // Loop over the rows of the first matrix in parallel (outer index == row)
      27          38 :     oneapi::tbb::parallel_for(
      28        3014 :         oneapi::tbb::blocked_range<Eigen::Index>(0, matrix1.outerSize()), [&](const auto &range) {
      29        5969 :             for (Eigen::Index row1 = range.begin(); row1 != range.end(); ++row1) {
      30             : 
      31        2984 :                 const auto &range_row2 = basis_final->get_index_range(row1);
      32             : 
      33             :                 // Loop over the rows of the second matrix that are energetically allowed
      34       14759 :                 for (auto row2 = static_cast<Eigen::Index>(range_row2.min());
      35       14762 :                      row2 < static_cast<Eigen::Index>(range_row2.max()); ++row2) {
      36             : 
      37       11766 :                     Eigen::Index row = basis_final->get_ket_index_from_tuple(row1, row2);
      38       11758 :                     if (row < 0) {
      39        2368 :                         continue;
      40             :                     }
      41             : 
      42             :                     // Loop over the non-zero column elements of the first matrix
      43      172670 :                     for (typename Eigen::SparseMatrix<Scalar, Eigen::RowMajor>::InnerIterator it1(
      44             :                              matrix1, row1);
      45      169853 :                          it1; ++it1) {
      46             : 
      47      161416 :                         Eigen::Index col1 = it1.col();
      48      161403 :                         Scalar value1 = it1.value();
      49             : 
      50             :                         // Calculate the minimum and maximum values of the index pointer of the
      51             :                         // second matrix
      52      160982 :                         Eigen::Index begin_idxptr2 = matrix2.outerIndexPtr()[row2];
      53      160857 :                         Eigen::Index end_idxptr2 = matrix2.outerIndexPtr()[row2 + 1];
      54             : 
      55             :                         // The minimum value is chosen such that we start with an energetically
      56             :                         // allowed column
      57      162261 :                         const auto &range_col2 = basis_initial->get_index_range(it1.index());
      58      161142 :                         begin_idxptr2 +=
      59      160999 :                             std::distance(matrix2.innerIndexPtr() + begin_idxptr2,
      60      159633 :                                           std::lower_bound(matrix2.innerIndexPtr() + begin_idxptr2,
      61      156064 :                                                            matrix2.innerIndexPtr() + end_idxptr2,
      62      157078 :                                                            range_col2.min()));
      63             : 
      64             :                         // Loop over the non-zero column elements of the second matrix that are
      65             :                         // energetically allowed (we break the loop if the index pointer corresponds
      66             :                         // to a column that is not energetically allowed)
      67      222719 :                         for (Eigen::Index idxptr2 = begin_idxptr2; idxptr2 < end_idxptr2;
      68             :                              ++idxptr2) {
      69             : 
      70      202458 :                             Eigen::Index col2 = matrix2.innerIndexPtr()[idxptr2];
      71      201874 :                             if (col2 >= static_cast<Eigen::Index>(range_col2.max())) {
      72      143019 :                                 break;
      73             :                             }
      74             : 
      75       61505 :                             Eigen::Index col = basis_initial->get_ket_index_from_tuple(col1, col2);
      76       61628 :                             if (col < 0) {
      77       37571 :                                 continue;
      78             :                             }
      79             : 
      80       24057 :                             Scalar value2 = matrix2.valuePtr()[idxptr2];
      81             : 
      82             :                             // Store the entry
      83           0 :                             Scalar value = value1 * value2;
      84       24046 :                             triplets.emplace_back(row, col, value);
      85             :                         }
      86             :                     }
      87             :                 }
      88             :             }
      89             :         });
      90             : 
      91             :     // Construct the combined matrix from the triplets
      92          38 :     Eigen::SparseMatrix<Scalar, Eigen::RowMajor> matrix(basis_final->get_number_of_kets(),
      93          38 :                                                         basis_initial->get_number_of_kets());
      94          38 :     matrix.setFromTriplets(triplets.begin(), triplets.end());
      95          38 :     matrix.makeCompressed();
      96             : 
      97          76 :     return matrix;
      98          38 : }
      99             : 
     100             : // Explicit instantiations
     101             : template Eigen::SparseMatrix<double, Eigen::RowMajor>
     102             : calculate_tensor_product(const std::shared_ptr<const BasisPair<double>> &,
     103             :                          const std::shared_ptr<const BasisPair<double>> &,
     104             :                          const Eigen::SparseMatrix<double, Eigen::RowMajor> &,
     105             :                          const Eigen::SparseMatrix<double, Eigen::RowMajor> &);
     106             : template Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor>
     107             : calculate_tensor_product(const std::shared_ptr<const BasisPair<std::complex<double>>> &,
     108             :                          const std::shared_ptr<const BasisPair<std::complex<double>>> &,
     109             :                          const Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor> &,
     110             :                          const Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor> &);
     111             : 
     112             : } // namespace pairinteraction::utils

Generated by: LCOV version 1.16