#include "p-spin.hpp" template double segmentCost(const Vector& z, const Vector& dz, const Vector& dH) { Vector zD = zDot(z, dH); return 1.0 - pow(real(zD.dot(dz)), 2) / zD.squaredNorm() / dz.squaredNorm(); } class ropeRelaxationStallException: public std::exception { virtual const char* what() const throw() { return "Gradient descent stalled."; } }; template Vector variation(const Vector& z, const Vector& z´, const Vector& z´´, const Vector& dH, const Matrix& ddH) { double z² = z.squaredNorm(); double z´² = z´.squaredNorm(); Vector ż = zDot(z, dH); double ż² = ż.squaredNorm(); double Reż·z´ = real(ż.dot(z´)); Matrix dż = (dH.conjugate() - (dH.dot(z) / z²) * z.conjugate()) * z.adjoint() / z²; Matrix dżc = -ddH + (ddH * z.conjugate()) * z.transpose() / z² + (z.dot(dH) / z²) * ( Matrix::Identity(ddH.rows(), ddH.cols()) - z.conjugate() * z.transpose() / z² ); Vector dLdz = - Reż·z´ * ( dżc * z´ + dż * z´.conjugate() - (dż * ż.conjugate() + dżc * ż) * Reż·z´ / ż² ) / (ż² * z´²); Vector ż´ = -(ddH * z´).conjugate() + ((ddH * z´).dot(z) / z²) * z.conjugate() + ( dH.dot(z) * z´.conjugate() + dH.dot(z´) * z.conjugate() - ( dH.dot(z) * (z´.dot(z) + z.dot(z´)) / z² ) * z.conjugate() ) / z²; double dReż·z´ = real(ż.dot(z´´) + ż´.dot(z´)); Vector ddtdLdz´ = - ( Reż·z´ * ( ż´.conjugate() - ( Reż·z´ * z´´.conjugate() + dReż·z´ * z´.conjugate() - (Reż·z´ / z´²) * (z´´.dot(z´) + z´.dot(z´´)) * z´.conjugate() ) / z´² ) + dReż·z´ * (ż.conjugate() - Reż·z´ / z´² * z´.conjugate()) - Reż·z´ * ( (ż.dot(ż´) + ż´.dot(ż)) / ż² + (z´´.dot(z´) + z´.dot(z´´)) / z´² ) * (ż.conjugate() - Reż·z´ / z´² * z´.conjugate()) ) / (ż² * z´²); return dLdz - ddtdLdz´; } template class Rope { public: std::vector> z; Rope(unsigned N, const Vector& z1, const Vector& z2) : z(N + 2) { for (unsigned i = 0; i < N + 2; i++) { z[i] = normalize(z1 + (z2 - z1) * ((double)i / (N + 1.0))); } } Vector dz(unsigned i) const { return z[i + 1] - z[i - 1]; } Vector ddz(unsigned i) const { return 4.0 * (z[i + 1] + z[i - 1] - 2.0 * z[i]); } template std::vector> δz(const Tensor& J) const { std::vector> δz(z.size()); #pragma omp parallel for for (unsigned i = 1; i < z.size() - 1; i++) { Vector dH; Matrix ddH; std::tie(std::ignore, dH, ddH) = hamGradHess(J, z[i]); δz[i] = variation(z[i], this->dz(i), this->ddz(i), dH, ddH); } return δz; } template double perturb(const Tensor& J, double δ0) { std::vector> Δz = this->δz(J); Rope rNew = *this; double δ = δ0; while (rNew.cost(J) >= this->cost(J)) { for (unsigned i = 1; i < z.size() - 1; i++) { rNew.z[i] = normalize(z[i] - δ * Δz[i].conjugate()); } δ /= 2; if (δ < 1e-30) { throw ropeRelaxationStallException(); } } z = rNew.z; return δ; } void spread() { double l = 0; for (unsigned i = 0; i < z.size() - 1; i++) { l += (z[i + 1] - z[i]).norm(); } double a = 0; unsigned pos = 0; std::vector> zNew = z; for (unsigned i = 1; i < z.size() - 1; i++) { double b = i * l / (z.size() - 1); while (b > a) { pos++; a += (z[pos] - z[pos - 1]).norm(); } Vector δz = z[pos] - z[pos - 1]; zNew[i] = normalize(z[pos] - (a - b) / δz.norm() * δz); } z = zNew; } template double step(const Tensor& J, double δ) { double δNew = this->perturb(J, δ); this->spread(); return δNew; } template double cost(const Tensor& J) const { double c = 0; for (unsigned i = 1; i < z.size() - 1; i++) { Vector dH; std::tie(std::ignore, dH, std::ignore) = hamGradHess(J, z[i]); c += segmentCost(z[i], this->dz(i), dH); } return c; } template void relax(const Tensor& J, unsigned N, double δ0) { double δ = δ0; try { for (unsigned i = 0; i < N; i++) { δ = 2 * this->step(J, δ); } } catch (std::exception& e) { } } Rope interpolate() const { Rope r(2 * (z.size() - 2) + 1, z[0], z[z.size() - 1]); for (unsigned i = 0; i < z.size(); i++) { r.z[2 * i] = z[i]; } for (unsigned i = 0; i < z.size() - 1; i++) { r.z[2 * i + 1] = normalize(((z[i] + z[i + 1]) / 2.0)); } return r; } };