9#include <triqs/utility/report_stream.hpp>
17 embedding::embedding(std::vector<long> sigma_embed_decomposition, std::vector<std::vector<long>> imp_decompositions, nda::array<imp_block_t, 2> psi,
19 : sigma_embed_decomp{std::move(sigma_embed_decomposition)},
20 imp_decomps{std::move(imp_decompositions)},
24 alpha_names = range(
n_alpha()) |
25 stdv::transform([](
auto i) {
return std::to_string(i); }) | tl::to<std::vector>();
28 reverse_psi = imp_decomps | stdv::transform([&](
auto &v) {
return nda::array<std::vector<std::array<long, 2>>, 2>(v.size(),
n_sigma()); })
29 | tl::to<std::vector>();
31 for (
auto [alpha, sigma] : this->psi.indices()) {
32 auto const &y = this->psi(alpha, sigma);
33 if (y.imp_idx == -1)
continue;
34 reverse_psi[y.imp_idx](y.gamma, y.tau).push_back(std::array{alpha, sigma});
40 embedding make_embedding(std::vector<std::string>
const &spin_names, nda::array<std::vector<long>, 2>
const &block_decomposition,
41 std::vector<long>
const &atom_to_imp) {
44 if (spin_names.empty())
throw std::runtime_error(
"[make_embedding] spin_names must not be empty");
46 auto n_atoms = block_decomposition.extent(0);
47 if (
long(atom_to_imp.size()) != n_atoms)
48 throw std::runtime_error(
49 fmt::format(
"[make_embedding] block_decomposition has {} atoms but atom_to_imp has {} entries", n_atoms, atom_to_imp.size()));
51 for (
long atom = 0; atom < n_atoms; ++atom) {
52 if (atom_to_imp[atom] < 0)
53 throw std::runtime_error(fmt::format(
"[make_embedding] atom_to_imp[{}] = {} is negative", atom, atom_to_imp[atom]));
57 std::unordered_map<long, long> imp_to_first_atom;
58 for (
long atom = 0; atom < n_atoms; ++atom) {
59 auto imp = atom_to_imp[atom];
60 if (
auto it = imp_to_first_atom.find(imp); it != imp_to_first_atom.end()) {
61 auto first_atom = it->second;
62 if (block_decomposition(atom, 0) != block_decomposition(first_atom, 0))
63 throw std::runtime_error(fmt::format(
64 "[make_embedding] Atoms {} and {} are mapped to the same impurity {} but have different block decompositions", first_atom, atom, imp));
66 imp_to_first_atom[imp] = atom;
70 long n_alpha = stdr::fold_left(block_decomposition(
r_all, 0) | stdv::transform([](
auto const &x) {
return long(x.size()); }), 0, std::plus<>());
71 long n_sigma = spin_names.size();
73 auto embed_bl_sizes = std::vector<long>{};
74 auto imp_decompositions = std::vector<std::vector<long>>{};
75 auto psi = nda::array<embedding::imp_block_t, 2>(n_alpha, n_sigma);
77 std::set<long> seen_impurities;
79 for (
auto atom : range(n_atoms)) {
80 for (
auto &&[idx, bl_size] : enumerate(block_decomposition(atom, 0))) {
81 for (
auto sigma : range(n_sigma)) { psi(embed_bl_sizes.size(), sigma) = {atom_to_imp[atom], idx, sigma}; }
82 embed_bl_sizes.emplace_back(bl_size);
84 auto build_impurity = !seen_impurities.contains(atom_to_imp[atom]);
86 imp_decompositions.push_back(std::move(block_decomposition(atom, 0)));
87 seen_impurities.insert(atom_to_imp[atom]);
90 return embedding{std::move(embed_bl_sizes), std::move(imp_decompositions), std::move(psi), std::move(spin_names)};
93 embedding make_embedding(std::vector<std::string>
const &spin_names, std::vector<std::vector<long>>
const &block_decomposition,
94 std::vector<long>
const &atom_to_imp) {
95 auto n_decomps = block_decomposition.size();
96 auto n_sigma = spin_names.size();
97 auto block_decomp_mat = nda::array<std::vector<long>, 2>(n_decomps, n_sigma);
98 for (
auto d : range(n_decomps))
99 for (
auto s : range(n_sigma)) block_decomp_mat(d, s) = block_decomposition[d];
105 std::unordered_map<long, long> atom_to_cls, cls_to_imp;
107 for (
auto const &[ish, sh] : enumerate(C_space.
atomic_shells())) {
108 atom_to_cls[ish] = sh.cls_idx;
109 if (not cls_to_imp.contains(sh.cls_idx)) cls_to_imp[sh.cls_idx] = imp_idx++;
112 nda::array<std::vector<long>, 2> decomp(C_space.
n_atoms(), C_space.
n_sigma());
113 if (use_atom_decomp) {
115 for (
auto &&[iatom, atom] : enumerate(atom_decomp)) {
116 for (
auto sigma : range(C_space.
n_sigma())) { decomp(iatom, sigma).emplace_back(atom); }
122 auto n_atoms_in_decomp = decomp.extent(0);
123 auto atom_to_imp_idx = range(n_atoms_in_decomp) | stdv::transform([&](
auto const &atom) {
return cls_to_imp[atom_to_cls[atom]]; })
124 | tl::to<std::vector>();
130 nda::array<std::vector<long>, 2> decomp(C_space.
n_atoms(), C_space.
n_sigma());
131 if (use_atom_decomp) {
133 for (
auto &&[iatom, atom] : enumerate(atom_decomp)) {
134 for (
auto sigma : range(C_space.
n_sigma())) { decomp(iatom, sigma).emplace_back(atom); }
140 auto n_atoms_in_decomp = decomp.extent(0);
141 auto atom_to_imp_idx = range(n_atoms_in_decomp) | tl::to<std::vector>();
155 for (
long alpha : range(
n_alpha())) res(alpha,
r_all) = sigma_embed_decomp[alpha];
156 return {.names = {alpha_names, _sigma_names}, .dims = std::move(res)};
162 auto l = [
this](std::vector<long>
const &decomp) -> gf_struct_t {
164 for (
auto sigma : range(
n_sigma())) {
165 for (
auto const &[idx, bl_size] : enumerate(decomp)) res.emplace_back(fmt::format(
"{}_{}", _sigma_names[sigma], idx), bl_size);
169 return imp_decomps | stdv::transform(l) | tl::to<std::vector>();
174 if (
n_sigma() != 2)
throw std::runtime_error(fmt::format(
"Can not swap sigma when {} != 2",
n_sigma()));
175 if (alpha >=
n_alpha())
throw std::runtime_error(fmt::format(
"Out of bounds {} >= {}", alpha,
n_alpha()));
176 auto new_psi = this->psi;
177 for (
auto sigma : range(
n_sigma())) new_psi(alpha, sigma).tau = 1 - new_psi(alpha, sigma).tau;
178 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
184 for (
auto alpha : alphas) { res = res.swap_sigma(alpha); }
191 if (
n_sigma() != 2)
throw std::runtime_error(fmt::format(
"Can not slice sigma when {} != 2",
n_sigma()));
192 auto new_psi = nda::array<imp_block_t, 2>(
n_alpha(), 1);
193 auto new_sigma_names = std::vector<std::string>{
"ud"};
195 return {this->sigma_embed_decomp, this->imp_decomps, std::move(new_psi), new_sigma_names};
208 std::vector<long> alphas;
212 std::vector<group_t> groups;
214 for (
long alpha = 0; alpha <
n_alpha(); ++alpha) {
215 auto const &m = psi(alpha, 0);
217 bool start_new_group =
true;
218 if (m.imp_idx >= 0 && !groups.empty()) {
219 auto &prev = groups.back();
220 auto const &prev_m = psi(prev.alphas.back(), 0);
221 if (prev.imp_idx == m.imp_idx && m.gamma > prev_m.gamma) { start_new_group =
false; }
224 if (start_new_group) {
225 groups.push_back({{alpha}, m.imp_idx});
227 groups.back().alphas.push_back(alpha);
232 auto new_sigma_embed_decomp = std::vector<long>{};
233 for (
auto const &g : groups) {
235 for (
auto a : g.alphas) total += sigma_embed_decomp[a];
236 new_sigma_embed_decomp.push_back(total);
242 auto new_imp_decomps = std::vector<std::vector<long>>(
n_impurities());
243 auto imp_seen = std::vector<bool>(
n_impurities(),
false);
244 for (
long g_idx = 0; g_idx < long(groups.size()); ++g_idx) {
245 auto const &g = groups[g_idx];
246 if (g.imp_idx < 0)
continue;
247 if (!imp_seen[g.imp_idx]) {
248 new_imp_decomps[g.imp_idx].push_back(new_sigma_embed_decomp[g_idx]);
249 imp_seen[g.imp_idx] =
true;
255 auto new_psi = nda::array<imp_block_t, 2>(
long(groups.size()),
n_sigma());
257 for (
long g_idx = 0; g_idx < long(groups.size()); ++g_idx) {
258 auto const &g = groups[g_idx];
260 for (
auto sigma : range(
n_sigma())) new_psi(g_idx, sigma) = {-1, 0, 0};
262 for (
auto sigma : range(
n_sigma())) {
263 auto tau = psi(g.alphas[0], sigma).tau;
264 new_psi(g_idx, sigma) = {g.imp_idx, 0, tau};
269 return {std::move(new_sigma_embed_decomp), std::move(new_imp_decomps), std::move(new_psi), this->_sigma_names};
275 auto new_imp_decomps = this->imp_decomps;
276 auto new_psi = this->psi;
277 new_imp_decomps.erase(begin(new_imp_decomps) + imp_idx);
278 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
279 if (b.imp_idx < imp_idx)
return {b.imp_idx, b.gamma, b.tau};
280 if (b.imp_idx > imp_idx)
return {b.imp_idx - 1, b.gamma, b.tau};
283 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
288 auto new_psi = this->psi;
290 throw std::runtime_error(fmt::format(
"Block structures of imp_idx_old={} and imp_idx_new={} do not match; cannot redirect.",
291 imp_idx_old, imp_idx_new));
292 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
293 if (b.imp_idx == imp_idx_old)
return {imp_idx_new, b.gamma, b.tau};
296 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
303 auto new_psi = this->psi;
304 auto new_imp_decomps = this->imp_decomps;
305 auto const &igs = new_imp_decomps[imp_idx];
306 auto indices = nda::range(
long(igs.size())) | tl::to<std::vector>();
309 auto mid = std::stable_partition(begin(indices), end(indices), p);
312 auto get_igs = [&](
int i) {
return igs[i]; };
313 auto stru1 = stdr::subrange{begin(indices), mid} | stdv::transform(get_igs) | tl::to<std::vector>();
314 auto stru2 = stdr::subrange{mid, end(indices)} | stdv::transform(get_igs) | tl::to<std::vector>();
315 long L1 = long(stru1.size());
318 new_imp_decomps[imp_idx] = std::move(stru1);
319 new_imp_decomps.insert(begin(new_imp_decomps) + imp_idx + 1, std::move(stru2));
322 auto indices_inv = indices;
323 for (
auto i : range(indices.size())) indices_inv[indices[i]] = i;
325 new_psi = nda::map([&](imp_block_t
const &b) -> imp_block_t {
326 if (b.imp_idx < imp_idx)
return b;
327 if (b.imp_idx > imp_idx)
return {b.imp_idx + 1, b.gamma, b.tau};
328 long new_gamma = indices_inv[b.gamma];
329 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});
331 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
337 if (not stdr::all_of(block_list, [&](
auto i) {
return (i >= 0) and (i <
n_gamma(imp_idx)); }))
338 throw std::runtime_error(fmt::format(
"[embedding::split_imp] The list of block indices {} is incorrect. Indices i should all be 0<= i < N_γ = {}",
339 block_list,
n_gamma(imp_idx)));
340 return split_imp(imp_idx, [&](
long idx) {
return stdr::find(block_list, idx) != block_list.end(); });
349 throw std::runtime_error(fmt::format(
"Invalid impurity index {} (must be 0 <= imp_idx < {})", imp_idx,
n_impurities()));
351 if (gamma < 0 or gamma >=
n_gamma(imp_idx))
352 throw std::runtime_error(fmt::format(
"Invalid gamma {} for impurity {} (must be 0 <= gamma < {})", gamma, imp_idx,
n_gamma(imp_idx)));
354 auto old_dim = imp_decomps[imp_idx][gamma];
355 if (stdr::fold_left(new_dims, 0, std::plus<>()) != old_dim)
356 throw std::runtime_error(fmt::format(
"New dimensions sum {} != old dimension {}", stdr::fold_left(new_dims, 0, std::plus<>()), old_dim));
359 auto new_imp_decomps = imp_decomps;
360 new_imp_decomps[imp_idx].erase(begin(new_imp_decomps[imp_idx]) + gamma);
361 new_imp_decomps[imp_idx].insert(begin(new_imp_decomps[imp_idx]) + gamma, begin(new_dims), end(new_dims));
364 std::set<long> alphas_to_split;
365 auto const &alpha_list = reverse_psi[imp_idx](gamma, 0);
366 for (
auto const &[alpha, sigma] : alpha_list) { alphas_to_split.insert(alpha); }
368 if (alphas_to_split.empty())
369 throw std::runtime_error(fmt::format(
"No embedding block maps to impurity {}, gamma {}. Cannot update!", imp_idx, gamma));
371 std::vector<long> sorted_alphas(alphas_to_split.begin(), alphas_to_split.end());
372 stdr::sort(sorted_alphas, std::greater<>());
374 auto new_sigma_embed_decomp = sigma_embed_decomp;
375 long n_new_blocks = long(new_dims.size());
376 for (
auto alpha : sorted_alphas) {
377 new_sigma_embed_decomp.erase(begin(new_sigma_embed_decomp) + alpha);
378 new_sigma_embed_decomp.insert(begin(new_sigma_embed_decomp) + alpha, begin(new_dims), end(new_dims));
382 long n_new_alphas = long(new_sigma_embed_decomp.size());
383 auto new_psi = nda::array<imp_block_t, 2>(n_new_alphas,
n_sigma());
385 long new_alpha_idx = 0;
386 for (
long old_alpha = 0; old_alpha <
n_alpha(); ++old_alpha) {
387 auto old_map = psi(old_alpha, 0);
390 bool is_split_alpha = (old_map.imp_idx == imp_idx && old_map.gamma == gamma);
392 if (is_split_alpha) {
394 for (
long split_idx = 0; split_idx < n_new_blocks; ++split_idx) {
395 for (
auto sigma : range(
n_sigma())) {
396 auto m = psi(old_alpha, sigma);
397 new_psi(new_alpha_idx, sigma) = {m.imp_idx, gamma + split_idx, m.tau};
403 for (
auto sigma : range(
n_sigma())) {
404 auto m = psi(old_alpha, sigma);
405 if (m.imp_idx == imp_idx && m.gamma > gamma) {
406 new_psi(new_alpha_idx, sigma) = {m.imp_idx, m.gamma + n_new_blocks - 1, m.tau};
408 new_psi(new_alpha_idx, sigma) = m;
414 return {std::move(new_sigma_embed_decomp), std::move(new_imp_decomps), std::move(new_psi), this->_sigma_names};
419 if (
long(Sigma_imp_static_vec.size()) !=
n_impurities())
420 throw std::runtime_error(fmt::format(
"[embedding::embed] Wrong number of impurity static self-energies: got {} but embedding has {} impurities",
422 return detail::data_array_to_block2_array(this->
embed(detail::matrix_to_array(Sigma_imp_static_vec)), sigma_embed_decomp);
427 if (matrix_C.extent(1) !=
n_sigma())
428 throw std::runtime_error(
429 fmt::format(
"[embedding::extract] Wrong number of spin channels in matrix: got {} but embedding has n_sigma = {}", matrix_C.extent(1),
n_sigma()));
430 if (matrix_C.extent(0) != 1)
return extract(detail::gather_blocks_to_data_view(matrix_C));
431 auto data = range(
n_sigma()) | stdv::transform([&](
auto sigma) {
return nda::array<dcomplex, 2>{matrix_C(0, sigma)}; }) | tl::to<std::vector>();
432 return detail::array_to_matrix(this->
extract(data));
std::vector< gf_struct_t > imp_block_structure() const
Block structure (names and dimensions) for each impurity solver.
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 .
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.
std::vector< std::string > sigma_names() const
The names of the sigma indices.
long n_alpha() const
Number of blocks in for the .
embedding swap_sigma(long alpha) const
Swap the (spin) assignment for block alpha.
C2PY_IGNORE gf_struct2_t embed_block_structure() const
Block structure (names and dimensions) for the embedded self-energy .
embedding slice_sigma() const
Slice the embedding to a single channel ("ud").
embedding drop_imp(long imp_idx) const
Remove an impurity from the embedding table .
embedding split_imp(long imp_idx, std::function< bool(long)> p) const
Split impurity imp_idx using a predicate.
embedding replace_imp(long imp_idx_old, long imp_idx_new) const
Redirect all entries from one impurity to another.
std::vector< std::vector< nda::array< dcomplex, Rank > > > extract(std::vector< nda::array< dcomplex, Rank > > const &X) const
Extract impurity data from embedded arrays.
embedding split_imp_block(long imp_idx, long gamma, std::vector< long > const &new_dims) const
Split a single block of an impurity into multiple blocks.
std::vector< nda::array< dcomplex, Rank > > embed(std::vector< std::vector< nda::array< dcomplex, Rank > > > const &imps_blocks) const
Embed impurity data into the full correlated space.
embedding merge_embed_block_by_imp() const
Merge consecutive blocks belonging to the same impurity into a single block.
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.
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.
std::vector< long > atomic_decomposition() const
Dimensions of each atomic shell, in order.
embedding make_embedding(std::vector< std::string > const &spin_names, nda::array< std::vector< long >, 2 > const &block_decomposition, std::vector< long > const &atom_to_imp)
embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp)
embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp)
static constexpr auto r_all
nda::array< nda::matrix< dcomplex >, 2 > block2_matrix_t