Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
dmrg_lanczos.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include <uni20/core/math.hpp>
14
15#include <algorithm>
16#include <cmath>
17#include <cstddef>
18#include <stdexcept>
19#include <type_traits>
20#include <utility>
21#include <vector>
22
24{
25
31template <uni20::Real Real> struct DmrgLanczosOptions
32{
34 std::size_t matvec_iterations = 4;
35};
36
40template <uni20::Real Real, class Vector> struct DmrgLanczosResult
41{
47 Vector vector;
52};
53
54namespace detail
55{
56
57template <uni20::LapackRealOrComplex Scalar>
58auto dmrg_lanczos_projection_scalar(Scalar value,
60{
62 using std::abs;
63 Real const real_part = static_cast<Real>(uni20::real(value));
64 if constexpr (uni20::Complex<Scalar>)
65 {
66 Real const scale = std::max({Real{1}, local_scale, static_cast<Real>(abs(value))});
67 Real const tolerance = Real{100} * uni20::numeric_limits<Real>::epsilon() * scale;
68 if (abs(static_cast<Real>(uni20::imag(value))) > tolerance)
69 throw std::runtime_error("DMRG Lanczos received a non-real projected diagonal");
70 }
71 return real_part;
72}
73
74template <uni20::Real Real> auto dmrg_lanczos_breakdown(Real beta, Real alpha, Real previous_beta) -> bool
75{
76 using std::abs;
77 Real const scale = std::max(abs(alpha), abs(previous_beta));
79}
80
81template <uni20::LapackRealOrComplex Scalar, class Vector, class Ops>
82void normalize_dmrg_lanczos_vector(Ops& ops, Vector& vector, uni20::make_real_t<Scalar> norm)
83{
85 Real const maximum = uni20::numeric_limits<Real>::max();
86 Real const reciprocal = Real{1} / norm;
87 if (uni20::isfinite(reciprocal))
88 {
89 ops.scal(vector, static_cast<Scalar>(reciprocal));
90 return;
91 }
92
93 // A uniformly tiny vector still has a meaningful direction, but its direct
94 // reciprocal is not representable. Lift it into the normal range first.
95 ops.scal(vector, static_cast<Scalar>(maximum));
96 Real const lifted_norm = krylov::norm_or_inner_product<Scalar>(ops, vector);
97 if (!(lifted_norm > Real{}) || !uni20::isfinite(lifted_norm))
98 throw std::runtime_error("DMRG Lanczos could not normalize a finite nonzero vector");
99 ops.scal(vector, Scalar{1} / static_cast<Scalar>(lifted_norm));
100}
101
102} // namespace detail
103
120template <uni20::LapackRealOrComplex Scalar, class Vector, krylov::KrylovMatrixFreeOperator<Vector, Scalar> Ops>
121[[nodiscard]] auto dmrg_lanczos_ground_state(Ops& ops, Vector const& initial,
123 -> DmrgLanczosResult<uni20::make_real_t<Scalar>, Vector>
124{
126 using std::abs;
127
128 if (options.matvec_iterations == 0)
129 throw std::invalid_argument("DMRG Lanczos requires at least one matvec iteration");
130 std::size_t const problem_dimension = krylov::validate_matrix_free_dimensions(ops, initial, "DMRG Lanczos");
131 std::size_t const basis_limit = std::min(problem_dimension, options.matvec_iterations);
132
133 std::vector<Vector> basis;
134 std::vector<Real> diagonal;
135 std::vector<Real> subdiagonal;
136 basis.reserve(basis_limit);
137 diagonal.reserve(basis_limit);
138 subdiagonal.reserve(basis_limit - 1);
139
140 Vector start = ops.allocate_like(initial);
141 ops.copy(start, initial);
142 Real const start_norm = krylov::norm_or_inner_product<Scalar>(ops, start);
143 if (!(start_norm > Real{}) || !uni20::isfinite(start_norm))
144 throw std::invalid_argument("DMRG Lanczos initial vector must have a finite nonzero norm");
145 detail::normalize_dmrg_lanczos_vector<Scalar>(ops, start, start_norm);
146 basis.push_back(std::move(start));
147
148 Real final_residual_norm{};
149 int matvec_count = 0;
150 for (std::size_t step = 0; step < basis_limit; ++step)
151 {
152 Vector residual = ops.allocate_like(basis[step]);
153 ops.matvec(residual, basis[step]);
154 ++matvec_count;
155
156 Real const previous_beta = step == 0 ? Real{} : subdiagonal[step - 1];
157 if (step > 0) ops.axpy(residual, -static_cast<Scalar>(previous_beta), basis[step - 1]);
158
159 Real projection_scale = Real{1};
160 if constexpr (uni20::Complex<Scalar>) projection_scale = krylov::norm_or_inner_product<Scalar>(ops, residual);
161 Real const alpha =
162 detail::dmrg_lanczos_projection_scalar<Scalar>(ops.inner_product(basis[step], residual), projection_scale);
163 diagonal.push_back(alpha);
164 ops.axpy(residual, -static_cast<Scalar>(alpha), basis[step]);
165
166 Real const beta = krylov::norm_or_inner_product<Scalar>(ops, residual);
167 if (!uni20::isfinite(beta)) throw std::runtime_error("DMRG Lanczos produced a non-finite residual norm");
168 final_residual_norm = beta;
169 if (step + 1 == basis_limit || detail::dmrg_lanczos_breakdown(beta, alpha, previous_beta)) break;
170
171 detail::normalize_dmrg_lanczos_vector<Scalar>(ops, residual, beta);
172 subdiagonal.push_back(beta);
173 basis.push_back(std::move(residual));
174 }
175
176 auto projected = krylov::symmetric_tridiagonal_eigensystem(std::move(diagonal), std::move(subdiagonal), true);
177 Real const final_coefficient = projected.eigenvectors[basis.size() - 1, 0];
178
179 Vector vector = ops.allocate_like(initial);
180 ops.copy(vector, basis.front());
181 ops.scal(vector, static_cast<Scalar>(projected.eigenvectors[0, 0]));
182 for (std::size_t row = 1; row < basis.size(); ++row)
183 ops.axpy(vector, static_cast<Scalar>(projected.eigenvectors[row, 0]), basis[row]);
184
185 return {.energy = projected.eigenvalues.front(),
186 .residual_bound = final_residual_norm * abs(final_coefficient),
187 .vector = std::move(vector),
188 .iteration_count = static_cast<int>(basis.size()),
189 .matvec_count = matvec_count};
190}
191
192} // namespace uni20::tensor_network
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
Concept for real scalar types (float, double, etc.).
Definition scalar_concepts.hpp:69
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
locale_t value
Definition data_table.cpp:49
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
constexpr T & real(detail::standard_complex< T > &z) noexcept
Provides mutable access to the real component of a uni20::complex value.
Definition math.hpp:173
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Scalar math helper utilities.
TridiagonalEigensystem< Scalar > symmetric_tridiagonal_eigensystem(std::vector< Scalar > diagonal, std::vector< Scalar > subdiagonal, bool compute_vectors)
Solve a real symmetric tridiagonal eigensystem through LAPACK sterf or steqr.
Definition dense_subspace.hpp:288
std::size_t validate_matrix_free_dimensions(Ops const &ops, Vector const &vector, char const *context)
Validate that an initial/prototype vector matches the matrix-free problem dimension.
Definition matrix_free.hpp:549
Definition right_first_rabc.hpp:34
auto dmrg_lanczos_ground_state(Ops &ops, Vector const &initial, DmrgLanczosOptions< uni20::make_real_t< Scalar > > const &options={}) -> DmrgLanczosResult< uni20::make_real_t< Scalar >, Vector >
Perform a lightweight fixed-step Lanczos local ground-state update.
Definition dmrg_lanczos.hpp:121
constexpr auto abs(basic_half_int< T > value) -> basic_half_int< T >
Return the absolute value of a half-integer.
Definition half_int.hpp:431
mpreal norm(mpcomplex const &z)
Definition mpcomplex.hpp:494
void scale(Tensor &tensor, Scalar factor)
Multiply every stored numerical block by a scalar in place.
Definition block_tensor_linear.hpp:400
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16
Numerical policy for one lightweight DMRG local Lanczos solve.
Definition dmrg_lanczos.hpp:32
std::size_t matvec_iterations
Maximum number of effective-Hamiltonian applications per local update.
Definition dmrg_lanczos.hpp:34
Approximate local ground state produced by fixed-step DMRG Lanczos.
Definition dmrg_lanczos.hpp:41
int matvec_count
Number of effective-Hamiltonian applications.
Definition dmrg_lanczos.hpp:51
int iteration_count
Number of completed Lanczos projection steps.
Definition dmrg_lanczos.hpp:49
Vector vector
Smallest Ritz vector reconstructed in the original vector space.
Definition dmrg_lanczos.hpp:47
Real energy
Smallest Ritz value of the final projected problem.
Definition dmrg_lanczos.hpp:43
Real residual_bound
Final three-term-recurrence Ritz residual estimate.
Definition dmrg_lanczos.hpp:45