From 7bf6e952b53699977f5091a78f0f9f48f7b359c5 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Tue, 9 Nov 2021 10:13:59 +0100 Subject: Generalized code to easily allow mixed p-spins. --- p-spin.hpp | 101 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 37 deletions(-) (limited to 'p-spin.hpp') diff --git a/p-spin.hpp b/p-spin.hpp index 6111b75..a5f6c9a 100644 --- a/p-spin.hpp +++ b/p-spin.hpp @@ -12,66 +12,93 @@ Vector normalize(const Eigen::MatrixBase& z) return z * sqrt((Real)z.size() / (typename Derived::Scalar)(z.transpose() * z)); } -template -std::tuple, Matrix> hamGradHess(const Tensor& J, const Tensor& ... Js, const Vector& z) { - Matrix Jz = contractDown(J, z); // Contracts J into p - 2 copies of z. +template +std::tuple, Tensor> hamGradTensorHelper(const Vector& z, const Tensor& J) { + Tensor J3(z.size(), z.size(), z.size());; + J3.setZero(); + Matrix Jz = Eigen::Map>(J.data(), z.size(), z.size()); + + return {Jz, J3}; +} + +template +std::tuple, Tensor> hamGradTensorHelper(const Vector& z, const Tensor& J) { + Tensor J3 = contractDown(J, z); + Tensor zT = Eigen::TensorMap>(z.data(), {z.size()}); + Tensor J3zT = J3.contract(zT, ip00); + Matrix Jz = Eigen::Map>(J3zT.data(), z.size(), z.size()); + + return {Jz, J3}; +} + +template +std::tuple, Matrix, Tensor> hamGradHessHelper(const Vector& z, const Tensor& J, const Tensor& ...Js) { + auto [Jz, J3] = hamGradTensorHelper(z, J); + Vector Jzz = Jz * z; Scalar Jzzz = Jzz.transpose() * z; Real pBang = factorial(p); + Tensor dddH = ((p - 2) * (p - 1) * p / pBang) * J3; Matrix ddH = ((p - 1) * p / pBang) * Jz; Vector dH = (p / pBang) * Jzz; Scalar H = Jzzz / pBang; if constexpr (sizeof...(Js) > 0) { - auto [Hs, dHs, ddHs] = hamGradHess(Js..., z); + auto [Hs, dHs, ddHs, dddHs] = hamGradHess(z, Js...); H += Hs; dH += dHs; ddH += ddHs; + dddH += dddHs; } - return {H, dH, ddH}; + return {H, dH, ddH, dddH}; } -template -Scalar getHamiltonian(const Tensor& J, const Vector& z) { - Scalar H; - std::tie(H, std::ignore, std::ignore) = hamGradHess(J, z); - return H; -} +template +class pSpinModel { +public: + std::tuple...> Js; -template -Vector getGradient(const Tensor& J, const Vector& z) { - Vector dH; - std::tie(std::ignore, dH, std::ignore) = hamGradHess(J, z); - return dH; -} + unsigned dimension() const { + return std::get<0>(Js).dimension(0); + } -template -Matrix getHessian(const Tensor& J, const Vector& z) { - Matrix ddH; - std::tie(std::ignore, std::ignore, ddH) = hamGradHess(J, z); - return ddH; -} + template + pSpinModel cast() const { + pSpinModel M; + M.Js = std::apply( + [] (const Tensor& ...Ks) -> std::tuple...> { + return std::make_tuple(Ks.template cast()...); + }, Js + ); -template -Real getThresholdEnergyDensity(unsigned p, Scalar κ, Scalar ε, Real a) { - Real apm2 = pow(a, p - 2); - Scalar δ = κ / apm2; - Real θ = arg(κ) + 2 * arg(ε); + return M; + } - return (p - 1) * apm2 / (2 * p) * pow(1 - norm(δ), 2) / (1 + norm(δ) - 2 * abs(δ) * cos(θ)); -} + std::tuple, Matrix, Tensor> hamGradHess(const Vector& z) const { + return std::apply([&z](const Tensor& ...Ks) -> std::tuple, Matrix, Tensor> { return hamGradHessHelper(z, Ks...); }, Js); + } -template -Real getProportionOfThreshold(Scalar κ, const Tensor& J, const Vector& z) { - Real N = z.size(); - Scalar ε = getHamiltonian(J, z) / N; - Real a = z.squaredNorm() / N; + Scalar getHamiltonian(const Vector& z) const { + Scalar H; + std::tie(H, std::ignore, std::ignore, std::ignore) = hamGradHess(z); + return H; + } - return norm(ε) / getThresholdEnergyDensity(p, κ, ε, a); -} + Vector getGradient(const Vector& z) const { + Vector dH; + std::tie(std::ignore, dH, std::ignore, std::ignore) = hamGradHess(z); + return dH; + } + + Matrix getHessian(const Vector& z) const { + Matrix ddH; + std::tie(std::ignore, std::ignore, ddH, std::ignore) = hamGradHess(z); + return ddH; + } +}; template Vector zDot(const Vector& z, const Vector& dH) { -- cgit v1.2.3-54-g00ecf