21#include "./worker.hpp"
29#include <itertools/itertools.hpp>
38using namespace triqs::arrays;
40namespace triqs::atom_diag {
43#define ATOM_DIAG_CONSTRUCTOR(ARGS) template <bool Complex> atom_diag<Complex>::atom_diag ARGS
44#define ATOM_DIAG_METHOD(RET, F) template <bool Complex> auto atom_diag<Complex>::F->RET
46 ATOM_DIAG_CONSTRUCTOR((many_body_op_t
const &h,
fundamental_operator_set const &fops, std::vector<many_body_op_t>
const &qn_vector))
47 : h_atomic(h), fops(fops), full_hs(fops), vacuum(full_hs.
size()) {
48 atom_diag_worker<Complex>{
this}.partition_with_qn(qn_vector);
49 fill_first_eigenstate_of_subspace();
56 : h_atomic(h), fops(fops), full_hs(fops), vacuum(full_hs.
size()) {
57 atom_diag_worker<Complex>{
this}.autopartition(hyb);
58 fill_first_eigenstate_of_subspace();
65 : h_atomic(h), fops(fops), full_hs(fops), vacuum(full_hs.
size()) {
66 atom_diag_worker<Complex>{
this}.autopartition();
67 fill_first_eigenstate_of_subspace();
72 : h_atomic(h), fops(fops), full_hs(fops), vacuum(full_hs.
size()) {
73 atom_diag_worker<Complex>{
this, n_min, n_max}.autopartition();
74 fill_first_eigenstate_of_subspace();
80 ATOM_DIAG_METHOD(
void, fill_first_eigenstate_of_subspace()) {
82 first_eigenstate_of_subspace.resize(n_subspaces());
83 if (n_subspaces() == 0)
return;
84 first_eigenstate_of_subspace[0] = 0;
85 for (
int sp = 1; sp < n_subspaces(); ++sp) first_eigenstate_of_subspace[sp] = first_eigenstate_of_subspace[sp - 1] + get_subspace_dim(sp - 1);
90 ATOM_DIAG_METHOD(
void, compute_vacuum()) {
93 for (
auto sp : range(sub_hilbert_spaces.size())) {
95 vacuum_subspace_index = sp;
96 vacuum(index_range_of_subspace(sp)) = dagger(eigensystems[sp].unitary_matrix)(range::all, 0);
104 ATOM_DIAG_METHOD(std::vector<std::vector<double>>, get_energies()
const) {
105 std::vector<std::vector<double>> R;
106 for (
auto const &es : eigensystems) R.emplace_back(es.eigenvalues.begin(), es.eigenvalues.end());
115 template <
bool Complex>
124 state<class hilbert_space, scalar_t, true> initial_st(full_hs, i);
126 auto final_st = monomial_op(initial_st);
130 EXPECTS(final_st.nterms() <= 1);
132 for (
auto const &sp : sub_hilbert_spaces) {
133 if (sp.has_state(j)) {
138 m(sp.get_state_index(j), i_idx) = x;
146 return {-1, std::move(m)};
152 ATOM_DIAG_METHOD(op_block_mat_t, get_op_mat(many_body_op_t
const &op)
const) {
153 op_block_mat_t op_mat(n_subspaces());
155 for (
auto b : range(n_subspaces())) {
156 for (
auto const &term : op) {
157 auto [bb, mat] = get_matrix_element_of_monomial(term.monomial, b);
158 if (bb == -1)
continue;
160 if (op_mat.connection(b) == -1) {
161 op_mat.connection(b) = bb;
162 op_mat.block_mat[b] = term.coef * mat;
163 }
else if (op_mat.connection(b) != bb) {
164 TRIQS_RUNTIME_ERROR <<
"ERROR: <atom_diag::get_op_mat> Monomials in operator does not connect the same subspaces.";
166 op_mat.block_mat[b] += term.coef * mat;
173 static const bool check_issue833 = std::getenv(
"CHECK_ISSUE833");
174 if (check_issue833) {
175 auto U_left = dagger(eigensystems[op_mat.connection(b)].unitary_matrix);
176 auto U_right = eigensystems[b].unitary_matrix;
177 auto diff = op_mat.block_mat[b] - U_left * op_mat.block_mat[b] * U_right;
178 if (max_element(abs(make_regular(diff))) > 1e-10)
180 <<
"ERROR: The result of the get_op_mat function was previously affected by issue 833 (https://github.com/TRIQS/triqs/issues/833).\n"
181 "If you used the function prior to release 3.1.0 of TRIQS the result was incorrect.";
187#undef ATOM_DIAG_METHOD
193 template <
bool Complex>
void h5_write(h5::group fg, std::string
const &name,
atom_diag<Complex> const &ad) {
195 auto gr = fg.create_group(name);
196 write_hdf5_format(gr, ad);
199 h5::write(gr,
"h_atomic", ad.h_atomic);
200 h5::write(gr,
"full_hs", ad.full_hs);
201 h5::write(gr,
"sub_hilbert_spaces", ad.sub_hilbert_spaces);
202 h5::write(gr,
"eigensystems", ad.eigensystems);
203 h5::write(gr,
"creation_connection", ad.creation_connection);
204 h5::write(gr,
"annihilation_connection", ad.annihilation_connection);
206 auto write_sparse = [&](std::string na, std::vector<std::vector<matrix_t>>
const &Mvv) {
207 auto gr2 = gr.create_group(na);
208 for (
int i = 0; i < Mvv.size(); ++i)
209 for (
int j = 0; j < Mvv[i].size(); ++j)
213 write_sparse(
"c_matrices", ad.c_matrices);
214 write_sparse(
"cdag_matrices", ad.cdag_matrices);
216 h5::write(gr,
"gs_energy", ad.gs_energy);
217 h5::write(gr,
"vacuum_subspace_index", ad.vacuum_subspace_index);
218 h5::write(gr,
"vacuum", ad.vacuum);
219 h5::write(gr,
"quantum_numbers", ad.quantum_numbers);
223 template <
bool Complex>
void h5_read(h5::group fg, std::string
const &name,
atom_diag<Complex> &ad) {
225 auto gr = fg.open_group(name);
228 h5::try_read(gr,
"h_atomic", ad.h_atomic);
229 h5::read(gr,
"full_hs", ad.full_hs);
230 h5::read(gr,
"sub_hilbert_spaces", ad.sub_hilbert_spaces);
231 h5::read(gr,
"eigensystems", ad.eigensystems);
232 h5::read(gr,
"creation_connection", ad.creation_connection);
233 h5::read(gr,
"annihilation_connection", ad.annihilation_connection);
235 auto read_sparse = [&](std::string na, std::vector<std::vector<matrix_t>> &Mvv) {
236 Mvv.resize(ad.creation_connection.extent(0), std::vector<matrix_t>(ad.creation_connection.extent(1)));
237 auto gr2 = gr.open_group(na);
238 for (
auto s : gr2.get_all_dataset_names()) {
239 std::stringstream ss(s);
240 std::string item1, item2;
241 std::getline(ss, item1,
' ');
242 std::getline(ss, item2,
' ');
243 int i = std::stoi(item1), j = std::stoi(item2);
244 h5::read(gr2, s, Mvv[i][j]);
248 read_sparse(
"c_matrices", ad.c_matrices);
249 read_sparse(
"cdag_matrices", ad.cdag_matrices);
251 h5::read(gr,
"gs_energy", ad.gs_energy);
252 h5::read(gr,
"vacuum_subspace_index", ad.vacuum_subspace_index);
253 h5::read(gr,
"vacuum", ad.vacuum);
254 h5::try_read(gr,
"quantum_numbers", ad.quantum_numbers);
255 ad.fill_first_eigenstate_of_subspace();
260 template <
bool Complex> std::ostream &operator<<(std::ostream &os,
atom_diag<Complex> const &ad) {
261 os <<
"Dimension of full Hilbert space: " << ad.get_full_hilbert_space_dim() << std::endl;
262 os <<
"Number of invariant subspaces: " << ad.n_subspaces() << std::endl;
263 for (
int n_sp = 0; n_sp < ad.n_subspaces(); ++n_sp) {
264 os <<
"Subspace " << n_sp <<
", ";
265 os <<
"lowest energy level : " << ad.eigensystems[n_sp].eigenvalues[0] << std::endl;
266 os <<
"Subspace dimension = " << ad.eigensystems[n_sp].eigenvalues.size() << std::endl;
278 template void h5_write(h5::group fg, std::string
const &,
atom_diag<false> const &);
279 template void h5_write(h5::group fg, std::string
const &,
atom_diag<true> const &);
280 template void h5_read(h5::group fg, std::string
const &,
atom_diag<false> &);
281 template void h5_read(h5::group fg, std::string
const &,
atom_diag<true> &);
283 template std::ostream &operator<<(std::ostream &,
atom_diag<true> const &);
284 template std::ostream &operator<<(std::ostream &,
atom_diag<false> const &);
int size() const
Get the total number of blocks.
Backward-compatibility umbrella header pulling in the nda array library.
Provides a lightweight exact diagonalization solver for fermionic Hamiltonians.
Lightweight exact diagonalization solver for finite fermionic Hamiltonians.
matrix< scalar_t > matrix_t
Dense matrix type with scalar entries of type scalar_t.
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 .
triqs::operators::many_body_operator_generic< scalar_t > many_body_op_t
Many-body operator type compatible with scalar_t.
int get_subspace_dim(int sp_index) const
Get the dimension of invariant subspace .
std::conditional_t< Complex, std::complex< double >, double > scalar_t
Scalar type of the matrix elements: double or std::complex<double>.
matrix< scalar_t > const & get_unitary_matrix(int sp_index) const
Get the unitary matrix mapping the Fock basis of subspace to its eigenbasis.
Class representing a fundamental operator set.
Representation of a many-body operator acting on many-body states.
void h5_read_attribute(h5::object obj, std::string const &name, fundamental_operator_set &fops)
void h5_write_attribute(h5::object obj, std::string const &name, fundamental_operator_set const &fops)
uint64_t fock_state_t
Integer type representing a fermionic fock state .
nda::matrix< double > matrix_t
Matrix type for transformations involving real and reciprocal space vectors.
std::vector< canonical_ops_t > monomial_t
Type used to represent a monomial of canonical second quantization operators.
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
string to_string(string const &str)
Identity overload for std::string.
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 a type for many-body states in a Hilbert (Fock) space.