TRIQS/triqs_ctseg 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
split_spin_segment.cpp
1// Copyright (c) 2022--present, The Simons Foundation
2// Copyright (c) 2022--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 "split_spin_segment.hpp"
8#include "../logs.hpp"
9#include <cmath>
10#include <tuple>
11
12namespace triqs_ctseg::moves {
13
14 double split_spin_segment::attempt() {
15
16 LOG("\n =================== ATTEMPT SPLIT SPIN ================ \n");
17
18 // ------------ Choose a spin line --------------
19
20 auto &jl = config.Jperp_list;
21
22 if (jl.empty()) {
23 LOG("No bosonic lines!");
24 return 0;
25 }
26
27 line_idx = rng(jl.size());
28 auto &line = jl[line_idx];
29 LOG("Splitting S_plus at {}, S_minus at {}", line.tau_Splus, line.tau_Sminus);
30
31 ln_trace_ratio = 0;
32 prop_ratio = jl.size();
33
34 // ----------- Propose move in each color ----------
35
36 std::tie(idx_c_up, idx_cdag_dn, tau_up) = propose(0); // spin up
37 std::tie(idx_c_dn, idx_cdag_up, tau_dn) = propose(1); // spin down
38
39 // ----------- Trace ratio ----------
40 // Correct for the overlap between the two modified segments
41 auto &sl_up = config.seglists[0];
42 auto &sl_dn = config.seglists[1];
43 auto old_seg_up = sl_up[idx_c_up];
44 auto old_seg_dn = sl_dn[idx_c_dn];
45 auto new_seg_up = segment_t{tau_up, old_seg_up.tau_cdag};
46 auto new_seg_dn = segment_t{tau_dn, old_seg_dn.tau_cdag};
47
48 ln_trace_ratio += -wdata.U(0, 1)
49 * (overlap(new_seg_up, new_seg_dn) + overlap(old_seg_up, old_seg_dn) - //
50 overlap(new_seg_up, old_seg_dn) - overlap(new_seg_dn, old_seg_up));
51
52 // Correct for the dynamical interaction between the two operators that have been moved
53 if (wdata.has_Dt) {
54 ln_trace_ratio -= real(wdata.K(double(tau_up - old_seg_dn.tau_c))(0, 1));
55 ln_trace_ratio -= real(wdata.K(double(tau_dn - old_seg_up.tau_c))(0, 1));
56 ln_trace_ratio += real(wdata.K(double(tau_dn - tau_up))(0, 1));
57 ln_trace_ratio += real(wdata.K(double(old_seg_up.tau_c - old_seg_dn.tau_c))(0, 1));
58 }
59
60 double trace_ratio = std::exp(ln_trace_ratio);
61 trace_ratio /= -real(wdata.Jperp(double(line.tau_Splus - line.tau_Sminus))(0, 0)) / 2;
62
63 // ----------- Det ratio -----------
64 double det_ratio = 1;
65
66 // Spin up
67 auto &D_up = wdata.dets[0];
68 det_ratio *= D_up.try_insert(det_lower_bound_x(D_up, sl_up[idx_cdag_up].tau_cdag), //
69 det_lower_bound_y(D_up, tau_up), //
70 {sl_up[idx_cdag_up].tau_cdag, 0}, {tau_up, 0});
71
72 // Spin down
73 auto &D_dn = wdata.dets[1];
74 det_ratio *=
75 D_dn.try_insert(det_lower_bound_x(D_dn, sl_dn[idx_cdag_dn].tau_cdag), det_lower_bound_y(D_dn, tau_dn), //
76 {sl_dn[idx_cdag_dn].tau_cdag, 0}, {tau_dn, 0});
77
78 LOG("trace_ratio = {}, prop_ratio = {}, det_ratio = {}", trace_ratio, prop_ratio, det_ratio);
79
80 double prod = trace_ratio * det_ratio * prop_ratio;
81 det_sign = (det_ratio > 0) ? 1.0 : -1.0;
82
83 return (std::isfinite(prod) ? prod : det_sign);
84 }
85
86 //--------------------------------------------------
87
88 double split_spin_segment::accept() {
89
90 LOG("\n - - - - - ====> ACCEPT - - - - - - - - - - -\n");
91
92 double initial_sign = trace_sign(wdata);
93 LOG("Initial sign is {}. Initial configuration: {}", initial_sign, config);
94
95 // Update the dets
96 wdata.dets[0].complete_operation();
97 wdata.dets[1].complete_operation();
98
99 // Update the segments
100 auto &sl_up = config.seglists[0];
101 auto &sl_dn = config.seglists[1];
102
103 sl_up[idx_c_up].tau_c = tau_up;
104 sl_dn[idx_c_dn].tau_c = tau_dn;
105
106 // Update spin tags
107 sl_up[idx_c_up].J_c = false;
108 sl_up[idx_cdag_up].J_cdag = false;
109 sl_dn[idx_c_dn].J_c = false;
110 sl_dn[idx_cdag_dn].J_cdag = false;
111
112 fix_ordering_first_last(sl_up);
113 fix_ordering_first_last(sl_dn);
114
115 // Remove Jperp line
116 auto &jl = config.Jperp_list;
117 jl.erase(begin(jl) + line_idx);
118
119 // Compute sign
120 double final_sign = trace_sign(wdata);
121 double sign_ratio = final_sign / initial_sign;
122 LOG("Final sign is {}", final_sign);
123
124 // Check invariant
125 if constexpr (print_logs or ctseg_debug) check_invariant(config, wdata);
126
127 if (sign_ratio * det_sign == -1.0) wdata.minus_sign = true;
128
129 LOG("Configuration is {}", config);
130 return sign_ratio;
131 }
132
133 //--------------------------------------------------
134
135 void split_spin_segment::reject() {
136
137 LOG("\n - - - - - ====> REJECT - - - - - - - - - - -\n");
138 wdata.dets[0].reject_last_try();
139 wdata.dets[1].reject_last_try();
140 }
141
142 //--------------------------------------------------
143
144 std::tuple<long, long, tau_t> split_spin_segment::propose(int color) {
145
146 auto &line = config.Jperp_list[line_idx];
147 int other_color = 1 - color;
148 auto &sl = config.seglists[color];
149 auto &dsl = config.seglists[other_color];
150
151 // --------- Find the c connected to the chosen spin line ----------
152
153 // In spin up color, the c connected to the J line is a at tau_Sminus
154 // In spin down color, the c connected to the J line is a at tau_Splus
155 long idx_c = lower_bound(sl, (color == 0 ? line.tau_Sminus : line.tau_Splus)) - sl.cbegin();
156 auto tau_c = sl[idx_c].tau_c;
157
158 // ---------- Find the cdag in opposite color -----------
159
160 // FIXME : ok, the vector is always of size 1 ...
161 auto idx_cdag = cdag_in_window(tau_c + tau_t::epsilon(), tau_c - tau_t::epsilon(), dsl).back();
162
163 // -------- Propose new position for the c ---------
164
165 // Determine window in which the c will be moved
166 auto idx_left = (idx_c == 0) ? sl.size() - 1 : idx_c - 1;
167 auto wtau_left = sl[idx_left].tau_cdag;
168 auto wtau_right = sl[idx_c].tau_cdag;
169 if (idx_c == idx_left) { // only one segment ...
170 wtau_left = tau_t::beta();
171 wtau_right = tau_t::zero();
172 }
173 tau_t window_length = wtau_left - wtau_right;
174
175 // Choose random time in window left-right (possibly cyclic)
176 auto dt = tau_t::random(rng, window_length);
177 auto tau_c_new = sl[idx_left].tau_cdag - dt;
178
179 LOG("Spin {}: moving c at position {} from {} to {}.", (color == 0) ? "up" : "down", idx_c, tau_c, tau_c_new);
180 auto new_seg = segment_t{tau_c_new, sl[idx_c].tau_cdag};
181
182 // -------- Trace ratio ---------
183 ln_trace_ratio += wdata.mu(color) * (double(new_seg.length()) - double(sl[idx_c].length()));
184 for (auto const &[c, slc] : itertools::enumerate(config.seglists)) {
185 if (c != color) {
186 ln_trace_ratio += -wdata.U(c, color) * overlap(slc, new_seg);
187 ln_trace_ratio -= -wdata.U(c, color) * overlap(slc, sl[idx_c]);
188 }
189 if (wdata.has_Dt) {
190 ln_trace_ratio += K_overlap(slc, tau_c_new, true, wdata.K, c, color);
191 ln_trace_ratio -= K_overlap(slc, tau_c, true, wdata.K, c, color);
192 }
193 }
194 if (wdata.has_Dt) ln_trace_ratio -= real(wdata.K(double(tau_c_new - tau_c))(color, color));
195
196 // --------- Prop ratio ---------
197 // T direct = 1/window_length
198 // T inverse =
199 prop_ratio *= window_length / (double(sl.size()) * cdag_in_window(wtau_left, wtau_right, dsl).size());
200
201 return {idx_c, idx_cdag, tau_c_new};
202 }
203
204} // namespace triqs_ctseg::moves
static tau_t epsilon()
Get epsilon, defined as $\epsilon = \beta /N_max$.
Definition tau_t.hpp:73
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