#include "space_wolff.hpp" template using Sphere = Spin; template double softPotential(double a, double k, const Vector& diff, double σ) { double δ = σ - sqrt(diff.transpose() * diff); if (δ > -a * σ) { return 0.5 * k * (2 * pow(a * σ, 2) - pow(δ, 2)); } else if (δ > -2 * a * σ) { return 0.5 * k * pow(δ + 2 * a * σ, 2); } else { return 0; } } template double hardPotential(const Vector& diff, double σ) { if (pow(σ, 2) < diff.transpose() * diff) { return 0; } else { return -std::numeric_limits::infinity(); } } template std::function&, const Spin&)> zSpheres(double a, double k) { return [a, k](const Spin& s1, const Spin& s2) -> double { Vector d = s1.x - s2.x; return softPotential(a, k, d, s1.s + s2.s); }; } template std::function&, const Spin&)> zSpheresTorus(double L, double a, double k) { return [L, a, k](const Spin& s1, const Spin& s2) -> double { return softPotential(a, k, diff(L, s1.x, s2.x), s1.s + s2.s); }; } template std::function>&, const Spin>&)> zDimers(std::function&, const Sphere&)> zSingle) { return [zSingle](const Spin>& s1, const Spin>& s2) -> double { Spin s11 = {.x = s1.x + s1.s.relativePosition, .s = s1.s.radius}; Spin s12 = {.x = s1.x - s1.s.relativePosition, .s = s1.s.radius}; Spin s21 = {.x = s2.x + s2.s.relativePosition, .s = s2.s.radius}; Spin s22 = {.x = s2.x - s2.s.relativePosition, .s = s2.s.radius}; return zSingle(s11, s21) + zSingle(s12, s21) + zSingle(s11, s22) + zSingle(s12, s22); }; } template std::function)> bCenter(double H) { return [H](Spin s) -> double { return H * s.x.norm(); }; } template Euclidean flipAround(double θ, Vector& t₀) { Matrix m; m(0, 0) = -cos(2 * θ); m(1, 1) = cos(2 * θ); m(0, 1) = -2 * cos(θ) * sin(θ); m(1, 0) = -2 * cos(θ) * sin(θ); return Euclidean(t₀ - m * t₀, m); } template Gen, S> nudgeGen(double ε) { return [ε](Model, S>& M, Rng& rng) -> Transformation, S>* { double θ = rng.uniform((double)0.0, 2 * M_PI); Spin* s = rng.pick(M.s); Vector t = s->x; for (unsigned j = 0; j < D; j++) { t(j) += rng.variate(0.0, ε); } return new SpinFlip, S>(M, flipAround(θ, t), s); }; } template Gen, S> swapGen(double ε) { return [ε](Model, S>& M, Rng& rng) -> Transformation, S>* { Spin* s1 = rng.pick(M.s); Spin* s2 = rng.pick(M.s); while (s1 == s2) { s2 = rng.pick(M.s); } Vector t1 = s1->x; Vector t2 = s2->x; Vector t12 = t1 - t2; Vector t = (t1 + t2) / 2; double θ = atan2(t12(1), t12(0)) + rng.variate(0.0, ε) / t12.norm(); return new PairFlip, S>(M, flipAround(θ, t), s1, s2); }; } template Gen, S> accrossGen(double ε) { return [ε](Model, S>& M, Rng& rng) -> Transformation, S>* { Spin* s1 = rng.pick(M.s); Spin* s2 = rng.pick(M.s); while (s1 == s2) { s2 = rng.pick(M.s); } Vector t1 = s1->x; Vector t2 = s2->x; Vector t12 = t1 - t2; Vector t = t2; double θ = atan2(t12(1), t12(0)) + rng.variate(0.0, ε) / t12.norm(); return new SpinFlip, S>(M, flipAround(θ, t), s1); }; } template Gen, S> centerGen(double ε) { return [ε](Model, S>& M, Rng& rng) -> Transformation, S>* { double θ = rng.uniform((double)0.0, 2 * M_PI); Vector t = M.s0.t; for (unsigned j = 0; j < D; j++) { t(j) += rng.variate(0.0, ε); } Spin* s = rng.pick(M.s); return new SpinFlip, S>(M, flipAround(θ, t), s); }; }