#include "stokes.hpp" #include "complex_normal.hpp" #include using Complex = std::complex; template Tensor makeSpikeHelper(const Vector& x) { Eigen::array, 0> ei = {}; Tensor xT = Eigen::TensorMap>(x.data(), {x.size()}); return xT.contract(makeSpikeHelper

(x), ei); } template <> Tensor makeSpikeHelper(const Vector& x) { Tensor xT = Eigen::TensorMap>(x.data(), {x.size()}); return xT; } template Tensor makeSpike(const Vector& x) { return makeSpikeHelper

(x); } template int getFirstP() { return p; } template void collectStokesData(std::string tag, unsigned N, Generator& r, Real ε, Real δz₀, bool minimum, bool spike, T... μs) { unsigned nIts = 5; unsigned nGs = 4; unsigned coDim = 16; Real newSaddleThres = 1e-4; pSpinModel ReM(N, r, μs...); std::normal_distribution Red(0, 1); Vector xMin(N); if (minimum) { xMin = randomMinimum(ReM, Red, r, ε); } else { xMin = randomSaddle(ReM, Red, r, ε); } Real Hx; std::tie(Hx, std::ignore, std::ignore, std::ignore) = ReM.hamGradHess(xMin); if (spike) { const unsigned p = getFirstP(); Real εgs = sqrt((p - 1) * log(p - 1) / (p - 2)); Real εth = sqrt((p - 1) * 2.0 / p); Real εTarget = std::uniform_real_distribution(εth, εgs)(r); std::get<0>(ReM.Js) -= factorial(p) * (εTarget * N + Hx) * makeSpike(xMin) / pow(N, p); } Vector dHx; Matrix ddHx; std::tie(Hx, dHx, ddHx, std::ignore) = ReM.hamGradHess(xMin); Matrix xHess = ddHx - xMin.dot(dHx) * Matrix::Identity(xMin.size(), xMin.size()) / (Real)N; xHess -= (xHess * xMin) * xMin.transpose() / (Real)N; Eigen::EigenSolver> eigenS(xHess); complex_normal_distribution d(0, 1, 0); pSpinModel M = ReM.template cast();; Vector zMin = xMin.cast(); Vector zSaddle = zMin; Real δz = δz₀; while ((zSaddle - zMin).norm() < newSaddleThres * N || abs(imag(M.getHamiltonian(zSaddle))) < 1e-10) { Vector z0 = normalize(zSaddle + δz * randomVector(N, d, r)); zSaddle = findSaddle(M, z0, ε); δz *= 1.01; } Complex Hz; Vector dHz; Matrix ddHz; std::tie(Hz, dHz, ddHz, std::ignore) = M.hamGradHess(zSaddle); Matrix zHess = ddHz - (zSaddle.transpose() * dHz) * Matrix::Identity(N, N) / (Real)N; zHess -= (zHess * zSaddle) * zSaddle.adjoint() / zSaddle.squaredNorm(); Eigen::ComplexEigenSolver> eigenSz(zHess); Real φ = atan2(Hz.imag(), Hx - Hz.real()); M *= exp(Complex(0, φ)); std::ofstream file("stokes_info_" + tag + ".dat"); file.precision(15); file << N << std::endl; ((file << ps << " "), ...) << std::endl;; ((file << μs << " "), ...) << std::endl;; std::ofstream tensorFile("stokes_tensor_" + tag + ".dat", std::ios::out | std::ios::binary | std::ios::trunc); std::apply([&tensorFile](const Tensor&... Js) -> void { (tensorFile.write((char*)Js.data(), Js.size() * sizeof(Real)), ...); } , ReM.Js); file << xMin.transpose() << std::endl; file << Hx << std::endl; file << eigenS.eigenvalues().real().transpose() << std::endl; file << zSaddle.transpose() << std::endl; file << Hz << " " << zSaddle.squaredNorm() << std::endl; file << eigenSz.eigenvalues().transpose() << std::endl; file << φ << " " << (xMin - zSaddle).norm() << std::endl; unsigned nTest = 1000; file << nIts << " " << nGs << " " << coDim << " " << nTest << std::endl; std::vector> oldGs; for (int j = 0; j < nIts; j++) { Cord c(M, zMin, zSaddle, nGs + pow(2, j)); for (unsigned i = 0; i < oldGs.size(); i++) { c.gs[i] = oldGs[i]; } c.relaxNewton(c.gs.size() * 2, 1, 1e-10, 1e4); oldGs = c.gs; Real reConstraintError = 0; Real imConstraintError = 0; Real imEnergyError = 0; Real ell = 0; for (unsigned i = 0; i < nTest; i++) { Real t = (i + 1.0) / (nTest + 1.0); Vector zi = c.f(t); imEnergyError += pow(std::imag(M.getHamiltonian(zi) - M.getHamiltonian(zMin)), 2); Complex constraintError = (Complex)(zi.transpose() * zi) - (Complex)N; reConstraintError += pow(real(constraintError), 2); imConstraintError += pow(imag(constraintError), 2); ell += c.df(t).norm(); } file << oldGs.size() << " " << ell / nTest << " " << c.totalCost(nTest) / (nTest) << " " << sqrt(imEnergyError / (Real)(nTest)) << " " << sqrt(reConstraintError / (Real)(nTest)) << " " << sqrt(imConstraintError / (Real)(nTest)) << std::endl; for (const Vector& gi : c.gs) { file << gi.transpose() << std::endl; } } }