#pragma once #include #include #include #include #include "p-spin.hpp" #include "stereographic.hpp" class gradientDescentStallException: public std::exception { virtual const char* what() const throw() { return "Gradient descent stalled."; } }; template std::tuple> gradientDescent(const Tensor& J, const Vector& z0, Real ε, Real γ0 = 1, Real δγ = 2) { Vector z = z0; Real γ = γ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 gradientDescentStallException(); } } return {W, z}; } template Vector findSaddle(const Tensor& J, const Vector& z0, Real ε, Real δW = 2, Real γ0 = 1, Real δγ = 2) { Vector z = z0; Vector dH; Matrix ddH; std::tie(std::ignore, dH, ddH) = hamGradHess(J, z); Scalar zz = z.transpose() * z; Vector ż = zDot(z, dH) + z * (zz - (Real)z.size()); Matrix dż = dzDot(z, dH) + Matrix::Identity(z.size(), z.size()) * (zz - (Real)z.size()) + 2.0 * z * z.transpose(); Matrix dżc = dzDotConjugate(z, dH, ddH); Vector b(2 * z.size()); Matrix M(2 * z.size(), 2 * z.size()); b << ż.conjugate(), ż; M << dż.conjugate(), dżc, dżc.conjugate(), dż; while (ż.norm() > ε) { Vector dz = M.partialPivLu().solve(b).tail(z.size()); dz -= z.conjugate().dot(dz) / z.squaredNorm() * z.conjugate(); z = normalize(z - dz); std::cout << "error : " << z.transpose() * z << " "<< ż.norm() << " " << dz.norm() << std::endl; getchar(); std::tie(std::ignore, dH, ddH) = hamGradHess(J, z); zz = z.transpose() * z; ż = zDot(z, dH) + z * (zz - (Real)z.size()); dż = dzDot(z, dH) + Matrix::Identity(z.size(), z.size()) * (zz - (Real)z.size()) + 2.0 * z * z.transpose(); dżc = dzDotConjugate(z, dH, ddH); b << ż.conjugate(), ż; M << dż.conjugate(), dżc, dżc.conjugate(), dż; } return 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; } template std::tuple> metropolis(const Tensor& J, const Vector& z0, std::function&, const Vector&)>& energy, Real T, Real γ, unsigned N, Distribution d, Generator& r) { Vector z = z0; Real E = energy(J, z); std::uniform_real_distribution D(0, 1); for (unsigned i = 0; i < N; i++) { Vector zNew = normalize(z + γ * randomVector(z.size(), d, r)); Real ENew = energy(J, zNew); if (E - ENew > T * log(D(r))) { z = zNew; E = ENew; } } return {E, z}; } template Vector randomSaddle(const Tensor& J, Distribution d, Generator& r, Real ε) { Vector zSaddle; bool foundSaddle = false; while (!foundSaddle) { Vector z0 = normalize(randomVector(J.dimension(0), d, r.engine())); try { zSaddle = findSaddle(J, z0, ε); foundSaddle = true; } catch (std::exception& e) {} } return zSaddle; }