#include #include #include #include "pcg-cpp/include/pcg_random.hpp" #include "randutils/randutils.hpp" #include "eigen/Eigen/Dense" #include "eigen/unsupported/Eigen/CXX11/Tensor" #include "eigen/unsupported/Eigen/CXX11/TensorSymmetry" using Rng = randutils::random_generator; using Real = double; using Vector = Eigen::Matrix; using Matrix = Eigen::Matrix; class Tensor : public Eigen::Tensor { using Eigen::Tensor::Tensor; public: Matrix operator*(const Vector& x) const { std::array, 1> ip20 = {Eigen::IndexPair(2, 0)}; const Eigen::Tensor xT = Eigen::TensorMap>(x.data(), x.size()); const Eigen::Tensor JxT = contract(xT, ip20); return Eigen::Map(JxT.data(), dimension(0), dimension(1)); } }; Vector normalize(const Vector& x) { return x * sqrt(x.size() / x.squaredNorm()); } class Spherical3Spin { private: Tensor J; public: unsigned N; Spherical3Spin(unsigned N, Rng& r) : J(N, N, N), N(N) { Eigen::StaticSGroup, Eigen::Symmetry<1,2>> sym123; for (unsigned i = 0; i < N; i++) { for (unsigned j = i; j < N; j++) { for (unsigned k = j; k < N; k++) { sym123(J, i, j, k) = r.variate(0, sqrt(12) / N); } } } } std::tuple H_∂H_∂∂H(const Vector& x) const { Matrix ∂∂H = J * x; Vector ∂H = ∂∂H * x / 2; Real H = ∂H.dot(x) / 6; return {H, ∂H, ∂∂H}; } }; class ConstrainedHeight { private: Vector x0; Real E; public: Spherical3Spin S; unsigned N; ConstrainedHeight(unsigned N, Real E, Rng& r) : x0(N), E(E), S(N, r), N(N) { for (Real& x0ᵢ : x0) { x0ᵢ = r.variate(); } x0 = normalize(x0); } Real overlap(const Vector& v) const { return v.head(N).dot(x0) / N; } std::tuple ∂L_∂∂L(const Vector& v) const { Vector x = v.head(N); Real ω₀ = v(N); Real ω₁ = v(N + 1); auto [H, ∂H∂x, ∂²H∂²x] = S.H_∂H_∂∂H(x); Vector ∂L∂x = x0 + ω₀ * x + ω₁ * ∂H∂x; Real ∂L∂ω₀ = 0.5 * (x.squaredNorm() - N); Real ∂L∂ω₁ = H - N * E; Vector ∂L(N + 2); ∂L << ∂L∂x, ∂L∂ω₀, ∂L∂ω₁; Matrix ∂L²∂x² = ω₀ * Matrix::Identity(N, N) + ω₁ * ∂²H∂²x; Vector ∂²L∂x∂ω₀ = x; Vector ∂²L∂x∂ω₁ = ∂H∂x; Matrix ∂∂L(N + 2, N + 2); ∂∂L << ∂L²∂x², ∂²L∂x∂ω₀, ∂²L∂x∂ω₁, ∂²L∂x∂ω₀.transpose(), 0, 0, ∂²L∂x∂ω₁.transpose(), 0, 0; return {∂L, ∂∂L}; } Vector newtonMethod(const Vector& v0, Real γ = 1) { Vector v = v0; Vector ∂L; Matrix ∂∂L; while (std::tie(∂L, ∂∂L) = ∂L_∂∂L(v), ∂L.squaredNorm() > 1e-10) { v -= γ * ∂∂L.partialPivLu().solve(∂L); v.head(N) = normalize(v.head(N)); // might as well stay on the sphere } return v; } }; int main(int argc, char* argv[]) { unsigned N = 10; double E = 0; double γ = 1; unsigned samples = 10; int opt; while ((opt = getopt(argc, argv, "N:E:g:n:")) != -1) { switch (opt) { case 'N': N = (unsigned)atof(optarg); break; case 'E': E = atof(optarg); break; case 'g': γ = atof(optarg); break; case 'n': samples = atoi(optarg); break; default: exit(1); } } Rng r; Vector x = Vector::Zero(N); x(0) = sqrt(N); std::cout << std::setprecision(15); for (unsigned sample = 0; sample < samples; sample++) { Vector v0(N + 2); v0 << x, r.variate(), r.variate(); ConstrainedHeight M(N, E, r); Vector v = M.newtonMethod(v0, γ); std::cout << M.overlap(v) << std::endl; } return 0; }