pairinteraction
A Rydberg Interaction Calculator
Operator.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
15
16#include <Eigen/SparseCore>
17#include <memory>
18
19namespace pairinteraction {
20template <typename Derived>
21Operator<Derived>::Operator(std::shared_ptr<const basis_t> basis) : basis(std::move(basis)) {
22 this->matrix = Eigen::SparseMatrix<scalar_t, Eigen::RowMajor>(
23 this->basis->get_number_of_states(), this->basis->get_number_of_states());
24}
25
26template <typename Derived>
28 Eigen::SparseMatrix<scalar_t, Eigen::RowMajor> tmp(this->basis->get_number_of_kets(),
29 this->basis->get_number_of_kets());
30 tmp.reserve(Eigen::VectorXi::Constant(this->basis->get_number_of_kets(), 1));
31 size_t idx = 0;
32 for (const auto &ket : this->basis->get_kets()) {
33 tmp.insert(idx, idx) = ket->get_energy();
34 ++idx;
35 }
36 tmp.makeCompressed();
37
38 this->matrix =
39 this->basis->get_coefficients().adjoint() * tmp * this->basis->get_coefficients();
40}
41
42template <typename Derived>
44 Eigen::SparseMatrix<scalar_t, Eigen::RowMajor> &&matrix) {
45 if (static_cast<size_t>(matrix.rows()) != this->basis->get_number_of_states() ||
46 static_cast<size_t>(matrix.cols()) != this->basis->get_number_of_states()) {
47 throw std::invalid_argument("The matrix has the wrong dimensions.");
48 }
49 this->matrix = std::move(matrix);
50}
51
52template <typename Derived>
53const Derived &Operator<Derived>::derived() const {
54 return static_cast<const Derived &>(*this);
57template <typename Derived>
59 return static_cast<Derived &>(*this);
61
62template <typename Derived>
63std::shared_ptr<const typename Operator<Derived>::basis_t> Operator<Derived>::get_basis() const {
64 return basis;
65}
66
67template <typename Derived>
68std::shared_ptr<const typename Operator<Derived>::basis_t> &Operator<Derived>::get_basis() {
69 return basis;
70}
71
72template <typename Derived>
73const Eigen::SparseMatrix<typename Operator<Derived>::scalar_t, Eigen::RowMajor> &
75 return matrix;
76}
78template <typename Derived>
79Eigen::SparseMatrix<typename Operator<Derived>::scalar_t, Eigen::RowMajor> &
81 return matrix;
82}
83
84template <typename Derived>
87 return basis->get_transformation();
88}
89
90template <typename Derived>
93 return basis->get_rotator(alpha, beta, gamma);
94}
95
96template <typename Derived>
97Sorting Operator<Derived>::get_sorter(const std::vector<TransformationType> &labels) const {
98 basis->perform_sorter_checks(labels);
99
100 // Split labels into three parts (one before SORT_BY_ENERGY, one with SORT_BY_ENERGY, and one
101 // after)
102 auto it = std::find(labels.begin(), labels.end(), TransformationType::SORT_BY_ENERGY);
103 std::vector<TransformationType> before_energy(labels.begin(), it);
104 bool contains_energy = (it != labels.end());
105 std::vector<TransformationType> after_energy(contains_energy ? it + 1 : labels.end(),
106 labels.end());
107
108 // Initialize transformation
109 Sorting transformation;
110 transformation.matrix.resize(matrix.rows());
111 transformation.matrix.setIdentity();
112
113 // Apply sorting for labels before SORT_BY_ENERGY
114 if (!before_energy.empty()) {
115 basis->get_sorter_without_checks(before_energy, transformation);
116 }
117
118 // Apply SORT_BY_ENERGY if present
119 if (contains_energy) {
120 std::vector<real_t> energies_of_states;
121 energies_of_states.reserve(matrix.rows());
122 for (int i = 0; i < matrix.rows(); ++i) {
123 energies_of_states.push_back(std::real(matrix.coeff(i, i)));
124 }
125
126 std::stable_sort(
127 transformation.matrix.indices().data(),
128 transformation.matrix.indices().data() + transformation.matrix.indices().size(),
129 [&](int i, int j) { return energies_of_states[i] < energies_of_states[j]; });
130
132 }
133
134 // Apply sorting for labels after SORT_BY_ENERGY
135 if (!after_energy.empty()) {
136 basis->get_sorter_without_checks(after_energy, transformation);
137 }
138
139 // Check if all labels have been used for sorting
140 if (labels != transformation.transformation_type) {
141 throw std::invalid_argument("The states could not be sorted by all the requested labels.");
142 }
143
144 return transformation;
145}
146
147template <typename Derived>
148std::vector<IndicesOfBlock>
149Operator<Derived>::get_indices_of_blocks(const std::vector<TransformationType> &labels) const {
150 basis->perform_sorter_checks(labels);
151
152 std::set<TransformationType> unique_labels(labels.begin(), labels.end());
153 basis->perform_blocks_checks(unique_labels);
154
155 // Split labels into two parts (one with SORT_BY_ENERGY and one without)
156 auto it = unique_labels.find(TransformationType::SORT_BY_ENERGY);
157 bool contains_energy = (it != unique_labels.end());
158 if (contains_energy) {
159 unique_labels.erase(it);
160 }
161
162 // Initialize blocks
163 IndicesOfBlocksCreator blocks_creator({0, static_cast<size_t>(matrix.rows())});
164
165 // Handle all labels except SORT_BY_ENERGY
166 if (!unique_labels.empty()) {
167 basis->get_indices_of_blocks_without_checks(unique_labels, blocks_creator);
168 }
169
170 // Handle SORT_BY_ENERGY if present
171 if (contains_energy) {
172 scalar_t last_energy = std::real(matrix.coeff(0, 0));
173 for (int i = 0; i < matrix.rows(); ++i) {
174 if (std::real(matrix.coeff(i, i)) != last_energy) {
175 blocks_creator.add(i);
176 last_energy = std::real(matrix.coeff(i, i));
177 }
178 }
179 }
180
181 return blocks_creator.create();
182}
183
184template <typename Derived>
186 const Transformation<typename Operator<Derived>::scalar_t> &transformation) const {
187 auto transformed = derived();
188 if (matrix.cols() == 0) {
189 return transformed;
190 }
191 transformed.matrix = transformation.matrix.adjoint() * matrix * transformation.matrix;
192 transformed.basis = basis->transformed(transformation);
193 return transformed;
194}
195
196template <typename Derived>
197Derived Operator<Derived>::transformed(const Sorting &transformation) const {
198 auto transformed = derived();
199 if (matrix.cols() == 0) {
200 return transformed;
201 }
202 transformed.matrix = matrix.twistedBy(transformation.matrix.inverse());
203 transformed.basis = basis->transformed(transformation);
204 return transformed;
205}
206
207// Overloaded operators
208template <typename Derived>
209Derived operator*(const typename Operator<Derived>::scalar_t &lhs, const Operator<Derived> &rhs) {
210 Derived result = rhs.derived();
211 result.matrix *= lhs;
212 return result;
213}
214
215template <typename Derived>
216Derived operator*(const Operator<Derived> &lhs, const typename Operator<Derived>::scalar_t &rhs) {
217 Derived result = lhs.derived();
218 result.matrix *= rhs;
219 return result;
220}
221
222template <typename Derived>
223Derived operator/(const Operator<Derived> &lhs, const typename Operator<Derived>::scalar_t &rhs) {
224 Derived result = lhs.derived();
225 result.matrix /= rhs;
226 return result;
227}
228
229template <typename Derived>
231 if (lhs.basis != rhs.basis) {
232 throw std::invalid_argument("The basis of the operators is not the same.");
233 }
234 lhs.matrix += rhs.matrix;
235 return lhs.derived_mutable();
236}
237
238template <typename Derived>
240 if (lhs.basis != rhs.basis) {
241 throw std::invalid_argument("The basis of the operators is not the same.");
242 }
243 lhs.matrix -= rhs.matrix;
244 return lhs.derived_mutable();
245}
246
247template <typename Derived>
248Derived operator+(const Operator<Derived> &lhs, const Operator<Derived> &rhs) {
249 if (lhs.basis != rhs.basis) {
250 throw std::invalid_argument("The basis of the operators is not the same.");
251 }
252 Derived result = lhs.derived();
253 result.matrix += rhs.matrix;
254 return result;
255}
256
257template <typename Derived>
258Derived operator-(const Operator<Derived> &lhs, const Operator<Derived> &rhs) {
259 if (lhs.basis != rhs.basis) {
260 throw std::invalid_argument("The basis of the operators is not the same.");
261 }
262 Derived result = lhs.derived();
263 result.matrix -= rhs.matrix;
264 return result;
265}
266
267// Explicit instantiations
268// NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
269#define INSTANTIATE_OPERATOR_HELPER(SCALAR, TYPE) \
270 template class Operator<TYPE<SCALAR>>; \
271 template TYPE<SCALAR> operator*(const SCALAR &lhs, const Operator<TYPE<SCALAR>> &rhs); \
272 template TYPE<SCALAR> operator*(const Operator<TYPE<SCALAR>> &lhs, const SCALAR &rhs); \
273 template TYPE<SCALAR> operator/(const Operator<TYPE<SCALAR>> &lhs, const SCALAR &rhs); \
274 template TYPE<SCALAR> &operator+=(Operator<TYPE<SCALAR>> &lhs, \
275 const Operator<TYPE<SCALAR>> &rhs); \
276 template TYPE<SCALAR> &operator-=(Operator<TYPE<SCALAR>> &lhs, \
277 const Operator<TYPE<SCALAR>> &rhs); \
278 template TYPE<SCALAR> operator+(const Operator<TYPE<SCALAR>> &lhs, \
279 const Operator<TYPE<SCALAR>> &rhs); \
280 template TYPE<SCALAR> operator-(const Operator<TYPE<SCALAR>> &lhs, \
281 const Operator<TYPE<SCALAR>> &rhs);
282#define INSTANTIATE_OPERATOR(SCALAR) \
283 INSTANTIATE_OPERATOR_HELPER(SCALAR, OperatorAtom) \
284 INSTANTIATE_OPERATOR_HELPER(SCALAR, OperatorPair)
285// NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
286
288INSTANTIATE_OPERATOR(std::complex<double>)
289
290#undef INSTANTIATE_OPERATOR_HELPER
291#undef INSTANTIATE_OPERATOR
292
293} // namespace pairinteraction
#define INSTANTIATE_OPERATOR(SCALAR)
Definition: Operator.cpp:282
const Transformation< scalar_t > & get_transformation() const override
Definition: Operator.cpp:86
typename traits::CrtpTraits< Derived >::real_t real_t
Definition: Operator.hpp:45
void initialize_as_energy_operator()
Definition: Operator.cpp:27
std::shared_ptr< const basis_t > basis
Definition: Operator.hpp:86
Operator(std::shared_ptr< const basis_t > basis)
Definition: Operator.cpp:21
std::shared_ptr< const basis_t > get_basis() const
Definition: Operator.cpp:63
Eigen::SparseMatrix< scalar_t, Eigen::RowMajor > matrix
Definition: Operator.hpp:87
typename traits::CrtpTraits< Derived >::scalar_t scalar_t
Definition: Operator.hpp:44
Derived transformed(const Transformation< scalar_t > &transformation) const
const Eigen::SparseMatrix< scalar_t, Eigen::RowMajor > & get_matrix() const
Definition: Operator.cpp:74
std::vector< IndicesOfBlock > get_indices_of_blocks(const std::vector< TransformationType > &labels) const override
Definition: Operator.cpp:149
Transformation< scalar_t > get_rotator(real_t alpha, real_t beta, real_t gamma) const override
Definition: Operator.cpp:92
void initialize_from_matrix(Eigen::SparseMatrix< scalar_t, Eigen::RowMajor > &&matrix)
Definition: Operator.cpp:43
Sorting get_sorter(const std::vector< TransformationType > &labels) const override
Definition: Operator.cpp:97
Derived operator+(const Operator< Derived > &lhs, const Operator< Derived > &rhs)
Definition: Operator.cpp:248
Derived & operator-=(Operator< Derived > &lhs, const Operator< Derived > &rhs)
Definition: Operator.cpp:239
Derived operator*(const typename Operator< Derived >::scalar_t &lhs, const Operator< Derived > &rhs)
Definition: Operator.cpp:209
Derived & operator+=(Operator< Derived > &lhs, const Operator< Derived > &rhs)
Definition: Operator.cpp:230
Derived operator/(const Operator< Derived > &lhs, const typename Operator< Derived >::scalar_t &rhs)
Definition: Operator.cpp:223
Derived operator-(const Operator< Derived > &lhs, const Operator< Derived > &rhs)
Definition: Operator.cpp:258
Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic > matrix
std::vector< TransformationType > transformation_type