#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(spin s) { 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) { vector tnew = r * x.t + t; matrix rnew = r * x.r; euclidean pnew(this->L, tnew, rnew); return pnew; } euclidean inverse() { vector tnew = - r.transpose() * t; matrix rnew = r.transpose(); euclidean pnew(this->L, tnew, rnew); return pnew; } }; 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) { 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 on_site(vector x) { return d[dictionary_index(x)]; }; template std::set nearest_neighbors(vector x) { unsigned ind = dictionary_index(x); std::set ns; for (unsigned i = 0; i < D; 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)); for (unsigned nii : d[ni]) { ns.insert(nii); } } } return ns; }; template std::set next_nearest_neighbors(vector x) { unsigned ind = dictionary_index(x); std::set ns; for (unsigned i = 0; i < D; 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)); for (unsigned k = 0; k < D; k++) { if (k != i) { for (signed l : {-1, 1}) { unsigned nni = pow(L, k + 1) * (ni / ((unsigned)pow(L, k + 1))) + fmod(pow(L, k + 1) + ni + l * pow(L, k), pow(L, k + 1)); for (unsigned nnii : d[nni]) { ns.insert(nnii); } } } } } } return ns; }; template std::set next_next_nearest_neighbors(vector x) { unsigned ind = dictionary_index(x); std::set ns; for (unsigned i = 0; i < D; 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)); for (unsigned k = 0; k < D; k++) { if (k != i) { for (signed l : {-1, 1}) { unsigned nni = pow(L, k + 1) * (ni / ((unsigned)pow(L, k + 1))) + fmod(pow(L, k + 1) + ni + l * pow(L, k), pow(L, k + 1)); for (unsigned m = 0; m < D; m++) { if (m != i && m != k) { for (signed n : {-1, 1}) { unsigned nnni = pow(L, m + 1) * (nni / ((unsigned)pow(L, m + 1))) + fmod(pow(L, m + 1) + nni + n * pow(L, m), pow(L, m + 1)); for (unsigned nnnii : d[nnni]) { ns.insert(nnnii); } } } } } } } } } return ns; }; }; 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; double E; 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) { } void step(double T, unsigned ind, euclidean r, std::mt19937& rng) { 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); } } } } 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); } } }; int main(int argc, char* argv[]) { unsigned L = 32; const unsigned D = 2; std::function, spin)> Z = [] (spin s1, spin s2) -> double { bool one_one = false; bool many_ones = false; bool any_two = false; for (unsigned i = 0; i < D; i++) { unsigned diff = abs(s1.x(i) - s2.x(i)); if (diff == 1 && !one_one) { one_one = true; } else if (diff == 1 && one_one) { many_ones = true; break; } else if (diff > 1) { any_two = true; break; } } if (!one_one && !any_two) { return -std::numeric_limits::infinity(); } else if (one_one && !many_ones && !any_two) { return s1.s * s2.s; } else { return 0; } }; std::function)> B = [] (spin s) -> double { return 100 * s.s * smiley[s.x(0) / 2][s.x(1) / 2]; }; std::function(model&, unsigned, spin)> neighbors = [] (model& m, unsigned i0, spin s1) -> std::set { std::set nn; if (i0 < m.s.size()) { std::set os1 = m.dict.on_site(s1.x); std::set nn0 = m.dict.nearest_neighbors(m.s[i0].x); std::set nn1 = m.dict.nearest_neighbors(s1.x); nn.insert(nn0.begin(), nn0.end()); nn.insert(nn1.begin(), nn1.end()); nn.insert(os1.begin(), os1.end()); nn.insert(m.s.size()); } else { for (unsigned i = 0; i < m.s.size(); i++) { nn.insert(i); } } return nn; }; model ising(L, Z, B, neighbors); randutils::auto_seed_128 seeds; std::mt19937 rng{seeds}; std::uniform_int_distribution coin(0, 1); unsigned n = 0; unsigned up = 0; unsigned down = 0; for (unsigned i = 0; i < L; i++) { for (unsigned j = 0; j < L; j++) { if ((coin(rng) && up < pow(L, 2) / 2) || down >= pow(L, 2) / 2) { ising.s.push_back({{i, j}, 1}); up++; } else { ising.s.push_back({{i, j}, -1}); down++; } ising.dict.record({i, j}, n); n++; } } /* for (unsigned i = 0; i < L; i++) { for (unsigned j = 0; j < L; j++) { if (i < L / 2) { ising.s.push_back({{i, j}, 1}); } else { ising.s.push_back({{i, j}, -1}); } ising.dict.record({i, j}, n); n++; } } */ ising.wolff(2.0 / log(1.0 + sqrt(2.0)), 5000, rng); std::vector output(pow(L, D)); for (spin s : ising.s) { spin rs = ising.s0.inverse().act(s); output[L * rs.x(1) + rs.x(0)] = s.s; } for (unsigned i = 0; i < L; i++) { for (unsigned j = 0; j < L; j++) { unsigned out = output[L * i + j] == 1 ? 1 : 0; std::cout << out; } std::cout << "\n"; } return 0; }