#include #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 < 0) ? (a + (1 - a / (signed)b) * b) : a) % b; } template Vector mod(const Eigen::MatrixBase& v, unsigned b) { Vector u; for (unsigned i = 0; i < D; i++) { u(i) = mod(v(i), b); } return u; } template void one_sequences(std::list>& sequences, unsigned level) { if (level > 0) { unsigned new_level = level - 1; unsigned old_length = sequences.size(); for (std::array& sequence : sequences) { std::array new_sequence = sequence; new_sequence[new_level] = -1; sequences.push_front(new_sequence); } one_sequences(sequences, new_level); } } template std::vector> generateTorusMatrices() { std::vector> mats; std::array ini_sequence; ini_sequence.fill(1); std::list> sequences; sequences.push_back(ini_sequence); one_sequences(sequences, D); sequences.pop_back(); // don't want the identity matrix! for (std::array sequence : sequences) { Matrix m; for (unsigned i = 0; i < D; i++) { for (unsigned j = 0; j < D; j++) { if (i == j) { m(i, j) = sequence[i]; } else { m(i, j) = 0; } } } mats.push_back(m); } for (unsigned i = 0; i < D; i++) { for (unsigned j = 0; j < D; j++) { if (i != j) { Matrix m; for (unsigned k = 0; k < D; k++) { for (unsigned l = 0; l < D; l++) { if ((k == i && l == j) || (k == j && l == i)) { if (i < j) { m(k, l) = 1; } else { m(k, l) = -1; } } else if (k == l && (k != i && k != j)) { m(k, l) = 1; } else { m(k, l) = 0; } } } mats.push_back(m); } } } return mats; } template class State : public Vector { public: State() : Vector(Vector::Zero()) {} State(const Vector& v) : Vector(v) {} State(unsigned a, signed b) : Vector(Vector::Zero()) { this->operator()(a) = b; } State(Rng& r) : State(r.uniform((unsigned)0, D - 1), r.pick({-1, 1})) {} bool isEmpty() const { return this->squaredNorm() == 0; } void remove() { this->setZero(); } }; template class Transformation { public: unsigned L; Matrix m; Vector v; Transformation(unsigned L, const Matrix& m, const Vector& v) : L(L), m(m), v(v) {} Transformation(unsigned L, const std::vector>& ms, Rng& r) : m(r.pick(ms)), L(L) { for (unsigned i = 0; i < D; i++) { v[i] = r.uniform((unsigned)0, L - 1); } } Vector apply(const Vector& x) const { return mod(v + m * (x - v), L); } State apply(const State& x) const { return State(m * x); } }; 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); vertices[i].marked = false; } 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 insert(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 (insert(v, State(r))) { return true; } } else { if (insert(r.pick(v.adjacentEdges).neighbor, State(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.setZero() = 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()) { insert(v, State(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); } } unsigned flipCluster(const Transformation& R, Vertex& v0, Rng& r, bool dry = false) { std::queue>> q; q.push(v0); unsigned n = 0; while (!q.empty()) { Vertex& v = q.front(); q.pop(); if (!v.marked) { Vector xNew = R.apply(v.position); Vertex& vNew = vertices[vectorToIndex(xNew)]; v.marked = true; vNew.marked = true; State s = R.apply(v.state); State sNew = R.apply(vNew.state); std::list>> overlaps1 = overlaps(vNew, s, true); std::list>> overlaps2 = overlaps(v, sNew, true); overlaps1.splice(overlaps1.begin(), overlaps2); for (Vertex& vn : overlaps1) { if (!vn.marked) { q.push(vn); } } if (!dry) { v.state = sNew; vNew.state = s; } n += 1; } } return n; } void swendsenWang(const Transformation& R, Rng& r) { for (Vertex& v : vertices) { if (!v.marked) { unsigned n = flipCluster(R, v, r, 0.5 < r.uniform(0.0, 1.0)); std::cerr << n << " "; } } std::cerr << std::endl; for (Vertex& v : vertices) { v.marked = false; } } }; void print(const System<2>& s) { for (const Vertex<2>& v : s.vertices) { if (v.state(0) == 1 && v.state(1) == 0) { std::cerr << "▶"; } else if (v.state(0) == -1 && v.state(1) == 0) { std::cerr << "◀"; } else if (v.state(0) == 0 && v.state(1) == -1) { std::cerr << "▲"; } else if (v.state(0) == 0 && v.state(1) == 1) { std::cerr << "▼"; } else if (v.state(0) == 0 && v.state(1) == 0) { std::cerr << " "; } else { std::cerr << "X"; } if (v.position(0) == s.L - 1) { std::cerr << std::endl; } } } 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; double z = exp(1 / 0.15); s.setGroundState(); std::vector> ms = generateTorusMatrices(); for (unsigned n = 0; n < 1e3; n++) { s.sweepGrandCanonical(z, r); } if (s.compatible()) { std::cerr << "Still compatible!" << std::endl; } for (unsigned n = 0; n < 10; n++) { s.swendsenWang(Transformation(L, ms, r), r); } if (s.compatible()) { std::cerr << "Still compatible!" << std::endl; } /* 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; }