21#include "./worker.hpp"
37using namespace triqs::hilbert_space;
39namespace triqs::atom_diag {
42#define ATOM_DIAG_WORKER_METHOD(RET, F) template <bool Complex> auto atom_diag_worker<Complex>::F->RET
47 ATOM_DIAG_WORKER_METHOD(
bool, fock_state_filter(
fock_state_t s)) {
48 auto c = std::bitset<64>(s).count();
49 return ((c >= n_min) && (c <= n_max));
54 ATOM_DIAG_WORKER_METHOD(
void, autopartition(many_body_op_t
const &hyb)) {
58 many_body_op_t
const &h = hdiag->get_h_atomic();
61 imperative_operator_t hamiltonian(h, fops);
62 imperative_operator_t hybridization(hyb, fops);
63 state<class hilbert_space, scalar_t, true> st(hdiag->full_hs);
67 space_partition_t SP(st, hamiltonian,
false, hybridization);
69 std::vector<typename space_partition_t::matrix_element_map_t> creation_melem(fops.size());
70 std::vector<typename space_partition_t::matrix_element_map_t> annihilation_melem(fops.size());
72 for (
auto const &o : fops) {
73 auto create = many_body_op_t::make_canonical(
true, o.index);
74 auto destroy = many_body_op_t::make_canonical(
false, o.index);
76 imperative_operator_t op_c_dag(create, fops), op_c(destroy, fops);
78 int n = o.linear_index;
79 std::tie(creation_melem[n], annihilation_melem[n]) = SP.merge_subspaces(op_c_dag, op_c,
true);
83 auto &h_spaces = hdiag->sub_hilbert_spaces;
85 h_spaces.reserve(SP.n_subspaces());
86 for (
int sp = 0; sp < SP.n_subspaces(); ++sp) h_spaces.emplace_back(sp);
89 if (fock_state_filter(s)) h_spaces[spn].add_fock_state(s);
93 h_spaces.erase(std::remove_if(h_spaces.begin(), h_spaces.end(), [](
sub_hilbert_space const &sp) { return sp.size() == 0; }), h_spaces.end());
96 std::map<int, int> remap;
97 for (
auto const &sp : h_spaces) remap.emplace(sp.
get_index(), remap.size());
100 hdiag->creation_connection.resize(fops.size(), h_spaces.size());
101 hdiag->annihilation_connection.resize(fops.size(), h_spaces.size());
102 hdiag->creation_connection.as_array_view() = -1;
103 hdiag->annihilation_connection.as_array_view() = -1;
105 for (
auto const &o : fops) {
106 int n = o.linear_index;
107 for (
auto const &[fs_pair, val] : creation_melem[n]) {
108 auto [i, f] = fs_pair;
109 auto i_remap_it = remap.find(SP.lookup_basis_state(i));
110 if (i_remap_it == remap.end())
continue;
111 auto f_remap_it = remap.find(SP.lookup_basis_state(f));
112 if (f_remap_it == remap.end())
continue;
113 hdiag->creation_connection(n, i_remap_it->second) = f_remap_it->second;
115 for (
auto const &[fs_pair, val] : annihilation_melem[n]) {
116 auto [i, f] = fs_pair;
117 auto i_remap_it = remap.find(SP.lookup_basis_state(i));
118 if (i_remap_it == remap.end())
continue;
119 auto f_remap_it = remap.find(SP.lookup_basis_state(f));
120 if (f_remap_it == remap.end())
continue;
121 hdiag->annihilation_connection(n, i_remap_it->second) = f_remap_it->second;
126 for (
int i = 0; i < h_spaces.size(); ++i) h_spaces[i].set_index(i);
133 ATOM_DIAG_WORKER_METHOD(
void, partition_with_qn(std::vector<many_body_op_t>
const &qn_vector)) {
139 auto lt_dbl = [](std::vector<double>
const &v1, std::vector<double>
const &v2) {
140 for (
int i = 0; i < v1.size(); ++i) {
141 if (v1[i] < (v2[i] - 1e-8))
143 else if (v2[i] < (v1[i] - 1e-8))
150 std::map<std::vector<double>, int,
decltype(lt_dbl)> map_qn_n(lt_dbl);
153 std::vector<imperative_operator<class hilbert_space, scalar_t>> qsize;
154 for (
auto &qn : qn_vector) qsize.emplace_back(qn, fops);
157 auto get_quantum_numbers = [&qsize](state<class hilbert_space, scalar_t, false>
const &s) {
158 std::vector<quantum_number_t> qn;
159 for (
auto const &op : qsize) {
160 auto y = dot_product(s, op(s));
162 qn.push_back(std::real(y));
169 for (
int r = 0; r < full_hs.size(); ++r) {
175 state<class hilbert_space, scalar_t, false> s(full_hs);
179 std::vector<quantum_number_t> qn = get_quantum_numbers(s);
182 if (map_qn_n.count(qn) == 0) {
183 auto n_blocks = hdiag->sub_hilbert_spaces.size();
184 hdiag->sub_hilbert_spaces.emplace_back(n_blocks);
185 hdiag->quantum_numbers.push_back(qn);
186 map_qn_n[qn] = n_blocks;
190 hdiag->sub_hilbert_spaces[map_qn_n[qn]].add_fock_state(fs);
195 auto creation_map = std::vector<std::vector<int>>(fops.size(), std::vector<int>(hdiag->sub_hilbert_spaces.size(), -1));
196 auto annihilation_map = creation_map;
199 hdiag->creation_connection.resize(fops.size(), hdiag->sub_hilbert_spaces.size());
200 hdiag->annihilation_connection.resize(fops.size(), hdiag->sub_hilbert_spaces.size());
201 hdiag->creation_connection.as_array_view() = -1;
202 hdiag->annihilation_connection.as_array_view() = -1;
204 for (
auto const &x : fops) {
207 int n = x.linear_index;
208 auto create = many_body_op_t::make_canonical(
true, x.index);
209 auto destroy = many_body_op_t::make_canonical(
false, x.index);
215 std::vector<quantum_number_t> qn_before, qn_after;
218 for (
int r = 0; r < full_hs.size(); ++r) {
221 state<class hilbert_space, scalar_t, false> s(full_hs);
223 qn_before = get_quantum_numbers(s);
226 qn_after = get_quantum_numbers(op_c_dag(s));
230 auto origin = hdiag->sub_hilbert_spaces[map_qn_n[qn_before]].get_index();
231 auto target = hdiag->sub_hilbert_spaces[map_qn_n[qn_after]].get_index();
232 if (creation_map[n][origin] == -1)
233 creation_map[
n][origin] = target;
234 else if (creation_map[n][origin] != target)
235 TRIQS_RUNTIME_ERROR <<
"partition_with_qn(): internal error while filling creation_connection";
236 hdiag->creation_connection(n, map_qn_n[qn_before]) = map_qn_n[qn_after];
240 qn_after = get_quantum_numbers(op_c(s));
244 auto origin = hdiag->sub_hilbert_spaces[map_qn_n[qn_before]].get_index();
245 auto target = hdiag->sub_hilbert_spaces[map_qn_n[qn_after]].get_index();
246 if (annihilation_map[n][origin] == -1)
247 annihilation_map[
n][origin] = target;
248 else if (annihilation_map[n][origin] != target)
249 TRIQS_RUNTIME_ERROR <<
"partition_with_qn(): internal error while filling annihilation_connection";
250 hdiag->annihilation_connection(n, map_qn_n[qn_before]) = map_qn_n[qn_after];
259 ATOM_DIAG_WORKER_METHOD(matrix_t, make_op_matrix(many_body_op_t
const &op,
int from_spn,
int to_spn)
const) {
263 auto const &from_sp = hdiag->sub_hilbert_spaces[from_spn];
264 auto const &to_sp = hdiag->sub_hilbert_spaces[to_spn];
268 auto M = matrix_t::zeros({to_sp.size(), from_sp.size()});
270 for (
int i = 0; i < from_sp.size(); ++i) {
271 state<class hilbert_space, scalar_t, true> from_s(full_hs);
272 from_s(from_sp.get_fock_state(i)) = 1.0;
273 auto to_s = imp_op(from_s);
275 foreach (proj_s, [&](
int j, scalar_t ampl) { M(j, i) = ampl; });
278 return dagger(hdiag->eigensystems[to_spn].unitary_matrix) * M * hdiag->eigensystems[from_spn].unitary_matrix;
283 ATOM_DIAG_WORKER_METHOD(
void, complete()) {
286 many_body_op_t
const &h = hdiag->get_h_atomic();
291 int n_subspaces = hdiag->sub_hilbert_spaces.size();
292 hdiag->eigensystems.resize(n_subspaces);
293 hdiag->gs_energy = std::numeric_limits<double>::infinity();
297 double energy_split = 1.e-10;
298 for (
int spn = 0; spn < n_subspaces; ++spn) {
299 auto const &sp = hdiag->sub_hilbert_spaces[spn];
302 state<sub_hilbert_space, scalar_t, false> i_state(sp);
305 for (
int i = 0; i < sp.
size(); ++i) {
306 i_state.amplitudes()() = 0;
308 auto f_state = hamiltonian(i_state);
309 h_matrix(range::all, i) = f_state.amplitudes();
312 auto eig = linalg::eigh(h_matrix);
313 eigensystem.eigenvalues = eig.first;
314 eigensystem.unitary_matrix = eig.second;
315 hdiag->gs_energy = std::min(hdiag->gs_energy, eigensystem.eigenvalues[0]);
317 eign_map.insert({{eigensystem.eigenvalues(0) + energy_split * spn, spn}, eigensystem});
322 auto tmp = hdiag->sub_hilbert_spaces;
323 std::map<int, int> remap;
325 for (
auto const &x : eign_map) {
326 hdiag->eigensystems[i] = x.second;
327 tmp[i] = hdiag->sub_hilbert_spaces[x.first.second];
329 remap[x.first.second] = i;
332 std::swap(tmp, hdiag->sub_hilbert_spaces);
333 auto remap_connection = [&](matrix<long> &connection) {
334 auto c2 = connection;
335 for (
int n = 0;
n < first_dim(connection); ++
n)
336 for (
int j = 0; j < second_dim(connection); ++j) connection(n, remap[j]) = (c2(n, j) == -1 ? -1 : remap[
static_cast<int>(c2(n, j))]);
338 remap_connection(hdiag->creation_connection);
339 remap_connection(hdiag->annihilation_connection);
343 for (
auto &eigensystem : hdiag->eigensystems) eigensystem.
eigenvalues() -= hdiag->get_gs_energy();
345 for (
auto const &x : fops) {
347 int n = x.linear_index;
350 auto create = many_body_op_t::make_canonical(
true, x.index);
351 auto destroy = many_body_op_t::make_canonical(
false, x.index);
355 auto make_c_mat = [&](
int m, matrix<long>
const &connection, many_body_op_t
const &op) {
356 std::vector<matrix_t> cmat(second_dim(connection));
357 for (
int B = 0; B < second_dim(connection); ++B) {
358 auto Bp = connection(m, B);
359 if (Bp == -1)
continue;
360 cmat[B] = make_op_matrix(op, B, Bp);
366 hdiag->c_matrices.push_back(make_c_mat(n, hdiag->annihilation_connection, destroy));
367 hdiag->cdag_matrices.push_back(make_c_mat(n, hdiag->creation_connection, create));
375 template struct atom_diag_worker<false>;
376 template struct atom_diag_worker<true>;
Class representing a fundamental operator set.
Fermionic Hilbert (Fock) space generated by a fundamental operator set.
Representation of a many-body operator acting on many-body states.
Automatic partitioning of a Hilbert (Fock) space into invariant subspaces of a Hermitian operator.
Subspace of a fermionic Hilbert (Fock) space.
auto size() const
Get the dimension of the subspace.
auto get_index() const
Get the subspace index .
uint64_t fock_state_t
Integer type representing a fermionic fock state .
TargetState project(OriginalState const &psi, hilbert_space const &proj_hs)
Project a state to a new Hilbert (Fock) space .
nda::matrix< double > matrix_t
Matrix type for transformations involving real and reciprocal space vectors.
many_body_operator_generic< T > n(IndexTypes... indices)
Create a number operator .
many_body_operator_generic< T > c(IndexTypes... indices)
Create an annihilation operator .
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
bool is_zero(I const &x)
Exact zero check for integral values.
Provides a fundamental operator set class.
Provides a fast imperative representation of a many-body operator acting on states.
Provides generic many-body operators.
Provides the automatic partitioning algorithm of a Hilbert (Fock) space into invariant subspaces.
Provides a type for many-body states in a Hilbert (Fock) space.
Eigensystem of a single invariant subspace of the Hamiltonian .
vector< double > eigenvalues
Eigenvalues sorted in ascending order.