|
5 | 5 | * that implements a variety of quantum chemistry methods for strongly
|
6 | 6 | * correlated electrons.
|
7 | 7 | *
|
8 |
| - * Copyright (c) 2012-2024 by its authors (see COPYING, COPYING.LESSER, AUTHORS). |
| 8 | + * Copyright (c) 2012-2025 by its authors (see COPYING, COPYING.LESSER, AUTHORS). |
9 | 9 | *
|
10 | 10 | * The copyrights for code used from other parties are included in
|
11 | 11 | * the corresponding files.
|
|
39 | 39 |
|
40 | 40 | namespace forte {
|
41 | 41 |
|
| 42 | +// This is a naive implementation of the operator application that is used for testing |
42 | 43 | SparseState apply_operator_impl_naive(bool is_antihermitian, const SparseOperator& sop,
|
43 | 44 | const SparseState& state, double screen_thresh);
|
44 | 45 |
|
| 46 | +// This is the grouped implementation of the operator application. Fast, but scaling is not optimal. |
45 | 47 | SparseState apply_operator_impl_grouped(bool is_antihermitian, const SparseOperator& sop,
|
46 | 48 | const SparseState& state, double screen_thresh);
|
47 | 49 |
|
| 50 | +// The default implementation is the grouped implementation with grouping into alfa strings |
| 51 | +SparseState apply_operator_impl_grouped_string(bool is_antihermitian, const SparseOperator& sop, |
| 52 | + const SparseState& state, double screen_thresh); |
| 53 | + |
48 | 54 | SparseState apply_operator_lin(const SparseOperator& sop, const SparseState& state,
|
49 | 55 | double screen_thresh) {
|
50 |
| - return apply_operator_impl_grouped(false, sop, state, screen_thresh); |
| 56 | + return apply_operator_impl_grouped_string(false, sop, state, screen_thresh); |
51 | 57 | }
|
52 | 58 |
|
53 | 59 | SparseState apply_operator_antiherm(const SparseOperator& sop, const SparseState& state,
|
54 | 60 | double screen_thresh) {
|
55 |
| - return apply_operator_impl_grouped(true, sop, state, screen_thresh); |
| 61 | + return apply_operator_impl_grouped_string(true, sop, state, screen_thresh); |
56 | 62 | }
|
57 | 63 |
|
58 | 64 | // This is a naive implementation of the operator application that is used for testing
|
@@ -172,6 +178,87 @@ SparseState apply_operator_impl_grouped(bool is_antihermitian, const SparseOpera
|
172 | 178 | return new_terms;
|
173 | 179 | }
|
174 | 180 |
|
| 181 | +// This is a kernel that applies the operator to the state using a grouped approach |
| 182 | +// It has a lower cost complexity |
| 183 | +// It assumes that the operator is grouped by the annihilation operators and that these are prepared |
| 184 | +// in another function calling this kernel |
| 185 | +template <bool positive> |
| 186 | +void apply_operator_kernel_string(const auto& sop_groups, const auto& state_groups, |
| 187 | + const auto& screen_thresh, auto& new_terms) { |
| 188 | + Determinant new_det; |
| 189 | + Determinant sign_mask; |
| 190 | + Determinant idx; |
| 191 | + for (const auto& [sqop_ann_a, sqop_group] : sop_groups) { |
| 192 | + for (const auto& [det_a, state_group] : state_groups) { |
| 193 | + // can we annihilate the alfa string? |
| 194 | + if (det_a.fast_a_and_b_equal_b(sqop_ann_a)) { |
| 195 | + // loop over the creation operators in this group |
| 196 | + for (const auto& [sqop_ann, sqop_cre, t] : sqop_group) { |
| 197 | + for (const auto& [det, c] : state_group) { |
| 198 | + if (det.faster_can_apply_operator(sqop_cre, sqop_ann)) { |
| 199 | + if (std::abs(c * t) > screen_thresh) { |
| 200 | + compute_sign_mask(sqop_cre, sqop_ann, sign_mask, idx); |
| 201 | + const auto value = faster_apply_operator_to_det( |
| 202 | + det, new_det, sqop_cre, sqop_ann, sign_mask); |
| 203 | + if constexpr (positive) { |
| 204 | + new_terms[new_det] += value * t * c; |
| 205 | + } else { |
| 206 | + new_terms[new_det] -= value * t * c; |
| 207 | + } |
| 208 | + } |
| 209 | + } |
| 210 | + } |
| 211 | + } |
| 212 | + } |
| 213 | + } |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +// This is the grouped implementation of the operator application. It mostly prepares the |
| 218 | +// operator and state and then calls the kernel to apply the operator |
| 219 | +SparseState apply_operator_impl_grouped_string(bool is_antihermitian, const SparseOperator& sop, |
| 220 | + const SparseState& state, double screen_thresh) { |
| 221 | + if (screen_thresh < 0) { |
| 222 | + throw std::invalid_argument( |
| 223 | + "apply_operator_impl_grouped:screen_thresh must be non-negative"); |
| 224 | + } |
| 225 | + SparseState new_terms; |
| 226 | + |
| 227 | + // Group the determinants by common alfa strings |
| 228 | + std::unordered_map<String, std::vector<std::pair<Determinant, sparse_scalar_t>>, String::Hash> |
| 229 | + state_groups; |
| 230 | + for (const auto& [det, c] : state) { |
| 231 | + state_groups[det.get_alfa_bits()].emplace_back(det, c); |
| 232 | + } |
| 233 | + |
| 234 | + // Group the operators by common alfa annihilation strings |
| 235 | + std::unordered_map<String, std::vector<std::tuple<Determinant, Determinant, sparse_scalar_t>>, |
| 236 | + String::Hash> |
| 237 | + sop_groups; |
| 238 | + for (const auto& [sqop, t] : sop.elements()) { |
| 239 | + sop_groups[sqop.ann().get_alfa_bits()].emplace_back(sqop.ann(), sqop.cre(), t); |
| 240 | + } |
| 241 | + |
| 242 | + // Call the kernel to apply the operator (adding the result) |
| 243 | + apply_operator_kernel_string<true>(sop_groups, state_groups, screen_thresh, new_terms); |
| 244 | + |
| 245 | + if (not is_antihermitian) { |
| 246 | + return new_terms; |
| 247 | + } |
| 248 | + |
| 249 | + // Group the operators by common alfa creation strings |
| 250 | + // Here we swap the annihilation and creation operators for the antihermitian case |
| 251 | + sop_groups.clear(); |
| 252 | + for (const auto& [sqop, t] : sop.elements()) { |
| 253 | + sop_groups[sqop.cre().get_alfa_bits()].emplace_back(sqop.cre(), sqop.ann(), t); |
| 254 | + } |
| 255 | + |
| 256 | + // Call the kernel to apply the operator (subtracting the result) |
| 257 | + apply_operator_kernel_string<false>(sop_groups, state_groups, screen_thresh, new_terms); |
| 258 | + |
| 259 | + return new_terms; |
| 260 | +} |
| 261 | + |
175 | 262 | std::vector<sparse_scalar_t> get_projection(const SparseOperatorList& sop, const SparseState& ref,
|
176 | 263 | const SparseState& state) {
|
177 | 264 | local_timer t;
|
|
0 commit comments