16 embedding::embedding(std::vector<long> sigma_embed_decomposition, std::vector<std::vector<long>> imp_decompositions, nda::array<imp_block_t, 2> psi,
17 std::vector<std::string> sigma_names)
18 : sigma_embed_decomp{std::move(sigma_embed_decomposition)},
19 imp_decomps{std::move(imp_decompositions)},
20 _sigma_names{std::move(sigma_names)},
23 alpha_names = range(
n_alpha()) |
24 stdv::transform([](
auto i) {
return std::to_string(i); }) | tl::to<std::vector>();
27 reverse_psi = imp_decomps | stdv::transform([&](
auto &v) {
return nda::array<std::vector<std::array<long, 2>>, 2>(v.size(),
n_sigma()); })
28 | tl::to<std::vector>();
30 for (
auto [alpha, sigma] : this->psi.indices()) {
31 auto const &y = this->psi(alpha, sigma);
32 if (y.imp_idx == -1)
continue;
33 reverse_psi[y.imp_idx](y.gamma, y.tau).push_back(std::array{alpha, sigma});
40 std::optional<std::vector<long>>
const &atom_to_imp) {
42 long n_alpha = stdr::fold_left(block_decomposition(
r_all, 0) | stdv::transform([](
auto const &x) {
return long(x.size()); }), 0, std::plus<>());
44 auto embed_bl_sizes = std::vector<long>{};
45 auto imp_decompositions = std::vector<std::vector<long>>{};
46 auto psi = nda::array<embedding::imp_block_t, 2>(n_alpha, C_space.
n_sigma());
50 auto const &atom_imp_map = (atom_to_imp) ? *atom_to_imp : range(n_atoms) | tl::to<std::vector>();
52 for (
auto atom : range(n_atoms)) {
53 for (
auto &&[idx, bl_size] : enumerate(block_decomposition(atom, 0))) {
54 for (
auto sigma : range(C_space.
n_sigma())) { psi(embed_bl_sizes.size(), sigma) = {atom_imp_map[atom], idx, sigma}; }
55 embed_bl_sizes.emplace_back(bl_size);
58 if (build_impurity || !atom_to_imp) imp_decompositions.push_back(std::move(block_decomposition(atom, 0)));
60 return embedding{std::move(embed_bl_sizes), std::move(imp_decompositions), std::move(psi), C_space.
sigma_names()};
65 std::unordered_map<long, long> atom_to_cls, cls_to_imp;
67 for (
auto const &[ish, sh] : enumerate(C_space.
atomic_shells())) {
68 atom_to_cls[ish] = sh.cls_idx;
69 if (not cls_to_imp.contains(sh.cls_idx)) cls_to_imp[sh.cls_idx] = imp_idx++;
71 auto atom_to_imp_idx = range(C_space.
atomic_shells().size()) | stdv::transform([&](
auto const &atom) {
return cls_to_imp[atom_to_cls[atom]]; })
72 | tl::to<std::vector>();
93 return fmt::format(
"(imp_idx = {}, γ = {}, τ = {})", p.imp_idx, p.gamma, p.tau);
102 std::ostringstream out;
108 out <<
"Embedding: ";
109 out << fmt::format(
"{} impurities\n", this->
n_impurities());
110 out1 <<
"Σ_embed block decomposition:\n";
111 auto pr_vec = [](
auto const &V) {
112 return fmt::format(
"{}\n", fmt::join(V | stdv::transform([](
auto x) {
return fmt::format(
"{:>3}", x); }),
" "));
114 out2 <<
"dim_α: " << pr_vec(this->sigma_embed_decomp);
115 out2 <<
" α: " << pr_vec(range(this->sigma_embed_decomp.size()));
116 out1 <<
"\nImpurities\n";
117 out2 <<
"Block dimensions, dim_γ for all γ:\n";
118 for (
auto &&[n, dec] : enumerate(this->imp_decomps)) {
119 auto head = fmt::format(
"[n_imp = {}]", n);
120 out3 << fmt::format(
"{} dim_γ = {}", head, pr_vec(dec));
121 out3 << fmt::format(
"{:>{}} γ = {}",
" ", head.size(), pr_vec(range(dec.size())));
126 out <<
"Embedding:\n";
127 out1 << fmt::format(
"Spin index (σ/τ) names: {}\n\n", this->
sigma_names());
128 out1 <<
"Σ_embed block decomposition:\n";
129 auto pr_vec = [](
auto const &V) {
130 return fmt::format(
"{}\n", fmt::join(V | stdv::transform([](
auto x) {
return fmt::format(
"{:>3}", x); }),
" "));
132 out2 <<
"dim_α: " << pr_vec(this->sigma_embed_decomp);
133 out2 <<
" α: " << pr_vec(range(this->sigma_embed_decomp.size()));
135 out1 <<
"\nImpurities\n";
136 out2 <<
"Block dimensions, dim_γ for all γ:\n";
137 for (
auto &&[n, dec] : enumerate(this->imp_decomps)) {
138 auto head = fmt::format(
"[n_imp = {}]", n);
139 out3 << fmt::format(
"{} dim_γ = {}", head, pr_vec(dec));
140 out3 << fmt::format(
"{:>{}} γ = {}",
" ", head.size(), pr_vec(range(dec.size())));
142 out2 <<
"Gf Block structures for solvers as names, [dim]:\n";
143 for (
auto &&[n, ish] : enumerate(impurities_shape_list)) {
144 auto formatted_vec = ish | stdv::transform([](
auto &&p) {
return fmt::format(
"{} [{}]", p.first, p.second); }) | tl::to<std::vector>();
145 out3 << fmt::format(
"[imp_idx = {}] {}\n", n, fmt::join(formatted_vec,
", "));
147 out1 <<
"\nMapping ψ(α,σ) = (imp_idx, γ, τ) \n";
149 auto row_labels = range(this->
n_alpha()) | stdv::transform([](
auto x) {
return fmt::format(
"α = {}", x); }) | tl::to<std::vector>();
150 auto col_labels = range(this->
n_sigma()) | stdv::transform([&](
auto i) {
return fmt::format(
"σ = {} / {}", i, this->
sigma_names()[i]); })
151 | tl::to<std::vector>();
166 for (
long alpha : range(
n_alpha())) res(alpha,
r_all) = sigma_embed_decomp[alpha];
167 return {.names = {alpha_names, _sigma_names}, .dims = std::move(res)};
173 auto l = [
this](std::vector<long>
const &decomp) -> gf_struct_t {
175 for (
auto sigma : range(
n_sigma())) {
176 for (
auto const &[idx, bl_size] : enumerate(decomp)) res.emplace_back(fmt::format(
"{}_{}", _sigma_names[sigma], idx), bl_size);
180 return imp_decomps | stdv::transform(l) | tl::to<std::vector>();
185 if (
n_sigma() != 2)
throw std::runtime_error(fmt::format(
"Can not flip spin when {} != 2",
n_sigma()));
186 auto new_psi = this->psi;
187 for (
auto sigma : range(
n_sigma())) new_psi(alpha, sigma).tau = 1 - new_psi(alpha, sigma).tau;
188 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
194 for (
auto alpha : alphas) { res = res.
flip_spin(alpha); }
201 auto new_imp_decomps = this->imp_decomps;
202 auto new_psi = this->psi;
203 new_imp_decomps.erase(begin(new_imp_decomps) + imp_idx);
204 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
205 if (b.imp_idx < imp_idx)
return {b.imp_idx, b.gamma, b.tau};
206 if (b.imp_idx > imp_idx)
return {b.imp_idx - 1, b.gamma, b.tau};
209 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
215 auto new_psi = this->psi;
217 throw std::runtime_error(fmt::format(
"The number of blocks that imp_to_remove= {} and imp_to_replace_with={} connect to do not match!",
218 imp_idx_to_remove, imp_idx_to_replace_with));
219 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
220 if (b.imp_idx == imp_idx_to_remove)
return {imp_idx_to_replace_with, b.gamma, b.tau};
223 return embedding(this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names).
drop(imp_idx_to_remove);
230 auto new_psi = this->psi;
231 auto new_imp_decomps = this->imp_decomps;
232 auto const &igs = new_imp_decomps[imp_idx];
233 auto indices = nda::range(
long(igs.size())) | tl::to<std::vector>();
236 auto mid = std::stable_partition(begin(indices), end(indices), p);
239 auto get_igs = [&](
int i) {
return igs[i]; };
240 auto stru1 = stdr::subrange{begin(indices), mid} | stdv::transform(get_igs) | tl::to<std::vector>();
241 auto stru2 = stdr::subrange{mid, end(indices)} | stdv::transform(get_igs) | tl::to<std::vector>();
242 long L1 = long(stru1.size());
245 new_imp_decomps[imp_idx] = std::move(stru1);
246 new_imp_decomps.insert(begin(new_imp_decomps) + imp_idx + 1, std::move(stru2));
249 auto indices_inv = indices;
250 for (
auto i : range(indices.size())) indices_inv[indices[i]] = i;
252 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
253 if (b.imp_idx < imp_idx)
return b;
254 if (b.imp_idx > imp_idx)
return {b.imp_idx + 1, b.gamma, b.tau};
255 long new_gamma = indices_inv[b.gamma];
256 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});
258 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
264 if (not stdr::all_of(block_list, [&](
auto i) {
return (i >= 0) and (i <
n_gamma(imp_idx)); }))
265 throw std::runtime_error(fmt::format(
"[embedding::split] The list of block indices {} is incorrect. Indices i should all be 0<= i < N_γ = {}",
266 block_list,
n_gamma(imp_idx)));
267 return split(imp_idx, [&](
long idx) {
return stdr::find(block_list, idx) != block_list.end(); });
273 auto Sigma_static_embed = nda::array<nda::matrix<dcomplex>, 2>(
n_alpha(),
n_sigma());
274 for (
auto &&[alpha, sigma] : psi.indices()) {
275 auto bl_size = sigma_embed_decomp[alpha];
276 Sigma_static_embed(alpha, sigma) = nda::zeros<dcomplex>(bl_size, bl_size);
278 for (
auto &&[S, m] : zip(Sigma_static_embed, psi)) {
279 if (m.imp_idx == -1)
continue;
280 S = Sigma_imp_static_vec[m.imp_idx][m.gamma +
n_gamma(m.imp_idx) * m.tau];
282 return Sigma_static_embed;
290 auto matrix_E = nda::matrix<nda::matrix<dcomplex>>(
n_alpha(),
n_sigma());
292 for (
auto sigma : range(
n_sigma())) { matrix_E(alpha, sigma) = matrix_C(0, sigma)(r_alpha, r_alpha); }
295 auto extract_one_imp = [&](
long n_imp) {
296 auto matrix_imp = std::vector<nda::matrix<dcomplex>>{};
297 for (
auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { matrix_imp.emplace_back(bl_size, bl_size); }
298 auto const &rpsi = reverse_psi[n_imp];
299 for (
auto [gamma, tau] : rpsi.indices()) {
300 auto [alpha, sigma] = rpsi(gamma, tau)[0];
301 matrix_imp[gamma +
n_gamma(n_imp) * tau] = matrix_E(alpha, sigma);
306 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
311 std::vector<std::vector<nda::array<dcomplex, 3>>>
embedding::extract(nda::array<dcomplex, 4>
const &g_loc)
const {
314 auto n_w = g_loc.extent(0);
316 auto gloc_E = nda::array<nda::array<dcomplex, 3>, 2>(
n_alpha(),
n_sigma());
318 for (
auto sigma : range(
n_sigma())) { gloc_E(alpha, sigma) = g_loc(
r_all, sigma, r_alpha, r_alpha); }
320 auto extract_one_imp = [&](
long n_imp) {
321 auto g_imp = std::vector<nda::array<dcomplex, 3>>{};
322 for (
auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { g_imp.emplace_back(n_w, bl_size, bl_size); }
323 auto const &rpsi = reverse_psi[n_imp];
324 for (
auto [gamma, tau] : rpsi.indices()) {
325 auto [alpha, sigma] = rpsi(gamma, tau)[0];
326 g_imp[gamma +
n_gamma(n_imp) * tau] = gloc_E(alpha, sigma);
331 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
335 nda::array<nda::array<dcomplex, 3>, 2>
embedding::embed(std::vector<std::vector<nda::array<dcomplex, 3>>>
const &Sigma_imp_vec)
const {
336 auto Sigma_embed = nda::array<nda::array<dcomplex, 3>, 2>(
n_alpha(),
n_sigma());
337 for (
auto &&[S, m] : zip(Sigma_embed, psi)) {
338 if (m.imp_idx == -1)
continue;
339 S = Sigma_imp_vec[m.imp_idx][m.gamma +
n_gamma(m.imp_idx) * m.tau];
346 std::vector<nda::array<dcomplex, 5>>
embedding::extract(nda::array<dcomplex, 5>
const &pi_loc)
const {
348 auto Pi_E = std::vector<nda::array<dcomplex, 5>>{};
349 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)); }
351 auto extract_one_imp = [&](
long n_imp) {
352 auto const &rpsi = reverse_psi[n_imp];
353 auto [alpha, sigma] = rpsi(0, 0)[0];
357 return range(
n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
362 std::vector<nda::array<dcomplex, 5>>
embedding::embed(std::vector<nda::array<dcomplex, 5>>
const &pi_imp_vec)
const {
363 auto Pi_embed = std::vector<nda::array<dcomplex, 5>>(
n_alpha());
364 for (
auto alpha : range(
n_alpha())) {
365 auto const &m = psi(alpha, 0);
366 if (m.imp_idx == -1)
continue;
367 Pi_embed[alpha] = pi_imp_vec[m.imp_idx];
A custom output stream that automatically indents each new line by a specified number of spaces.
C2PY_IGNORE gf_struct2_t sigma_embed_block_shape() const
Gf block structure for Σ_embed.
long n_impurities() const
Number of impurities.
long n_gamma(long imp_idx) const
Number of blocks in γ for the Σ_imp[imp_idx].
long n_sigma() const
Number of blocks in σ for the Σ_embed.
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)
Default constructor.
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
embed tensors
long n_alpha() const
Number of blocks in α for the Σ_embed.
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
Predicate p (long block_idx) -> 0 or 1.
embedding replace(long imp_idx_to_remove, long imp_idx_to_replace_with) const
Replaces one impurity in the embedding table ψ.
block2_gf< Mesh, matrix_valued > embed(std::vector< block_gf< Mesh, matrix_valued > > const &Sigma_imp_vec) const
embed single-particle quantities
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
List of all blocks spanning 𝓒 space -> atoms_block_decomposition.
std::vector< atomic_orbs > const & atomic_shells() const
List of all atomic shells spanning the 𝓒 space.
std::vector< std::string > sigma_names() const
names of spin indices for naming blocks in block_gf
long first_shell_of_its_equiv_cls(long idx) const
Given the index idx of an atomic shell, return the index of the first atomic shell of its equivalence...
embedding make_embedding(local_space const &C_space, bool use_atom_equivalences)
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.
embedding make_embedding_with_no_equivalences(local_space const &C_space)
std::ostream & operator<<(std::ostream &out, one_body_elements_on_grid const &)
embedding make_embedding_with_equivalences(local_space const &C_space)
auto format_as(embedding::imp_block_t const &p)
embedding make_embedding_impl(local_space const &C_space, nda::array< std::vector< long >, 2 > const &block_decomposition, std::optional< 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)