#include #include #include #include #include "pcg-cpp/include/pcg_random.hpp" #include "randutils/randutils.hpp" using Rng = randutils::random_generator; template using Vector = Eigen::Matrix; template using Matrix = Eigen::Matrix; int iPow(int x, unsigned p) { if (p == 0) return 1; if (p == 1) return x; int tmp = iPow(x, p / 2); if (p % 2 == 0) return tmp * tmp; else return x * tmp * tmp; } unsigned mod(signed a, unsigned b) { return ((a %= b) < 0) ? a + b : a; } template class State { public: Vector σ; State(unsigned a, signed b) : σ(Vector::Zero()) { σ[a] = b; } State() : σ(Vector::Zero()) {} bool isEmpty() const { return σ.squaredNorm() == 0; } void remove() { σ = Vector::Zero(); } State apply(const Matrix& m) const { return {m * σ}; } }; template State randomState(Rng& r) { return State(r.uniform((unsigned)0, D - 1), r.pick({-1, 1})); } template class HalfEdge; template class Vertex { public: Vector position; State state; std::vector> adjacentEdges; bool marked; bool isEmpty() const { return state.isEmpty(); } }; template class HalfEdge { public: Vertex& neighbor; Vector Δx; HalfEdge(Vertex& n, const Vector& d) : neighbor(n), Δx(d) {} }; template class System { public: const unsigned L; unsigned N; std::vector> vertices; unsigned vectorToIndex(const Vector& x) const { unsigned i = 0; for (unsigned d = 0; d < D; d++) { i += x[d] * iPow(L, d); } return i; } Vector indexToVector(unsigned i) const { Vector x; for (unsigned d = 0; d < D; d++) { x[d] = (i / iPow(L, d)) % L; } return x; } System(unsigned L) : L(L), N(0), vertices(iPow(L, D)) { for (unsigned i = 0; i < iPow(L, D); i++) { vertices[i].position = indexToVector(i); vertices[i].adjacentEdges.reserve(2 * D); } for (unsigned d = 0; d < D; d++) { Vector Δx = Vector::Zero(); Δx[d] = 1; for (signed i = 0; i < iPow(L, D); i++) { unsigned j = iPow(L, d + 1) * (i / iPow(L, d + 1)) + mod(i + iPow(L, d), pow(L, d + 1)); vertices[i].adjacentEdges.push_back(HalfEdge(vertices[j], Δx)); vertices[j].adjacentEdges.push_back(HalfEdge(vertices[i], -Δx)); } } } std::list>> overlaps(Vertex& v, const State& s, bool excludeSelf = false) { std::list>> o; if (s.isEmpty()) { return o; } if (!v.isEmpty() && !excludeSelf) { o.push_back(v); } for (const HalfEdge& e : v.adjacentEdges) { if (!e.neighbor.isEmpty()) { if (s.σ.dot(e.Δx) == 1 || e.neighbor.state.σ.dot(e.Δx) == -1) { o.push_back(e.neighbor); } } } return o; } bool tryInsertion(Vertex& v, const State& s) { if (overlaps(v, s).empty()) { v.state = s; N++; return true; } else { return false; } } bool tryDeletion(Vertex& v) { if (v.isEmpty()) { return false; } else { v.state.remove(); N--; return true; } } bool tryRandomMove(Rng& r) { Vertex& v = r.pick(vertices); State oldState = v.state; if (!tryDeletion(v)) { return false; } if (0.2 > r.uniform(0.0, 1.0)) { if (tryInsertion(v, randomState(r))) { return true; } } else { if (tryInsertion(r.pick(v.adjacentEdges).neighbor, randomState(r))) { return true; } } v.state = oldState; N++; return false; } bool trySwap(Vertex& v1, Vertex& v2) { if (overlaps(v1, v2.state, true).size() == 0 && overlaps(v2, v1.state, true).size() == 0) { std::swap(v1.state, v2.state); return true; } else { return false; } } bool tryRandomSwap(Rng& r) { Vertex& v1 = r.pick(vertices); Vertex& v2 = r.pick(vertices); return trySwap(v1, v2); } void setGroundState() { N = 0; for (Vertex& v : vertices) { unsigned a = 0; for (unsigned d = 0; d < D; d++) { a += (d + 1) * v.position(d); } a %= 2 * D + 1; v.state.σ = Vector::Zero(); if (0 < a && a <= D) { v.state.σ(a - 1) = -1; N++; } else if (D < a) { v.state.σ(2 * D - a) = 1; N++; } } } bool compatible() { for (Vertex& v : vertices) { if (overlaps(v, v.state, true).size() > 0) { return false; } } return true; } double density() const { return N / pow(L, D); } unsigned maxOccupation() const { // return (2 * D * iPow(L, D)) / (2 * D + 1); return iPow(L, D); } void sweepGrandCanonical(double z, Rng& r) { for (unsigned i = 0; i < iPow(L, D); i++) { if (0.5 < r.uniform(0.0, 1.0)) { double pIns = maxOccupation() * z / (N + 1); if (pIns > r.uniform(0.0, 1.0)) { while (true) { Vertex& v = r.pick(vertices); if (v.isEmpty()) { tryInsertion(v, randomState(r)); break; } } } } else { double pDel = N / (z * maxOccupation()); if (pDel > r.uniform(0.0, 1.0)) { tryDeletion(r.pick(vertices)); } } tryRandomMove(r); tryRandomSwap(r); } } void sweepLocal(double z, Rng& r) { for (unsigned i = 0; i < iPow(L, D); i++) { tryRandomMove(r); } } void sweepSwap(double z, Rng& r) { for (unsigned i = 0; i < iPow(L, D); i++) { tryRandomSwap(r); } } void flipCluster(const Matrix& R, Vertex& v0, Rng& r, bool dry = false) { std::list>> q = {v0}; while (!q.empty()) { Vertex& v = q.front(); q.pop_front(); Vector xNew = R * v.position; State sNew = v.state.apply(R); for (Vertex& vn : overlaps(vertices[vectorToIndex(xNew)], sNew)) { if (!vn.marked) { vn.marked = true; q.push_back(vn); } } } } }; template Vector randomVector(unsigned L, Rng& r) { Vector x; for (unsigned i = 0; i < D; i++) { x[i] = r.uniform((unsigned)0, L - 1); } return x; } int main() { const unsigned D = 3; unsigned L = 28; unsigned Nmin = 2e2; unsigned Nmax = 2e5; double Tmin = 0.04; double Tmax = 0.2; double δT = 0.02; System s(L); Rng r; for (unsigned N = Nmin; N <= Nmax; N *= 10) { s.setGroundState(); for (double T = Tmin; T < Tmax; T *= 1 + δT) { double z = exp(1 / T); for (unsigned n = 0; n < N; n++) { s.sweepGrandCanonical(z, r); } std::cout << L << " " << T << " " << N << " " << δT << " " << 1 / s.density() << std::endl; } for (double T = Tmax; T > Tmin; T /= 1 + δT) { double z = exp(1 / T); for (unsigned n = 0; n < N; n++) { s.sweepGrandCanonical(z, r); } std::cout << L << " " << T << " " << N << " " << δT << " " << 1 / s.density() << std::endl; } } return 0; }