#include #include #include #include #include #include #include #include #include #include "randutils/randutils.hpp" const std::array, 16> smiley = {{ {{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}}, {{0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}}, {{0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}}, {{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}, {{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}}, {{1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1}}, {{1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1}}, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {{1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1}}, {{1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}}, {{1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1}}, {{0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0}}, {{0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0}}, {{0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}}, {{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}} }}; template using vector = Eigen::Matrix; template using matrix = Eigen::Matrix; template class spin { public: vector x; state s; }; template class euclidean { private: unsigned L; public: vector t; matrix r; euclidean(unsigned L) : L(L) { for (unsigned i = 0; i < D; i++) { t(i) = 0; r(i, i) = 1; for (unsigned j = 1; j < D; j++) { r(i, (i + j) % D) = 0; } } } euclidean(unsigned L, vector t0, matrix r0) : L(L) { t = t0; r = r0; } template spin act(const spin& s) const { spin s_new; s_new.x = t + r * s.x; s_new.s = s.s; for (unsigned i = 0; i < D; i++) { s_new.x(i) = fmod(L + s_new.x(i), L); } return s_new; } euclidean act(const euclidean& x) const { vector tnew = r * x.t + t; matrix rnew = r * x.r; euclidean pnew(this->L, tnew, rnew); return pnew; } euclidean inverse() const { vector tnew = - r.transpose() * t; matrix rnew = r.transpose(); euclidean pnew(this->L, tnew, rnew); return pnew; } }; // to-do: clean up nnn... code template class dictionary { private: unsigned L; std::vector> d; public: dictionary(unsigned Li) : L(Li), d(pow(Li, D)) {}; template unsigned dictionary_index(vector x) const { unsigned pos_ind = 0; for (unsigned i = 0; i < D; i++) { pos_ind += pow(L, i) * (unsigned)x(i); }; return pos_ind; } template void record(vector x, unsigned ind) { d[dictionary_index(x)].insert(ind); }; template void remove(vector x, unsigned ind) { d[dictionary_index(x)].erase(ind); }; template std::set neighbors(vector x, unsigned depth) const { return nearest_neighbors_of(dictionary_index(x), depth, {}); }; std::set nearest_neighbors_of(unsigned ind, unsigned depth, std::list ignores) const { std::set ns = d[ind]; if (depth > 0) { for (unsigned i = 0; i < D; i++) { if (std::none_of(ignores.begin(), ignores.end(), [i](unsigned k){return i==k;})) { std::list ignores_new = ignores; ignores_new.push_back(i); for (signed j : {-1, 1}) { unsigned ni = pow(L, i + 1) * (ind / ((unsigned)pow(L, i + 1))) + fmod(pow(L, i + 1) + ind + j * pow(L, i), pow(L, i + 1)); std::set nns = nearest_neighbors_of(ni, depth - 1, ignores_new); for (unsigned guy : nns) { ns.insert(guy); } } } } } return ns; }; }; class quantity { private: double total; double total2; std::vector C; unsigned wait; public: unsigned n; std::list hist; quantity(unsigned lag, unsigned wait) : C(lag), wait(wait) { n = 0; total = 0; total2 = 0; } void add(double x) { if (n > wait) { hist.push_front(x); if (hist.size() > C.size()) { hist.pop_back(); unsigned t = 0; for (double a : hist) { C[t] += a * x; t++; } total += x; total2 += pow(x, 2); } } n++; } double avg() const { return total / (n - wait); } double avg2() const { return total2 / (n - wait); } std::vector ρ() const { double C0 = C.front() / (n - wait); double avg2 = pow(total / (n - wait), 2); std::vector ρtmp; for (double Ct : C) { ρtmp.push_back((Ct / (n - wait) - avg2) / (C0 - avg2)); } return ρtmp; } std::array τ() const { double τtmp = 0.5; unsigned M = 1; double c = 8.0; std::vector ρ_tmp = this->ρ(); while (c * τtmp > M && M < C.size()) { τtmp += ρ_tmp[M]; M++; } return {τtmp, 2.0 * (2.0 * M + 1) * pow(τtmp, 2) / (n - wait)}; } double σ() const { return 2.0 / (n - wait) * this->τ()[0] * (C[0] / (n - wait) - pow(this->avg(), 2)); } double serr() const { return sqrt(this->σ()); } }; template class model { public: unsigned L; euclidean s0; std::vector> s; dictionary dict; std::function(model&, unsigned, spin)> neighbors; std::function, spin)> Z; std::function)> B; long double E; quantity Eq; quantity Cq; model(unsigned L, std::function, spin)> Z, std::function)> B, std::function(model&, unsigned, spin)> ns) : L(L), s0(L), dict(L), neighbors(ns), Z(Z), B(B), Eq(1000, 1000), Cq(1000, 1000) { } void update_energy() { E = 0; for (unsigned i = 0; i < s.size(); i++) { for (unsigned j = 0; j < i; j++) { E -= Z(s[i], s[j]); } E -= B(s0.inverse().act(s[i])); } } void step(double T, unsigned ind, euclidean r, std::mt19937& rng) { unsigned cluster_size = 0; std::uniform_real_distribution dist(0.0, 1.0); std::queue queue; queue.push(ind); std::vector visited(s.size() + 1, false); while (!queue.empty()) { unsigned i = queue.front(); queue.pop(); if (!visited[i]) { visited[i] = true; bool we_are_ghost = i == s.size(); spin si_new; euclidean s0_new(L); if (we_are_ghost) { s0_new = r.act(s0); } else { si_new = r.act(s[i]); } for (unsigned j : neighbors(*this, i, si_new)) { if (j != i) { double dE; bool neighbor_is_ghost = j == s.size(); if (we_are_ghost || neighbor_is_ghost) { spin s0s_old, s0s_new; unsigned non_ghost; if (neighbor_is_ghost) { non_ghost = i; s0s_old = s0.inverse().act(s[i]); s0s_new = s0.inverse().act(si_new); } else { non_ghost = j; s0s_old = s0.inverse().act(s[j]); s0s_new = s0_new.inverse().act(s[j]); } dE = B(s0s_old) - B(s0s_new); } else { dE = Z(s[i], s[j]) - Z(si_new, s[j]); } double p = 1.0 - exp(-dE / T); if (dist(rng) < p) { queue.push(j); } } } if (we_are_ghost) { s0 = s0_new; } else { dict.remove(s[i].x, i); s[i] = si_new; dict.record(s[i].x, i); cluster_size++; } } } Cq.add(cluster_size); } void wolff(double T, unsigned N, std::mt19937& rng) { std::uniform_real_distribution t_dist(0, L); std::uniform_int_distribution r_dist(0, D - 1); std::uniform_int_distribution ind_dist(0, s.size() - 1); for (unsigned i = 0; i < N; i++) { vector t; matrix m; for (unsigned j = 0; j < D; j++) { t(j) = (U)t_dist(rng); } unsigned flip_D1 = r_dist(rng); unsigned flip_D2 = r_dist(rng); for (unsigned j = 0; j < D; j++) { for (unsigned k = 0; k < D; k++) { if ((j == flip_D1 && k == flip_D2) || (j == flip_D2 && k == flip_D1)) { if (flip_D1 <= flip_D2) { m(j, k) = -1; } else { m(j, k) = 1; } } else if ((j == k && j != flip_D1) && j != flip_D2) { m(j, k) = 1; } else { m(j, k) = 0; } } } euclidean g(L, t, m); this->step(T, ind_dist(rng), g, rng); this->update_energy(); Eq.add(E); } } };