diff options
-rw-r--r-- | space_wolff.hpp | 265 | ||||
-rw-r--r-- | spheres.cpp | 50 |
2 files changed, 150 insertions, 165 deletions
diff --git a/space_wolff.hpp b/space_wolff.hpp index 4c02406..cc4cd4f 100644 --- a/space_wolff.hpp +++ b/space_wolff.hpp @@ -29,12 +29,14 @@ const std::array<std::array<unsigned, 16>, 16> smiley = { {{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 <class U, unsigned D> using vector = Eigen::Matrix<U, D, 1>; +template <class T, int D> using Vector = Eigen::Matrix<T, D, 1>; -template <class U, unsigned D> using matrix = Eigen::Matrix<U, D, D>; +template <class T, int D> using Matrix = Eigen::Matrix<T, D, D>; -template <class U, unsigned D> vector<U, D> diff(U L, vector<U, D> v1, vector<U, D> v2) { - vector<U, D> v; +/** brief diff - periodic subtraction of vectors + */ +template <class T, int D> Vector<T, D> diff(T L, Vector<T, D> v1, Vector<T, D> v2) { + Vector<T, D> v; for (unsigned i = 0; i < D; i++) { v(i) = std::abs(v1(i) - v2(i)); @@ -46,20 +48,23 @@ template <class U, unsigned D> vector<U, D> diff(U L, vector<U, D> v1, vector<U, return v; } -template <class U, unsigned D, class state> class spin { +template <class T, int D, class S> class Spin { public: - vector<U, D> x; - state s; + Vector<T, D> x; + S s; }; -template <class U, unsigned D> class euclidean { +template <class T, int D> class Euclidean { private: - U L; + T L; public: - vector<U, D> t; - matrix<U, D> r; - euclidean(U L) : L(L) { + Vector<T, D> t; + Matrix<T, D> r; + + /** brief Euclidean - default constructor, constructs the identity + */ + Euclidean(T L) : L(L) { for (unsigned i = 0; i < D; i++) { t(i) = 0; r(i, i) = 1; @@ -69,14 +74,13 @@ public: } } - euclidean(U L, vector<U, D> t0, matrix<U, D> r0) : L(L) { + Euclidean(T L, Vector<T, D> t0, Matrix<T, D> r0) : L(L) { t = t0; r = r0; } - template <class state> - spin<U, D, state> act(const spin<U, D, state> &s) const { - spin<U, D, state> s_new; + template <class S> Spin<T, D, S> act(const Spin<T, D, S>& s) const { + Spin<T, D, S> s_new; s_new.x = t + r * s.x; s_new.s = s.s; @@ -88,85 +92,80 @@ public: return s_new; } - euclidean act(const euclidean& x) const { - vector<U, D> tnew = r * x.t + t; - matrix<U, D> rnew = r * x.r; + Euclidean act(const Euclidean& x) const { + Vector<T, D> tnew = r * x.t + t; + Matrix<T, D> rnew = r * x.r; for (unsigned i = 0; i < D; i++) { tnew(i) = fmod(L + tnew(i), L); } - euclidean pnew(this->L, tnew, rnew); + Euclidean pnew(this->L, tnew, rnew); return pnew; } - euclidean inverse() const { - vector<U, D> tnew = -r.transpose() * t; - matrix<U, D> rnew = r.transpose(); + Euclidean inverse() const { + Vector<T, D> tnew = -r.transpose() * t; + Matrix<T, D> rnew = r.transpose(); - euclidean pnew(this->L, tnew, rnew); + Euclidean pnew(this->L, tnew, rnew); return pnew; } }; -template <class T, unsigned D> class dictionary { +template <class T, int D, class S> class Octree { private: - unsigned N; T L; - std::vector<std::set<unsigned>> d; + unsigned N; + std::vector<std::set<Spin<T, D, S>*>> data; public: - dictionary(unsigned Ni, double Li) : N(Ni), L(Li), d(pow(Ni, D)) {}; + Octree(T L, unsigned depth) : L(L), N(pow(2, depth)), data(pow(N, D)){}; - unsigned dictionary_index(vector<T, D> x) const { + unsigned ind(Vector<T, D> x) const { unsigned pos_ind = 0; for (unsigned i = 0; i < D; i++) { - pos_ind += pow(N, i) * (unsigned)std::floor(x(i) * N / L); - }; + pos_ind += pow(N, i) * (unsigned)std::floor(N * x(i) / L); + } + + assert(pos_ind < data.size()); return pos_ind; } - void record(vector<T, D> x, unsigned ind) { - d[this->dictionary_index(x)].insert(ind); - }; + void insert(Spin<T, D, S>* s) { data[ind(s->x)].insert(s); }; - void remove(vector<T, D> x, unsigned ind) { - d[this->dictionary_index(x)].erase(ind); - }; + void remove( Spin<T, D, S>* s) { data[ind(s->x)].erase(s); }; - std::set<unsigned> neighbors(vector<T, D> x, unsigned depth) const { - return nearest_neighbors_of(this->dictionary_index(x), depth, {}); + std::set<Spin<T, D, S>*> neighbors(const Vector<T, D>& x, unsigned depth) const { + std::set<Spin<T, D, S>*> ns; + std::set<unsigned> seen; + nearest_neighbors_of(ind(x), depth, ns, seen); + return ns; }; - std::set<unsigned> nearest_neighbors_of(unsigned ind, unsigned depth, - std::list<unsigned> ignores) const { - std::set<unsigned> ns = d[ind]; + void nearest_neighbors_of(unsigned ind, unsigned depth, std::set<Spin<T, D, S>*>& ns, + std::set<unsigned>& seen) const { + ns.insert(data[ind].begin(), data[ind].end()); + seen.insert(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<unsigned> 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<unsigned> nns = nearest_neighbors_of(ni, depth - 1, ignores_new); + for (signed j : {-1, 1}) { + unsigned nind = pow(N, i + 1) * (ind / ((unsigned)pow(N, i + 1))) + + fmod(pow(N, i + 1) + ind + j * pow(N, i), pow(N, i + 1)); - for (unsigned guy : nns) { - ns.insert(guy); - } + if (!seen.contains(nind)) { + seen.insert(nind); + nearest_neighbors_of(nind, depth - 1, ns, seen); } } } } - - return ns; - }; + } }; class quantity { @@ -244,20 +243,36 @@ public: unsigned num_added() const { return n - wait; } }; -template <class U, unsigned D, class state> class model { +template <class U, int D, class S> class Model; + +/* +template <class U, int D, class S> + class measurement { + public: + virtual void pre_cluster(const Model<U, D, S>&, unsigned, const Euclidean<U, D>&) {}; + virtual void plain_bond_visited(const Model<U, D, S>&, const X_t&, double) {}; + virtual void plain_site_transformed(const system<R_t, X_t, G_t>&, const typename G_t::vertex& v, const X_t&) {}; + + virtual void ghost_bond_visited(const system<R_t, X_t, G_t>&, const typename G_t::vertex& v, const X_t&, const X_t&, double) {}; + virtual void ghost_site_transformed(const system<R_t, X_t, G_t>&, const R_t&) {}; + + virtual void post_cluster(unsigned, unsigned, const system<R_t, X_t, G_t>&) {}; + }; + */ + +template <class U, int D, class S> class Model { public: U L; - euclidean<U, D> s0; - std::vector<spin<U, D, state>> s; - dictionary<U, D> dict; - std::function<std::set<unsigned>(model<U, D, state>&, unsigned, spin<U, D, state>)> neighbors; - std::function<double(spin<U, D, state>, spin<U, D, state>)> Z; - std::function<double(spin<U, D, state>)> B; - std::vector<matrix<U, D>> mats; - std::vector<vector<U, D>> steps; - long double E; - quantity Eq; - quantity Cq; + Euclidean<U, D> s0; + std::vector<Spin<U, D, S>> s; + Octree<U, D, S> dict; + unsigned dDepth; + unsigned nDepth; + std::function<double(const Spin<U, D, S>&, const Spin<U, D, S>&)> Z; + std::function<double(const Spin<U, D, S>&)> B; + std::vector<Matrix<U, D>> mats; + std::vector<Vector<U, D>> steps; + double E; void one_sequences(std::list<std::array<double, D>>& sequences, unsigned level) { if (level > 0) { @@ -272,10 +287,9 @@ public: } } - model(U L, unsigned N, std::function<double(spin<U, D, state>, spin<U, D, state>)> Z, - std::function<double(spin<U, D, state>)> B, - std::function<std::set<unsigned>(model<U, D, state>&, unsigned, spin<U, D, state>)> ns) - : L(L), s0(L), dict(N, L), neighbors(ns), Z(Z), B(B), Eq(1000, 1000), Cq(1000, 1000) { + Model(U L, std::function<double(const Spin<U, D, S>&, const Spin<U, D, S>&)> Z, + std::function<double(const Spin<U, D, S>&)> B, unsigned dDepth, unsigned nDepth) + : L(L), s0(L), dict(L, dDepth), Z(Z), B(B), dDepth(dDepth), nDepth(nDepth) { std::array<double, D> ini_sequence; ini_sequence.fill(1); std::list<std::array<double, D>> sequences; @@ -286,7 +300,7 @@ public: sequences.pop_front(); // don't want the identity matrix! for (std::array<double, D> sequence : sequences) { - matrix<U, D> m; + Matrix<U, D> m; for (unsigned i = 0; i < D; i++) { for (unsigned j = 0; j < D; j++) { if (i == j) { @@ -299,7 +313,7 @@ public: mats.push_back(m); - vector<U, D> v; + Vector<U, D> v; for (unsigned i = 0; i < D; i++) { if (sequence[i] == 1) { v(i) = 0; @@ -314,7 +328,7 @@ public: for (unsigned i = 0; i < D; i++) { for (unsigned j = 0; j < D; j++) { if (i != j) { - matrix<U, D> m; + Matrix<U, D> m; for (unsigned k = 0; k < D; k++) { for (unsigned l = 0; l < D; l++) { if ((k == i && l == j) || (k == j && l == i)) { @@ -338,82 +352,71 @@ public: E = 0; for (unsigned i = 0; i < s.size(); i++) { for (unsigned j = 0; j < i; j++) { - E -= Z(s[i], s[j]); + E -= Z(s[i], s[j]); } E -= B(s0.inverse().act(s[i])); } } - void step(double T, unsigned ind, euclidean<U, D> r, std::mt19937& rng) { + void step(double T, unsigned ind, Euclidean<U, D> r, std::mt19937& rng) { unsigned cluster_size = 0; std::uniform_real_distribution<double> dist(0.0, 1.0); - std::queue<unsigned> queue; - queue.push(ind); + std::queue<Spin<U, D, S>*> queue; + queue.push(&(s[ind])); - std::vector<bool> visited(s.size() + 1, false); + std::set<Spin<U, D, S>*> visited; while (!queue.empty()) { - unsigned i = queue.front(); + Spin<U, D, S>* si = queue.front(); queue.pop(); - if (!visited[i]) { - visited[i] = true; + if (!visited.contains(si)) { + visited.insert(si); - bool we_are_ghost = i == s.size(); - - spin<U, D, state> si_new; - euclidean<U, D> s0_new(L); - - if (we_are_ghost) { - s0_new = r.act(s0); + if (si == NULL) { + Euclidean<U, D> s0_new = r.act(s0); + for (Spin<U, D, S>& ss : s) { + Spin<U, D, S> s0s_old = s0.inverse().act(ss); + Spin<U, D, S> s0s_new = s0_new.inverse().act(ss); + double p = 1.0 - exp(-(B(s0s_new) - B(s0s_old)) / T); + if (dist(rng) < p) { + queue.push(&ss); + } + s0 = s0_new; + } } else { - si_new = r.act(s[i]); - } - - for (unsigned j : neighbors(*this, i, si_new)) { - if (j != i) { - double p; - bool neighbor_is_ghost = j == s.size(); - - if (we_are_ghost || neighbor_is_ghost) { - spin<U, D, state> 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); + Spin<U, D, S> si_new = r.act(*si); + std::set<Spin<U, D, S>*> all_neighbors; + std::set<Spin<U, D, S>*> current_neighbors = dict.neighbors(si->x, nDepth); + std::set<Spin<U, D, S>*> new_neighbors = dict.neighbors(si_new.x, nDepth); + + all_neighbors.insert(current_neighbors.begin(), current_neighbors.end()); + all_neighbors.insert(new_neighbors.begin(), new_neighbors.end()); + all_neighbors.insert(NULL); + for (Spin<U, D, S>* sj : all_neighbors) { + if (sj != si) { + double p; + if (sj == NULL) { + Spin<U, D, S> s0s_old = s0.inverse().act(*si); + Spin<U, D, S> s0s_new = s0.inverse().act(si_new); + p = 1.0 - exp(-(B(s0s_new) - B(s0s_old)) / T); } else { - non_ghost = j; - s0s_old = s0.inverse().act(s[j]); - s0s_new = s0_new.inverse().act(s[j]); + p = 1.0 - exp(-(Z(si_new, *sj) - Z(*si, *sj)) / T); + } + if (dist(rng) < p) { + queue.push(sj); } - - p = 1.0 - exp(-(B(s0s_new) - B(s0s_old)) / T); - } else { - p = 1.0 - exp(-(Z(si_new, s[j]) - Z(s[i], s[j])) / 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); + dict.remove(si); + *si = si_new; + dict.insert(si); cluster_size++; } } } - - Cq.add(cluster_size); } void wolff(double T, unsigned N, std::mt19937& rng) { @@ -423,8 +426,8 @@ public: std::uniform_int_distribution<unsigned> coin(0, mats.size() + steps.size() - 1); for (unsigned i = 0; i < N; i++) { - vector<U, D> t; - matrix<U, D> m; + Vector<U, D> t; + Matrix<U, D> m; unsigned flip = coin(rng); if (flip < mats.size()) { for (unsigned j = 0; j < D; j++) { @@ -445,13 +448,11 @@ public: t = steps[flip - mats.size()]; } - euclidean<U, D> g(L, t, m); + Euclidean<U, D> g(L, t, m); this->step(T, ind_dist(rng), g, rng); this->update_energy(); - Eq.add(E); } } }; - diff --git a/spheres.cpp b/spheres.cpp index b0f4fb4..633a26a 100644 --- a/spheres.cpp +++ b/spheres.cpp @@ -34,65 +34,49 @@ int main(int argc, char* argv[]) { } } - std::function<double(spin<double, D, double>, spin<double, D, double>, spin<double, D, double>)> Z = - [L] (spin<double, D, double> s1, spin<double, D, double> s2, spin<double, D, double> s1_new) -> double { - vector<double, D> diff_old = diff(L, s1.x, s2.x); - vector<double, D> diff_new = diff(L, s1_new.x, s2.x); + std::function<double(const Spin<double, D, double>&, const Spin<double, D, double>&)> Z = + [L] (const Spin<double, D, double>& s1, const Spin<double, D, double>& s2) -> double { + Vector<double, D> d = diff(L, s1.x, s2.x); double rad_sum = pow(s1.s + s2.s, 2); - bool old_overlap = diff_old.transpose() * diff_old < rad_sum; - bool new_overlap = diff_new.transpose() * diff_new < rad_sum; + bool overlap = d.transpose() * d < rad_sum; - if (new_overlap) { - return 1.0; + if (overlap) { + return -1e8; } else { - return 0.0; + return 0; } }; - std::function<double(spin<double, D, double>)> B = - [L, H] (spin<double, D, double> s) -> double { + std::function<double(Spin<double, D, double>)> B = + [L, H] (Spin<double, D, double> s) -> double { return H * sin(2 * M_PI * 3 * s.x(0) / L); }; - std::function<std::set<unsigned>(model<double, D, double>&, unsigned, spin<double, D, double>)> neighbors = - [] (model<double, D, double>& m, unsigned i0, spin<double, D, double> s1) -> std::set<unsigned> { - std::set<unsigned> nn; - if (i0 < m.s.size()) { - std::set<unsigned> n_old = m.dict.neighbors(m.s[i0].x, 1); - std::set<unsigned> n_new = m.dict.neighbors(s1.x, 1);; - nn.insert(n_old.begin(), n_old.end()); - nn.insert(n_new.begin(), n_new.end()); - nn.insert(m.s.size()); - } else { - for (unsigned i = 0; i < m.s.size(); i++) { - nn.insert(i); - } - } - return nn; - }; - - model<double, D, double> sphere(L, Z, B, neighbors); + Model<double, D, double> sphere(L, Z, B, std::floor(log2(L)), 2); randutils::auto_seed_128 seeds; std::mt19937 rng{seeds}; std::uniform_real_distribution<double> dist(0.0, L); + sphere.s.reserve(n); + for (unsigned i = 0; i < n; i++) { - vector<double, D> pos = {dist(rng), dist(rng)}; + Vector<double, D> pos = {dist(rng), dist(rng)}; sphere.s.push_back({pos, 0.5}); - sphere.dict.record<double>(pos, i); + sphere.dict.insert(&sphere.s.back()); } + sphere.wolff(T, N, rng); std::ofstream snapfile; snapfile.open("sphere_snap.dat"); - for (spin<double, D, double> s : sphere.s) { - spin<double, D, double> rs = sphere.s0.inverse().act(s); + for (Spin<double, D, double> s : sphere.s) { + Spin<double, D, double> rs = sphere.s0.inverse().act(s); snapfile << rs.x.transpose() << "\n"; } |