TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
atom_diag.hpp
Go to the documentation of this file.
1// Copyright (c) 2017-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2017-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2022 Simons Foundation
4// Copyright (c) 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: Maxime Charlebois, Michel Ferrero, Igor Krivenko, Olivier Parcollet, Hugo U. R. Strand, Nils Wentzell
20
25
26#pragma once
27
28#include "../arrays.hpp"
32#include "../utility/macros.hpp"
33
34#include <h5/h5.hpp>
35#include <itertools/itertools.hpp>
36#include <nda/h5.hpp>
37#include <nda/nda.hpp>
38
39#include <complex>
40#include <initializer_list>
41#include <iostream>
42#include <string>
43#include <type_traits>
44#include <vector>
45
46namespace triqs::atom_diag {
47
48 // Import tools from the hilbert_space and arrays namespace.
49 using namespace triqs::hilbert_space;
50 using namespace triqs::arrays;
51
52 // Forward declarations.
53 template <bool C> class atom_diag;
54 template <bool C> struct atom_diag_worker;
55 template <bool C> std::ostream &operator<<(std::ostream &, atom_diag<C> const &);
56 template <bool C> void h5_write(h5::group, std::string const &, atom_diag<C> const &);
57 template <bool C> void h5_read(h5::group, std::string const &, atom_diag<C> &);
58
63
66
68 using quantum_number_t = double;
69
91 template <bool Complex> class atom_diag {
92 public:
94 using scalar_t = std::conditional_t<Complex, std::complex<double>, double>;
95
97 using matrix_t = matrix<scalar_t>;
98
100 using block_matrix_t = std::vector<matrix_t>;
101
103 using full_hilbert_space_state_t = vector<scalar_t>;
104
107
110
118 struct C2PY_IGNORE eigensystem_t {
120 vector<double> eigenvalues;
121
124
126 bool operator==(eigensystem_t const &) const = default;
127
135 C2PY_IGNORE friend void mpi_broadcast(eigensystem_t &es, mpi::communicator c = {}, int root = 0) {
136 mpi::broadcast(es.eigenvalues, c, root);
137 mpi::broadcast(es.unitary_matrix, c, root);
138 }
139
141 [[nodiscard]] static std::string hdf5_format() { return "atom_diag::eigensystem_t"; }
142
150 friend void h5_write(h5::group g, std::string const &name, eigensystem_t const &es) {
151 auto gr = g.create_group(name);
152 h5_write(gr, "eigenvalues", es.eigenvalues);
153 h5_write(gr, "unitary_matrix", es.unitary_matrix);
154 }
155
163 friend void h5_read(h5::group g, std::string const &name, eigensystem_t &es) {
164 auto gr = g.open_group(name);
165 h5_read(gr, "eigenvalues", es.eigenvalues);
166 h5_read(gr, "unitary_matrix", es.unitary_matrix);
167 }
168 };
169
181 struct C2PY_IGNORE op_block_mat_t {
183 array<long, 1> connection;
184
186 std::vector<matrix_t> block_mat;
187
197
199 int n_blocks() const { return block_mat.size(); }
200
208 friend std::ostream &operator<<(std::ostream &os, op_block_mat_t const &op_mat) {
209 os << "Operator block matrix:\n"
210 << " n_blocks = " << op_mat.n_blocks() << "\n";
211 for (auto bidx : range(op_mat.n_blocks())) {
212 auto &m = op_mat.block_mat[bidx];
213 auto b2 = op_mat.connection(bidx);
214 os << "Block: "
215 << "blocks (" << bidx << ", " << b2 << ") "
216 << "size (" << first_dim(m) << ", " << second_dim(m) << ") " << op_mat.block_mat[bidx] << "\n";
217 }
218 return os;
219 };
220 };
221
223 C2PY_IGNORE atom_diag() = default;
224
238
254
268 atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, int n_min, int n_max);
269
284 atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, std::vector<many_body_op_t> const &qn_vector);
285
295 C2PY_IGNORE atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, std::initializer_list<many_body_op_t> const &init_lst)
296 : atom_diag(h, fops, std::vector<many_body_op_t>{init_lst}) {};
297
299 C2PY_IGNORE many_body_op_t const &get_h_atomic() const { return h_atomic; }
300
302 C2PY_PROPERTY_GET(h_atomic) operators::many_body_operator get_h_atomic_as_mbop() const { return h_atomic; }
303
305 C2PY_IGNORE fundamental_operator_set const &get_fops() const { return fops; }
306
308 C2PY_PROPERTY_GET(fops) fops_data_t const &get_fops_as_data() const { return fops.data(); }
309
311 C2PY_IGNORE class hilbert_space const &get_full_hilbert_space() const { return full_hs; }
312
314 C2PY_PROPERTY_GET(full_hilbert_space_dim) int get_full_hilbert_space_dim() const { return full_hs.size(); }
315
317 C2PY_PROPERTY_GET(n_subspaces) int n_subspaces() const { return eigensystems.size(); }
318
325 int get_subspace_dim(int sp_index) const { return eigensystems[sp_index].eigenvalues.size(); }
326
332 std::vector<int> get_subspace_dims() const {
333 auto dims = std::vector<int>(n_subspaces());
334 for (long i : range(n_subspaces())) dims[i] = get_subspace_dim(i);
335 return dims;
336 }
337
344 C2PY_IGNORE std::vector<fock_state_t> const &get_fock_states(int sp_index) const { return sub_hilbert_spaces[sp_index].get_all_fock_states(); }
345
352 C2PY_PROPERTY_GET(fock_states) std::vector<std::vector<fock_state_t>> get_fock_states() const {
353 std::vector<std::vector<fock_state_t>> fock_states(n_subspaces());
354 for (auto i : range(n_subspaces())) fock_states[i] = sub_hilbert_spaces[i].get_all_fock_states();
355 return fock_states;
356 }
357
365 matrix<scalar_t> const &get_unitary_matrix(int sp_index) const { return eigensystems[sp_index].unitary_matrix; }
366
372 C2PY_PROPERTY_GET(unitary_matrices) std::vector<matrix<scalar_t>> get_unitary_matrices() const {
373 std::vector<matrix<scalar_t>> umat(n_subspaces());
374 for (auto i : range(n_subspaces())) umat[i] = get_eigensystems()[i].unitary_matrix;
375 return umat;
376 }
377
391 int flatten_subspace_index(int sp_index, int i) const { return first_eigenstate_of_subspace[sp_index] + i; }
392
400 C2PY_IGNORE range index_range_of_subspace(int sp_index) const {
401 return range{first_eigenstate_of_subspace[sp_index], first_eigenstate_of_subspace[sp_index] + get_subspace_dim(sp_index)};
402 }
403
405 C2PY_IGNORE std::vector<eigensystem_t> const &get_eigensystems() const { return eigensystems; }
406
414 double get_eigenvalue(int sp_index, int i) const { return eigensystems[sp_index].eigenvalues[i]; }
415
422 C2PY_PROPERTY_GET(energies) std::vector<std::vector<double>> get_energies() const;
423
430 C2PY_PROPERTY_GET(quantum_numbers) std::vector<std::vector<quantum_number_t>> const &get_quantum_numbers() const { return quantum_numbers; }
431
433 C2PY_PROPERTY_GET(gs_energy) double get_gs_energy() const { return gs_energy; }
434
436 C2PY_PROPERTY_GET(vacuum_subspace_index) long get_vacuum_subspace_index() const { return vacuum_subspace_index; }
437
445 C2PY_PROPERTY_GET(vacuum_state) full_hilbert_space_state_t const &get_vacuum_state() const { return vacuum; }
446
462 long c_connection(int op_linear_index, int sp_index) const { return annihilation_connection(op_linear_index, sp_index); }
463
479 long cdag_connection(int op_linear_index, int sp_index) const { return creation_connection(op_linear_index, sp_index); }
480
492 matrix_t const &c_matrix(int op_linear_index, int sp_index) const { return c_matrices[op_linear_index][sp_index]; }
493
505 matrix_t const &cdag_matrix(int op_linear_index, int sp_index) const { return cdag_matrices[op_linear_index][sp_index]; }
506
523 C2PY_IGNORE std::pair<int, matrix_t> get_matrix_element_of_monomial(operators::monomial_t const &op_vec, int B) const;
524
535 C2PY_IGNORE op_block_mat_t get_op_mat(many_body_op_t const &op) const;
536
538 bool operator==(atom_diag const &rhs) const = default;
539
541 [[nodiscard]] static std::string hdf5_format() { return Complex ? "AtomDiagComplex" : "AtomDiagReal"; }
542
543 // Friend declarations.
544 friend struct atom_diag_worker<Complex>;
545 friend std::ostream &operator<< <Complex>(std::ostream &os, atom_diag const &ss);
546 friend void h5_write<Complex>(h5::group gr, std::string const &name, atom_diag const &);
547 friend void h5_read<Complex>(h5::group gr, std::string const &name, atom_diag &);
548
549 private:
550 void fill_first_eigenstate_of_subspace();
551 void compute_vacuum();
552
553 private:
554 many_body_op_t h_atomic; // Hamiltonian
555 fundamental_operator_set fops; // Keep it to compute the Green's function
556 class hilbert_space full_hs; // Full Hilbert space of the problem
557 std::vector<sub_hilbert_space> sub_hilbert_spaces; // The invariant subspaces, i.e. the lists of Fock states
558 std::vector<eigensystem_t> eigensystems; // Eigensystem in each subspace
559 matrix<long> creation_connection; // creation_connection(i, B) -> B', target subspace of c†_i acting on B
560 matrix<long> annihilation_connection; // idem for annihilation operators
561 std::vector<std::vector<matrix_t>> cdag_matrices; // cdag_matrices[i][B] = block of c†_i mapping B -> B'
562 std::vector<std::vector<matrix_t>> c_matrices; // idem for annihilation operators
563 double gs_energy{0.0}; // Energy of the ground state
564 long vacuum_subspace_index{-1}; // Invariant subspace containing |0>
565 full_hilbert_space_state_t vacuum; // Vacuum vector (in the eigenbasis)
566 std::vector<std::vector<quantum_number_t>> quantum_numbers; // Values of the quantum numbers for each subspace
567 std::vector<int> first_eigenstate_of_subspace; // Index of the first eigenstate of each subspace
568 };
569
571
572} // namespace triqs::atom_diag
friend void h5_read(h5::group fg, std::string const &subgroup_name, this_t &g)
Read a block Green's function from HDF5.
friend void h5_write(h5::group fg, std::string const &subgroup_name, this_t const &g)
Write a block Green's function to HDF5.
friend std::ostream & operator<<(std::ostream &out, this_t const &)
Write a Green's function to an output stream.
Backward-compatibility umbrella header pulling in the nda array library.
Lightweight exact diagonalization solver for finite fermionic Hamiltonians.
Definition atom_diag.hpp:91
fops_data_t const & get_fops_as_data() const
Get the data of the fundamental operator set used at construction.
long c_connection(int op_linear_index, int sp_index) const
Get the target subspace of the annihilation operator acting on subspace .
fundamental_operator_set const & get_fops() const
Get the fundamental operator set used at construction.
long get_vacuum_subspace_index() const
Get the index of the invariant subspace containing the vacuum state.
atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, int n_min, int n_max)
Diagonalize a Hamiltonian restricted to a particle-number window.
atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, std::vector< many_body_op_t > const &qn_vector)
Reduce a Hamiltonian to a block-diagonal form using user-supplied quantum numbers,...
int get_full_hilbert_space_dim() const
Get the dimension of the full Hilbert space.
matrix< scalar_t > matrix_t
Dense matrix type with scalar entries of type scalar_t.
Definition atom_diag.hpp:97
static std::string hdf5_format()
Get the HDF5 format tag ("AtomDiagReal" or "AtomDiagComplex").
std::vector< eigensystem_t > const & get_eigensystems() const
Get the eigensystems of all invariant subspaces.
operators::many_body_operator get_h_atomic_as_mbop() const
Get the Hamiltonian used at construction as a generic many-body operator.
std::vector< fock_state_t > const & get_fock_states(int sp_index) const
Get the Fock states spanning invariant subspace .
std::pair< int, matrix_t > get_matrix_element_of_monomial(operators::monomial_t const &op_vec, int B) const
Get the matrix representation of a monomial operator restricted to source subspace .
matrix_t const & cdag_matrix(int op_linear_index, int sp_index) const
Get the matrix block of the creation operator acting on subspace .
triqs::operators::many_body_operator_generic< scalar_t > many_body_op_t
Many-body operator type compatible with scalar_t.
std::vector< std::vector< double > > get_energies() const
Get all eigenvalues grouped by invariant subspace.
std::vector< std::vector< quantum_number_t > > const & get_quantum_numbers() const
Get the values of all quantum-number operators, grouped by invariant subspace.
matrix_t const & c_matrix(int op_linear_index, int sp_index) const
Get the matrix block of the annihilation operator acting on subspace .
many_body_op_t const & get_h_atomic() const
Get the Hamiltonian used at construction, with its native scalar type.
long cdag_connection(int op_linear_index, int sp_index) const
Get the target subspace of the creation operator acting on subspace .
atom_diag()=default
Default constructor leaves the solver in an uninitialized state.
full_hilbert_space_state_t const & get_vacuum_state() const
Get the vacuum state as a vector in the full Hilbert space.
atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops)
Reduce a Hamiltonian to a block-diagonal form using auto-partitioning, then diagonalize the blocks.
triqs::hilbert_space::fundamental_operator_set::data_t fops_data_t
Data type of a fundamental operator set.
std::vector< int > get_subspace_dims() const
Get the dimensions of all invariant subspaces.
std::vector< std::vector< fock_state_t > > get_fock_states() const
Get the Fock states of every invariant subspace.
vector< scalar_t > full_hilbert_space_state_t
State vector type of the full Hilbert space.
bool operator==(atom_diag const &rhs) const =default
Default equal-to operator compares all data members.
range index_range_of_subspace(int sp_index) const
Get the range of full-Hilbert-space indices corresponding to subspace .
atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, many_body_op_t const &hyb)
Reduce a Hamiltonian to a block-diagonal form using auto-partitioning refined by a hybridization term...
int get_subspace_dim(int sp_index) const
Get the dimension of invariant subspace .
atom_diag(many_body_op_t const &h, fundamental_operator_set const &fops, std::initializer_list< many_body_op_t > const &init_lst)
Initializer-list overload of atom_diag(many_body_op_t const &, fundamental_operator_set const &,...
std::vector< matrix_t > block_matrix_t
Block-diagonal matrix type, one dense block per invariant subspace.
std::conditional_t< Complex, std::complex< double >, double > scalar_t
Scalar type of the matrix elements: double or std::complex<double>.
Definition atom_diag.hpp:94
matrix< scalar_t > const & get_unitary_matrix(int sp_index) const
Get the unitary matrix mapping the Fock basis of subspace to its eigenbasis.
double get_eigenvalue(int sp_index, int i) const
Get the eigenvalue of the Hamiltonian.
class hilbert_space const & get_full_hilbert_space() const
Get the full Hilbert space over which the diagonalization problem is defined.
double get_gs_energy() const
Get the ground-state energy, i.e. the minimum eigenvalue across all invariant subspaces.
std::vector< matrix< scalar_t > > get_unitary_matrices() const
Get the unitary matrices for every invariant subspace.
op_block_mat_t get_op_mat(many_body_op_t const &op) const
Get the block-matrix representation of a generic many-body operator.
int n_subspaces() const
Get the number of invariant subspaces produced by the chosen partitioning scheme.
int flatten_subspace_index(int sp_index, int i) const
Map a subspace-local pair to its linear index in the full Hilbert space.
Class representing a fundamental operator set.
std::vector< indices_t > data_t
Container type to store .
triqs::hilbert_space::indices_t indices_t
Index type to represent a single .
Fermionic Hilbert (Fock) space generated by a fundamental operator set.
fundamental_operator_set::indices_t indices_t
Index type used by the fundamental operator set associated with the diagonalization problem.
Definition atom_diag.hpp:65
double quantum_number_t
Type used to store quantum-number values. Quantum-number operators are Hermitian, so their eigenvalue...
Definition atom_diag.hpp:68
many_body_operator_generic< real_or_complex > many_body_operator
Many-body operator with real or complex coefficients (see triqs::operators::many_body_operator_generi...
std::vector< canonical_ops_t > monomial_t
Type used to represent a monomial of canonical second quantization operators.
Provides a fundamental operator set class.
Provides a class to represent Hilbert (Fock) spaces.
Common macros used in TRIQS.
Provides generic many-body operators.
Eigensystem of a single invariant subspace of the Hamiltonian .
friend void h5_write(h5::group g, std::string const &name, eigensystem_t const &es)
Write an eigensystem to HDF5.
static std::string hdf5_format()
Get the HDF5 format tag.
matrix_t unitary_matrix
Unitary matrix mapping the Fock basis to the eigenbasis.
vector< double > eigenvalues
Eigenvalues sorted in ascending order.
friend void h5_read(h5::group g, std::string const &name, eigensystem_t &es)
Read an eigensystem from HDF5.
bool operator==(eigensystem_t const &) const =default
Default equal-to operator compares the eigenvalues and unitary matrix.
friend void mpi_broadcast(eigensystem_t &es, mpi::communicator c={}, int root=0)
Broadcast an eigensystem to all ranks of an MPI communicator.
Block-matrix representation of an operator that respects the block structure of the Hamiltonian.
std::vector< matrix_t > block_mat
Vector of dense matrix blocks describing the action in the eigenbasis.
op_block_mat_t(int n_blocks)
Construct an empty block-matrix representation for a problem with the given number of subspaces.
array< long, 1 > connection
Array of subspace-to-subspace connections induced by the operator.
int n_blocks() const
Number of invariant subspaces.
friend std::ostream & operator<<(std::ostream &os, op_block_mat_t const &op_mat)
Pretty-print the block matrix to a stream.