18 embedding::embedding(std::vector<long> sigma_embed_decomposition, std::vector<std::vector<long>> imp_decompositions, nda::array<imp_block_t, 2> psi,
19 std::vector<std::string> sigma_names)
20 : sigma_embed_decomp{std::move(sigma_embed_decomposition)},
21 imp_decomps{std::move(imp_decompositions)},
22 _sigma_names{std::move(sigma_names)},
25 alpha_names = range(
n_alpha()) |
26 stdv::transform([](
auto i) {
return std::to_string(i); }) | tl::to<std::vector>();
29 reverse_psi = imp_decomps | stdv::transform([&](
auto &v) {
return nda::array<std::vector<std::array<long, 2>>, 2>(v.size(),
n_sigma()); })
30 | tl::to<std::vector>();
32 for (
auto [alpha, sigma] : this->psi.indices()) {
33 auto const &y = this->psi(alpha, sigma);
34 if (y.imp_idx == -1)
continue;
35 reverse_psi[y.imp_idx](y.gamma, y.tau).push_back(std::array{alpha, sigma});
42 std::vector<long>
const &atom_to_imp) {
44 long n_alpha = stdr::fold_left(block_decomposition(
r_all, 0) | stdv::transform([](
auto const &x) {
return long(x.size()); }), 0, std::plus<>());
45 long n_sigma = spin_names.size();
47 auto embed_bl_sizes = std::vector<long>{};
48 auto imp_decompositions = std::vector<std::vector<long>>{};
49 auto psi = nda::array<embedding::imp_block_t, 2>(n_alpha, n_sigma);
51 std::set<long> seen_impurities;
53 auto n_atoms = block_decomposition.extent(0);
54 for (
auto atom : range(n_atoms)) {
55 for (
auto &&[idx, bl_size] : enumerate(block_decomposition(atom, 0))) {
56 for (
auto sigma : range(n_sigma)) { psi(embed_bl_sizes.size(), sigma) = {atom_to_imp[atom], idx, sigma}; }
57 embed_bl_sizes.emplace_back(bl_size);
59 auto build_impurity = !seen_impurities.contains(atom_to_imp[atom]);
61 imp_decompositions.push_back(std::move(block_decomposition(atom, 0)));
62 seen_impurities.insert(atom_to_imp[atom]);
65 return embedding{std::move(embed_bl_sizes), std::move(imp_decompositions), std::move(psi), std::move(spin_names)};
69 std::vector<long>
const &atom_to_imp) {
70 auto n_decomps = block_decomposition.size();
71 auto n_sigma = spin_names.size();
72 auto block_decomp_mat = nda::array<std::vector<long>, 2>(n_decomps, n_sigma);
73 for (
auto d : range(n_decomps))
74 for (
auto s : range(n_sigma)) block_decomp_mat(d, s) = block_decomposition[d];
80 std::unordered_map<long, long> atom_to_cls, cls_to_imp;
82 for (
auto const &[ish, sh] : enumerate(C_space.
atomic_shells())) {
83 atom_to_cls[ish] = sh.cls_idx;
84 if (not cls_to_imp.contains(sh.cls_idx)) cls_to_imp[sh.cls_idx] = imp_idx++;
86 auto atom_to_imp_idx = range(C_space.
atomic_shells().size()) | stdv::transform([&](
auto const &atom) {
return cls_to_imp[atom_to_cls[atom]]; })
87 | tl::to<std::vector>();
89 nda::array<std::vector<long>, 2> decomp(C_space.
n_atoms(), C_space.
n_sigma());
90 if (use_atom_decomp) {
92 for (
auto &&[iatom, atom] : enumerate(atom_decomp)) {
93 for (
auto sigma : range(C_space.
n_sigma())) { decomp(atom, sigma).emplace_back(atom); }
103 nda::array<std::vector<long>, 2> decomp(C_space.
n_atoms(), C_space.
n_sigma());
104 if (use_atom_decomp) {
106 for (
auto &&[iatom, atom] : enumerate(atom_decomp)) {
107 for (
auto sigma : range(C_space.
n_sigma())) { decomp(atom, sigma).emplace_back(atom); }
113 auto atom_to_imp_idx = range(C_space.
atomic_shells().size()) | tl::to<std::vector>();
127 return fmt::format(
"(imp_idx = {}, γ = {}, τ = {})", p.imp_idx, p.gamma, p.tau);
136 std::ostringstream out;
142 out <<
"Embedding: ";
143 out << fmt::format(
"{} impurities\n", this->
n_impurities());
144 out1 <<
"Σ_embed block decomposition:\n";
145 auto pr_vec = [](
auto const &V) {
146 return fmt::format(
"{}\n", fmt::join(V | stdv::transform([](
auto x) {
return fmt::format(
"{:>3}", x); }),
" "));
148 out2 <<
"dim_α: " << pr_vec(this->sigma_embed_decomp);
149 out2 <<
" α: " << pr_vec(range(this->sigma_embed_decomp.size()));
150 out1 <<
"\nImpurities\n";
151 out2 <<
"Block dimensions, dim_γ for all γ:\n";
152 for (
auto &&[n, dec] : enumerate(this->imp_decomps)) {
153 auto head = fmt::format(
"[n_imp = {}]", n);
154 out3 << fmt::format(
"{} dim_γ = {}", head, pr_vec(dec));
155 out3 << fmt::format(
"{:>{}} γ = {}",
" ", head.size(), pr_vec(range(dec.size())));
160 out <<
"Embedding:\n";
161 out1 << fmt::format(
"Spin index (σ/τ) names: {}\n\n", this->
sigma_names());
162 out1 <<
"Σ_embed block decomposition:\n";
163 auto pr_vec = [](
auto const &V) {
164 return fmt::format(
"{}\n", fmt::join(V | stdv::transform([](
auto x) {
return fmt::format(
"{:>3}", x); }),
" "));
166 out2 <<
"dim_α: " << pr_vec(this->sigma_embed_decomp);
167 out2 <<
" α: " << pr_vec(range(this->sigma_embed_decomp.size()));
169 out1 <<
"\nImpurities\n";
170 out2 <<
"Block dimensions, dim_γ for all γ:\n";
171 for (
auto &&[n, dec] : enumerate(this->imp_decomps)) {
172 auto head = fmt::format(
"[n_imp = {}]", n);
173 out3 << fmt::format(
"{} dim_γ = {}", head, pr_vec(dec));
174 out3 << fmt::format(
"{:>{}} γ = {}",
" ", head.size(), pr_vec(range(dec.size())));
176 out2 <<
"Gf Block structures for solvers as names, [dim]:\n";
177 for (
auto &&[n, ish] : enumerate(impurities_shape_list)) {
178 auto formatted_vec = ish | stdv::transform([](
auto &&p) {
return fmt::format(
"{} [{}]", p.first, p.second); }) | tl::to<std::vector>();
179 out3 << fmt::format(
"[imp_idx = {}] {}\n", n, fmt::join(formatted_vec,
", "));
181 out1 <<
"\nMapping ψ(α,σ) = (imp_idx, γ, τ) \n";
183 auto row_labels = range(this->
n_alpha()) | stdv::transform([](
auto x) {
return fmt::format(
"α = {}", x); }) | tl::to<std::vector>();
184 auto col_labels = range(this->
n_sigma()) | stdv::transform([&](
auto i) {
return fmt::format(
"σ = {} / {}", i, this->
sigma_names()[i]); })
185 | tl::to<std::vector>();
200 for (
long alpha : range(
n_alpha())) res(alpha,
r_all) = sigma_embed_decomp[alpha];
201 return {.names = {alpha_names, _sigma_names}, .dims = std::move(res)};
207 auto l = [
this](std::vector<long>
const &decomp) -> gf_struct_t {
209 for (
auto sigma : range(
n_sigma())) {
210 for (
auto const &[idx, bl_size] : enumerate(decomp)) res.emplace_back(fmt::format(
"{}_{}", _sigma_names[sigma], idx), bl_size);
214 return imp_decomps | stdv::transform(l) | tl::to<std::vector>();
219 if (
n_sigma() != 2)
throw std::runtime_error(fmt::format(
"Can not flip spin when {} != 2",
n_sigma()));
220 if (alpha >=
n_alpha())
throw std::runtime_error(fmt::format(
"Out of bounds {} >= {}", alpha,
n_alpha()));
221 auto new_psi = this->psi;
222 for (
auto sigma : range(
n_sigma())) new_psi(alpha, sigma).tau = 1 - new_psi(alpha, sigma).tau;
223 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
229 for (
auto alpha : alphas) { res = res.
flip_spin(alpha); }
236 auto new_imp_decomps = this->imp_decomps;
237 auto new_psi = this->psi;
238 new_imp_decomps.erase(begin(new_imp_decomps) + imp_idx);
239 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
240 if (b.imp_idx < imp_idx)
return {b.imp_idx, b.gamma, b.tau};
241 if (b.imp_idx > imp_idx)
return {b.imp_idx - 1, b.gamma, b.tau};
244 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
250 auto new_psi = this->psi;
252 throw std::runtime_error(fmt::format(
"The number of blocks that imp_to_remove= {} and imp_to_replace_with={} connect to do not match!",
253 imp_idx_to_remove, imp_idx_to_replace_with));
254 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
255 if (b.imp_idx == imp_idx_to_remove)
return {imp_idx_to_replace_with, b.gamma, b.tau};
258 return embedding(this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names).
drop(imp_idx_to_remove);
265 auto new_psi = this->psi;
266 auto new_imp_decomps = this->imp_decomps;
267 auto const &igs = new_imp_decomps[imp_idx];
268 auto indices = nda::range(
long(igs.size())) | tl::to<std::vector>();
271 auto mid = std::stable_partition(begin(indices), end(indices), p);
274 auto get_igs = [&](
int i) {
return igs[i]; };
275 auto stru1 = stdr::subrange{begin(indices), mid} | stdv::transform(get_igs) | tl::to<std::vector>();
276 auto stru2 = stdr::subrange{mid, end(indices)} | stdv::transform(get_igs) | tl::to<std::vector>();
277 long L1 = long(stru1.size());
280 new_imp_decomps[imp_idx] = std::move(stru1);
281 new_imp_decomps.insert(begin(new_imp_decomps) + imp_idx + 1, std::move(stru2));
284 auto indices_inv = indices;
285 for (
auto i : range(indices.size())) indices_inv[indices[i]] = i;
287 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
288 if (b.imp_idx < imp_idx)
return b;
289 if (b.imp_idx > imp_idx)
return {b.imp_idx + 1, b.gamma, b.tau};
290 long new_gamma = indices_inv[b.gamma];
291 return (new_gamma < L1 ? imp_block_t{b.imp_idx, new_gamma, b.tau} : imp_block_t{b.imp_idx + 1, new_gamma - L1, b.tau});
293 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
299 if (not stdr::all_of(block_list, [&](
auto i) {
return (i >= 0) and (i <
n_gamma(imp_idx)); }))
300 throw std::runtime_error(fmt::format(
"[embedding::split] The list of block indices {} is incorrect. Indices i should all be 0<= i < N_γ = {}",
301 block_list,
n_gamma(imp_idx)));
302 return split(imp_idx, [&](
long idx) {
return stdr::find(block_list, idx) != block_list.end(); });
308 auto Sigma_static_embed = nda::array<nda::matrix<dcomplex>, 2>(
n_alpha(),
n_sigma());
309 for (
auto &&[alpha, sigma] : psi.indices()) {
310 auto bl_size = sigma_embed_decomp[alpha];
311 Sigma_static_embed(alpha, sigma) = nda::zeros<dcomplex>(bl_size, bl_size);
313 for (
auto &&[S, m] : zip(Sigma_static_embed, psi)) {
314 if (m.imp_idx == -1)
continue;
315 S = Sigma_imp_static_vec[m.imp_idx][m.gamma +
n_gamma(m.imp_idx) * m.tau];
317 return Sigma_static_embed;
326 auto matrix_E = nda::matrix<nda::matrix<dcomplex>>(
n_alpha(),
n_sigma());
328 for (
auto sigma : range(
n_sigma())) { matrix_E(alpha, sigma) = matrix_C(0, sigma)(r_alpha, r_alpha); }
331 auto extract_one_imp = [&](
long n_imp) {
332 auto matrix_imp = std::vector<nda::matrix<dcomplex>>{};
333 for (
auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { matrix_imp.emplace_back(bl_size, bl_size); }
334 auto const &rpsi = reverse_psi[n_imp];
335 for (
auto [gamma, tau] : rpsi.indices()) {
336 auto [alpha, sigma] = rpsi(gamma, tau)[0];
337 matrix_imp[gamma +
n_gamma(n_imp) * tau] = matrix_E(alpha, sigma);
342 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
350 auto tensor_E = std::vector<nda::array<dcomplex, 4>>(
n_alpha());
351 for (
auto [alpha, r_alpha] :
enumerated_sub_slices(sigma_embed_decomp)) { tensor_E[alpha] = U_tensor(r_alpha, r_alpha, r_alpha, r_alpha); }
353 auto extract_one_imp = [&](
long n_imp) {
355 auto tensor_imp = nda::zeros<dcomplex>(bl_size, bl_size, bl_size, bl_size);
356 auto alpha = reverse_psi[n_imp](0, 0)[0][0];
357 return tensor_E[alpha];
359 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
364 auto Utensor_E = std::vector<nda::array<dcomplex, 4>>(
n_alpha());
366 for (
auto alpha : range(
n_alpha())) {
367 auto bl_size = sigma_embed_decomp[alpha];
368 Utensor_E[alpha] = nda::zeros<dcomplex>(bl_size, bl_size, bl_size, bl_size);
371 for (
auto &&[U, a] : zip(Utensor_E, range(
n_alpha()))) {
372 if (psi(a, 0).imp_idx == -1)
continue;
373 U = U_tensor_vec[psi(a, 0).imp_idx];
376 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
377 auto U_tensor_C = nda::array<dcomplex, 4>(dim_C, dim_C, dim_C, dim_C);
378 for (
auto &&[index, sli] :
enumerated_sub_slices(sigma_embed_decomp)) { U_tensor_C(sli, sli, sli, sli) = Utensor_E[index]; }
383 std::vector<std::vector<nda::array<dcomplex, 3>>>
embedding::extract_1p(nda::array<dcomplex, 4>
const &g_loc)
const {
386 auto n_w = g_loc.extent(0);
388 auto gloc_E = nda::array<nda::array<dcomplex, 3>, 2>(
n_alpha(),
n_sigma());
390 for (
auto sigma : range(
n_sigma())) { gloc_E(alpha, sigma) = g_loc(
r_all, sigma, r_alpha, r_alpha); }
392 auto extract_one_imp = [&](
long n_imp) {
393 auto g_imp = std::vector<nda::array<dcomplex, 3>>{};
394 for (
auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { g_imp.emplace_back(n_w, bl_size, bl_size); }
395 auto const &rpsi = reverse_psi[n_imp];
396 for (
auto [gamma, tau] : rpsi.indices()) {
397 auto [alpha, sigma] = rpsi(gamma, tau)[0];
398 g_imp[gamma +
n_gamma(n_imp) * tau] = gloc_E(alpha, sigma);
403 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
407 std::vector<nda::array<dcomplex, 3>>
embedding::embed_1p(std::vector<std::vector<nda::array<dcomplex, 3>>>
const &Sigma_imp_vec)
const {
409 auto Sigma_embed = nda::array<nda::array<dcomplex, 3>, 2>(
n_alpha(),
n_sigma());
410 auto n_w = Sigma_imp_vec[0][0].extent(0);
412 for (
auto &&[alpha, sigma] : psi.indices()) {
413 auto bl_size = sigma_embed_decomp[alpha];
414 Sigma_embed(alpha, sigma) = nda::zeros<dcomplex>(n_w, bl_size, bl_size);
417 for (
auto &&[S, m] : zip(Sigma_embed, psi)) {
418 if (m.imp_idx == -1)
continue;
419 S = Sigma_imp_vec[m.imp_idx][m.gamma +
n_gamma(m.imp_idx) * m.tau];
422 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
424 range(
n_sigma()) | stdv::transform([&](
auto const &sig) {
return nda::array<dcomplex, 3>(n_w, dim_C, dim_C); }) | tl::to<std::vector>();
425 for (
auto sigma : range(
n_sigma())) {
426 for (
auto &&[index, sli] :
enumerated_sub_slices(sigma_embed_decomp)) { Sigma_C[sigma](
r_all, sli, sli) = Sigma_embed(index, sigma); }
436 auto Pi_E = std::vector<nda::array<dcomplex, 5>>{};
437 for (
auto [alpha, r_alpha] :
enumerated_sub_slices(sigma_embed_decomp)) { Pi_E.emplace_back(pi_loc(
r_all, r_alpha, r_alpha, r_alpha, r_alpha)); }
439 auto extract_one_imp = [&](
long n_imp) {
440 auto const &rpsi = reverse_psi[n_imp];
441 auto [alpha, sigma] = rpsi(0, 0)[0];
445 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
450 nda::array<dcomplex, 5>
embedding::embed_2p(std::vector<nda::array<dcomplex, 5>>
const &pi_imp_vec)
const {
452 auto n_w = pi_imp_vec[0].extent(0);
454 auto Pi_embed = std::vector<nda::array<dcomplex, 5>>(
n_alpha());
455 for (
auto alpha : range(
n_alpha())) {
456 auto bl_size = sigma_embed_decomp[alpha];
457 Pi_embed[alpha] = nda::zeros<dcomplex>(n_w, bl_size, bl_size, bl_size, bl_size);
460 for (
auto alpha : range(
n_alpha())) {
461 auto const &m = psi(alpha, 0);
462 if (m.imp_idx == -1)
continue;
463 Pi_embed[alpha] = pi_imp_vec[m.imp_idx];
466 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
467 auto Pi_C = nda::array<dcomplex, 5>(n_w, dim_C, dim_C, dim_C, dim_C);
A custom output stream that automatically indents each new line by a specified number of spaces.
std::vector< nda::array< dcomplex, 3 > > embed_1p(std::vector< std::vector< nda::array< dcomplex, 3 > > > const &Sigma_imp_vec) const
Embed single-particle quantities (CoQui).
C2PY_IGNORE gf_struct2_t sigma_embed_block_shape() const
Gf block structure for .
nda::array< dcomplex, 4 > embed_tensor(std::vector< nda::array< dcomplex, 4 > > const &U_tensor_vec) const
Embed tensors (CoQui).
long n_impurities() const
Number of impurities.
long n_gamma(long imp_idx) const
Number of blocks in for the [imp_idx].
long n_sigma() const
Number of blocks in for the .
std::vector< gf_struct_t > imp_block_shape() const
Gf block structure for the impurity solvers.
embedding flip_spin(long alpha) const
Flip the spins ( ) for block .
embedding(std::vector< long > sigma_embed_decomposition, std::vector< std::vector< long > > imp_decompositions, nda::array< imp_block_t, 2 > psi, std::vector< std::string > sigma_names)
Construct an embedding object.
nda::array< dcomplex, 5 > embed_2p(std::vector< nda::array< dcomplex, 5 > > const &pi_imp_vec) const
Embed two-particle quantities (CoQui).
std::vector< std::string > sigma_names() const
The names of the sigma indices.
std::vector< block_gf< Mesh, matrix_valued > > extract(block2_gf< Mesh, matrix_valued > const &g_loc) const
Extract single-particle quantities (TRIQS/ModEST).
long n_alpha() const
Number of blocks in for the .
std::vector< long > imp_decomposition(long imp_idx) const
The impurity decomposition.
std::vector< nda::array< dcomplex, 5 > > extract_2p(nda::array< dcomplex, 5 > const &Pi_loc) const
Extract two-particle quantities (CoQui).
std::vector< std::vector< nda::array< dcomplex, 3 > > > extract_1p(nda::array< dcomplex, 4 > const &g_loc) const
Extract single-particle quantities (CoQui).
std::string description(bool verbosity=false) const
Summarize the embedding object.
embedding drop(long imp_idx) const
Remove an impurity from the embedding table .
embedding split(long imp_idx, std::function< bool(long)> p) const
Split impurity imp_idx.
embedding replace(long imp_idx_to_remove, long imp_idx_to_replace_with) const
Replaces one impurity in the embedding table .
std::vector< nda::array< dcomplex, 4 > > extract_tensor(nda::array< dcomplex, 4 > const &U_tensor) const
Extract tensors (CoQui).
block2_gf< Mesh, matrix_valued > embed(std::vector< block_gf< Mesh, matrix_valued > > const &Sigma_imp_vec) const
Embed single-particle quantities (TRIQS/ModEST).
Describe the atomic orbitals within downfolded space.
long n_sigma() const
Dimension of the index.
nda::array< std::vector< long >, 2 > const & atoms_block_decomposition() const
2-dim array of all blocks spanning space -> atoms_block_decomposition.
auto atomic_decomposition() const
Transformed view containing the dimension of each atomic shell.
std::vector< atomic_orbs > const & atomic_shells() const
List of all atomic shells spanning the space.
long n_atoms() const
The number of atoms.
std::vector< std::string > sigma_names() const
Names of spin indices for naming blocks in block GFs.
embedding make_embedding(local_space const &C_space, bool use_atom_equivalences, bool use_atom_decomp)
Make an embedding from the local space.
void format_as_table(std::ostream &out, nda::Matrix auto const &mat, auto const &row_labels, auto const &col_labels)
Format the matrix mat as a table, with row/col_labels.
std::ostream & operator<<(std::ostream &out, one_body_elements_on_grid const &)
embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp)
auto format_as(embedding::imp_block_t const &p)
embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp)
embedding embedding_builder(std::vector< std::string > const &spin_names, nda::array< std::vector< long >, 2 > const &block_decomposition, std::vector< long > const &atom_to_imp)
nda::array< nda::matrix< dcomplex >, 2 > block2_matrix_t
static constexpr auto r_all
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)