#pragma once #include #include #include #include #include #include "randutils/randutils.hpp" #include "euclidean.hpp" #include "octree.hpp" #include "quantity.hpp" #include "spin.hpp" template class Model; template class measurement { public: virtual void pre_cluster(const Model&, unsigned, const R&){}; virtual void plain_bond_visited(const Model&, const Spin*, const Spin*, const Spin&, double){}; virtual void plain_site_transformed(const Model&, const Spin*, const Spin&){}; virtual void ghost_bond_visited(const Model&, const Spin&, const Spin&, double){}; virtual void ghost_site_transformed(const Model&, const R&){}; virtual void post_cluster(const Model&){}; }; template class Model { public: U L; R s0; std::vector> s; Octree dict; std::function&, const Spin&)> Z; std::function&)> B; randutils::mt19937_rng rng; Model(U L, std::function&, const Spin&)> Z, std::function&)> B) : L(L), s0(L), Z(Z), B(B), rng(), dict(L, std::floor(L)) {} void step(double T, unsigned ind, R& r, measurement& A) { std::queue*> queue; queue.push(&(s[ind])); std::set*> visited; while (!queue.empty()) { Spin* si = queue.front(); queue.pop(); if (!visited.contains(si)) { visited.insert(si); if (si == NULL) { R s0_new = r.act(s0); for (Spin& ss : s) { Spin s0s_old = s0.inverse().act(ss); Spin s0s_new = s0_new.inverse().act(ss); double p = 1.0 - exp(-(B(s0s_new) - B(s0s_old)) / T); A.ghost_bond_visited(*this, s0s_old, s0s_new, p); if (rng.uniform(0.0, 1.0) < p) { queue.push(&ss); } } A.ghost_site_transformed(*this, s0_new); s0 = s0_new; } else { Spin si_new = r.act(*si); std::set*> all_neighbors; std::set*> current_neighbors = dict.neighbors(si->x); std::set*> new_neighbors = dict.neighbors(si_new.x); all_neighbors.insert(current_neighbors.begin(), current_neighbors.end()); all_neighbors.insert(new_neighbors.begin(), new_neighbors.end()); all_neighbors.insert(NULL); for (Spin* sj : all_neighbors) { if (sj != si) { double p; if (sj == NULL) { Spin s0s_old = s0.inverse().act(*si); Spin s0s_new = s0.inverse().act(si_new); p = 1.0 - exp(-(B(s0s_new) - B(s0s_old)) / T); A.ghost_bond_visited(*this, s0s_old, s0s_new, p); } else { p = 1.0 - exp(-(Z(*si, *sj) - Z(si_new, *sj)) / T); A.plain_bond_visited(*this, si, sj, si_new, p); } if (rng.uniform(0.0, 1.0) < p) { queue.push(sj); } } } A.plain_site_transformed(*this, si, si_new); dict.remove(si); *si = si_new; dict.insert(si); } } } } void resize(double T, double P) {} void wolff(double T, std::function&, randutils::mt19937_rng&)> g, measurement& A, unsigned N) { for (unsigned i = 0; i < N; i++) { R r = g(*this, rng); unsigned ind = rng.uniform((unsigned)0, (unsigned)(s.size() - 1)); A.pre_cluster(*this, ind, r); this->step(T, ind, r, A); A.post_cluster(*this); } } };