From 136fcddcd38d0b8f3b40faf7c1cb7365d9b2a753 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Fri, 15 Jan 2021 14:45:19 +0100 Subject: Converted more of library to templates accepting generic Scalar types and p --- langevin.cpp | 156 ++++++++++------------------------------------------------- 1 file changed, 26 insertions(+), 130 deletions(-) (limited to 'langevin.cpp') diff --git a/langevin.cpp b/langevin.cpp index a4c9cf3..870879b 100644 --- a/langevin.cpp +++ b/langevin.cpp @@ -1,127 +1,21 @@ -#include #include -#include -#include - #include "complex_normal.hpp" #include "p-spin.hpp" -#include "stereographic.hpp" +#include "dynamics.hpp" #include "pcg-cpp/include/pcg_random.hpp" #include "randutils/randutils.hpp" #include "unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h" -using Rng = randutils::random_generator; - -Vector normalize(const Vector& z) { - return z * sqrt((double)z.size() / (Scalar)(z.transpose() * z)); -} - -template -Vector randomVector(unsigned N, Distribution d, Generator& r) { - Vector z(N); - - for (unsigned i = 0; i < N; i++) { - z(i) = d(r); - } - - return z; -} - -class gradientDescentStallException: public std::exception { - virtual const char* what() const throw() { - return "Gradient descent stalled."; - } -} gradientDescentStall; - -std::tuple gradientDescent(const Tensor& J, const Vector& z0, double ε, double γ0 = 1, double δγ = 2) { - Vector z = z0; - double γ = γ0; - - auto [W, dW] = WdW(J, z); - - while (W > ε) { - Vector zNew = normalize(z - γ * dW.conjugate()); - - auto [WNew, dWNew] = WdW(J, zNew); - - if (WNew < W) { // If the step lowered the objective, accept it! - z = zNew; - W = WNew; - dW = dWNew; - γ = γ0; - } else { // Otherwise, shrink the step and try again. - γ /= δγ; - } - - if (γ < 1e-50) { - throw gradientDescentStall; - } - } +#define PSPIN_P 3 +const int p = PSPIN_P; // polynomial degree of Hamiltonian +using Complex = std::complex; +using ComplexVector = Vector; +using ComplexMatrix = Matrix; +using ComplexTensor = Tensor; - return {W, z}; -} - -Vector findSaddle(const Tensor& J, const Vector& z0, double ε, double δW = 2, double γ0 = 1, double δγ = 2) { - Vector z = z0; - Vector ζ = euclideanToStereographic(z); - - double W; - std::tie(W, std::ignore) = WdW(J, z); - - Vector dH; - Matrix ddH; - std::tie(std::ignore, dH, ddH) = stereographicHamGradHess(J, ζ, z); - - while (W > ε) { - // ddH is complex symmetric, which is (almost always) invertible, so a - // partial pivot LU decomposition can be used. - Vector dζ = ddH.partialPivLu().solve(dH); - Vector ζNew = ζ - dζ; - Vector zNew = stereographicToEuclidean(ζNew); - - double WNew; - std::tie(WNew, std::ignore) = WdW(J, zNew); - - if (WNew < W) { // If Newton's step lowered the objective, accept it! - ζ = ζNew; - z = zNew; - W = WNew; - } else { // Otherwise, do gradient descent until W is a factor δW smaller. - std::tie(W, z) = gradientDescent(J, z, W / δW, γ0, δγ); - ζ = euclideanToStereographic(z); - } - - std::tie(std::ignore, dH, ddH) = stereographicHamGradHess(J, ζ, z); - } - - return z; -} - -std::tuple langevin(const Tensor& J, const Vector& z0, double T, double γ, unsigned N, Rng& r) { - Vector z = z0; - - double W; - std::tie(W, std::ignore) = WdW(J, z); - - complex_normal_distribution<> d(0, γ, 0); - - for (unsigned i = 0; i < N; i++) { - Vector dz = randomVector(z.size(), d, r.engine()); - Vector zNew = normalize(z + dz); - - double WNew; - std::tie(WNew, std::ignore) = WdW(J, zNew); - - if (exp((W - WNew) / T) > r.uniform(0.0, 1.0)) { - z = zNew; - W = WNew; - } - } - - return {W, z}; -} +using Rng = randutils::random_generator; int main(int argc, char* argv[]) { // model parameters @@ -178,22 +72,24 @@ int main(int argc, char* argv[]) { } } - Scalar κ(Rκ, Iκ); + Complex κ(Rκ, Iκ); double σ = sqrt(factorial(p) / (2.0 * pow(N, p - 1))); Rng r; - Tensor J = generateCouplings(N, complex_normal_distribution<>(0, σ, κ), r.engine()); - Vector z0 = normalize(randomVector(N, complex_normal_distribution<>(0, 1, 0), r.engine())); + complex_normal_distribution<> d(0, 1, 0); + + ComplexTensor J = generateCouplings(N, complex_normal_distribution<>(0, σ, κ), r.engine()); + ComplexVector z0 = normalize(randomVector(N, d, r.engine())); - Vector zSaddle = findSaddle(J, z0, ε); - Vector zSaddlePrev = Vector::Zero(N); - Vector z = zSaddle; + ComplexVector zSaddle = findSaddle(J, z0, ε); + ComplexVector zSaddlePrev = ComplexVector::Zero(N); + ComplexVector z = zSaddle; while (δ < (zSaddle - zSaddlePrev).norm()) { // Until we find two saddles sufficiently close... - std::tie(std::ignore, z) = langevin(J, z, T, γ, M, r); + std::tie(std::ignore, z) = langevin(J, z, T, γ, M, d, r.engine()); try { - Vector zSaddleNext = findSaddle(J, z, ε); + ComplexVector zSaddleNext = findSaddle(J, z, ε); if (Δ < (zSaddleNext - zSaddle).norm()) { // Ensure we are finding distinct saddles. zSaddlePrev = zSaddle; zSaddle = zSaddleNext; @@ -209,20 +105,20 @@ int main(int argc, char* argv[]) { complex_normal_distribution<> dJ(0, εJ * σ, 0); - std::function)> perturbJ = - [&dJ, &r] (Tensor& JJ, std::array ind) { - Scalar Ji = getJ(JJ, ind); - setJ(JJ, ind, Ji + dJ(r.engine())); + std::function)> perturbJ = + [&dJ, &r] (ComplexTensor& JJ, std::array ind) { + Complex Ji = getJ(JJ, ind); + setJ(JJ, ind, Ji + dJ(r.engine())); }; for (unsigned i = 0; i < n; i++) { - Tensor Jp = J; + ComplexTensor Jp = J; - iterateOver(Jp, perturbJ); + iterateOver(Jp, perturbJ); try { - Vector zSaddleNew = findSaddle(Jp, zSaddle, ε); - Vector zSaddlePrevNew = findSaddle(Jp, zSaddlePrev, ε); + ComplexVector zSaddleNew = findSaddle(Jp, zSaddle, ε); + ComplexVector zSaddlePrevNew = findSaddle(Jp, zSaddlePrev, ε); std::cout << zSaddleNew.transpose() << " " << zSaddlePrevNew.transpose() << std::endl; } catch (std::exception& e) { -- cgit v1.2.3-70-g09d2