From 12668d99bd872539ff74d82a966ed049e66acde9 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Thu, 4 Apr 2024 15:27:42 +0200 Subject: Some optimizations. --- least_squares.cpp | 57 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/least_squares.cpp b/least_squares.cpp index 648592f..2ede87c 100644 --- a/least_squares.cpp +++ b/least_squares.cpp @@ -73,7 +73,7 @@ public: return {H, gradH, hessH}; } - Real getHamiltonian(const Vector& x) const { + virtual Real getHamiltonian(const Vector& x) const { Real H; std::tie(H, std::ignore, std::ignore) = HdHddH(x); return H; @@ -129,6 +129,15 @@ public: return {H, dH, ddH}; } + + /* Unfortunately benchmarking indicates that ignorning entries of a returned tuple doesn't result + * in those execution paths getting optimized out. It is much more efficient to compute the + * energy alone when only the energy is needed. + */ + Real getHamiltonian(const Vector& x) const override { + Vector V = b + (A + 0.5 * (J * x)) * x; + return 0.5 * V.squaredNorm(); + } }; class CubicModel : public Model { @@ -217,30 +226,36 @@ Vector findMinimum(const Model& M, const Vector& x0, Real ε = 1e-12) { return x; } -Vector metropolisStep(const Model& M, const Vector& x0, Real β, Rng& r, Real ε = 1) { - Vector Δx(M.N); +Vector metropolisSweep(const Model& M, const Vector& x0, Real β, Rng& r, unsigned sweeps = 1, Real ε = 1) { + Vector x = x0; + Real H = M.getHamiltonian(x); - for (Real& Δxᵢ : Δx) { - Δxᵢ = ε * r.variate(); - } + for (unsigned j = 0; j < sweeps; j++) { + Real rate = 0; - Vector xNew = normalize(x0 + Δx); + for (unsigned i = 0; i < M.N; i++) { + Vector xNew = x; - Real Hold = M.getHamiltonian(x0); - Real Hnew = M.getHamiltonian(xNew); + for (Real& xNewᵢ : xNew) { + xNewᵢ += ε * r.variate(); + } - if (exp(-β * (Hnew - Hold)) > r.uniform(0.0, 0.1)) { - return xNew; - } else { - return x0; - } -} + xNew = normalize(xNew); -Vector metropolisSweep(const Model& M, const Vector& x0, Real β, Rng& r, Real ε = 1) { - Vector x = x0; + Real Hnew = M.getHamiltonian(xNew); + + if (exp(-β * (Hnew - H)) > r.uniform(0.0, 0.1)) { + x = xNew; + H = Hnew; + rate++; + } + } - for (unsigned i = 0; i < M.N; i++) { - x = metropolisStep(M, x, β, r, ε); + if (rate / M.N < 0.5) { + ε /= 1.5; + } else { + ε *= 1.5; + } } return x; @@ -300,9 +315,7 @@ int main(int argc, char* argv[]) { for (unsigned sample = 0; sample < samples; sample++) { QuadraticModel leastSquares(N, M, r, σ, A, J); - for (unsigned i = 0; i < sweeps; i++) { - x = metropolisSweep(leastSquares, x, β, r); - } + x = metropolisSweep(leastSquares, x, β, r, sweeps); x = findMinimum(leastSquares, x); std::cout << " " << leastSquares.getHamiltonian(x) / N; } -- cgit v1.2.3-70-g09d2