pairinteraction
A Rydberg Interaction Calculator
BasisPair.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2024 Pairinteraction Developers
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
5
14
15#include <memory>
16#include <oneapi/tbb.h>
17#include <vector>
18
19namespace pairinteraction {
20template <typename Scalar>
21BasisPair<Scalar>::BasisPair(Private /*unused*/, ketvec_t &&kets,
22 map_range_t &&map_range_of_state_index2,
23 map_indices_t &&state_indices_to_ket_index,
24 std::shared_ptr<const BasisAtom<Scalar>> basis1,
25 std::shared_ptr<const BasisAtom<Scalar>> basis2)
26 : Basis<BasisPair<Scalar>>(std::move(kets)),
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)) {}
30
31template <typename Scalar>
32const typename BasisPair<Scalar>::range_t &
33BasisPair<Scalar>::get_index_range(size_t state_index1) const {
34 return map_range_of_state_index2.at(state_index1);
35}
36
37template <typename Scalar>
38std::shared_ptr<const BasisAtom<Scalar>> BasisPair<Scalar>::get_basis1() const {
39 return basis1;
40}
41
42template <typename Scalar>
43std::shared_ptr<const BasisAtom<Scalar>> BasisPair<Scalar>::get_basis2() const {
44 return basis2;
45}
46
47template <typename Scalar>
48int BasisPair<Scalar>::get_ket_index_from_tuple(size_t state_index1, size_t state_index2) const {
49 if (state_indices_to_ket_index.count({state_index1, state_index2}) == 0) {
50 return -1;
51 }
52 return state_indices_to_ket_index.at({state_index1, state_index2});
53}
54
55template <typename Scalar>
57BasisPair<Scalar>::get_amplitudes(std::shared_ptr<const KetAtom> ket1,
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))
61 .transpose();
62}
63
64template <typename Scalar>
65Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
67 std::shared_ptr<const BasisAtom<Scalar>> other2) const {
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.");
71 }
72
73 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
74
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();
79
80 oneapi::tbb::concurrent_vector<Eigen::Triplet<Scalar>> triplets;
81
82 // Loop over the rows of the first coefficient matrix
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) {
87
88 const auto &range_row2 = this->get_index_range(row1);
89
90 // Loop over the rows of the second coefficient matrix that are energetically
91 // allowed
92 for (auto row2 = static_cast<Eigen::Index>(range_row2.min());
93 row2 < static_cast<Eigen::Index>(range_row2.max()); ++row2) {
94
95 Eigen::Index row = get_ket_index_from_tuple(row1, row2);
96 if (row < 0) {
97 continue;
98 }
99
100 // Loop over the non-zero column elements of the first coefficient matrix
101 for (typename Eigen::SparseMatrix<Scalar, Eigen::RowMajor>::InnerIterator it1(
102 coefficients1, row1);
103 it1; ++it1) {
104
105 Eigen::Index col1 = it1.col();
106 Scalar value1 = it1.value();
107
108 // Loop over the non-zero column elements of the second coefficient matrix
109 for (typename Eigen::SparseMatrix<Scalar, Eigen::RowMajor>::InnerIterator
110 it2(coefficients2, row2);
111 it2; ++it2) {
112
113 Eigen::Index col2 = it2.col();
114 Scalar value2 = it2.value();
115 Eigen::Index col = col1 * coefficients2.cols() + col2;
116
117 // Store the entry
118 Scalar value = value1 * value2;
119 if (std::abs(value) > numerical_precision) {
120 triplets.emplace_back(row, col, value);
121 }
122 }
123 }
124 }
125 }
126 });
127
128 // Construct the combined matrix from the triplets
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();
134
135 return matrix.adjoint() * this->get_coefficients();
136}
137
138template <typename Scalar>
140BasisPair<Scalar>::get_overlaps(std::shared_ptr<const KetAtom> ket1,
141 std::shared_ptr<const KetAtom> ket2) const {
142 return get_amplitudes(ket1, ket2).cwiseAbs2();
143}
144
145template <typename Scalar>
146Eigen::SparseMatrix<typename BasisPair<Scalar>::real_t, Eigen::RowMajor>
148 std::shared_ptr<const BasisAtom<Scalar>> other2) const {
149 return get_amplitudes(other1, other2).cwiseAbs2();
150}
151
152template <typename Scalar>
154 OperatorType /*type*/,
155 int /*q*/) const {
156 throw std::invalid_argument("It is required to specify one operator for each atom.");
157}
158
159template <typename Scalar>
160Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
161BasisPair<Scalar>::get_matrix_elements(std::shared_ptr<const Type> /*final*/, OperatorType /*type*/,
162 int /*q*/) const {
163 throw std::invalid_argument("It is required to specify one operator for each atom.");
164}
165
166template <typename Scalar>
167Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
168BasisPair<Scalar>::get_matrix_elements(std::shared_ptr<const Type> final, OperatorType type1,
169 OperatorType type2, int q1, int q2) const {
170 auto initial1 = this->get_basis1();
171 auto initial2 = this->get_basis2();
172 auto final1 = final->get_basis1();
173 auto final2 = final->get_basis2();
174
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);
179 auto matrix_elements = utils::calculate_tensor_product(this->shared_from_this(), final,
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());
183
184 return final->get_coefficients().adjoint() * matrix_elements * this->get_coefficients();
185}
186
187template <typename Scalar>
188Eigen::SparseMatrix<Scalar, Eigen::RowMajor>
190 std::shared_ptr<const BasisAtom<Scalar>> final2,
191 OperatorType type1, OperatorType type2, int q1,
192 int q2) const {
193 // Construct a pair basis with the two single-atom bases
194 auto system1 = SystemAtom<Scalar>(final1);
195 auto system2 = SystemAtom<Scalar>(final2);
196 auto final = BasisPairCreator<Scalar>().add(system1).add(system2).create();
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());
201
202 return this->get_matrix_elements(final, type1, type2, q1, q2);
203}
204
205template <typename Scalar>
207BasisPair<Scalar>::get_matrix_elements(std::shared_ptr<const ket_t> ket, OperatorType type1,
208 OperatorType type2, int q1, int q2) const {
209 // Construct a pair basis containing only the pair ket
210 auto final = this->get_canonical_state_from_ket(ket);
211 assert(final->get_number_of_states() == 1);
212
213 return this->get_matrix_elements(final, type1, type2, q1, q2).row(0);
214}
215
216template <typename Scalar>
218BasisPair<Scalar>::get_matrix_elements(std::shared_ptr<const KetAtom> ket1,
219 std::shared_ptr<const KetAtom> ket2, OperatorType type1,
220 OperatorType type2, int q1, int q2) const {
221 // Construct a pair basis with the two single-atom kets
222 auto final1 = this->get_basis1()->get_canonical_state_from_ket(ket1);
223 auto final2 = this->get_basis2()->get_canonical_state_from_ket(ket2);
224 auto system1 = SystemAtom<Scalar>(final1);
225 auto system2 = SystemAtom<Scalar>(final2);
226 auto final = BasisPairCreator<Scalar>().add(system1).add(system2).create();
227 assert(final->get_number_of_states() == 1);
228 assert(final->get_number_of_kets() == 1);
229
230 return this->get_matrix_elements(final, type1, type2, q1, q2).row(0);
231}
232
233// Explicit instantiations
234template class BasisPair<double>;
235template class BasisPair<std::complex<double>>;
236} // namespace pairinteraction
Class for creating a basis of atomic kets.
Definition: BasisAtom.hpp:40
BasisPairCreator< Scalar > & add(const SystemAtom< Scalar > &system_atom)
int get_ket_index_from_tuple(size_t state_index1, size_t state_index2) const
Definition: BasisPair.cpp:48
const range_t & get_index_range(size_t state_index1) const
Definition: BasisPair.cpp:33
Eigen::VectorX< Scalar > get_amplitudes(std::shared_ptr< const KetAtom > ket1, std::shared_ptr< const KetAtom > ket2) const
Definition: BasisPair.cpp:57
std::shared_ptr< const BasisAtom< Scalar > > get_basis2() const
Definition: BasisPair.cpp:43
std::unordered_map< std::vector< size_t >, size_t, utils::hash< std::vector< size_t > > > map_indices_t
Definition: BasisPair.hpp:60
typename traits::CrtpTraits< Type >::ketvec_t ketvec_t
Definition: BasisPair.hpp:55
std::shared_ptr< const BasisAtom< Scalar > > get_basis1() const
Definition: BasisPair.cpp:38
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)
Definition: BasisPair.cpp:21
typename traits::CrtpTraits< Type >::real_t real_t
Definition: BasisPair.hpp:53
std::unordered_map< size_t, range_t > map_range_t
Definition: BasisPair.hpp:58
Base class for a basis.
Definition: Basis.hpp:41
std::shared_ptr< const Derived > get_canonical_state_from_ket(size_t ket_index) const
Definition: Basis.cpp:296
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)
Definition: tensor.cpp:20