TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
space_partition.hpp
Go to the documentation of this file.
1// Copyright (c) 2015-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2015-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2023 Simons Foundation
4// Copyright (c) 2015-2016 Igor Krivenko
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: Maxime Charlebois, Michel Ferrero, Igor Krivenko, Olivier Parcollet, Nils Wentzell
20
25
26#pragma once
27
28#include "./state.hpp"
30
31#include <boost/pending/disjoint_sets.hpp>
32
33#include <cstdint>
34#include <map>
35#include <set>
36#include <utility>
37
38namespace triqs::hilbert_space {
39
44
78 template <typename S, typename OP> class space_partition {
79 public:
81 using idx_t = uint32_t;
82
84 using state_t = S;
85
87 using operator_t = OP;
88
90 using amplitude_t = typename state_t::value_type;
91
93 using block_mapping_t = std::set<std::pair<idx_t, idx_t>>;
94
102 using matrix_element_map_t = std::map<std::pair<idx_t, idx_t>, amplitude_t>;
103
129 space_partition(state_t const &psi, operator_t const &H, bool store_matrix_elements = true, operator_t const &delta = operator_t())
130 : tmp_state(make_zero_state(psi)), subspaces(psi.size()) {
131 auto size = tmp_state.size();
132
133 // Iteration over all initial basis states
134 for (idx_t i = 0; i < size; ++i) {
135 tmp_state(i) = amplitude_t(1);
136 state_t final_state = H(tmp_state);
137
138 auto mapping = [&](idx_t f, amplitude_t amplitude) {
140 if (is_zero(amplitude)) return;
141 auto i_subspace = subspaces.find_set(i);
142 auto f_subspace = subspaces.find_set(f);
143 if (i_subspace != f_subspace) subspaces.link(i_subspace, f_subspace);
144
145 if (store_matrix_elements) matrix_elements[std::make_pair(i, f)] = amplitude;
146 };
147
148 // Iterate over non-zero final amplitudes
149 foreach (final_state, mapping);
150
151 // redo for additionnal Hyb
152 if (not delta.is_empty()) {
153 final_state = delta(tmp_state);
154 foreach (final_state, mapping);
155 }
156
157 tmp_state(i) = amplitude_t(0.);
158 }
159
160 _update_index();
161 }
162
165
195 auto merge_subspaces(operator_t const &cd, operator_t const &c, bool store_matrix_elements = true) {
196
197 matrix_element_map_t Cd_elements, C_elements;
198 std::multimap<idx_t, idx_t> Cd_connections, C_connections;
199
200 auto size = tmp_state.size();
201
202 // Fill connection multimaps
203 for (idx_t i = 0; i < size; ++i) {
204 tmp_state(i) = amplitude_t(1);
205 auto i_subspace = subspaces.find_set(i);
206
207 auto fill_conn = [this, i, i_subspace, store_matrix_elements](operator_t const &op, std::multimap<idx_t, idx_t> &conn,
208 matrix_element_map_t &elem) {
209 state_t final_state = op(tmp_state);
210 // Iterate over non-zero final amplitudes
211 foreach (final_state, [&](idx_t f, amplitude_t amplitude) {
213 if (is_zero(amplitude)) return;
214 auto f_subspace = subspaces.find_set(f);
215 conn.insert({i_subspace, f_subspace});
216 if (store_matrix_elements) elem[{i, f}] = amplitude;
217 });
218 };
219
220 fill_conn(cd, Cd_connections, Cd_elements);
221 fill_conn(c, C_connections, C_elements);
222
223 tmp_state(i) = amplitude_t(0.);
224 }
225
226 // 'Zigzag' traversal algorithm
227 while (!Cd_connections.empty()) {
228
229 // Take one C^+ - connection
230 // C^+|lower_subspace> = |upper_subspace>
231 auto const [lower_subspace, upper_subspace] = *std::begin(Cd_connections);
232
233 // - Reveals all subspaces reachable from lower_subspace by application of
234 // a 'zigzag' product C^+ C C^+ C C^+ ... of any length.
235 // - Removes all visited connections from Cd_connections/C_connections.
236 // - Merges lower_subspace with all subspaces generated from lower_subspace by application of (C C^+)^(2*n).
237 // - Merges upper_subspace with all subspaces generated from upper_subspace by application of (C^+ C)^(2*n).
238 std::function<void(idx_t, bool)> zigzag_traversal = [this, lower_subspace, upper_subspace, &Cd_connections, &C_connections,
239 &zigzag_traversal](idx_t i_subspace, // find all connections starting from i_subspace
240 bool upwards // if true, C^+ connection, otherwise C connection
241 ) {
242 std::multimap<idx_t, idx_t>::iterator it;
243 while ((it = (upwards ? Cd_connections : C_connections).find(i_subspace)) != (upwards ? Cd_connections : C_connections).end()) {
244
245 auto f_subspace = it->second;
246 (upwards ? Cd_connections : C_connections).erase(it);
247
248 if (upwards)
249 subspaces.link(f_subspace, upper_subspace);
250 else
251 subspaces.link(f_subspace, lower_subspace);
252
253 // Recursively apply to all found f_subspace's with a 'flipped' direction
254 zigzag_traversal(f_subspace, !upwards);
255 }
256 };
257
258 // Apply to all C^+ connections starting from lower_subspace
259 zigzag_traversal(lower_subspace, true);
260 }
261
262 _update_index();
263
264 return std::make_pair(Cd_elements, C_elements);
265 }
266
271 idx_t n_subspaces() const { return representative_to_index.size(); }
272
284 template <typename F> friend void foreach (space_partition &sp, F f) {
285 for (idx_t n = 0; n < sp.tmp_state.size(); ++n) f(n, sp.lookup_basis_state(n));
286 }
287
295 idx_t lookup_basis_state(idx_t f) { return representative_to_index[subspaces.find_set(f)]; }
296
306 matrix_element_map_t const &get_matrix_elements() const { return matrix_elements; }
307
321 block_mapping_t find_mappings(operator_t const &op, bool diagonal_only = false) {
322
323 block_mapping_t mapping;
324
325 // Iteration over all initial basis states
326 for (idx_t i = 0; i < tmp_state.size(); ++i) {
327 state_t initial_state = tmp_state;
328 initial_state(i) = amplitude_t(1);
329 auto i_subspace = subspaces.find_set(i);
330
331 state_t final_state = op(initial_state);
332
333 // Iterate over non-zero final amplitudes
334 foreach (final_state, [&](idx_t f, amplitude_t amplitude) {
336 if (is_zero(amplitude)) return;
337 auto f_subspace = subspaces.find_set(f);
338 if ((!diagonal_only) || i_subspace == f_subspace)
339 mapping.insert(std::make_pair(representative_to_index[i_subspace], representative_to_index[f_subspace]));
340 });
341 }
342
343 return mapping;
344 }
345
346 private:
347 void _update_index() {
348 auto p = subspaces.parents();
349 subspaces.compress_sets(p.begin(), p.end()); // parents are representatives
350 subspaces.normalize_sets(p.begin(), p.end()); // the representative has the smallest index in the set
351
352 // Update representative_to_index
353 representative_to_index.clear();
354 for (idx_t n = 0; n < tmp_state.size(); ++n) {
355 representative_to_index.insert(std::make_pair(subspaces.find_set(n), representative_to_index.size()));
356 }
357 }
358
359 private:
360 mutable state_t tmp_state;
361 boost::disjoint_sets_with_storage<> subspaces;
362 matrix_element_map_t matrix_elements;
363 std::map<idx_t, idx_t> representative_to_index;
364 };
365
367
368} // namespace triqs::hilbert_space
iterator end()
Get an iterator past the last block.
int size() const
Get the total number of blocks.
idx_t n_subspaces() const
Get the number of invariant subspaces in the current partition.
std::set< std::pair< idx_t, idx_t > > block_mapping_t
Set of subspace-to-subspace connections, stored as (from-subspace, to-subspace) index pairs.
std::map< std::pair< idx_t, idx_t >, amplitude_t > matrix_element_map_t
Non-vanishing matrix elements of an operator in the Fock basis.
block_mapping_t find_mappings(operator_t const &op, bool diagonal_only=false)
Find all subspace-to-subspace connections generated by a given operator.
uint32_t idx_t
Index type for basis Fock states and for invariant subspaces .
matrix_element_map_t const & get_matrix_elements() const
Get the stored non-vanishing matrix elements of the Hamiltonian.
typename state_t::value_type amplitude_t
Amplitude type of the many-body states.
OP operator_t
Imperative operator type.
space_partition(space_partition const &)=default
Default copy constructor.
idx_t lookup_basis_state(idx_t f)
Look up the invariant subspace containing a given basis Fock state.
space_partition(state_t const &psi, operator_t const &H, bool store_matrix_elements=true, operator_t const &delta=operator_t())
Construct a space partition by running Phase I of the automatic partition algorithm.
auto merge_subspaces(operator_t const &cd, operator_t const &c, bool store_matrix_elements=true)
Run Phase II of the automatic partition algorithm.
auto make_zero_state(state< HS, T, BasedOnMap > const &phi)
Create a zero state in the same Hilbert (Fock) space as the given state.
Definition state.hpp:62
bool is_zero(I const &x)
Exact zero check for integral values.
Numeric helpers overloaded for various types.
Provides a type for many-body states in a Hilbert (Fock) space.