TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
det_manip_basic.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2013-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2016 Igor Krivenko
4// Copyright (c) 2018-2020 Simons Foundation
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You may obtain a copy of the License at
17// https://www.gnu.org/licenses/gpl-3.0.txt
18//
19// Authors: Michel Ferrero, JaksaVucicevic, Igor Krivenko, Laura Messio, Olivier Parcollet, Priyanka Seth, Hugo U. R. Strand, Nils Wentzell
20
25
26#pragma once
27
28#include "../arrays.hpp"
31
32#include <itertools/itertools.hpp>
33#include <nda/nda.hpp>
34
35#include <algorithm>
36#include <array>
37#include <cstdint>
38#include <iterator>
39#include <numeric>
40#include <vector>
41
42namespace triqs::det_manip {
43
44 namespace blas = nda::blas;
45
65 template <typename FunctionType> class det_manip_basic {
66 // ---------------------------------------------------------------------------------------------------
67 // Type Checks and Definitions
68 private:
70 static_assert(f_tr::arity == 2, "det_manip_basic : the function must take two arguments !");
71
72 using int_type = std::ptrdiff_t;
73 using range = itertools::range;
74
75 public:
76 using x_type = typename f_tr::template decay_arg_t<0>;
77 using y_type = typename f_tr::template decay_arg_t<1>;
78 using value_type = typename f_tr::result_type;
79 using det_type = value_type;
80 static_assert(std::is_floating_point_v<value_type> || nda::is_complex_v<value_type>,
81 "det_manip_basic : the function must return a floating number or a complex number");
82
83 using matrix_type = nda::matrix<value_type>;
84
85 // ---------------------------------------------------------------------------------------------------
86 // Data
87 private:
88 enum {
89 NoTry,
90 Insert,
91 Remove,
92 ChangeCol,
93 ChangeRow,
94 ChangeRowCol,
95 Insert2 = 10,
96 Remove2 = 11,
97 InsertK = 12,
98 RemoveK = 13,
99 Refill = 20
100 } last_try = NoTry; // keep in memory the last operation not completed
101
102 FunctionType f;
103
104 // Serialized data:
105
106 uint64_t n_opts = 0; // count the number of operation
107
108 long Nmax = 0;
109 long N = 0;
110
111 matrix_type mat;
112 det_type det = 1.0;
113
114 std::vector<x_type> x_values;
115 std::vector<y_type> y_values;
116
117 // Temporary objects: not serialized
118 matrix_type mat_new;
119 det_type det_new = 1.0;
120
121 mutable matrix_type mat_inverse;
122 mutable bool mat_inverse_is_valid = false;
123
124 // Temporary work data
125
126 // Working data for single-row/column operations: arguments x, y and positions i, j of the new/changed row/column.
127 struct work_data_type1 {
128 x_type x;
129 y_type y;
130 long i;
131 long j;
132 } w1;
133
134 // Working data for two-row/column operations: arguments and positions of the two new/changed rows/columns.
135 struct work_data_type2 {
136 std::array<x_type, 2> x;
137 std::array<y_type, 2> y;
138 std::array<long, 2> i, j;
139 } w2;
140
141 // Working data for k-row/column operations: arguments and positions of the k rows/columns (k = current count).
142 struct work_data_typek {
143 std::vector<x_type> x;
144 std::vector<y_type> y;
145 std::vector<long> i, j;
146 long k = 0;
147 void resize(long new_k) {
148 k = new_k;
149 x.resize(k);
150 y.resize(k);
151 i.resize(k);
152 j.resize(k);
153 }
154 } wk;
155
156 // Working data for the refill operation: the new matrix builder arguments.
157 struct work_data_type_refill {
158 std::vector<x_type> x_values;
159 std::vector<y_type> y_values;
160 void clear() {
161 x_values.clear();
162 y_values.clear();
163 }
164 void reserve(size_t s) {
165 x_values.reserve(s);
166 y_values.reserve(s);
167 }
168 } w_refill;
169
170 // ---------------------------------------------------------------------------------------------------
171 // Data Transfer: HDF5
172 private:
180 friend void h5_write(h5::group fg, std::string subgroup_name, det_manip_basic const &g) {
181 auto gr = fg.create_group(subgroup_name);
182 h5_write(gr, "n_opts", g.n_opts);
183 h5_write(gr, "N", g.N);
184 h5_write(gr, "mat", g.mat);
185 h5_write(gr, "det", g.det);
186 h5_write(gr, "x_values", g.x_values);
187 h5_write(gr, "y_values", g.y_values);
188 }
189
197 friend void h5_read(h5::group fg, std::string subgroup_name, det_manip_basic &g) {
198 auto gr = fg.open_group(subgroup_name);
199 h5_read(gr, "n_opts", g.n_opts);
200 h5_read(gr, "N", g.N);
201 h5_read(gr, "mat", g.mat);
202 g.Nmax = first_dim(g.mat); // restore Nmax
203 g.last_try = NoTry;
204 h5_read(gr, "det", g.det);
205 h5_read(gr, "x_values", g.x_values);
206 h5_read(gr, "y_values", g.y_values);
207 }
208
209 public:
220 void reserve(long new_size, long new_k = 1) {
221 (void)new_k; // unused, for API compatibility
222 if (new_size <= Nmax) return;
223 matrix_type Mcopy(mat);
224 long N0 = Nmax;
225 Nmax = new_size;
226 mat.resize(Nmax, Nmax);
227 mat_new.resize(Nmax, Nmax);
228 mat_inverse.resize(Nmax, Nmax);
229 mat(range(0, N0), range(0, N0)) = Mcopy; // keep the content of mat_inv ---> into the lib ?
230 x_values.reserve(Nmax);
231 y_values.reserve(Nmax);
232 mat_inverse_is_valid = false;
233 }
234
245 det_manip_basic(FunctionType F, long init_size) : f(std::move(F)) {
246 reserve(init_size);
247 mat() = 0;
248 }
249
260 template <typename ArgumentContainer1, typename ArgumentContainer2>
261 det_manip_basic(FunctionType F, ArgumentContainer1 const &X, ArgumentContainer2 const &Y) : f(std::move(F)) {
262 if (X.size() != Y.size()) TRIQS_RUNTIME_ERROR << " X.size != Y.size";
263 N = X.size();
264 if (N == 0) {
265 det = 1;
266 reserve(30);
267 return;
268 }
269 if (N > Nmax) reserve(2 * N); // put some margin..
270 std::copy(X.begin(), X.end(), std::back_inserter(x_values));
271 std::copy(Y.begin(), Y.end(), std::back_inserter(y_values));
272
273 build_matrix();
274 compute_determinant();
275 }
276
277 det_manip_basic(det_manip_basic const &) = default;
278 det_manip_basic(det_manip_basic &&rhs) noexcept = default;
279 det_manip_basic &operator=(const det_manip_basic &) = delete;
280 // det_manip_basic &operator = default;
281
285 void clear() {
286 N = 0;
287 det = 1;
288 last_try = NoTry;
289 x_values.clear();
290 y_values.clear();
291 }
292 //----------------------- Computations ----------------------------------
293
299 matrix_type build_matrix_scratch() {
300 TRIQS_ASSERT(x_values.size() == N)
301 TRIQS_ASSERT(y_values.size() == N)
302
303 matrix_type res(N, N);
304
305 for (long i = 0; i < N; i++) {
306 for (long j = 0; j < N; j++) { res(i, j) = f(x_values[i], y_values[j]); }
307 }
308
309 return res;
310 }
311
312 private:
313 // Rebuild the stored matrix mat from the stored arguments by evaluating f(x_i, y_j) for all i, j.
314 void build_matrix() {
315 TRIQS_ASSERT(x_values.size() == N)
316 TRIQS_ASSERT(y_values.size() == N)
317 if (N > Nmax) reserve(N); // TODO: no extra margin
318
319 for (long i = 0; i < N; i++) {
320 for (long j = 0; j < N; j++) { mat(i, j) = f(x_values[i], y_values[j]); }
321 }
322 }
323
324 // Recompute the determinant of the stored matrix from scratch.
325 void compute_determinant() {
326 range R(0, N);
327 det = nda::linalg::det(mat(R, R));
328 }
329
330 // Lazily recompute the inverse matrix from scratch (cached in mat_inverse, guarded by mat_inverse_is_valid).
331 void compute_inverse() const {
332 if (mat_inverse_is_valid) return;
333 if (N == 0) {
334 mat_inverse_is_valid = true;
335 return;
336 }
337 range R(0, N);
338 mat_inverse(R, R) = nda::linalg::inv(mat(R, R));
339 mat_inverse_is_valid = true;
340 }
341
342 //----------------------- READ ACCESS TO DATA ----------------------------------
343 public:
348 auto size() const { return N; }
349
354 auto get_x() const { return x_values; }
355
360 auto get_y() const { return y_values; }
361
367 x_type const &get_x(long i) const { return x_values[i]; }
368
374 y_type const &get_y(long j) const { return y_values[j]; }
375
382 auto const &get_x_internal_order() const { return x_values; }
383
390 auto const &get_y_internal_order() const { return y_values; }
391
396 FunctionType const &get_function() const { return f; }
397
402 auto determinant() { return det; }
403
409 nda::matrix_const_view<value_type> inverse_matrix() const {
410 compute_inverse();
411 range R(0, N);
412 return mat_inverse(R, R);
413 }
414
421 value_type inverse_matrix(int i, int j) const {
422 compute_inverse();
423 return mat_inverse(i, j);
424 }
425
432 nda::matrix_const_view<value_type> inverse_matrix_internal_order() const { return inverse_matrix(); }
433
442 value_type inverse_matrix_internal_order(int i, int j) const { return inverse_matrix(i, j); }
443
448 matrix_type matrix() const {
449 range R(0, N);
450 return mat(R, R);
451 }
452
459 value_type matrix(int i, int j) const { return mat(i, j); }
460
472 template <typename LambdaType> friend void foreach (det_manip_basic const &d, LambdaType const &func) {
473 d.compute_inverse();
474 nda::for_each(std::array{long(d.N), long(d.N)}, [&func, &d](int i, int j) { return func(d.x_values[i], d.y_values[j], d.mat_inverse(j, i)); });
475 }
476
477 // ------------------------- OPERATIONS -----------------------------------------------
478
497 value_type try_insert(long i, long j, x_type const &x, y_type const &y) {
498 // check input and store it for complete_operation
499 TRIQS_ASSERT(last_try == NoTry);
500 TRIQS_ASSERT(i <= N);
501 TRIQS_ASSERT(j <= N);
502 TRIQS_ASSERT(i >= 0);
503 TRIQS_ASSERT(j >= 0);
504 // TRIQS_ASSERT(N > 0); -- fix
505 w1.i = i;
506 w1.j = j;
507 w1.x = x;
508 w1.y = y;
509
510 if (N == Nmax) reserve(2 * Nmax);
511 last_try = Insert;
512
513 range Row_A(0, i);
514 range Row_B_0(i, N);
515 range Row_B_1 = Row_B_0 + std::ptrdiff_t{1};
516
517 range Col_A(0, j);
518 range Col_B_0(j, N);
519 range Col_B_1 = Col_B_0 + std::ptrdiff_t{1};
520
521 mat_new(Row_A, Col_A) = mat(Row_A, Col_A);
522 mat_new(Row_A, Col_B_1) = mat(Row_A, Col_B_0);
523 mat_new(Row_B_1, Col_A) = mat(Row_B_0, Col_A);
524 mat_new(Row_B_1, Col_B_1) = mat(Row_B_0, Col_B_0);
525
526 for (auto k : Row_A) { mat_new(k, j) = f(x_values[k], y); }
527 for (auto k : Row_B_0) { mat_new(k + 1, j) = f(x_values[k], y); }
528
529 for (auto k : Col_A) { mat_new(i, k) = f(x, y_values[k]); }
530 for (auto k : Col_B_0) { mat_new(i, k + 1) = f(x, y_values[k]); }
531
532 mat_new(i, j) = f(x, y);
533
534 range R(0, N + 1);
535 det_new = nda::linalg::det(mat_new(R, R));
536
537 return det_new / det;
538 }
539
540 //------------------------------------------------------------------------------------------
541 private:
542 // Complete the insert operation.
543 void complete_insert() {
544 N++;
545 x_values.insert(begin(x_values) + w1.i, w1.x);
546 y_values.insert(begin(y_values) + w1.j, w1.y);
547 std::swap(mat, mat_new);
548 }
549
550 public:
551 //------------------------------------------------------------------------------------------
552
574 value_type try_insert2(long i0, long i1, long j0, long j1, x_type const &x0_, x_type const &x1_, y_type const &y0_, y_type const &y1_) {
575
576 // first make sure i0<i1 and j0<j1
577 x_type const &x0((i0 < i1) ? x0_ : x1_);
578 x_type const &x1((i0 < i1) ? x1_ : x0_);
579 y_type const &y0((j0 < j1) ? y0_ : y1_);
580 y_type const &y1((j0 < j1) ? y1_ : y0_);
581 if (i0 > i1) std::swap(i0, i1);
582 if (j0 > j1) std::swap(j0, j1);
583
584 // check input and store it for complete_operation
585 TRIQS_ASSERT(last_try == NoTry);
586 TRIQS_ASSERT(i0 != i1);
587 TRIQS_ASSERT(j0 != j1);
588 TRIQS_ASSERT(i0 <= N);
589 TRIQS_ASSERT(j0 <= N);
590 TRIQS_ASSERT(i0 >= 0);
591 TRIQS_ASSERT(j0 >= 0);
592 TRIQS_ASSERT(i1 <= N + 1);
593 TRIQS_ASSERT(j1 <= N + 1);
594 TRIQS_ASSERT(i1 >= 0);
595 TRIQS_ASSERT(j1 >= 0);
596
597 i1--;
598 j1--;
599
600 if (N >= Nmax - 1) reserve(2 * Nmax);
601 last_try = Insert2;
602 w2.i[0] = i0;
603 w2.i[1] = i1;
604 w2.j[0] = j0;
605 w2.j[1] = j1;
606 w2.x[0] = x0;
607 w2.x[1] = x1;
608 w2.y[0] = y0;
609 w2.y[1] = y1;
610
611 // std::cerr << i0 << "," << i1 << "," << j0 << "," << j1 << " : " << x0 << "," << x1 << "," << y0 << "," << y1 << std::endl;
612
613 range Row_A(0, i0);
614 range Row_B_0(i0, i1);
615 range Row_B_1 = Row_B_0 + std::ptrdiff_t{1};
616 range Row_C_0(i1, N);
617 range Row_C_1 = Row_C_0 + std::ptrdiff_t{2};
618
619 range Col_A(0, j0);
620 range Col_B_0(j0, j1);
621 range Col_B_1 = Col_B_0 + std::ptrdiff_t{1};
622 range Col_C_0(j1, N);
623 range Col_C_1 = Col_C_0 + std::ptrdiff_t{2};
624
625 mat_new(Row_A, Col_A) = mat(Row_A, Col_A);
626 mat_new(Row_A, Col_B_1) = mat(Row_A, Col_B_0);
627 mat_new(Row_A, Col_C_1) = mat(Row_A, Col_C_0);
628
629 mat_new(Row_B_1, Col_A) = mat(Row_B_0, Col_A);
630 mat_new(Row_B_1, Col_B_1) = mat(Row_B_0, Col_B_0);
631 mat_new(Row_B_1, Col_C_1) = mat(Row_B_0, Col_C_0);
632
633 mat_new(Row_C_1, Col_A) = mat(Row_C_0, Col_A);
634 mat_new(Row_C_1, Col_B_1) = mat(Row_C_0, Col_B_0);
635 mat_new(Row_C_1, Col_C_1) = mat(Row_C_0, Col_C_0);
636
637 // Note: need to shift i1/j1 below by +1 to adjust for first row/column
638
639 for (auto k : Row_A) {
640 mat_new(k, j0) = f(x_values[k], y0);
641 mat_new(k, j1 + 1) = f(x_values[k], y1);
642 }
643 for (auto k : Row_B_0) {
644 mat_new(k + 1, j0) = f(x_values[k], y0);
645 mat_new(k + 1, j1 + 1) = f(x_values[k], y1);
646 }
647
648 for (auto k : Row_C_0) {
649 mat_new(k + 2, j0) = f(x_values[k], y0);
650 mat_new(k + 2, j1 + 1) = f(x_values[k], y1);
651 }
652
653 for (auto k : Col_A) {
654 mat_new(i0, k) = f(x0, y_values[k]);
655 mat_new(i1 + 1, k) = f(x1, y_values[k]);
656 }
657 for (auto k : Col_B_0) {
658 mat_new(i0, k + 1) = f(x0, y_values[k]);
659 mat_new(i1 + 1, k + 1) = f(x1, y_values[k]);
660 }
661 for (auto k : Col_C_0) {
662 mat_new(i0, k + 2) = f(x0, y_values[k]);
663 mat_new(i1 + 1, k + 2) = f(x1, y_values[k]);
664 }
665
666 mat_new(i0, j0) = f(x0, y0);
667 mat_new(i0, j1 + 1) = f(x0, y1);
668 mat_new(i1 + 1, j0) = f(x1, y0);
669 mat_new(i1 + 1, j1 + 1) = f(x1, y1);
670
671 range R(0, N + 2);
672 det_new = nda::linalg::det(mat_new(R, R));
673
674 return det_new / det;
675 }
676
677 //------------------------------------------------------------------------------------------
678 private:
679 // Complete the insert2 operation.
680 void complete_insert2() {
681 N += 2;
682 x_values.insert(begin(x_values) + w2.i[1], w2.x[1]);
683 x_values.insert(begin(x_values) + w2.i[0], w2.x[0]);
684 y_values.insert(begin(y_values) + w2.j[1], w2.y[1]);
685 y_values.insert(begin(y_values) + w2.j[0], w2.y[0]);
686 std::swap(mat, mat_new);
687 }
688
689 public:
690 //------------------------------------------------------------------------------------------
691
692 // Helper: flatten an nda::Array to a std::vector in C-order
693 template <nda::Array A> static auto flatten_array(A const &a) {
694 auto v = std::vector<typename A::value_type>(a.size());
695 long flat = 0;
696 nda::for_each(a.shape(), [&](auto... idx) { v[flat++] = a(idx...); });
697 return v;
698 }
699
716 template <nda::Array X, nda::Array Y>
717 requires(nda::get_rank<X> == nda::get_rank<Y>)
718 auto insert_ratios(long i, long j, X const &xs, Y const &ys) const -> nda::array<value_type, nda::get_rank<X>> {
719 constexpr int Rk = nda::get_rank<X>;
720 TRIQS_ASSERT(xs.shape() == ys.shape());
721 TRIQS_ASSERT(0 <= i and i <= N);
722 TRIQS_ASSERT(0 <= j and j <= N);
723
724 long nbatch = xs.size();
725 nda::array<value_type, Rk> result(xs.shape());
726 auto xs_flat = flatten_array(xs);
727 auto ys_flat = flatten_array(ys);
728
729 for (long m = 0; m < nbatch; ++m) result.data()[m] = compute_insert_ratio(i, j, xs_flat[m], ys_flat[m]);
730 return result;
731 }
732
733 private:
734 // Helper: compute a single rank-1 insertion det-ratio by building augmented matrix
735 auto compute_insert_ratio(long i, long j, x_type const &x, y_type const &y) const -> value_type {
736 matrix_type aug(N + 1, N + 1);
737 for (long r = 0; r < N; ++r)
738 for (long c = 0; c < N; ++c) aug(r < i ? r : r + 1, c < j ? c : c + 1) = mat(r, c);
739 for (long c = 0; c < N; ++c) aug(i, c < j ? c : c + 1) = f(x, y_values[c]);
740 for (long r = 0; r < N; ++r) aug(r < i ? r : r + 1, j) = f(x_values[r], y);
741 aug(i, j) = f(x, y);
742 return nda::linalg::det(aug) / det;
743 }
744
745 public:
763 value_type try_insert_k(std::vector<long> i, std::vector<long> j, std::vector<x_type> x, std::vector<y_type> y) {
764 TRIQS_ASSERT(last_try == NoTry);
765 TRIQS_ASSERT(i.size() == j.size());
766 TRIQS_ASSERT(j.size() == x.size());
767 TRIQS_ASSERT(x.size() == y.size());
768
769 long k = static_cast<long>(i.size());
770 wk.resize(k);
771
772 // Sort indices to ensure proper insertion order
773 auto argsort = [](auto const &vec) {
774 std::vector<long> idx(vec.size());
775 std::iota(idx.begin(), idx.end(), 0L);
776 std::stable_sort(idx.begin(), idx.end(), [&vec](long lhs, long rhs) { return vec[lhs] < vec[rhs]; });
777 return idx;
778 };
779 std::vector<long> idx = argsort(i);
780 std::vector<long> idy = argsort(j);
781
782 // Store sorted values for complete_operation
783 for (long l = 0; l < k; ++l) {
784 wk.i[l] = i[idx[l]];
785 wk.x[l] = x[idx[l]];
786 wk.j[l] = j[idy[l]];
787 wk.y[l] = y[idy[l]];
788 }
789
790 // Check consistency: each position must be valid at insertion time
791 // After sorting, wk.i[l] must be <= N + l (valid for size N + l)
792 for (long l = 0; l < k; ++l) {
793 TRIQS_ASSERT(0 <= wk.i[l] && wk.i[l] <= N + l);
794 TRIQS_ASSERT(0 <= wk.j[l] && wk.j[l] <= N + l);
795 }
796 for (long l = 0; l < k - 1; ++l) {
797 TRIQS_ASSERT(wk.i[l] != wk.i[l + 1]);
798 TRIQS_ASSERT(wk.j[l] != wk.j[l + 1]);
799 }
800
801 if (N + k > Nmax) reserve(2 * (N + k));
802 last_try = InsertK;
803
804 // Build new matrix with k inserted rows/columns
805 // Create mapping from old indices to new indices
806 std::vector<long> row_map(N), col_map(N);
807 {
808 long offset = 0;
809 long insert_idx = 0;
810 for (long old_idx = 0; old_idx < N; ++old_idx) {
811 while (insert_idx < k && wk.i[insert_idx] <= old_idx + offset) {
812 ++offset;
813 ++insert_idx;
814 }
815 row_map[old_idx] = old_idx + offset;
816 }
817 }
818 {
819 long offset = 0;
820 long insert_idx = 0;
821 for (long old_idx = 0; old_idx < N; ++old_idx) {
822 while (insert_idx < k && wk.j[insert_idx] <= old_idx + offset) {
823 ++offset;
824 ++insert_idx;
825 }
826 col_map[old_idx] = old_idx + offset;
827 }
828 }
829
830 // Copy existing matrix elements to their new positions
831 for (long old_i = 0; old_i < N; ++old_i) {
832 for (long old_j = 0; old_j < N; ++old_j) { mat_new(row_map[old_i], col_map[old_j]) = mat(old_i, old_j); }
833 }
834
835 // Fill in new rows
836 for (long l = 0; l < k; ++l) {
837 long new_row = wk.i[l];
838 // Elements from existing columns
839 for (long old_j = 0; old_j < N; ++old_j) { mat_new(new_row, col_map[old_j]) = f(wk.x[l], y_values[old_j]); }
840 // Elements from new columns
841 for (long m = 0; m < k; ++m) { mat_new(new_row, wk.j[m]) = f(wk.x[l], wk.y[m]); }
842 }
843
844 // Fill in new columns (for existing rows)
845 for (long l = 0; l < k; ++l) {
846 long new_col = wk.j[l];
847 for (long old_i = 0; old_i < N; ++old_i) { mat_new(row_map[old_i], new_col) = f(x_values[old_i], wk.y[l]); }
848 }
849
850 range R(0, N + k);
851 det_new = nda::linalg::det(mat_new(R, R));
852
853 return det_new / det;
854 }
855
856 //------------------------------------------------------------------------------------------
857 private:
858 // Complete the insert_k operation.
859 void complete_insert_k() {
860 long k = wk.k;
861 N += k;
862 // Insert in forward order: position wk.i[l] is valid for size N-k+l
863 for (long l = 0; l < k; ++l) {
864 x_values.insert(begin(x_values) + wk.i[l], wk.x[l]);
865 y_values.insert(begin(y_values) + wk.j[l], wk.y[l]);
866 }
867 std::swap(mat, mat_new);
868 }
869
870 public:
871 //------------------------------------------------------------------------------------------
872
885 value_type try_remove(long i, long j) {
886 TRIQS_ASSERT(last_try == NoTry);
887 TRIQS_ASSERT(i < N);
888 TRIQS_ASSERT(j < N);
889 TRIQS_ASSERT(i >= 0);
890 TRIQS_ASSERT(j >= 0);
891 w1.i = i;
892 w1.j = j;
893 last_try = Remove;
894
895 // Treat N = 1 specially -> goes to zero
896 if (N == 1) {
897 det_new = 1.0;
898 return det_new / det;
899 }
900
901 range Row_A(0, i);
902 range Row_B_0(i + 1, N);
903 range Row_B_1 = Row_B_0 + std::ptrdiff_t{-1};
904
905 range Col_A(0, j);
906 range Col_B_0(j + 1, N);
907 range Col_B_1 = Col_B_0 + std::ptrdiff_t{-1};
908
909 mat_new(Row_A, Col_A) = mat(Row_A, Col_A);
910 mat_new(Row_A, Col_B_1) = mat(Row_A, Col_B_0);
911 mat_new(Row_B_1, Col_A) = mat(Row_B_0, Col_A);
912 mat_new(Row_B_1, Col_B_1) = mat(Row_B_0, Col_B_0);
913
914 range R(0, N - 1);
915 det_new = nda::linalg::det(mat_new(R, R));
916
917 return det_new / det;
918 }
919 //------------------------------------------------------------------------------------------
920 private:
921 // Complete the remove operation.
922 void complete_remove() {
923 N--;
924 x_values.erase(begin(x_values) + w1.i);
925 y_values.erase(begin(y_values) + w1.j);
926 std::swap(mat, mat_new);
927 }
928
929 public:
930 //------------------------------------------------------------------------------------------
931
946 value_type try_remove2(long i0, long i1, long j0, long j1) {
947
948 // first make sure i0<i1 and j0<j1
949 if (i0 > i1) std::swap(i0, i1);
950 if (j0 > j1) std::swap(j0, j1);
951
952 TRIQS_ASSERT(last_try == NoTry);
953 TRIQS_ASSERT(N >= 2);
954 TRIQS_ASSERT(i0 != i1);
955 TRIQS_ASSERT(j0 != j1);
956 TRIQS_ASSERT(i0 < N);
957 TRIQS_ASSERT(j0 < N);
958 TRIQS_ASSERT(i0 >= 0);
959 TRIQS_ASSERT(j0 >= 0);
960 TRIQS_ASSERT(i1 < N + 1);
961 TRIQS_ASSERT(j1 < N + 1);
962 TRIQS_ASSERT(i1 >= 0);
963 TRIQS_ASSERT(j1 >= 0);
964
965 last_try = Remove2;
966
967 w2.i[0] = std::min(i0, i1);
968 w2.i[1] = std::max(i0, i1);
969 w2.j[0] = std::min(j0, j1);
970 w2.j[1] = std::max(j0, j1);
971
972 // Treat N = 2 specially -> goes to N = 0
973 if (N == 2) {
974 det_new = 1.0;
975 return det_new / det;
976 }
977
978 range Row_A(0, i0);
979 range Row_B_0(i0 + 1, i1);
980 range Row_B_1 = Row_B_0 + std::ptrdiff_t{-1};
981 range Row_C_0(i1 + 1, N);
982 range Row_C_1 = Row_C_0 + std::ptrdiff_t{-2};
983
984 range Col_A(0, j0);
985 range Col_B_0(j0 + 1, j1);
986 range Col_B_1 = Col_B_0 + std::ptrdiff_t{-1};
987 range Col_C_0(j1 + 1, N);
988 range Col_C_1 = Col_C_0 + std::ptrdiff_t{-2};
989
990 mat_new(Row_A, Col_A) = mat(Row_A, Col_A);
991 mat_new(Row_A, Col_B_1) = mat(Row_A, Col_B_0);
992 mat_new(Row_A, Col_C_1) = mat(Row_A, Col_C_0);
993
994 mat_new(Row_B_1, Col_A) = mat(Row_B_0, Col_A);
995 mat_new(Row_B_1, Col_B_1) = mat(Row_B_0, Col_B_0);
996 mat_new(Row_B_1, Col_C_1) = mat(Row_B_0, Col_C_0);
997
998 mat_new(Row_C_1, Col_A) = mat(Row_C_0, Col_A);
999 mat_new(Row_C_1, Col_B_1) = mat(Row_C_0, Col_B_0);
1000 mat_new(Row_C_1, Col_C_1) = mat(Row_C_0, Col_C_0);
1001
1002 range R(0, N - 2);
1003 det_new = nda::linalg::det(mat_new(R, R));
1004
1005 return det_new / det;
1006 }
1007 //------------------------------------------------------------------------------------------
1008 private:
1009 // Complete the remove2 operation.
1010 void complete_remove2() {
1011 N -= 2;
1012
1013 // Note: need to erase in correct order!
1014 x_values.erase(begin(x_values) + w2.i[1]);
1015 x_values.erase(begin(x_values) + w2.i[0]);
1016 y_values.erase(begin(y_values) + w2.j[1]);
1017 y_values.erase(begin(y_values) + w2.j[0]);
1018
1019 std::swap(mat, mat_new);
1020 }
1021
1022 public:
1023 //------------------------------------------------------------------------------------------
1024
1038 value_type try_remove_k(std::vector<long> i, std::vector<long> j) {
1039 TRIQS_ASSERT(last_try == NoTry);
1040 TRIQS_ASSERT(i.size() == j.size());
1041 TRIQS_ASSERT(N >= static_cast<long>(i.size()));
1042
1043 long k = static_cast<long>(i.size());
1044 wk.resize(k);
1045
1046 // Sort indices in descending order for proper removal
1047 std::ranges::sort(i);
1048 std::ranges::sort(j);
1049
1050 // Check consistency
1051 for (long l = 0; l < k - 1; ++l) {
1052 TRIQS_ASSERT(i[l] != i[l + 1] && 0 <= i[l] && i[l] < N);
1053 TRIQS_ASSERT(j[l] != j[l + 1] && 0 <= j[l] && j[l] < N);
1054 }
1055 if (k > 0) {
1056 TRIQS_ASSERT(0 <= i[k - 1] && i[k - 1] < N);
1057 TRIQS_ASSERT(0 <= j[k - 1] && j[k - 1] < N);
1058 }
1059
1060 // Store sorted indices for complete_operation
1061 for (long l = 0; l < k; ++l) {
1062 wk.i[l] = i[l];
1063 wk.j[l] = j[l];
1064 }
1065
1066 last_try = RemoveK;
1067
1068 // Treat N = k specially -> goes to N = 0
1069 if (N == k) {
1070 det_new = 1.0;
1071 return det_new / det;
1072 }
1073
1074 // Build set of indices to keep
1075 std::vector<long> row_keep, col_keep;
1076 row_keep.reserve(N - k);
1077 col_keep.reserve(N - k);
1078 {
1079 long remove_idx = 0;
1080 for (long idx = 0; idx < N; ++idx) {
1081 if (remove_idx < k && idx == wk.i[remove_idx]) {
1082 ++remove_idx;
1083 } else {
1084 row_keep.push_back(idx);
1085 }
1086 }
1087 }
1088 {
1089 long remove_idx = 0;
1090 for (long idx = 0; idx < N; ++idx) {
1091 if (remove_idx < k && idx == wk.j[remove_idx]) {
1092 ++remove_idx;
1093 } else {
1094 col_keep.push_back(idx);
1095 }
1096 }
1097 }
1098
1099 // Copy remaining elements to new matrix
1100 for (long new_i = 0; new_i < static_cast<long>(row_keep.size()); ++new_i) {
1101 for (long new_j = 0; new_j < static_cast<long>(col_keep.size()); ++new_j) { mat_new(new_i, new_j) = mat(row_keep[new_i], col_keep[new_j]); }
1102 }
1103
1104 range R(0, N - k);
1105 det_new = nda::linalg::det(mat_new(R, R));
1106
1107 return det_new / det;
1108 }
1109
1110 //------------------------------------------------------------------------------------------
1111 private:
1112 // Complete the remove_k operation.
1113 void complete_remove_k() {
1114 long k = wk.k;
1115 N -= k;
1116
1117 // Erase in reverse order (largest index first) to maintain correct positions
1118 for (long l = k - 1; l >= 0; --l) {
1119 x_values.erase(begin(x_values) + wk.i[l]);
1120 y_values.erase(begin(y_values) + wk.j[l]);
1121 }
1122
1123 std::swap(mat, mat_new);
1124 }
1125
1126 //------------------------------------------------------------------------------------------
1127 public:
1140 value_type try_change_col(long j, y_type const &y) {
1141 TRIQS_ASSERT(last_try == NoTry);
1142 TRIQS_ASSERT(j < N);
1143 TRIQS_ASSERT(j >= 0);
1144 w1.j = j;
1145 last_try = ChangeCol;
1146 w1.y = y;
1147
1148 range R(0, N);
1149 mat_new(R, R) = mat(R, R);
1150 for (auto k : R) { mat_new(k, j) = f(x_values[k], y); }
1151
1152 det_new = nda::linalg::det(mat_new(R, R));
1153
1154 return det_new / det;
1155 }
1156
1157 //------------------------------------------------------------------------------------------
1158 private:
1159 // Complete the change column operation.
1160 void complete_change_col() {
1161 y_values[w1.j] = w1.y;
1162 std::swap(mat, mat_new);
1163 }
1164
1165 //------------------------------------------------------------------------------------------
1166 public:
1179 value_type try_change_row(long i, x_type const &x) {
1180 TRIQS_ASSERT(last_try == NoTry);
1181 TRIQS_ASSERT(i < N);
1182 TRIQS_ASSERT(i >= 0);
1183 w1.i = i;
1184 last_try = ChangeRow;
1185 w1.x = x;
1186
1187 range R(0, N);
1188 mat_new(R, R) = mat(R, R);
1189 for (auto k : R) { mat_new(i, k) = f(x, y_values[k]); }
1190
1191 det_new = nda::linalg::det(mat_new(R, R));
1192
1193 return det_new / det;
1194 }
1195 //------------------------------------------------------------------------------------------
1196 private:
1197 // Complete the change row operation.
1198 void complete_change_row() {
1199 x_values[w1.i] = w1.x;
1200 std::swap(mat, mat_new);
1201 }
1202
1203 //------------------------------------------------------------------------------------------
1204 public:
1220 value_type try_change_col_row(long i, long j, x_type const &x, y_type const &y) {
1221 TRIQS_ASSERT(last_try == NoTry);
1222 TRIQS_ASSERT(j < N);
1223 TRIQS_ASSERT(j >= 0);
1224 TRIQS_ASSERT(i < N);
1225 TRIQS_ASSERT(i >= 0);
1226
1227 last_try = ChangeRowCol;
1228 w1.i = i;
1229 w1.j = j;
1230 w1.x = x;
1231 w1.y = y;
1232
1233 range R(0, N);
1234 mat_new(R, R) = mat(R, R);
1235
1236 for (auto k : R) {
1237 mat_new(i, k) = f(x, y_values[k]);
1238 mat_new(k, j) = f(x_values[k], y);
1239 }
1240 mat_new(i, j) = f(x, y);
1241
1242 det_new = nda::linalg::det(mat_new(R, R));
1243
1244 return det_new / det;
1245 }
1246
1247 //------------------------------------------------------------------------------------------
1248 private:
1249 // Complete the change row and column operation.
1250 void complete_change_col_row() {
1251 x_values[w1.i] = w1.x;
1252 y_values[w1.j] = w1.y;
1253 std::swap(mat, mat_new);
1254 }
1255
1256 //------------------------------------------------------------------------------------------
1257 public:
1273 template <typename ArgumentContainer1, typename ArgumentContainer2>
1274 value_type try_refill(ArgumentContainer1 const &X, ArgumentContainer2 const &Y) {
1275 TRIQS_ASSERT(last_try == NoTry);
1276 TRIQS_ASSERT(X.size() == Y.size());
1277
1278 long s = X.size();
1279 if (s > Nmax) {
1280 w_refill.reserve(2 * s);
1281 reserve(2 * s);
1282 }
1283 last_try = Refill;
1284
1285 w_refill.clear();
1286 if (s == 0) { // treat empty matrix separately
1287 det_new = 1.0;
1288 } else {
1289 std::copy(X.begin(), X.end(), std::back_inserter(w_refill.x_values));
1290 std::copy(Y.begin(), Y.end(), std::back_inserter(w_refill.y_values));
1291 for (long i = 0; i < s; ++i)
1292 for (long j = 0; j < s; ++j) mat_new(i, j) = f(w_refill.x_values[i], w_refill.y_values[j]);
1293
1294 range R(0, s);
1295 det_new = nda::linalg::det(mat_new(R, R));
1296 }
1297
1298 return det_new / det;
1299 }
1300
1301 //------------------------------------------------------------------------------------------
1302 private:
1303 // Complete the refill operation.
1304 void complete_refill() {
1305 N = w_refill.x_values.size();
1306
1307 // special empty case again
1308 if (N == 0) {
1309 clear();
1310 return;
1311 }
1312
1313 std::swap(x_values, w_refill.x_values);
1314 std::swap(y_values, w_refill.y_values);
1315 std::swap(mat, mat_new);
1316 }
1317
1318 //------------------------------------------------------------------------------------------
1319
1320 public:
1328 switch (last_try) {
1329 case (Insert): complete_insert(); break;
1330 case (Remove): complete_remove(); break;
1331 case (ChangeCol): complete_change_col(); break;
1332 case (ChangeRow): complete_change_row(); break;
1333 case (ChangeRowCol): complete_change_col_row(); break;
1334 case (Insert2): complete_insert2(); break;
1335 case (Remove2): complete_remove2(); break;
1336 case (InsertK): complete_insert_k(); break;
1337 case (RemoveK): complete_remove_k(); break;
1338 case (Refill): complete_refill(); break;
1339 case (NoTry): return; break;
1340 default: TRIQS_RUNTIME_ERROR << "Misuing det_manip_basic"; // Never used?
1341 }
1342
1343 mat_inverse_is_valid = false;
1344 det = det_new;
1345 ++n_opts;
1346
1347 last_try = NoTry;
1348 }
1349
1354 void reject_last_try() { last_try = NoTry; }
1355
1356 // ----------------- A few short cuts -----------------
1357
1358 public:
1368 value_type insert(long i, long j, x_type const &x, y_type const &y) {
1369 auto r = try_insert(i, j, x, y);
1371 return r;
1372 }
1373
1381 value_type insert_at_end(x_type const &x, y_type const &y) { return insert(N, N, x, y); }
1382
1392 value_type insert2(long i0, long i1, long j0, long j1, x_type const &x0, x_type const &x1, y_type const &y0, y_type const &y1) {
1393 auto r = try_insert2(i0, i1, j0, j1, x0, x1, y0, y1);
1395 return r;
1396 }
1397
1405 value_type insert2_at_end(x_type const &x0, x_type const &x1, y_type const &y0, y_type const &y1) {
1406 return insert2(N, N + 1, N, N + 1, x0, x1, y0, y1);
1407 }
1408
1416 value_type remove(long i, long j) {
1417 auto r = try_remove(i, j);
1419 return r;
1420 }
1421
1427 value_type remove_at_end() { return remove(N - 1, N - 1); }
1428
1436 value_type remove2(long i0, long i1, long j0, long j1) {
1437 auto r = try_remove2(i0, i1, j0, j1);
1439 return r;
1440 }
1441
1447 value_type remove2_at_end() { return remove2(N - 1, N - 2, N - 1, N - 2); }
1448
1456 value_type change_col(long j, y_type const &y) {
1457 auto r = try_change_col(j, y);
1459 return r;
1460 }
1461
1469 value_type change_row(long i, x_type const &x) {
1470 auto r = try_change_row(i, x);
1472 return r;
1473 }
1474
1485 value_type change_one_row_and_one_col(long i, long j, x_type const &x, y_type const &y) {
1486 auto r = try_change_col_row(i, j, x, y);
1488 return r;
1489 }
1490
1503 enum RollDirection { None, Up, Down, Left, Right };
1504
1519 switch (roll) {
1520 case (None): return 1;
1521 case (Down): std::rotate(begin(x_values), end(x_values) - 1, end(x_values)); break;
1522 case (Up): std::rotate(begin(x_values), begin(x_values) + 1, end(x_values)); break;
1523 case (Right): std::rotate(begin(y_values), end(y_values) - 1, end(y_values)); break;
1524 case (Left): std::rotate(begin(y_values), begin(y_values) + 1, end(y_values)); break;
1525 default: assert(0);
1526 }
1527 for (long i = 0; i < N; ++i)
1528 for (long j = 0; j < N; ++j) mat(i, j) = f(x_values[i], y_values[j]);
1529 // signature of the cycle of order N : (-1)^(N-1)
1530 if ((N - 1) % 2 == 1) {
1531 det = -det;
1532 return -1;
1533 }
1534 return 1;
1535 }
1536 };
1537
1538} // namespace triqs::det_manip
iterator end()
Get an iterator past the last block.
iterator begin()
Get an iterator to the first block.
Backward-compatibility umbrella header pulling in the nda array library.
Provides a trait inspecting the operator() of a callable type.
Simple reference implementation of determinant manipulation for CTQMC solvers.
value_type change_col(long j, y_type const &y)
Change one column.
x_type const & get_x(long i) const
Get the matrix builder argument that determines the elements of the ith row.
value_type change_row(long i, x_type const &x)
Change one row.
friend void h5_read(h5::group fg, std::string subgroup_name, det_manip_basic &g)
Read a triqs::det_manip::det_manip_basic object from HDF5.
value_type try_change_row(long i, x_type const &x)
Try to change one row in the matrix .
matrix_type matrix() const
Get the matrix .
value_type try_remove_k(std::vector< long > i, std::vector< long > j)
Try to remove rows and columns.
value_type try_insert2(long i0, long i1, long j0, long j1, x_type const &x0_, x_type const &x1_, y_type const &y0_, y_type const &y1_)
Try to insert two rows and columns.
value_type try_insert(long i, long j, x_type const &x, y_type const &y)
Try to insert one row and column.
auto insert_ratios(long i, long j, X const &xs, Y const &ys) const -> nda::array< value_type, nda::get_rank< X > >
Compute independent single-insertion determinant ratios at position for paired elements of xs and ys...
value_type try_insert_k(std::vector< long > i, std::vector< long > j, std::vector< x_type > x, std::vector< y_type > y)
Try to insert rows and columns.
value_type matrix(int i, int j) const
Get an element of the matrix .
value_type try_change_col(long j, y_type const &y)
Try to change one column in the matrix .
det_manip_basic(FunctionType F, ArgumentContainer1 const &X, ArgumentContainer2 const &Y)
Construct a det_manip_basic object with a callable FunctionType and two containers holding the argume...
value_type remove_at_end()
Remove the last row and column of the matrix.
value_type try_refill(ArgumentContainer1 const &X, ArgumentContainer2 const &Y)
Try to fill the matrix with new elements.
value_type inverse_matrix(int i, int j) const
Get an element of the inverse matrix .
void clear()
Clear the data storages and reset the matrix to size zero.
value_type try_remove2(long i0, long i1, long j0, long j1)
Try to remove two rows and two columns.
auto determinant()
Get the determinant of the matrix .
int roll_matrix(RollDirection roll)
Perform a circular shift permutation on the rows or columns of the matrix .
value_type insert2(long i0, long i1, long j0, long j1, x_type const &x0, x_type const &x1, y_type const &y0, y_type const &y1)
Insert two rows and columns.
FunctionType const & get_function() const
Get the callable FunctionType object used as the matrix builder.
friend void h5_write(h5::group fg, std::string subgroup_name, det_manip_basic const &g)
Write a triqs::det_manip::det_manip_basic object to HDF5.
auto get_y() const
Get a vector with all matrix builder arguments .
value_type try_remove(long i, long j)
Try to remove one row and column.
auto const & get_x_internal_order() const
Get the matrix builder arguments in internal storage order.
det_manip_basic(FunctionType F, long init_size)
Construct a det_manip_basic object with a callable FunctionType and an initial capacity for the data ...
value_type inverse_matrix_internal_order(int i, int j) const
Get an element of the inverse matrix in internal storage order.
void complete_operation()
Complete the last try-operation.
value_type try_change_col_row(long i, long j, x_type const &x, y_type const &y)
Try to change one column and one row in the matrix .
matrix_type build_matrix_scratch()
Build the matrix from scratch from the stored arguments.
auto get_x() const
Get a vector with all matrix builder arguments .
value_type remove(long i, long j)
Remove one row and column.
RollDirection
Direction of the roll_matrix() operation.
nda::matrix_const_view< value_type > inverse_matrix() const
Get the full inverse matrix .
y_type const & get_y(long j) const
Get the matrix builder argument that determines the elements of the jth column.
auto size() const
Get the current size of the matrix.
auto const & get_y_internal_order() const
Get the matrix builder arguments in internal storage order.
value_type remove2(long i0, long i1, long j0, long j1)
Remove two rows and columns.
value_type change_one_row_and_one_col(long i, long j, x_type const &x, y_type const &y)
Change one row and one column.
value_type remove2_at_end()
Remove the last two rows and columns of the matrix.
nda::matrix_const_view< value_type > inverse_matrix_internal_order() const
Get the full inverse matrix in internal storage order.
value_type insert2_at_end(x_type const &x0, x_type const &x1, y_type const &y0, y_type const &y1)
Insert two rows and columns at the end of the matrix.
void reject_last_try()
Reject the last try-operation.
value_type insert_at_end(x_type const &x, y_type const &y)
Insert one row and column at the end of the matrix.
value_type insert(long i, long j, x_type const &x, y_type const &y)
Insert one row and column.
void reserve(long new_size, long new_k=1)
Reserve memory to increase the capacity of the data storages.
Compiler / platform glue and the dcomplex alias (must be included before any Boost header).
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
#define TRIQS_ASSERT(X)
Throw a triqs::runtime_error if the boolean expression X evaluates to false.
Type trait for a callable type with a single, non-overloaded operator().