TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
extractors.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-2021 Simons Foundation
4// Copyright (c) 2015-2017 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: Thomas Ayral, Michel Ferrero, Igor Krivenko, Olivier Parcollet, Nils Wentzell
20
25
26#pragma once
27
29#include "../../arrays.hpp"
32
33#include <complex>
34#include <map>
35#include <string>
36#include <tuple>
37#include <variant>
38
39namespace triqs::operators::utils {
40
45
46 // Elevate `nda::array` to the `triqs::operators::utils` namespace.
47 using nda::array;
48
49 // Elevate triqs::hilbert_space::fundamental_operator_set::indices_t to the `triqs::operators::utils` namespace.
51
53 template <typename T> using op_t = operators::many_body_operator_generic<T>;
54
56 template <typename T> using dict2_t = std::map<std::tuple<indices_t, indices_t>, T>;
57
59 template <typename T> using dict4_t = std::map<std::tuple<indices_t, indices_t, indices_t, indices_t>, T>;
60
62 template <int N> using real_or_complex_array = std::variant<array<double, N>, array<std::complex<double>, N>>;
63
65 template <typename T> using block_matrix_t = array<nda::matrix<T>, 1>;
66
87 template <typename T> [[nodiscard]] dict2_t<T> extract_h_dict(op_t<T> const &h, bool ignore_irrelevant = false) {
88 auto h_dict = dict2_t<T>{};
89
90 for (auto const &term : h) {
91 auto const &coef = term.coef;
92 auto const &m = term.monomial;
93
94 if (m.size() == 2) {
95 if (!(m[0].dagger && !m[1].dagger)) {
96 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_h_dict: monomial is not of the form C^+(i) C(j)";
97 } else { // everything ok
98 h_dict.insert({std::make_tuple(m[0].indices, m[1].indices), coef});
99 }
100 } else {
101 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_h_dict: monomial must have 2 operators";
102 }
103 }
104
105 return h_dict;
106 }
107
130 template <typename T> [[nodiscard]] dict2_t<T> extract_U_dict2(op_t<T> const &h, bool ignore_irrelevant = false) {
131 auto U_dict = dict2_t<T>{};
132
133 for (auto const &term : h) {
134 auto const &coef = term.coef;
135 auto const &m = term.monomial;
136
137 if (m.size() == 4) {
138 if (!(m[0].dagger && m[1].dagger && !m[2].dagger && !m[3].dagger) || (m[0].indices != m[3].indices) || (m[1].indices != m[2].indices)) {
139 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_U_dict2: monomial is not of the form C^+(i) C^+(j) C(j) C(i)";
140 } else { //everything ok
141 U_dict.insert({std::make_tuple(m[0].indices, m[1].indices), coef});
142 U_dict.insert({std::make_tuple(m[1].indices, m[0].indices), coef});
143 }
144 } else {
145 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_U_dict2: monomial must have 4 operators";
146 }
147 }
148
149 return U_dict;
150 }
151
174 template <typename T> [[nodiscard]] dict4_t<T> extract_U_dict4(op_t<T> const &h, bool ignore_irrelevant = false) {
175 auto U_dict = dict4_t<T>{};
176
177 for (auto const &term : h) {
178 T const &coef = term.coef;
179 auto const &m = term.monomial;
180
181 if (m.size() == 4) {
182 if (!(m[0].dagger && m[1].dagger && !m[2].dagger && !m[3].dagger)) {
183 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_U_dict4: monomial is not of the form C^+(i) C^+(j) C(l) C(k)";
184 } else { // everything ok
185 U_dict.insert({std::make_tuple(m[0].indices, m[1].indices, m[3].indices, m[2].indices), T(0.5) * coef});
186 U_dict.insert({std::make_tuple(m[1].indices, m[0].indices, m[2].indices, m[3].indices), T(0.5) * coef});
187 U_dict.insert({std::make_tuple(m[0].indices, m[1].indices, m[2].indices, m[3].indices), T(-0.5) * coef});
188 U_dict.insert({std::make_tuple(m[1].indices, m[0].indices, m[3].indices, m[2].indices), T(-0.5) * coef});
189 }
190 } else {
191 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "extract_U_dict4: monomial must have 4 operators";
192 }
193 }
194
195 return U_dict;
196 }
197
216 template <typename T = double, typename D, std::size_t R = std::tuple_size_v<typename D::key_type>>
217 [[nodiscard]] array<T, R> dict_to_matrix(D const &dict, hilbert_space::fundamental_operator_set const &fs) {
219
220 // check if a given alpha_i is in the fops and return its linear index
221 auto indices_to_linear = [&fs](indices_t const &indices) {
222 if (!fs.has_indices(indices))
223 TRIQS_RUNTIME_ERROR << "dict_to_matrix: key [" << format_indices(indices) << "] of dict not in fundamental_operator_set/gf_struct";
224 return fs[indices];
225 };
226
227 // create and fill the coefficient array
228 auto arr = nda::zeros<T>(nda::stdutil::make_initialized_array<R>(fs.size()));
229 for (auto const &[key, value] : dict) std::apply([&](auto const &...ks) -> auto & { return arr(indices_to_linear(ks)...); }, key) = T(value);
230 return arr;
231 }
232
247 template <typename D, std::size_t R = std::tuple_size_v<typename D::key_type>>
249 for (auto const &[key, value] : dict) {
250 if (!value.is_real()) return dict_to_matrix<std::complex<double>>(dict, fs);
251 }
252 return dict_to_matrix<double>(dict, fs);
253 }
254
266 template <typename T> [[nodiscard]] op_t<T> filter_op(op_t<T> const &h, long len) {
267 auto h_filtered = op_t<T>{};
268 for (auto const &term : h) {
269 if (term.monomial.size() == len) h_filtered += term;
270 }
271 return h_filtered;
272 }
273
281 template <typename T> [[nodiscard]] op_t<T> quadratic_terms(op_t<T> const &h) { return filter_op(h, 2); }
282
290 template <typename T> [[nodiscard]] op_t<T> quartic_terms(op_t<T> const &h) { return filter_op(h, 4); }
291
312 template <typename T>
314 bool ignore_irrelevant = false) {
315 auto n_bl = gf_struct.size();
316 auto bl_mat = nda::array<nda::matrix<T>, 1>(n_bl);
317 for (auto bl : range(n_bl)) {
318 auto bl_size = gf_struct[bl].second;
319 bl_mat[bl] = nda::zeros<T>(bl_size, bl_size);
320 }
321
322 auto name_to_bl = [&](auto &bl_name) {
323 auto it =
324 std::find_if(cbegin(gf_struct), cend(gf_struct), [&bl_name](auto const &blname_and_size) { return bl_name == blname_and_size.first; });
325 return std::distance(cbegin(gf_struct), it);
326 };
327
328 for (auto const &term : h) {
329 auto const &m = term.monomial;
330 T const &coef = term.coef;
331
332 if (m.size() == 2 and m[0].dagger and not m[1].dagger and m[0].indices[0] == m[1].indices[0] and m[0].indices.size() == 2
333 and m[1].indices.size() == 2) {
334 auto bl_name = std::get<std::string>(m[0].indices[0]);
335 auto op1_idx = std::get<long>(m[0].indices[1]);
336 auto op2_idx = std::get<long>(m[1].indices[1]);
337
338 bl_mat[name_to_bl(bl_name)](op1_idx, op2_idx) = coef;
339 } else {
340 if (!ignore_irrelevant) TRIQS_RUNTIME_ERROR << "block_matrix_from_op: Operator term is not of the form 'coeff * c_dag{bl,i} * c_{bl,j}'";
341 }
342 }
343
344 return bl_mat;
345 }
346
361 template <typename T> [[nodiscard]] op_t<T> op_from_block_matrix(block_matrix_t<T> const &bl_mat, hilbert_space::gf_struct_t const &gf_struct) {
362 EXPECTS(bl_mat.size() == gf_struct.size());
363 auto h = op_t<T>{};
364 for (long bl = 0; auto const &[bl_name, bl_size] : gf_struct) {
365 EXPECTS(bl_mat[bl].shape() == (std::array{bl_size, bl_size}));
366 for (auto [i, j] : itertools::product_range(bl_size, bl_size)) h += bl_mat[bl](i, j) * c_dag(bl_name, i) * c(bl_name, j);
367 ++bl;
368 }
369 return h;
370 }
371
373
374} // namespace triqs::operators::utils
auto cend()
Get a const iterator past the last block.
gf_struct_t gf_struct() const
Get the block structure.
auto cbegin()
Get a const iterator to the first block.
Backward-compatibility umbrella header pulling in the nda array library.
Class representing a fundamental operator set.
triqs::hilbert_space::indices_t indices_t
Index type to represent a single .
bool has_indices(indices_t const &alpha) const
Check if a given is in the set.
auto size() const
Get the number of single particle state indices in the set.
Compiler / platform glue and the dcomplex alias (must be included before any Boost header).
std::vector< std::pair< std::string, long > > gf_struct_t
Type describing the structure of a block Green's function.
Definition gf_struct.hpp:41
std::string format_indices(indices_t const &alpha, std::string_view sep, std::string_view prefix, std::string_view suffix)
String representation of a single particle state index .
array< T, R > dict_to_matrix(D const &dict, hilbert_space::fundamental_operator_set const &fs)
Convert a coefficient dictionary into a dense rank-N array indexed by integers from a fundamental ope...
dict4_t< T > extract_U_dict4(op_t< T > const &h, bool ignore_irrelevant=false)
Extract the coefficients of a general two-particle interaction operator.
real_or_complex_array< R > dict_to_variant_matrix(D const &dict, hilbert_space::fundamental_operator_set const &fs)
Convert a real or complex valued coefficient dictionary into a real_or_complex_array.
dict2_t< T > extract_U_dict2(op_t< T > const &h, bool ignore_irrelevant=false)
Extract the coefficients of a density-density interaction operator.
op_t< T > quadratic_terms(op_t< T > const &h)
Keep only quadratic terms of a many-body operator .
std::map< std::tuple< indices_t, indices_t >, T > dict2_t
Map from an index pair to a coefficient of type T.
op_t< T > op_from_block_matrix(block_matrix_t< T > const &bl_mat, hilbert_space::gf_struct_t const &gf_struct)
Build a block-diagonal quadratic operator from its block-matrix representation.
op_t< T > filter_op(op_t< T > const &h, long len)
Keep only terms of a given length of a many-body operator .
op_t< T > quartic_terms(op_t< T > const &h)
Keep only quartic terms of a many-body operator .
std::map< std::tuple< indices_t, indices_t, indices_t, indices_t >, T > dict4_t
Map from an index quadruple to a coefficient of type T.
array< nda::matrix< T >, 1 > block_matrix_t
Type of a block matrix.
std::variant< array< double, N >, array< std::complex< double >, N > > real_or_complex_array
Variant of a rank-N array that can hold either real or complex values.
block_matrix_t< T > block_matrix_from_op(op_t< T > const &h, hilbert_space::gf_struct_t const &gf_struct, bool ignore_irrelevant=false)
Convert a block-diagonal quadratic operator into its block-matrix representation.
dict2_t< T > extract_h_dict(op_t< T > const &h, bool ignore_irrelevant=false)
Extract the coefficients of a normal-ordered quadratic operator.
operators::many_body_operator_generic< T > op_t
Alias for triqs::operators::many_body_operator_generic.
many_body_operator_generic< T > c_dag(IndexTypes... indices)
Create a creation 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.
Provides a fundamental operator set class.
Provides generic many-body operators.