22#include "./configuration.hpp"
23#include "./parameters.hpp"
24#include "triqs/utility/rbt.hpp"
25#include <triqs/stat/histograms.hpp>
26#include <triqs/atom_diag/atom_diag.hpp>
31using histo_map_t = std::map<std::string, triqs::stat::histogram>;
32using triqs::stat::histogram;
33using triqs::utility::rb_tree;
34using triqs::utility::rbt_insert_error;
36namespace triqs_cthyb {
41 class impurity_trace {
44 bool use_norm_as_weight;
45 bool measure_density_matrix;
49 impurity_trace(
double beta, atom_diag
const &h_diag, histo_map_t *hist_map,
50 bool use_norm_as_weight=
false,
bool measure_density_matrix=
false,
bool performance_analysis=
false);
56 std::pair<h_scalar_t, h_scalar_t> compute(
double p_yee = -1,
double u_yee = 0);
60 const configuration *config;
61 const atom_diag *h_diag;
62 const int n_orbitals = h_diag->get_fops().size();
63 const int n_blocks = h_diag->n_subspaces();
64 const int n_eigstates = h_diag->get_full_hilbert_space_dim();
69 struct bool_and_matrix {
71 matrix<h_scalar_t> mat;
73 std::vector<bool_and_matrix> density_matrix;
74 std::vector<bool_and_matrix> atomic_rho;
79 std::vector<bool_and_matrix>
const &get_density_matrix()
const {
return density_matrix; }
86 double dtau_l = 0, dtau_r = 0;
87 std::vector<int> block_table;
88 std::vector<arrays::matrix<h_scalar_t>> matrices;
89 std::vector<double> matrix_lnorms;
90 std::vector<bool> matrix_norm_valid;
91 cache_t(
int n_blocks) : block_table(n_blocks), matrices(n_blocks), matrix_lnorms(n_blocks), matrix_norm_valid(n_blocks) {}
97 node_data_t(op_desc op,
int n_blocks) : op(op), cache(n_blocks) {}
98 void reset(op_desc op_new) { op = op_new; }
101 using rb_tree_t = rb_tree<time_pt, node_data_t, std::greater<time_pt>>;
102 using node = rb_tree_t::node;
109 std::vector<atom_diag::op_block_mat_t> aux_operators;
116 int get_block_dim(
int b)
const {
return h_diag->get_subspace_dim(b); }
119 double get_block_eigenval(
int b,
int i)
const {
return h_diag->get_eigenvalue(b, i); }
122 double get_block_emin(
int b)
const {
return get_block_eigenval(b, 0); }
125 int get_op_block_map(node n,
int b)
const {
126 if( n->op.linear_index >= 0 )
127 return (n->op.dagger ? h_diag->cdag_connection(n->op.linear_index, b) : h_diag->c_connection(n->op.linear_index, b));
129 int aux_idx = -n->op.linear_index - 1;
130 return aux_operators[aux_idx].connection(b);
135 matrix<h_scalar_t>
const &get_op_block_matrix(node n,
int b)
const {
136 if( n->op.linear_index >= 0 )
137 return (n->op.dagger ? h_diag->cdag_matrix(n->op.linear_index, b) : h_diag->c_matrix(n->op.linear_index, b));
139 int aux_idx = -n->op.linear_index - 1;
140 return aux_operators[aux_idx].block_mat[b];
145 int compute_block_table(node n,
int b);
146 std::pair<int, double> compute_block_table_and_bound(node n,
int b,
double bound_threshold,
bool use_threshold =
true);
147 std::pair<int, matrix_t> compute_matrix(node n,
int b);
149 void update_cache_impl(node n);
150 void update_dtau(node n);
152 bool use_norm_of_matrices_in_cache =
true;
155 void check_cache_integrity(
bool print =
false);
156 void check_cache_integrity_one_node(node n,
bool print);
157 int check_one_block_table_linear(node n,
int b,
bool print);
158 matrix_t check_one_block_matrix_linear(node n,
int b);
161 class nodes_storage {
164 std::vector<node> nodes;
168 node make_new_node() {
return new rb_tree_t::node_t(time_pt{}, node_data_t{{}, n_blocks},
false, 1); }
171 inline nodes_storage(
int n_blocks,
int size = 0) : n_blocks(n_blocks), i(-1) {
172 for (
int j = 0; j < size; ++j) nodes.push_back(make_new_node());
174 inline ~nodes_storage() {
175 for (
auto &n : nodes)
delete n;
179 inline void reserve(
int size) {
180 if (size > nodes.size())
181 for (
int j = nodes.size(); j < size; ++j) nodes.push_back(make_new_node());
183 inline int index()
const {
return i; }
184 inline bool is_index_reset()
const {
return i == -1; }
185 inline int reset_index() {
190 inline node swap_next(node n) {
191 std::swap(n, nodes[++i]);
194 inline node swap_prev(node n) {
195 std::swap(n, nodes[i--]);
198 inline node take_next() {
return nodes[++i]; }
199 inline node take_prev() {
return nodes[i--]; }
205 op_desc attach_aux_operator(many_body_op_t
const &op) {
206 aux_operators.push_back(h_diag->get_op_mat(op));
207 op_desc operator_desc{0, 0,
true, -
static_cast<int>(aux_operators.size())};
208 return operator_desc;
220 nodes_storage trial_nodes = {n_blocks, 4};
223 std::vector<std::pair<node, bool>> inserted_nodes = {{
nullptr,
false}, {
nullptr,
false}, {
nullptr,
false}, {
nullptr,
false}};
225 node try_insert_impl(node h, node n) {
226 if (h ==
nullptr)
return n;
227 if (h->key == n->key)
throw rbt_insert_error{};
228 auto smaller = tree.get_comparator()(n->key, h->key);
230 h->left = try_insert_impl(h->left, n);
232 h->right = try_insert_impl(h->right, n);
233 if (inserted_nodes[trial_nodes.index()].first ==
nullptr) inserted_nodes[trial_nodes.index()] = {h, smaller};
239 void cancel_insert_impl() {
240 for (
int i = 0; i <= trial_nodes.index(); ++i) {
241 auto &r = inserted_nodes[i];
242 if (r.first !=
nullptr) (r.second ? r.first->left : r.first->right)=
nullptr;
244 if (tree_size <= trial_nodes.index() + 1) tree.get_root() =
nullptr;
253 void try_insert(time_pt
const &tau, op_desc
const &op) {
254 if (trial_nodes.index() > 3) TRIQS_RUNTIME_ERROR <<
"Error : more than 4 insertions ";
255 auto &root = tree.get_root();
256 node n = trial_nodes.take_next();
257 inserted_nodes[trial_nodes.index()] = {
nullptr,
false};
259 root = try_insert_impl(root, n);
264 void cancel_insert() {
265 cancel_insert_impl();
266 trial_nodes.reset_index();
267 tree_size = tree.size();
268 tree.clear_modified();
269 check_cache_integrity();
273 void confirm_insert() {
274 cancel_insert_impl();
276 int imax = trial_nodes.reset_index();
277 for (
int i = 0; i <= imax; ++i) {
278 node n = trial_nodes.take_next();
279 tree.insert(n->key, {n->op, n_blocks});
281 trial_nodes.reset_index();
283 tree_size = tree.size();
284 tree.clear_modified();
285 check_cache_integrity();
292 std::vector<node> removed_nodes;
293 std::vector<time_pt> removed_keys;
298 time_pt try_delete(
int n,
int block_index,
bool dagger)
noexcept {
301 node x = find_if(tree, [&](node no) {
302 if (no->op.dagger == dagger && no->op.block_index == block_index) ++i;
305 removed_nodes.push_back(x);
306 removed_keys.push_back(x->key);
307 tree.set_modified_from_root_to(x->key);
308 x->delete_flag =
true;
314 void cancel_delete() {
315 for (
auto &n : removed_nodes) n->delete_flag =
false;
316 removed_nodes.clear();
317 removed_keys.clear();
318 tree_size = tree.size();
319 tree.clear_modified();
320 check_cache_integrity();
324 void confirm_delete() {
325 for (
auto &k : removed_keys) tree.delete_node(k);
326 removed_nodes.clear();
327 removed_keys.clear();
329 tree_size = tree.size();
330 tree.clear_modified();
331 check_cache_integrity();
341 void cancel_shift() {
344 cancel_insert_impl();
345 trial_nodes.reset_index();
348 for (
auto &n : removed_nodes) n->delete_flag =
false;
349 removed_nodes.clear();
350 removed_keys.clear();
352 tree_size = tree.size();
353 tree.clear_modified();
354 check_cache_integrity();
358 void confirm_shift() {
361 cancel_insert_impl();
364 int imax = trial_nodes.reset_index();
365 for (
int i = 0; i <= imax; ++i) {
366 node n = trial_nodes.take_next();
367 tree.insert(n->key, {n->op, n_blocks});
369 trial_nodes.reset_index();
372 for (
auto &k : removed_keys) tree.delete_node(k);
373 removed_nodes.clear();
374 removed_keys.clear();
378 tree_size = tree.size();
379 tree.clear_modified();
380 check_cache_integrity();
388 nodes_storage backup_nodes = {n_blocks};
390 node try_replace_impl(node n, configuration::oplist_t
const &updated_ops)
noexcept {
392 node new_left =
nullptr, new_right =
nullptr;
393 if (n->left) new_left = try_replace_impl(n->left, updated_ops);
394 if (n->right) new_right = try_replace_impl(n->right, updated_ops);
396 auto const &op = n->op;
397 auto it = updated_ops.find(n->key);
398 bool op_changed = it != updated_ops.end();
399 auto const &new_op = op_changed ? it->second : op;
401 if (op_changed || new_left != n->left || new_right != n->right) {
403 auto color = n->color;
406 new_node = backup_nodes.swap_next(n);
408 new_node->reset(key, new_op);
410 new_node->reset(key, op);
411 new_node->left = new_left;
412 new_node->right = new_right;
413 new_node->color = color;
415 new_node->modified =
true;
420 node cancel_replace_impl(node n) {
422 if (n_in_tree && n_in_tree->modified) n= backup_nodes.swap_prev(n);
423 if (n_in_tree->right) cancel_replace_impl(n_in_tree->right);
424 if (n_in_tree->left) cancel_replace_impl(n_in_tree->left);
429 void try_replace(configuration::oplist_t
const &updated_ops) {
430 if (tree_size == 0)
return;
432 if (!backup_nodes.is_index_reset()) TRIQS_RUNTIME_ERROR <<
"impurity_trace: improper use of try_replace()";
433 backup_nodes.reserve(tree.size());
434 auto &root = tree.get_root();
435 root = try_replace_impl(root, updated_ops);
438 void confirm_replace() {
439 backup_nodes.reset_index();
441 tree.clear_modified();
442 check_cache_integrity();
445 void cancel_replace() {
446 if (tree_size == 0 || backup_nodes.is_index_reset())
return;
447 auto &root = tree.get_root();
448 root = cancel_replace_impl(root);
449 check_cache_integrity();
454 struct histograms_t {
457 histogram &n_block_at_root;
459 histogram &n_block_kept;
462 histogram &dominant_block_bound;
463 histogram &dominant_block_trace;
464 histogram &dominant_block_energy_bound;
465 histogram &dominant_block_energy_trace;
468 histogram &trace_over_norm;
469 histogram &trace_abs_over_norm;
470 histogram &trace_over_trace_abs;
471 histogram &trace_over_bound;
472 histogram &trace_first_over_sec_term;
473 histogram &trace_first_term_trace;
475#define ADD_HISTO(NAME, HISTO) NAME(histos.emplace((#NAME), (HISTO)).first->second)
476 histograms_t(
int n_subspaces, histo_map_t &histos)
477 : ADD_HISTO(n_block_at_root, histogram(0, n_subspaces)),
478 ADD_HISTO(n_block_kept, histogram(0, n_subspaces)),
479 ADD_HISTO(dominant_block_bound, histogram(0, n_subspaces)),
480 ADD_HISTO(dominant_block_trace, histogram(0, n_subspaces)),
481 ADD_HISTO(dominant_block_energy_bound, histogram(0, 100, 100)),
482 ADD_HISTO(dominant_block_energy_trace, histogram(0, 100, 100)),
483 ADD_HISTO(trace_over_norm, histogram(0, 1.5, 100)),
484 ADD_HISTO(trace_abs_over_norm, histogram(0, 1.5, 100)),
485 ADD_HISTO(trace_over_trace_abs, histogram(0, 1.5, 100)),
486 ADD_HISTO(trace_over_bound, histogram(0, 1.5, 100)),
487 ADD_HISTO(trace_first_over_sec_term, histogram(0, 1.0, 100)),
488 ADD_HISTO(trace_first_term_trace, histogram(0, 1.0, 100)) {}
491 std::unique_ptr<histograms_t> histo;
494 friend std::ostream &operator<<(std::ostream &out, impurity_trace
const & imp_trace);