#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; 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 CiamarraState : public Vector { public: CiamarraState() : Vector(Vector::Zero()) {} CiamarraState(const Vector& v) : Vector(v) {} CiamarraState(unsigned a, signed b) : Vector(Vector::Zero()) { this->operator()(a) = b; } CiamarraState(Rng& r) : CiamarraState(r.uniform(0, D - 1), r.pick({-1, 1})) {} bool isEmpty() const { return this->squaredNorm() == 0; } void remove() { this->setZero(); } CiamarraState flip() const { CiamarraState s; for (unsigned i = 0; i < D; i++) { s(i) = -this->operator()(i); } return s; } }; class BiroliState { public: unsigned type; unsigned occupiedNeighbors; BiroliState() { type = std::numeric_limits::max(); occupiedNeighbors = 0; } BiroliState(unsigned t, unsigned o) { type = t; occupiedNeighbors = o; } BiroliState(Rng& r) { type = r.pick({1,2,2,2,2,2,3,3,3,3}); } bool isEmpty() const { return type == std::numeric_limits::max(); } void remove() { type = std::numeric_limits::max(); }; }; template class Transformation { public: unsigned L; Matrix m; Vector v; Transformation(unsigned L) : L(L) { m.setIdentity(); v.setZero(); } 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); } v = v - m * v; } Transformation inverse() const { return Transformation(L, m.transpose(), -m.transpose() * v); } Vector apply(const Vector& x) const { return mod(v + m * x, L); } Transformation apply(const Transformation& t) const { Transformation tNew(L); tNew.m = m * t.m; tNew.v = apply(t.v); return tNew; } CiamarraState apply(const CiamarraState& s) const { return CiamarraState(m * s); } BiroliState apply(const BiroliState& s) const { return s; } }; template class HalfEdge; template class Vertex { public: Vector position; std::vector> adjacentEdges; State state; 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; Transformation orientation; 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)), orientation(L) { 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)); } } } virtual std::list>> overlaps(Vertex&) { return {}; }; virtual bool insert(Vertex& v, const State& s, bool force = false) { return false; }; virtual bool remove(Vertex& v) { return false;}; virtual bool randomMove(Rng& r) { return false;}; virtual void swap(Vertex& v1, Vertex& v2) {}; virtual bool exchange(Vertex& v1, Vertex& v2) { return false;}; bool randomExchange(Rng& r) { Vertex& v1 = r.pick(vertices); Vertex& v2 = r.pick(vertices); return exchange(v1, v2); } bool compatible() { for (Vertex& v : vertices) { if (overlaps(v).size() > 0) { return false; } } return true; } double density() const { return N / pow(L, D); } unsigned size() const { return vertices.size(); } 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 = size() * 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 * size()); if (pDel > r.uniform(0.0, 1.0)) { remove(r.pick(vertices)); } } randomMove(r); } } void sweepLocal(Rng& r) { for (unsigned i = 0; i < iPow(L, D); i++) { randomMove(r); } } void sweepSwap(Rng& r) { for (unsigned i = 0; i < iPow(L, D); i++) { randomExchange(r); } } unsigned flipCluster(const Transformation& R, Vertex& v0, bool dry = false) { unsigned n = 0; Vertex& v0New = vertices[vectorToIndex(R.apply(v0.position))]; if (&v0New != &v0) { std::queue>> q; v0.marked = true; v0New.marked = true; swap(v0, v0New); for (Vertex& vn : overlaps(v0)) { if (!vn.marked) { q.push(vn); } } for (Vertex& vn : overlaps(v0New)) { if (!vn.marked) { q.push(vn); } } while (!q.empty()) { Vertex& v = q.front(); q.pop(); if (!v.marked && !overlaps(v).empty()) { v.marked = true; Vertex& vNew = vertices[vectorToIndex(R.apply(v.position))]; if (&vNew != &v) { vNew.marked = true; swap(v, vNew); for (Vertex& vn : overlaps(v)) { if (!vn.marked) { q.push(vn); } } for (Vertex& vn : overlaps(vNew)) { if (!vn.marked) { q.push(vn); } } n += 2; } else { n += 1; } } if (q.empty()) { for (Vertex& vv : vertices) { if (!vv.marked && !overlaps(vv).empty()) { // std::cerr << "Found bad state at end" << std::endl; q.push(vv); } } } } } if (n > size() / 4) { orientation = R.apply(orientation); } for (Vertex& v : vertices) { v.marked = false; } return n; } void swendsenWang(const Transformation& R, Rng& r) { for (Vertex& v : vertices) { if (!v.marked) { bool dry = 0.5 < r.uniform(0.0, 1.0); unsigned n = flipCluster(R, v, dry); if (n > size() / 4 && !dry) { orientation = R.apply(orientation); } } } for (Vertex& v : vertices) { v.marked = false; } } virtual int overlap(const System& s) const { return 0; }; }; template class CiamarraSystem : public System> { public: using System>::System; std::list>>> overlaps(Vertex>& v, const CiamarraState& s, bool excludeSelf = false) override { 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 CiamarraState& s, bool force = false) override { if (force || overlaps(v, s).empty()) { v.state = s; this->N++; return true; } else { return false; } } bool remove(Vertex>& v) override { if (v.isEmpty()) { return false; } else { v.state.remove(); this->N--; return true; } } bool randomMove(Rng& r) override { Vertex>& v = r.pick(this->vertices); CiamarraState oldState = v.state; if (!remove(v)) { return false; } if (1.0 / (2.0 * D) > r.uniform(0.0, 1.0)) { for (HalfEdge>& e : v.adjacentEdges) { if (1 == e.Δx.dot(oldState)) { if (insert(e.neighbor, oldState.flip())) { return true; } break; } } } else { CiamarraState newState(r); while (newState.dot(oldState) == 1) { newState = CiamarraState(r); } if (insert(v, newState)) { return true; } } v.state = oldState; this->N++; return false; } void swap(Vertex>& v1, Vertex>& v2) override { std::swap(v1.state, v2.state); } bool exchange(Vertex>& v1, Vertex>& v2) override { if (overlaps(v1, v2.state, true).size() == 0 && overlaps(v2, v1.state, true).size() == 0) { swap(v1, v2); return true; } else { return false; } } void setGroundState() { this->N = 0; for (Vertex>& v : this->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; this->N++; } else if (D < a) { v.state(2 * D - a) = 1; this->N++; } } } int overlap(const System>& s) const override { int o = 0; for (unsigned i = 0; i < this->vertices.size(); i++) { CiamarraState s2 = this->orientation.apply( s.vertices[this->vectorToIndex(this->orientation.inverse().apply(this->indexToVector(i)))].state); o += this->vertices[i].state.dot(s2); } return o; } }; template class BiroliSystem : public System { public: using System::System; bool canReplaceWith(const Vertex& v, const BiroliState& s) { if (s.isEmpty()) { return true; } if (s.type < v.state.occupiedNeighbors) { return false; } else { int Δn = 0; if (v.isEmpty()) { Δn += 1; } for (const HalfEdge& e : v.adjacentEdges) { if (e.neighbor.state.type < e.neighbor.state.occupiedNeighbors + Δn) { return false; } } } return true; } std::list>> overlaps(Vertex& v) override { std::list>> o; if (v.isEmpty()) { // an empty site cannot be frustrating anyone return o; } bool selfFrustrated = v.state.occupiedNeighbors > v.state.type; bool anyNeighborFrustrated = false; for (const HalfEdge& e : v.adjacentEdges) { if (!e.neighbor.isEmpty()) { bool thisNeighborFrustrated = e.neighbor.state.type < e.neighbor.state.occupiedNeighbors; if (thisNeighborFrustrated) { anyNeighborFrustrated = true; } if (selfFrustrated || thisNeighborFrustrated) { o.push_back(e.neighbor); } } } if (selfFrustrated || anyNeighborFrustrated) { o.push_back(v); } return o; } bool insert(Vertex& v, const BiroliState& s, bool force = false) override { if (force || (v.isEmpty() && canReplaceWith(v, s))) { v.state.type = s.type; for (HalfEdge& e : v.adjacentEdges) { e.neighbor.state.occupiedNeighbors++; } this->N++; return true; } else { return false; } } bool remove(Vertex& v) override { if (v.isEmpty()) { return false; } else { v.state.remove(); for (HalfEdge& e : v.adjacentEdges) { e.neighbor.state.occupiedNeighbors--; } this->N--; return true; } } bool randomMove(Rng& r) override { Vertex& v = r.pick(this->vertices); return exchange(v, r.pick(v.adjacentEdges).neighbor); } void swap(Vertex& v1, Vertex& v2) override { if (v1.state.type != v2.state.type) { if (!v1.isEmpty() && !v2.isEmpty()) { std::swap(v1.state.type, v2.state.type); } else if (v1.isEmpty()) { unsigned t = v2.state.type; remove(v2); insert(v1, BiroliState(t, 0), true); } else { unsigned t = v1.state.type; remove(v1); insert(v2, BiroliState(t, 0), true); } } } bool exchange(Vertex& v1, Vertex& v2) override { if (canReplaceWith(v1, v2.state) && canReplaceWith(v2, v1.state)) { swap(v1, v2); return true; } else { return false; } } int overlap(const System& s) const override { int o = 0; for (unsigned i = 0; i < this->vertices.size(); i++) { BiroliState s2 = this->orientation.apply( s.vertices[this->vectorToIndex(this->orientation.inverse().apply(this->indexToVector(i)))].state); if (s2.type > 0 && s2.type == this->vertices[i].state.type) { o++; } else { o--; } } return o; } };