311 template <
bool enforce_hermiticity = false,
typename M>
void setup_lss(M
const &m,
int n_A) {
313 using worker_t = std::conditional_t<enforce_hermiticity, nda::lapack::gelss_worker_hermitian, nda::lapack::gelss_worker<std::complex<double>>>;
319 double const z_max = std::abs(m.w_max());
321 std::vector<std::complex<double>> z_pts;
322 z_pts.reserve(fit_idxs_.size());
323 for (
long n : fit_idxs_) z_pts.push_back(z_max / m.to_value(n));
328 if (n_A + 1 > V_.extent(0) / 2)
TRIQS_RUNTIME_ERROR <<
"Error in tail-fitter::setup_lss: Insufficient data points for least square procedure";
331 auto worker_factory = [&](
int n) {
return std::make_unique<const worker_t>(V_(nda::range::all, nda::range(n_A, n + 1))); };
339 lss[n_A] = worker_factory(q_);
344 long q_max = std::min(
static_cast<long>(q_max_),
static_cast<long>(1. + 16. / std::log10(1 + std::abs(m.w_max()))));
346 q_max = std::min(q_max, V_.extent(0) / 2);
347 for (
long q = q_max; q >= n_A; --q) {
348 auto ptr = worker_factory(q);
349 if (ptr->S_vec()[ptr->S_vec().size() - 1] > rcond_) {
350 lss[n_A] = std::move(ptr);
357 if (!lss[n_A])
TRIQS_RUNTIME_ERROR <<
"Error in tail-fitter::setup_lss: Ill-conditioned Vandermonde matrix";
398 auto fit(M
const &m, nda::array_const_view<std::complex<double>, R> D,
bool rescale, nda::array_const_view<std::complex<double>, R> C,
399 std::optional<long> d = {}) {
401 static_assert(!enforce_hermiticity || std::is_same_v<M, imfreq>);
402 if (enforce_hermiticity and not d.has_value())
403 TRIQS_RUNTIME_ERROR <<
"Error in tail-fitter::fit: Enforcing hermiticity requires an inner matrix dimension";
404 if (m.positive_only())
TRIQS_RUNTIME_ERROR <<
"Error in tail-fitter::fit: Cannot fit on a positive_only mesh";
407 int const n_A = C.extent(0);
408 if (n_A > q_)
return std::pair<nda::array<std::complex<double>, R>,
double>{C, 0.0};
411 auto &lss = get_lss<enforce_hermiticity>();
412 if (!lss[n_A]) setup_lss<enforce_hermiticity>(m, n_A);
415 auto D_rot = nda::rotate_index_view<P>(D);
418 long const ncols = D_rot.size() / D_rot.shape()[0];
419 auto D_mat = nda::matrix<std::complex<double>>(V_.extent(0), ncols);
420 for (
auto [i, n] : itertools::enumerate(fit_idxs_)) {
421 if constexpr (R == 1) {
422 D_mat(i, 0) = D_rot(m.to_data_index(n));
424 for (
auto [j, x] : itertools::enumerate(D_rot(m.to_data_index(n), nda::ellipsis{}))) { D_mat(i, j) = x; }
429 double const z_max = std::abs(m.w_max());
432 if (ncols != C.size() / C.shape()[0])
433 TRIQS_RUNTIME_ERROR <<
"Error in tail-fitter::fit: Shape of C array incompatible with the shape of the D array";
437 auto C_mat = nda::matrix<std::complex<double>>(n_A, ncols);
438 for (
long i : nda::range(n_A)) {
439 if constexpr (R == 1) {
440 C_mat(i, 0) = z * C(i, nda::ellipsis{});
442 for (
auto [j, x] : itertools::enumerate(C(i, nda::ellipsis{}))) C_mat(i, j) = z * x;
448 D_mat -= V_(nda::range::all, nda::range(n_A)) * C_mat;
452 auto [A_mat, err] = (*lss[n_A])(D_mat, d);
457 for ([[maybe_unused]]
long i : nda::range(n_A)) z *= z_max;
458 for (
long i : nda::range(A_mat.extent(0))) {
459 A_mat(i, nda::range::all) *= z;
465 auto shape = D_rot.shape();
466 shape[0] = lss[n_A]->n_var() + n_A;
467 auto A = nda::array<std::complex<double>, R>{shape};
470 if (n_A) A(nda::range(n_A), nda::ellipsis{}) = C;
473 shape[0] = lss[n_A]->n_var();
474 auto idxmap =
typename nda::array<std::complex<double>, R>::layout_t{shape};
475 auto A_view = A(nda::range(n_A, A.shape()[0]), nda::ellipsis{});
476 A_view = nda::array_view<std::complex<double>, R>{idxmap, A_mat.storage()};
478 return std::pair<nda::array<std::complex<double>, R>,
double>{std::move(A), err};
498 auto fit_hermitian(M
const &m, nda::array_const_view<std::complex<double>, R> D,
bool rescale, nda::array_const_view<std::complex<double>, R> C,
499 std::optional<long> d = {}) {
500 return fit<P, true, M, R>(m, D, rescale, C, d);