#include "p-spin.hpp" #include 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 = - ( dżc * z´ + dż * z´.conjugate() - (dż * ż.conjugate() + dżc * ż) * Reż·z´ / ż² ) / sqrt(ż² * z´²) / 2; 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´ = - ( ( ż´.conjugate() - ( Reż·z´ * z´´.conjugate() + dReż·z´ * z´.conjugate() - (Reż·z´ / z´²) * (z´´.dot(z´) + z´.dot(z´´)) * z´.conjugate() ) / z´² ) - 0.5 * ( (ż.dot(ż´) + ż´.dot(ż)) / ż² + (z´´.dot(z´) + z´.dot(z´´)) / z´² ) * (ż.conjugate() - Reż·z´ / z´² * z´.conjugate()) ) / sqrt(ż² * z´²) / 2; return dLdz - ddtdLdz´; } template class Rope { public: std::vector> z; Rope(unsigned N) : z(N + 2) {} template Rope(unsigned N, const Vector& z1, const Vector& z2, const Tensor& J) : z(N + 2) { Scalar H1, H2; std::tie(H1, std::ignore, std::ignore) = hamGradHess(J, z1); std::tie(H2, std::ignore, std::ignore) = hamGradHess(J, z2); if (real(H1) > real(H2)) { z.front() = z1; z.back() = z2; } else { z.front() = z2; z.back() = z1; } for (unsigned i = 0; i < N + 2; i++) { z[i] = normalize(z.front() + (z.back() - z.front()) * ((double)i / (N + 1.0))); } } unsigned n() const { return z.size() - 2; } double length() const { double l = 0; for (unsigned i = 0; i < z.size() - 1; i++) { l += (z[i + 1] - z[i]).norm(); } return l; } template double error(const Tensor& J) const { Scalar H0, HN; std::tie(H0, std::ignore, std::ignore) = hamGradHess(J, z.front()); std::tie(HN, std::ignore, std::ignore) = hamGradHess(J, z.back()); double ImH = imag((H0 + HN) / 2.0); double err = 0; for (unsigned i = 1; i < z.size() - 1; i++) { Scalar Hi; std::tie(Hi, std::ignore, std::ignore) = hamGradHess(J, z[i]); err += pow(imag(Hi) - ImH, 2); } return sqrt(err); } 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], dz(i), ddz(i), dH, ddH); } for (unsigned i = 1; i < z.size() - 1; i++) { δz[i] = δz[i].conjugate() - (δz[i].dot(z[i]) / z[i].squaredNorm()) * z[i].conjugate(); // δz[i] = δz[i] - ((δz[i].conjugate().dot(dz(i))) / dz(i).squaredNorm()) * dz(i).conjugate(); } // We return a δz with average norm of one. double mag = 0; for (unsigned i = 1; i < z.size() - 1; i++) { mag += δz[i].norm(); } for (unsigned i = 1; i < z.size() - 1; i++) { δz[i] /= mag / n(); } return δz; } template double perturb(const Tensor& J, double δ0) { std::vector> Δz = δz(J); Rope rNew = *this; double δ = δ0; // We rescale the step size by the distance between points. double Δl = length() / (n() + 1); while (true) { for (unsigned i = 1; i < z.size() - 1; i++) { rNew.z[i] = normalize(z[i] - (δ * Δl) * Δz[i]); } if (rNew.cost(J) < cost(J)) { break; } else { δ /= 2; } if (δ < 1e-15) { throw ropeRelaxationStallException(); } } z = rNew.z; return δ; } void spread() { double l = length(); 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 δ0) { double δ = perturb(J, δ0); spread(); return δ; } template void relax(const Tensor& J, unsigned N, double δ0) { double δ = δ0; try { for (unsigned i = 0; i < N; i++) { δ = 1.1 * step(J, δ); } } catch (std::exception& e) { } } 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]); Vector zD = zDot(z[i], dH); c += 1.0 - real(zD.dot(dz(i))) / zD.norm() / dz(i).norm(); } return c; } Rope interpolate() const { Rope r(2 * n() + 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; } };