33namespace triqs::atom_diag {
35 using namespace triqs::arrays;
37#define ATOM_DIAG atom_diag<Complex>
38#define ATOM_DIAG_R atom_diag<false>
39#define ATOM_DIAG_C atom_diag<true>
40#define ATOM_DIAG_T typename atom_diag<Complex>
44 for (
auto const &es : atom.get_eigensystems()) z += sum(exp(-beta * es.eigenvalues));
53 int n_blocks = atom.n_subspaces();
54 ATOM_DIAG_T::block_matrix_t dm(n_blocks);
55 for (
int bl = 0; bl < n_blocks; ++bl) {
56 int bl_size = atom.get_subspace_dim(bl);
57 dm[bl] = ATOM_DIAG_T::matrix_t(bl_size, bl_size);
58 for (
int u = 0; u < bl_size; ++u) {
59 for (
int v = 0; v < bl_size; ++v) { dm[bl](u, v) = (u == v) ? std::exp(-beta * atom.get_eigenvalue(bl, u)) / z : 0; }
69 template <
bool Complex>
70 ATOM_DIAG_T::scalar_t
trace_rho_op(ATOM_DIAG_T::block_matrix_t
const &density_matrix, ATOM_DIAG_T::many_body_op_t
const &op,
71 ATOM_DIAG
const &atom) {
72 ATOM_DIAG_T::scalar_t result = 0;
73 if (atom.n_subspaces() != density_matrix.size())
TRIQS_RUNTIME_ERROR <<
"trace_rho_op : size mismatch : number of blocks differ";
74 for (
int sp = 0; sp < atom.n_subspaces(); ++sp) {
75 if (atom.get_subspace_dim(sp) != first_dim(density_matrix[sp]))
77 for (
auto const &x : op) {
78 auto b_m = atom.get_matrix_element_of_monomial(x.monomial, sp);
79 if (b_m.first == sp) result += x.coef * trace(b_m.second * density_matrix[sp]);
83 auto is_block_matrix_hermitian = [](ATOM_DIAG_T::block_matrix_t
const &bm) {
84 return std::all_of(bm.begin(), bm.end(), [](ATOM_DIAG_T::matrix_t
const &mat) { return max_element(abs(mat - dagger(mat))) == 0.0; });
93 if (is_op_hermitian(op) && is_block_matrix_hermitian(density_matrix)) {
94 return std::real(result);
98 template ATOM_DIAG_R::scalar_t
trace_rho_op(ATOM_DIAG_R::block_matrix_t
const &, ATOM_DIAG_R::many_body_op_t
const &, ATOM_DIAG_R
const &);
99 template ATOM_DIAG_C::scalar_t
trace_rho_op(ATOM_DIAG_C::block_matrix_t
const &, ATOM_DIAG_C::many_body_op_t
const &, ATOM_DIAG_C
const &);
102 template <
bool Complex>
103 auto act(ATOM_DIAG_T::many_body_op_t
const &op, ATOM_DIAG_T::full_hilbert_space_state_t
const &st, ATOM_DIAG
const &atom)
104 -> ATOM_DIAG_T::full_hilbert_space_state_t {
105 ATOM_DIAG_T::full_hilbert_space_state_t result(st.size());
107 for (
auto const &x : op) {
108 for (
int bl = 0; bl < atom.n_subspaces(); ++bl) {
109 auto b_m = atom.get_matrix_element_of_monomial(x.monomial, bl);
110 if (b_m.first == -1)
continue;
111 result(atom.index_range_of_subspace(b_m.first)) += x.coef * b_m.second * st(atom.index_range_of_subspace(bl));
116 template ATOM_DIAG_R::full_hilbert_space_state_t
act(ATOM_DIAG_R::many_body_op_t
const &, ATOM_DIAG_R::full_hilbert_space_state_t
const &,
117 ATOM_DIAG_R
const &);
118 template ATOM_DIAG_C::full_hilbert_space_state_t
act(ATOM_DIAG_C::many_body_op_t
const &, ATOM_DIAG_C::full_hilbert_space_state_t
const &,
119 ATOM_DIAG_C
const &);
122 template <
bool Complex>
123 auto quantum_number_eigenvalues(ATOM_DIAG_T::many_body_op_t
const &op, ATOM_DIAG
const &atom) -> std::vector<std::vector<quantum_number_t>> {
125 auto commutator = op * atom.get_h_atomic() - atom.get_h_atomic() * op;
126 if (!commutator.is_almost_zero())
TRIQS_RUNTIME_ERROR <<
"The operator is not a quantum number";
128 std::vector<std::vector<quantum_number_t>> result;
130 for (
int sp = 0; sp < atom.n_subspaces(); ++sp) {
131 auto dim = atom.get_subspace_dim(sp);
132 result.push_back(std::vector<quantum_number_t>(dim, 0));
133 for (
auto const &x : op) {
134 auto b_m = atom.get_matrix_element_of_monomial(x.monomial, sp);
135 if (b_m.first != sp)
continue;
136 for (
int i = 0; i < dim; ++i) result.back()[i] += std::real(x.coef * b_m.second(i, i));
141 template std::vector<std::vector<quantum_number_t>>
quantum_number_eigenvalues(ATOM_DIAG_R::many_body_op_t
const &, ATOM_DIAG_R
const &);
142 template std::vector<std::vector<quantum_number_t>>
quantum_number_eigenvalues(ATOM_DIAG_C::many_body_op_t
const &, ATOM_DIAG_C
const &);
145 template <
typename M>
147 inline bool is_diagonal(M
const &m) {
148 double static const threshold = 1.e-11;
152 template <
bool Complex>
154 -> std::vector<std::vector<quantum_number_t>> {
156 auto commutator = op * atom.get_h_atomic() - atom.get_h_atomic() * op;
157 if (!commutator.is_almost_zero())
TRIQS_RUNTIME_ERROR <<
"The operator is not a quantum number";
159 auto d = atom.get_full_hilbert_space_dim();
160 matrix<quantum_number_t> M(d, d);
162 std::vector<std::vector<quantum_number_t>> result;
164 for (
int sp = 0; sp < atom.n_subspaces(); ++sp) {
165 for (
auto const &x : op) {
166 auto b_m = atom.get_matrix_element_of_monomial(x.monomial, sp);
167 if (b_m.first == -1)
continue;
168 M(atom.index_range_of_subspace(b_m.first), atom.index_range_of_subspace(sp)) +=
real(x.coef * b_m.second);
171 if (!is_diagonal(M))
TRIQS_RUNTIME_ERROR <<
"The matrix of the operator is not diagonal !!!";
173 for (
int sp = 0; sp < atom.n_subspaces(); ++sp) {
174 auto dim = atom.get_subspace_dim(sp);
175 result.push_back(std::vector<quantum_number_t>(dim, 0));
176 for (
int i = 0; i < dim; ++i) result.back()[i] = M(atom.flatten_subspace_index(sp, i), atom.flatten_subspace_index(sp, i));
Backward-compatibility umbrella header pulling in the nda array library.
Provides a lightweight exact diagonalization solver for fermionic Hamiltonians.
Free functions that compute thermodynamic averages and act with operators on a solved diagonalization...
TRIQS exception hierarchy and related macros.
double partition_function(atom_diag< Complex > const &atom, double beta)
Compute the atomic partition function at inverse temperature .
atom_diag< Complex >::block_matrix_t atomic_density_matrix(atom_diag< Complex > const &atom, double beta)
Compute the atomic density matrix at inverse temperature .
atom_diag< Complex >::scalar_t trace_rho_op(typename atom_diag< Complex >::block_matrix_t const &density_matrix, typename atom_diag< Complex >::many_body_op_t const &op, atom_diag< Complex > const &atom)
Compute the trace of a many-body operator weighted by a block-diagonal density matrix.
std::vector< std::vector< quantum_number_t > > quantum_number_eigenvalues_checked(typename atom_diag< Complex >::many_body_op_t const &op, atom_diag< Complex > const &atom)
Tabulate the eigenvalues of a quantum-number operator , also checking that the operator is diagonal ...
std::vector< std::vector< quantum_number_t > > quantum_number_eigenvalues(typename atom_diag< Complex >::many_body_op_t const &op, atom_diag< Complex > const &atom)
Tabulate the eigenvalues of a quantum-number operator over all eigenstates of the Hamiltonian.
atom_diag< Complex >::full_hilbert_space_state_t act(typename atom_diag< Complex >::many_body_op_t const &op, typename atom_diag< Complex >::full_hilbert_space_state_t const &st, atom_diag< Complex > const &atom)
Act with a many-body operator on a state vector, .
G::regular_type::real_t real(G const &g)
Take the real part of a Green's function (no check), returning a new Green's function with a real tar...
#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.
Numeric helpers overloaded for various types.
Provides generic many-body operators.