#pragma once #include "p-spin.hpp" #include "dynamics.hpp" #include template Real jacobi(unsigned α, unsigned β, unsigned n, Real x) { Real f = 0; Real y = (x - 1) / 2; Real z = (x + 1) / 2; for (unsigned s = 0; s <= n; s++) { f += pow(y, n - s) * pow(z, s) / (tgamma(s + 1) * tgamma(n + α - s + 1) * tgamma(β + s + 1) * tgamma(n - s + 1)); } return tgamma(n + α + 1) * tgamma(n + β + 1) * f; } template Real dJacobi(unsigned α, unsigned β, unsigned n, Real x) { Real f = 0; Real y = (x - 1) / 2; Real z = (x + 1) / 2; for (unsigned s = 0; s < n; s++) { f += pow(y, n - s - 1) * pow(z, s) / (tgamma(s + 1) * tgamma(n + α - s + 1) * tgamma(β + s + 1) * tgamma(n - s - 1 + 1)); } for (unsigned s = 1; s <= n; s++) { f += pow(y, n - s) * pow(z, s - 1) / (tgamma(s - 1 + 1) * tgamma(n + α - s + 1) * tgamma(β + s + 1) * tgamma(n - s + 1)); } return tgamma(n + α + 1) * tgamma(n + β + 1) * f / 2; } template class Cord { public: const pSpinModel& M; std::vector> gs; Vector z0; Vector z1; Cord(const pSpinModel& M, const Vector& z2, const Vector& z3, unsigned ng) : M(M), gs(ng, Vector::Zero(z2.size())) { Scalar H2 = M.getHamiltonian(z2); Scalar H3 = M.getHamiltonian(z3); if (std::real(H2) > std::real(H3)) { z0 = z2; z1 = z3; } else { z0 = z3; z1 = z2; } } Real gCoeff(unsigned i, Real t) const { return (1 - t) * t * jacobi(1, 1, i, 2 * t - 1); } Real dgCoeff(unsigned i, Real t) const { return (1 - 2 * t) * jacobi(1, 1, i, 2 * t - 1) + 2 * (1 - t) * t * dJacobi(1, 1, i, 2 * t - 1); } Vector f(Real t) const { Vector z = (1 - t) * z0 + t * z1; for (unsigned i = 0; i < gs.size(); i++) { z += gCoeff(i, t) * gs[i]; } return z; } Vector df(Real t) const { Vector z = z1 - z0; for (unsigned i = 0; i < gs.size(); i++) { z += dgCoeff(i, t) * gs[i]; } return z; } Real cost(Real t) const { Vector z = f(t); Scalar H; Vector dH; std::tie(H, dH, std::ignore, std::ignore) = M.hamGradHess(z); Vector ż = zDot(z, dH); Vector dz = df(t); return 1 - std::real(ż.dot(dz)) / ż.norm() / dz.norm(); } Real totalCost(unsigned nt) const { Real tc = 0; for (unsigned i = 0; i < nt; i++) { Real t = (i + 1.0) / (nt + 1.0); tc += cost(t); } return tc; } std::pair, Matrix> gsGradHess(Real t) const { Vector z = f(t); auto [H, dH, ddH, dddH] = M.hamGradHess(z); Vector ż = zDot(z, dH); Tensor żT = Eigen::TensorMap>(ż.data(), {z.size()}); Vector dz = df(t); Tensor dzT = Eigen::TensorMap>(dz.data(), {z.size()}); Matrix dż = dzDot(z, dH); Matrix dżc = dzDotConjugate(z, dH, ddH); Tensor ddż = ddzDot(z, dH); Tensor dcdż = dcdzDot(z, dH, ddH); Tensor ddżc = ddzDotConjugate(z, dH, ddH, dddH); Eigen::array, 1> ip20 = {Eigen::IndexPair(2, 0)}; Tensor ddżcdzT = ddżc.contract(dzT, ip20); Matrix ddżcdz = Eigen::Map>(ddżcdzT.data(), z.size(), z.size()); Tensor ddżdzT = ddż.contract(dzT.conjugate(), ip20); Matrix ddżdz = Eigen::Map>(ddżdzT.data(), z.size(), z.size()); Tensor ddżcżT = ddżc.contract(żT, ip20); Matrix ddżcż = Eigen::Map>(ddżcżT.data(), z.size(), z.size()); Tensor ddżżcT = ddż.contract(żT.conjugate(), ip20); Matrix ddżżc = Eigen::Map>(ddżżcT.data(), z.size(), z.size()); Tensor dcdżcdzT = dcdż.conjugate().contract(dzT, ip20); Matrix dcdżcdz = Eigen::Map>(dcdżcdzT.data(), z.size(), z.size()); Tensor dcdżcżT = dcdż.conjugate().contract(żT, ip20); Matrix dcdżcż = Eigen::Map>(dcdżcżT.data(), z.size(), z.size()); Vector x(2 * z.size() * gs.size()); Matrix M(x.size(), x.size()); for (unsigned i = 0; i < gs.size(); i++) { Real fdgn = gCoeff(i, t); Real dfdgn = dgCoeff(i, t); Vector dC = - 1 / ż.norm() / dz.norm() / 2 * ( dfdgn * ż.conjugate() + fdgn * dżc * dz + fdgn * dż * dz.conjugate() - std::real(dz.dot(ż)) * ( dfdgn * dz.conjugate() / dz.squaredNorm() + fdgn * (dżc * ż + dż * ż.conjugate()) / ż.squaredNorm() ) ); x.segment(z.size() * i, z.size()) = dC; x.segment(z.size() * gs.size() + z.size() * i, z.size()) = dC.conjugate(); for (unsigned j = 0; j < gs.size(); j++) { Real fdgm = gCoeff(j, t); Real dfdgm = dgCoeff(j, t); Scalar CC = - std::real(dz.dot(ż)) / ż.norm() / dz.norm(); Vector dCm = - 1 / ż.norm() / dz.norm() / 2 * ( dfdgm * ż.conjugate() + fdgm * dżc * dz + fdgm * dż * dz.conjugate() - std::real(dz.dot(ż)) * ( dfdgm * dz.conjugate() / dz.squaredNorm() + fdgm * (dżc * ż + dż * ż.conjugate()) / ż.squaredNorm() ) ); Matrix ddC = 1 / ż.norm() / dz.norm() / 2 * ( - ( dfdgn * fdgm * dżc.transpose() + dfdgm * fdgn * dżc + fdgn * fdgm * ddżcdz + fdgn * fdgm * ddżdz ) - ż.norm() / dz.norm() * ( dfdgn * dz.conjugate() * dCm.transpose() + dfdgm * dC * dz.adjoint() ) - dz.norm() / ż.norm() * ( fdgn * (dżc * ż + dż * ż.conjugate()) * dCm.transpose() + fdgm * dC * (dżc * ż + dż * ż.conjugate()).transpose() ) - CC * dz.norm() / ż.norm() * fdgn * fdgm * ( ddżżc + ddżcż + dżc * dż.transpose() + dż * dżc.transpose() ) - CC / dz.norm() / ż.norm() / (Real)2 * ( dfdgn * fdgm * dz.conjugate() * (dżc * ż + dż * ż.conjugate()).transpose() + dfdgm * fdgn * (dżc * ż + dż * ż.conjugate()) * dz.adjoint() ) + CC * ż.norm() / (Real)2 / pow(dz.norm(), 3) * dfdgn * dfdgm * dz.conjugate() * dz.adjoint() + CC * dz.norm() / (Real)2 / pow(ż.norm(), 3) * fdgn * (dżc * ż + dż * ż.conjugate()) * fdgm * (dżc * ż + dż * ż.conjugate()).transpose() ) ; Matrix dcdC = 1 / ż.norm() / dz.norm() / 2 * ( - ( dfdgn * fdgm * dż.adjoint() + dfdgm * fdgn * dż + fdgn * fdgm * (dcdżcdz + dcdżcdz.adjoint()) ) - ż.norm() / dz.norm() * ( dfdgn * dz.conjugate() * dCm.adjoint() + dfdgm * dC * dz.transpose() ) - dz.norm() / ż.norm() * ( fdgn * (dżc * ż + dż * ż.conjugate()) * dCm.adjoint() + fdgm * dC * (dżc * ż + dż * ż.conjugate()).adjoint() ) - CC * ż.norm() / dz.norm() * dfdgn * dfdgm * Matrix::Identity(z.size(), z.size()) - CC * dz.norm() / ż.norm() * fdgn * fdgm * ( dcdżcż + dcdżcż.adjoint() + dżc * dżc.adjoint() + dż * dż.adjoint() ) - CC / dz.norm() / ż.norm() / (Real)2 * ( dfdgn * fdgm * dz.conjugate() * (dżc * ż + dż * ż.conjugate()).adjoint() + dfdgm * fdgn * (dżc * ż + dż * ż.conjugate()) * dz.transpose() ) + CC * ż.norm() / (Real)2 / pow(dz.norm(), 3) * dfdgn * dfdgm * dz.conjugate() * dz.transpose() + CC * dz.norm() / (Real)2 / pow(ż.norm(), 3) * fdgn * fdgm * (dżc * ż + dż * ż.conjugate()) * (dżc * ż + dż * ż.conjugate()).adjoint() ) ; M.block(z.size() * i, z.size() * j, z.size(), z.size()) = dcdC; M.block(z.size() * gs.size() + z.size() * i, z.size() * j, z.size(), z.size()) = ddC.conjugate(); M.block(z.size() * i, z.size() * gs.size() + z.size() * j, z.size(), z.size()) = ddC; M.block(z.size() * gs.size() + z.size() * i, z.size() * gs.size() + z.size() * j, z.size(), z.size()) = dcdC.conjugate(); } } return {x, M}; } std::tuple relaxStepNewton(unsigned nt, Real δ₀) { Vector dgsTot = Vector::Zero(2 * z0.size() * gs.size()); Matrix HessTot = Matrix::Zero(2 * z0.size() * gs.size(), 2 * z0.size() * gs.size()); for (unsigned i = 0; i < nt; i++) { Real t = (i + 1.0) / (nt + 1.0); auto [dgsi, Hessi] = gsGradHess(t); dgsTot += dgsi / nt; HessTot += Hessi / nt; } Real stepSize = dgsTot.norm(); Cord cNew(*this); Real δ = δ₀; Real oldCost = totalCost(nt); Real newCost = std::numeric_limits::infinity(); Matrix I = abs(HessTot.diagonal().array()).matrix().asDiagonal(); Vector δg(gs.size() * z0.size()); while (newCost > oldCost) { δg = (HessTot + δ * I).partialPivLu().solve(dgsTot).tail(gs.size() * z0.size()); for (unsigned i = 0; i < gs.size(); i++) { cNew.gs[i] = gs[i] - δg.segment(z0.size() * i, z0.size()); } newCost = cNew.totalCost(nt); δ *= 2; } std::cerr << newCost << " " << stepSize << " " << δ << std::endl; gs = cNew.gs; return {δ / 2, stepSize}; } void relaxNewton(unsigned nt, Real δ₀, Real ε, unsigned maxSteps) { Real δ = δ₀; Real stepSize = std::numeric_limits::infinity(); unsigned steps = 0; while (stepSize > ε && steps < maxSteps) { std::tie(δ, stepSize) = relaxStepNewton(nt, δ); if (δ > 100) { break; } δ /= 3; steps++; } } };