TRIQS/triqs_ctint 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
lazy_det_operation.cpp
1// Copyright (c) 2017--present, The Simons Foundation
2// This file is part of TRIQS/ctint and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#include "./lazy_det_operation.hpp"
7
8namespace triqs_ctint {
9
10 // lower_bound in a vector of length n, accessed by vec(i), where vec is a lambda
11 // Complexity log.
12 // Very similar to std::lower_bound, but computes a position and takes a lambda, not iterators.
13 // Implementation adapted from cppreference.com
14 template <typename Vec, typename Value> long lower_bound(int count, Vec const &vec, Value const &value) {
15 int p = 0, first = 0;
16 while (count > 0) {
17 p = first;
18 int step = count / 2;
19 p += step;
20 if (vec(p) < value) {
21 first = ++p;
22 count -= step + 1;
23 } else
24 count = step;
25 }
26 TRIQS_ASSERT(first >= 0);
27 return first;
28 }
29
30 // Find index of first row in determinant matrix that has an element not less than c.
31 long get_c_lower_bound(det_t const *d, c_t const &c) {
32 return lower_bound(d->size(), [d](int n) { return d->get_x(n); }, c);
33 }
34
35 // Find index of first column in determinant matrix that has an element not less than cdag.
36 long get_cdag_lower_bound(det_t const *d, cdag_t const &cdag) {
37 return lower_bound(d->size(), [d](int n) { return d->get_y(n); }, cdag);
38 }
39
40 // Sort a list and return the parity of the number of swaps.
41 static double parity_sort(auto begin, auto end) {
42 std::size_t n_swaps = insertion_sort(begin, end);
43 return (n_swaps % 2 == 0) ? 1.0 : -1.0;
44 }
45
46 g_tau_scalar_t lazy_det_operation_t::one_block::execute_try_insert(det_t *d) {
47
48 if (c_lst.size() != cdag_lst.size()) TRIQS_RUNTIME_ERROR << "Trying to insert unequal number of c and c_dag operators into block!";
49
50 long const c_count = c_lst.size();
51
52 // Prefactor to account for resorting of operators
53 double prefactor = 1.0;
54
55 if (c_count == 0) {
56 // Trivial insert
57 return 1.0;
58 } else if (c_count == 1) {
59 // Perform single insertion
60 long const pos_c = get_c_lower_bound(d, c_lst[0]);
61 long const pos_cdag = get_cdag_lower_bound(d, cdag_lst[0]);
62 if ((pos_c + pos_cdag) % 2) prefactor *= -1.0;
63 return d->try_insert(pos_c, pos_cdag, c_lst[0], cdag_lst[0]) * prefactor;
64 } else {
65 // Sort, since operators have to be inserted in order.
66 // If not ordered, operators are swapped with minus sign
67 prefactor *= parity_sort(c_lst.begin(), c_lst.end());
68 prefactor *= parity_sort(cdag_lst.begin(), cdag_lst.end());
69
70 // Calculate the insertion positions
71 std::vector<long> pos_c(c_count);
72 std::vector<long> pos_cdag(c_count);
73 for (long i = 0; i < c_count; ++i) {
74 pos_c[i] = i + get_c_lower_bound(d, c_lst[i]); // Shift by i to take into account of the insertion of previous ones.
75 pos_cdag[i] = i + get_cdag_lower_bound(d, cdag_lst[i]);
76 if ((pos_c[i] + pos_cdag[i]) % 2) prefactor *= -1.0;
77 }
78
79 return d->try_insert_k(pos_c, pos_cdag, c_lst, cdag_lst) * prefactor;
80 }
81 }
82
83 g_tau_scalar_t lazy_det_operation_t::one_block::execute_try_remove(det_t *d) {
84
85 if (c_lst.size() != cdag_lst.size()) TRIQS_RUNTIME_ERROR << "Trying to remove unequal number of c and c_dag operators from block!";
86
87 long const c_count = static_cast<long>(c_lst.size());
88
89 // Prefactor to account for resorting of operators
90 double prefactor = 1.0;
91
92 if (c_count == 0) {
93 // Trivial removal
94 return 1.0;
95 } else if (c_count == 1) {
96 // Perform single removal
97 long const pos_c = get_c_lower_bound(d, c_lst[0]);
98 long const pos_cdag = get_cdag_lower_bound(d, cdag_lst[0]);
99 if ((pos_c + pos_cdag) % 2) prefactor *= -1.0;
100 return d->try_remove(pos_c, pos_cdag) * prefactor;
101 } else {
102 // Sort, since operators have to be inserted in order.
103 // If not ordered, operators are swapped with minus sign
104 prefactor *= parity_sort(c_lst.begin(), c_lst.end());
105 prefactor *= parity_sort(cdag_lst.begin(), cdag_lst.end());
106
107 // Calculate the removal positions
108 std::vector<long> pos_c(c_count);
109 std::vector<long> pos_cdag(c_count);
110 for (long i = 0; i < c_count; ++i) {
111 pos_c[i] = get_c_lower_bound(d, c_lst[i]);
112 pos_cdag[i] = get_cdag_lower_bound(d, cdag_lst[i]);
113 if ((pos_c[i] + pos_cdag[i]) % 2) prefactor *= -1.0;
114 }
115
116 // Perform higher rank removal
117 return d->try_remove_k(pos_c, pos_cdag) * prefactor;
118 }
119 }
120
121 g_tau_scalar_t lazy_det_operation_t::one_block::execute_try_change_col_row(det_t *d) {
122
123 if (c_lst.size() != cdag_lst.size()) TRIQS_RUNTIME_ERROR << "Trying to remove unequal number of c and c_dag operators from block!";
124
125 long const c_count = static_cast<long>(c_lst.size());
126
127 // Trivial flip
128 if (c_count == 0) return 1.0;
129
130 // Calculate the flip positions
131 std::vector<long> pos_c(c_count);
132 std::vector<long> pos_cdag(c_count);
133 for (int i = 0; i < c_count; ++i) {
134 pos_c[i] = get_c_lower_bound(d, c_lst[i]);
135 pos_cdag[i] = get_cdag_lower_bound(d, cdag_lst[i]);
136 }
137
138 // Perform single spinflip
139 switch (c_count) {
140 case (1):
141 c_lst[0].s = 1 - c_lst[0].s;
142 cdag_lst[0].s = 1 - cdag_lst[0].s;
143 return d->try_change_col_row(pos_c[0], pos_cdag[0], c_lst[0], cdag_lst[0]);
144 default: TRIQS_RUNTIME_ERROR << "Not implemented"; return 0; // avoid compiler warning
145 }
146 }
147
148} // namespace triqs_ctint