16#include <oneapi/tbb.h>
20template <
typename Scalar>
27 map_range_of_state_index2(std::move(map_range_of_state_index2)),
28 state_indices_to_ket_index(std::move(state_indices_to_ket_index)), basis1(std::move(basis1)),
29 basis2(std::move(basis2)) {}
31template <
typename Scalar>
34 return map_range_of_state_index2.at(state_index1);
37template <
typename Scalar>
42template <
typename Scalar>
47template <
typename Scalar>
49 if (state_indices_to_ket_index.count({state_index1, state_index2}) == 0) {
52 return state_indices_to_ket_index.at({state_index1, state_index2});
55template <
typename Scalar>
58 std::shared_ptr<const KetAtom> ket2)
const {
59 return get_amplitudes(basis1->get_canonical_state_from_ket(ket1),
60 basis2->get_canonical_state_from_ket(ket2))
64template <
typename Scalar>
65Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
68 if (other1->get_id_of_kets() != basis1->get_id_of_kets() ||
69 other2->get_id_of_kets() != basis2->get_id_of_kets()) {
70 throw std::invalid_argument(
"The other objects must be expressed using the same kets.");
73 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
75 Eigen::SparseMatrix<Scalar, Eigen::RowMajor> coefficients1 =
76 basis1->get_coefficients().adjoint() * other1->get_coefficients();
77 Eigen::SparseMatrix<Scalar, Eigen::RowMajor> coefficients2 =
78 basis2->get_coefficients().adjoint() * other2->get_coefficients();
80 oneapi::tbb::concurrent_vector<Eigen::Triplet<Scalar>> triplets;
83 oneapi::tbb::parallel_for(
84 oneapi::tbb::blocked_range<Eigen::Index>(0, coefficients1.outerSize()),
85 [&](
const auto &range) {
86 for (Eigen::Index row1 = range.begin(); row1 != range.end(); ++row1) {
88 const auto &range_row2 = this->get_index_range(row1);
92 for (auto row2 = static_cast<Eigen::Index>(range_row2.min());
93 row2 < static_cast<Eigen::Index>(range_row2.max()); ++row2) {
95 Eigen::Index row = get_ket_index_from_tuple(row1, row2);
101 for (typename Eigen::SparseMatrix<Scalar, Eigen::RowMajor>::InnerIterator it1(
102 coefficients1, row1);
105 Eigen::Index col1 = it1.col();
106 Scalar value1 = it1.value();
109 for (typename Eigen::SparseMatrix<Scalar, Eigen::RowMajor>::InnerIterator
110 it2(coefficients2, row2);
113 Eigen::Index col2 = it2.col();
114 Scalar value2 = it2.value();
115 Eigen::Index col = col1 * coefficients2.cols() + col2;
118 Scalar value = value1 * value2;
119 if (std::abs(value) > numerical_precision) {
120 triplets.emplace_back(row, col, value);
129 Eigen::SparseMatrix<Scalar, Eigen::RowMajor> matrix(this->get_number_of_kets(),
130 other1->get_number_of_states() *
131 other2->get_number_of_states());
132 matrix.setFromTriplets(triplets.begin(), triplets.end());
133 matrix.makeCompressed();
135 return matrix.adjoint() * this->get_coefficients();
138template <
typename Scalar>
141 std::shared_ptr<const KetAtom> ket2)
const {
142 return get_amplitudes(ket1, ket2).cwiseAbs2();
145template <
typename Scalar>
146Eigen::SparseMatrix<typename BasisPair<Scalar>::real_t, Eigen::RowMajor>
149 return get_amplitudes(other1, other2).cwiseAbs2();
152template <
typename Scalar>
156 throw std::invalid_argument(
"It is required to specify one operator for each atom.");
159template <
typename Scalar>
160Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
163 throw std::invalid_argument(
"It is required to specify one operator for each atom.");
166template <
typename Scalar>
167Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
170 auto initial1 = this->get_basis1();
171 auto initial2 = this->get_basis2();
172 auto final1 =
final->get_basis1();
173 auto final2 =
final->get_basis2();
175 auto matrix_elements1 =
176 initial1->get_database().get_matrix_elements(initial1, final1, type1, q1);
177 auto matrix_elements2 =
178 initial2->get_database().get_matrix_elements(initial2, final2, type2, q2);
180 matrix_elements1, matrix_elements2);
181 assert(
static_cast<size_t>(matrix_elements.rows()) == final->get_number_of_kets());
182 assert(
static_cast<size_t>(matrix_elements.cols()) == this->get_number_of_kets());
184 return final->get_coefficients().adjoint() * matrix_elements * this->get_coefficients();
187template <
typename Scalar>
188Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
197 assert(final->get_number_of_states() ==
198 final1->get_number_of_states() * final2->get_number_of_states());
199 assert(final->get_number_of_kets() ==
200 final1->get_number_of_states() * final2->get_number_of_states());
202 return this->get_matrix_elements(
final, type1, type2, q1, q2);
205template <
typename Scalar>
210 auto final = this->get_canonical_state_from_ket(ket);
211 assert(final->get_number_of_states() == 1);
213 return this->get_matrix_elements(
final, type1, type2, q1, q2).row(0);
216template <
typename Scalar>
219 std::shared_ptr<const KetAtom> ket2,
OperatorType type1,
223 auto final2 = this->get_basis2()->get_canonical_state_from_ket(ket2);
227 assert(final->get_number_of_states() == 1);
228 assert(final->get_number_of_kets() == 1);
230 return this->get_matrix_elements(
final, type1, type2, q1, q2).row(0);
Class for creating a basis of atomic kets.
BasisPairCreator< Scalar > & add(const SystemAtom< Scalar > &system_atom)
int get_ket_index_from_tuple(size_t state_index1, size_t state_index2) const
const range_t & get_index_range(size_t state_index1) const
Eigen::VectorX< Scalar > get_amplitudes(std::shared_ptr< const KetAtom > ket1, std::shared_ptr< const KetAtom > ket2) const
std::shared_ptr< const BasisAtom< Scalar > > get_basis2() const
std::unordered_map< std::vector< size_t >, size_t, utils::hash< std::vector< size_t > > > map_indices_t
typename traits::CrtpTraits< Type >::ketvec_t ketvec_t
std::shared_ptr< const BasisAtom< Scalar > > get_basis1() const
BasisPair(Private, ketvec_t &&kets, map_range_t &&map_range_of_state_index2, map_indices_t &&state_indices_to_ket_index, std::shared_ptr< const BasisAtom< Scalar > > basis1, std::shared_ptr< const BasisAtom< Scalar > > basis2)
typename traits::CrtpTraits< Type >::real_t real_t
std::unordered_map< size_t, range_t > map_range_t
std::shared_ptr< const Derived > get_canonical_state_from_ket(size_t ket_index) const
Matrix< Type, Dynamic, 1 > VectorX
Eigen::SparseMatrix< Scalar, Eigen::RowMajor > calculate_tensor_product(const std::shared_ptr< const BasisPair< Scalar > > &basis_initial, const std::shared_ptr< const BasisPair< Scalar > > &basis_final, const Eigen::SparseMatrix< Scalar, Eigen::RowMajor > &matrix1, const Eigen::SparseMatrix< Scalar, Eigen::RowMajor > &matrix2)