TRIQS/triqs_ctseg 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
double_insert_segment.cpp
1// Copyright (c) 2025--present, The Simons Foundation
2// Copyright (c) 2025--present, Max Planck Institute for Polymer Research, Mainz, Germany
3// This file is part of TRIQS/ctseg and is licensed under the terms of GPLv3 or later.
4// SPDX-License-Identifier: GPL-3.0-or-later
5// See LICENSE in the root of this distribution for details.
6
7#include "double_insert_segment.hpp"
8#include "../logs.hpp"
9#include <cmath>
10
11namespace triqs_ctseg::moves {
12
13 double double_insert_segment::attempt() {
14
15 LOG("\n =================== ATTEMPT DOUBLE INSERT ================ \n");
16
17 // ------------ Choice of segments --------------
18 // Select insertion colors
19 int color_0 = rng(config.n_color());
20 int color_1 = rng(config.n_color() - 1);
21 if (color_1 >= color_0) ++color_1; // little trick to select another color
22 colors.assign({color_0, color_1});
23 LOG("Inserting at color ({}, {})", color_0, color_1);
24
25 // For each color, perform a single insert
26 for (auto const &[i, color] : itertools::enumerate(colors)) {
27 auto &sl = config.seglists[color];
28
29 // Select insertion window [tau_left,tau_right]
30 tau_t tau_left = tau_t::beta(), tau_right = tau_t::zero();
31
32 // If sl.empty, no segment, we have the window.
33 // Otherwise, we pick up one segment at random
34 if (not sl.empty()) {
35 if (is_full_line(sl.back())) {
36 LOG("Full line, cannot insert. (color {})", color);
37 return 0;
38 }
39 // Randomly choose one existing segment
40 long seg_idx = rng(sl.size());
41 tau_left = sl[seg_idx].tau_cdag; // tau_left is cdag of this segment
42 tau_right = sl[modulo(seg_idx + 1, sl.size())].tau_c; // tau_right is c of next segment, possibly cyclic
43 }
44
45 // We now have the insertion window [tau_left,tau_right]
46 // Warning : it can be cyclic !
47 LOG("Insertion window is tau_left = {}, tau_right = {} (color {})", tau_left, tau_right, color);
48 window_length[i] = tau_left - tau_right;
49
50 // Choose two random times in insertion window
51 auto dt1 = tau_t::random(rng, window_length[i]);
52 auto dt2 = tau_t::random(rng, window_length[i]);
53 if (dt1 == dt2) {
54 LOG("Insert_segment: generated equal times. Rejecting (color {})", color);
55 return 0;
56 }
57 // We ensure that dt1 < dt2, unless inserting in empty line because :
58 // 1- in non empty line, we insert a segment in a void so a [c cdag]
59 // 2- in an empty line, we can insert [c cdag] or [cdag c]
60 // BEWARE in the reverse move.
61 if (dt1 > dt2 and not sl.empty()) std::swap(dt1, dt2); // if inserting into an empty line, two ways to insert
62
63 // Here is the segment we propose to insert
64 prop_seg[i] = segment_t{tau_left - dt1, tau_left - dt2};
65 LOG("Inserting segment with c at {}, cdag at {} (color {})", prop_seg[i].tau_c, prop_seg[i].tau_cdag, color);
66 } // color
67
68 // ------------ Trace ratio -------------
69 double ln_trace_ratio = 0.0;
70 for (auto const &[i, color] : itertools::enumerate(colors)) {
71 ln_trace_ratio += wdata.mu(color) * prop_seg[i].length(); // chemical potential
72 // Overlaps
73 for (auto c : range(config.n_color())) {
74 if (c != color) ln_trace_ratio += -wdata.U(color, c) * overlap(config.seglists[c], prop_seg[i]);
75 if (wdata.has_Dt)
76 ln_trace_ratio += K_overlap(config.seglists[c], prop_seg[i].tau_c, prop_seg[i].tau_cdag, wdata.K, color, c);
77 }
78 if (wdata.has_Dt)
79 ln_trace_ratio += -real(wdata.K(double(prop_seg[i].length()))(color, color)); // Correct double counting
80 } // color
81
82 // Overlap between the inserted segments
83 ln_trace_ratio += -wdata.U(color_0, color_1) * overlap(prop_seg[1], prop_seg[0]);
84 if (wdata.has_Dt) {
85 std::vector<segment_t> seglist_temp = {prop_seg[1]};
86 ln_trace_ratio += K_overlap(seglist_temp, prop_seg[0].tau_c, prop_seg[0].tau_cdag, wdata.K, color_0, color_1);
87 }
88
89 double trace_ratio = std::exp(ln_trace_ratio);
90
91 // ------------ Det ratio ---------------
92 // insert tau_cdag as a line (first index) and tau_c as a column (second index).
93 auto &bl_0 = wdata.block_number[color_0];
94 auto &bl_1 = wdata.block_number[color_1];
95 auto &bl_idx_0 = wdata.index_in_block[color_0];
96 auto &bl_idx_1 = wdata.index_in_block[color_1];
97 is_same_block = bl_0 == bl_1;
98 double det_ratio;
99 if (is_same_block) { // insert two rows and columns on the same block
100 auto &D = wdata.dets[bl_0];
101 if (wdata.offdiag_Delta) {
102 if (cdag_in_det(prop_seg[0].tau_cdag, D) or c_in_det(prop_seg[0].tau_c, D) or
103 cdag_in_det(prop_seg[1].tau_cdag, D) or c_in_det(prop_seg[1].tau_c, D)) {
104 LOG("One of the proposed times already exists in another line of the same block. Rejecting.");
105 return 0;
106 }
107 if (prop_seg[0].tau_cdag == prop_seg[1].tau_cdag or prop_seg[0].tau_c == prop_seg[1].tau_c) {
108 LOG("Two identical times in inserted segments. Rejecting.");
109 return 0;
110 }
111 }
112 // Find the ordering of the two tau_cdag and the two tau_c to be inserted. They must be inserted in the correct (inceasing) order.
113 auto tau_cdag_lower = prop_seg[0].tau_cdag > prop_seg[1].tau_cdag ? prop_seg[1].tau_cdag : prop_seg[0].tau_cdag;
114 auto tau_cdag_upper = prop_seg[0].tau_cdag < prop_seg[1].tau_cdag ? prop_seg[1].tau_cdag : prop_seg[0].tau_cdag;
115 auto tau_c_lower = prop_seg[0].tau_c > prop_seg[1].tau_c ? prop_seg[1].tau_c : prop_seg[0].tau_c;
116 auto tau_c_upper = prop_seg[0].tau_c < prop_seg[1].tau_c ? prop_seg[1].tau_c : prop_seg[0].tau_c;
117 // Determine orbital indices (inside the block) corresponding to lower and upper tau values
118 auto idx_cdag_lower = prop_seg[0].tau_cdag > prop_seg[1].tau_cdag ? bl_idx_1 : bl_idx_0;
119 auto idx_cdag_upper = prop_seg[0].tau_cdag < prop_seg[1].tau_cdag ? bl_idx_1 : bl_idx_0;
120 auto idx_c_lower = prop_seg[0].tau_c > prop_seg[1].tau_c ? bl_idx_1 : bl_idx_0;
121 auto idx_c_upper = prop_seg[0].tau_c < prop_seg[1].tau_c ? bl_idx_1 : bl_idx_0;
122 det_ratio = D.try_insert2(det_lower_bound_x(D, tau_cdag_lower), det_lower_bound_x(D, tau_cdag_upper) + 1, // +1 to avoid duplicates
123 det_lower_bound_y(D, tau_c_lower) , det_lower_bound_y(D, tau_c_upper) + 1, // +1 to avoid duplicates
124 {tau_cdag_lower, idx_cdag_lower} , {tau_cdag_upper, idx_cdag_upper} ,
125 {tau_c_lower , idx_c_lower} , {tau_c_upper , idx_c_upper} );
126 }
127 else { // insert on different blocks
128 auto &D_0 = wdata.dets[bl_0];
129 auto &D_1 = wdata.dets[bl_1];
130 if (wdata.offdiag_Delta) {
131 if (cdag_in_det(prop_seg[0].tau_cdag, D_0) or c_in_det(prop_seg[0].tau_c, D_0) or
132 cdag_in_det(prop_seg[1].tau_cdag, D_1) or c_in_det(prop_seg[1].tau_c, D_1)) {
133 LOG("One of the proposed times already exists in another line of the same block. Rejecting.");
134 return 0;
135 }
136 }
137 auto det_ratio_0 = D_0.try_insert(det_lower_bound_x(D_0, prop_seg[0].tau_cdag),
138 det_lower_bound_y(D_0, prop_seg[0].tau_c),
139 {prop_seg[0].tau_cdag, bl_idx_0},
140 {prop_seg[0].tau_c, bl_idx_0});
141 auto det_ratio_1 = D_1.try_insert(det_lower_bound_x(D_1, prop_seg[1].tau_cdag),
142 det_lower_bound_y(D_1, prop_seg[1].tau_c),
143 {prop_seg[1].tau_cdag, bl_idx_1},
144 {prop_seg[1].tau_c, bl_idx_1});
145 det_ratio = det_ratio_0 * det_ratio_1;
146 }
147
148 // ------------ Proposition ratio ------------
149 double prop_ratio = 1.0;
150 for (auto const &[i, color] : itertools::enumerate(colors)) {
151 auto &sl = config.seglists[color];
152 double current_number_intervals = std::max(long(1), long(sl.size()));
153 double future_number_segments = sl.size() + 1;
154 // T direct = 1 / current_number_intervals * 1/window_length^2 *
155 // * (2 iif not empty as the proba to get the dt1, dt2 coupled is x 2)
156 // T inverse = 1 / future_number_segments
157 prop_ratio *= (current_number_intervals * window_length[i] * window_length[i] / (sl.empty() ? 1 : 2)) / future_number_segments;
158 // Account for absence of time swapping when inserting into empty line.
159 } // color
160
161 LOG("trace_ratio = {}, prop_ratio = {}, det_ratio = {}", trace_ratio, prop_ratio, det_ratio);
162
163 double prod = trace_ratio * det_ratio * prop_ratio;
164 det_sign = (det_ratio > 0) ? 1.0 : -1.0;
165
166 return (std::isfinite(prod) ? prod : det_sign);
167 }
168
169 //--------------------------------------------------
170
171 double double_insert_segment::accept() {
172
173 LOG("\n - - - - - ====> ACCEPT - - - - - - - - - - -\n");
174
175 double initial_sign = trace_sign(wdata);
176 LOG("Initial sign is {}. Initial configuration: {}", initial_sign, config);
177
178 // Insert the times into the det
179 if (is_same_block)
180 wdata.dets[wdata.block_number[colors[0]]].complete_operation();
181 else
182 for (auto const &color : colors)
183 wdata.dets[wdata.block_number[color]].complete_operation();
184
185 // Insert the segment in an ordered list
186 for (auto const &[i, color] : itertools::enumerate(colors)) {
187 auto &sl = config.seglists[color];
188 sl.insert(std::upper_bound(sl.begin(), sl.end(), prop_seg[i]), prop_seg[i]);
189 } // color
190
191 // Check invariant
192 if constexpr (print_logs or ctseg_debug) check_invariant(config, wdata);
193
194 double final_sign = trace_sign(wdata);
195 double sign_ratio = final_sign / initial_sign;
196 LOG("Final sign is {}", final_sign);
197
198 if (sign_ratio * det_sign == -1.0) wdata.minus_sign = true;
199
200 LOG("Configuration is {}", config);
201
202 return sign_ratio;
203 }
204
205 //--------------------------------------------------
206 void double_insert_segment::reject() {
207 LOG("\n - - - - - ====> REJECT - - - - - - - - - - -\n");
208 if (is_same_block)
209 wdata.dets[wdata.block_number[colors[0]]].reject_last_try();
210 else
211 for (auto const &color : colors)
212 wdata.dets[wdata.block_number[color]].reject_last_try();
213 }
214
215} // namespace triqs_ctseg::moves
static tau_t beta()
tau_t at tau = beta
Definition tau_t.hpp:67
static tau_t zero()
$\tau = 0$
Definition tau_t.hpp:70