summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaron Kent-Dobias <jaron@kent-dobias.com>2021-06-09 16:32:27 +0200
committerJaron Kent-Dobias <jaron@kent-dobias.com>2021-06-09 16:32:27 +0200
commit7548abd44c37d4495dd498193ea15b0df757b904 (patch)
treeddca95300a8b323192f2f6a8f4459bb08733d3f5
parent2bf71fe50bf2fb0a256b8f1511aafdd5031c47d9 (diff)
downloadlattice_glass-7548abd44c37d4495dd498193ea15b0df757b904.tar.gz
lattice_glass-7548abd44c37d4495dd498193ea15b0df757b904.tar.bz2
lattice_glass-7548abd44c37d4495dd498193ea15b0df757b904.zip
Lots of work.
-rw-r--r--biroli-mezard.cpp163
-rw-r--r--ciamarra.cpp489
-rw-r--r--glass.hpp677
3 files changed, 601 insertions, 728 deletions
diff --git a/biroli-mezard.cpp b/biroli-mezard.cpp
index 7e200b9..e2fb71a 100644
--- a/biroli-mezard.cpp
+++ b/biroli-mezard.cpp
@@ -5,6 +5,7 @@
#include <queue>
#include <vector>
#include <chrono>
+#include <unordered_set>
#include <eigen3/Eigen/Dense>
@@ -152,6 +153,7 @@ public:
unsigned occupiedNeighbors;
unsigned maximumNeighbors;
bool marked;
+ bool visited;
Vertex() {
occupiedNeighbors = 0;
@@ -181,6 +183,7 @@ template <int D> class System {
public:
const unsigned L;
std::vector<unsigned> N;
+ std::unordered_set<Vertex<D>*> occupants;
std::vector<Vertex<D>> vertices;
Transformation<D> orientation;
@@ -322,6 +325,9 @@ public:
}
N[t]++;
N[0]--;
+ if (t > 0) {
+ occupants.insert(&v);
+ }
return true;
} else {
return false;
@@ -332,6 +338,9 @@ public:
if (v.empty()) {
return false;
} else {
+ if (v.maximumNeighbors > 0) {
+ occupants.erase(&v);
+ }
N[v.maximumNeighbors]--;
N[0]++;
v.maximumNeighbors = Empty;
@@ -418,30 +427,32 @@ public:
return exchange(v1, v2);
}
- void sweepGrandCanonical(double z, Rng& r) {
- for (unsigned i = 0; i < size(); i++) {
- if (0.5 < r.uniform(0.0, 1.0)) {
- double pIns = size() * z / (occupancy() + 1);
-
- if (pIns > r.uniform(0.0, 1.0)) {
- while (true) {
- Vertex<D>& v = r.pick(vertices);
- if (v.empty()) {
- insert(v, r.pick({1, 2, 2, 2, 2, 2, 3, 3, 3, 3}));
- break;
- }
- }
- }
- } else {
+ const std::array<double, 3> ratios = {0.1, 0.5, 0.4};
- double pDel = density() / z;
+ void stepGrandCanonical(double z, Rng& r) {
+ if (1.0 / 11.0 < r.uniform(0.0, 1.0)) {
+ unsigned t = r.pick({1, 2, 2, 2, 2, 2, 3, 3, 3, 3});
+ double pIns = size() * z / (occupancy() + 1);
- if (pDel > r.uniform(0.0, 1.0)) {
- remove(r.pick(vertices));
- }
+ if (pIns > r.uniform(0.0, 1.0)) {
+ Vertex<D>& v = r.pick(vertices);
+ insert(v, t);
}
+ } else {
+ double pDel = density() / z;
- randomLocalExchange(r);
+ if (pDel > r.uniform(0.0, 1.0)) {
+ Vertex<D>* v = r.pick(occupants);
+ remove(*v);
+ }
+ }
+ }
+
+ void sweepGrandCanonical(double z, Rng& r) {
+ for (unsigned i = 0; i < size(); i++) {
+ stepGrandCanonical(z, r);
+
+ randomExchange(r);
}
}
@@ -457,6 +468,71 @@ public:
}
}
+ Vertex<D>& apply(const Transformation<D>& R, const Vertex<D>& v) {
+ return vertices[vectorToIndex(R.apply(v.position))];
+ }
+
+ bool eventChain(const Transformation<D>& R, Vertex<D>& v0) {
+ unsigned n = 0;
+
+ if (!v0.empty()) {
+ Vertex<D>& v0New = apply(R, v0);;
+ unsigned t0 = v0.maximumNeighbors;
+
+ std::queue<std::pair<std::reference_wrapper<Vertex<D>>, unsigned>> q;
+
+ q.push({v0New, t0});
+ remove(v0);
+
+ while (!q.empty()) {
+ auto [vr, t] = q.front();
+ Vertex<D>& v = vr;
+ q.pop();
+
+ if (!v.empty()) {
+ q.push({apply(R, v), v.maximumNeighbors});
+ remove(v);
+ }
+
+ insert(v, t, true);
+ v.marked = true;
+
+ for (Vertex<D>& vn : overlaps({v})) {
+ if (!vn.marked) {
+ q.push({apply(R, vn), vn.maximumNeighbors});
+ remove(vn);
+ vn.marked = true;
+ } else {
+ /* If a neighbor has already been moved but is still
+ * frustrated, it may be due to one of its neighbors!
+ */
+ if (&vn != &v) {
+ for (Vertex<D>& vnn : overlaps(vn)) {
+ if (!vnn.marked) {
+ q.push({apply(R, vnn), vnn.maximumNeighbors});
+ remove(vnn);
+ vnn.marked = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (Vertex<D>& v : vertices) {
+ v.marked = false;
+ }
+
+ return true;
+ }
+
+ bool randomEventChain(Rng& r) {
+ Transformation<D> R(L);
+ R.v[r.uniform((unsigned)0, (unsigned)D-1)] = r.pick({-1, 1});
+ return eventChain(R, r.pick(vertices));
+ }
+
unsigned flipCluster(const Transformation<D>& R, Vertex<D>& v0) {
unsigned n = 0;
@@ -546,30 +622,35 @@ int main() {
unsigned L = 15;
unsigned Nmin = 2e2;
unsigned Nmax = 2e5;
- double Tmin = 0.04;
- double Tmax = 0.2;
- double δT = 0.02;
+ double μmin = -3;
+ double μmax = 10;
+ double dμ = 0.05;
System<D> s(L, 3);
Rng r;
- double z = exp(1 / 0.15);
+ for (double μ = μmin; μ <= μmax; μ += dμ) {
+ double z = exp(μ);
+ for (unsigned i = 0; i < 1e4; i++) {
+ for (unsigned j = 0; j < s.size(); j++) {
+ s.stepGrandCanonical(z, r);
+// s.randomEventChain(r);
+ s.randomExchange(r);
+ }
- if (!s.compatible()) {
- std::cerr << "Storted incompatible!" << std::endl;
- return 1;
- }
+ if (!s.compatible()) {
+ std::cerr << "Not compatible!" << std::endl;
+ return 1;
+ }
- while (s.density() < 0.56) {
- s.sweepGrandCanonical(z, r);
- }
+ }
- if (!s.compatible()) {
- std::cerr << "Not compatible!" << std::endl;
- return 1;
+ std::cout << μ << " " << s.density() << std::endl;
}
+
+ /*
std::cerr << "Found state with appropriate density." << std::endl;
System<D> s0 = s;
@@ -586,22 +667,19 @@ int main() {
auto start = std::chrono::high_resolution_clock::now();
while (nC / s.size() < 1e5) {
if (n < 20 * log(i + 1)) {
+ auto stop = std::chrono::high_resolution_clock::now();
+ auto duration = duration_cast<std::chrono::microseconds>(stop - start);
n++;
- std::cout << nC / s.size() << " " << s.overlap(s0) << std::endl;
+ std::cout << duration.count() << " " << s.overlap(s0) << std::endl;
}
- //unsigned nn = s.flipCluster(Transformation<D>(L, ms, r), r.pick(s.vertices));
- //nC += nn;
+// unsigned nn = s.flipCluster(Transformation<D>(L, ms, r), r.pick(s.vertices));
+// nC += nn;
// clusterDist[nn]++;
//s.sweepLocal(r);
nC += s.size();
s.sweepSwap(r);
i++;
}
- auto stop = std::chrono::high_resolution_clock::now();
-
- auto duration = duration_cast<std::chrono::microseconds>(stop - start);
-
- std::cerr << duration.count() << std::endl;
if (!s.compatible()) {
std::cerr << "Not compatible!" << std::endl;
@@ -618,6 +696,7 @@ int main() {
file << i << " ";
}
file.close();
+ */
return 0;
}
diff --git a/ciamarra.cpp b/ciamarra.cpp
index 6b932bf..f2f44c1 100644
--- a/ciamarra.cpp
+++ b/ciamarra.cpp
@@ -1,10 +1,477 @@
+#include <eigen3/Eigen/Dense>
+#include <eigen3/Eigen/src/Core/CwiseNullaryOp.h>
#include <iostream>
+#include <list>
+#include <vector>
+#include <queue>
-#include "glass.hpp"
+#include "pcg-cpp/include/pcg_random.hpp"
+#include "randutils/randutils.hpp"
+using Rng = randutils::random_generator<pcg32>;
-void print(const CiamarraSystem<2>& s) {
- for (const Vertex<2, CiamarraState<2>>& v : s.vertices) {
+template <int D> using Vector = Eigen::Matrix<int, D, 1>;
+template <int D> using Matrix = Eigen::Matrix<int, D, D>;
+
+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 <int D, typename Derived> Vector<D> mod(const Eigen::MatrixBase<Derived>& v, unsigned b) {
+ Vector<D> u;
+ for (unsigned i = 0; i < D; i++) {
+ u(i) = mod(v(i), b);
+ }
+ return u;
+}
+
+template <int D> void one_sequences(std::list<std::array<double, D>>& sequences, unsigned level) {
+ if (level > 0) {
+ unsigned new_level = level - 1;
+ unsigned old_length = sequences.size();
+ for (std::array<double, D>& sequence : sequences) {
+ std::array<double, D> new_sequence = sequence;
+ new_sequence[new_level] = -1;
+ sequences.push_front(new_sequence);
+ }
+ one_sequences<D>(sequences, new_level);
+ }
+}
+
+template <unsigned D> std::vector<Matrix<D>> generateTorusMatrices() {
+ std::vector<Matrix<D>> mats;
+
+ std::array<double, D> ini_sequence;
+ ini_sequence.fill(1);
+ std::list<std::array<double, D>> sequences;
+ sequences.push_back(ini_sequence);
+
+ one_sequences<D>(sequences, D);
+
+ sequences.pop_back(); // don't want the identity matrix!
+
+ for (std::array<double, D> sequence : sequences) {
+ Matrix<D> 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<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)) {
+ 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 <unsigned D> class State : public Vector<D> {
+public:
+ State() : Vector<D>(Vector<D>::Zero()) {}
+
+ State(const Vector<D>& v) : Vector<D>(v) {}
+
+ State(unsigned a, signed b) : Vector<D>(Vector<D>::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(); }
+
+ State<D> flip() const {
+ State<D> s;
+ for (unsigned i = 0; i < D; i++) {
+ s(i) = -this->operator()(i);
+ }
+ return s;
+ }
+};
+
+template <unsigned D> class Transformation {
+ public:
+ unsigned L;
+ Matrix<D> m;
+ Vector<D> v;
+
+ Transformation(unsigned L) : L(L) {
+ m.setIdentity();
+ v.setZero();
+ }
+
+ Transformation(unsigned L, const Matrix<D>& m, const Vector<D>& v) : L(L), m(m), v(v) {}
+
+ Transformation(unsigned L, const std::vector<Matrix<D>>& 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;
+ }
+
+ Vector<D> apply(const Vector<D>& x) const {
+ return mod<D>(v + m * x, L);
+ }
+
+ Transformation<D> apply(const Transformation<D>& t) const {
+ Transformation<D> tNew(L);
+
+ tNew.m = m * t.m;
+ tNew.v = apply(t.v);
+
+ return tNew;
+ }
+
+ State<D> apply(const State<D>& x) const {
+ return State<D>(m * x);
+ }
+
+ Transformation<D> inverse() const {
+ return Transformation<D>(L, m.transpose(), -m.transpose() * v);
+ }
+};
+
+template <unsigned D> class HalfEdge;
+
+template <unsigned D> class Vertex {
+public:
+ Vector<D> position;
+ State<D> state;
+ std::vector<HalfEdge<D>> adjacentEdges;
+ bool marked;
+
+ bool isEmpty() const { return state.isEmpty(); }
+};
+
+template <unsigned D> class HalfEdge {
+public:
+ Vertex<D>& neighbor;
+ Vector<D> Δx;
+
+ HalfEdge(Vertex<D>& n, const Vector<D>& d) : neighbor(n), Δx(d) {}
+};
+
+template <unsigned D> class System {
+public:
+ const unsigned L;
+ unsigned N;
+ std::vector<Vertex<D>> vertices;
+ Transformation<D> orientation;
+
+ unsigned vectorToIndex(const Vector<D>& x) const {
+ unsigned i = 0;
+ for (unsigned d = 0; d < D; d++) {
+ i += x[d] * iPow(L, d);
+ }
+ return i;
+ }
+
+ Vector<D> indexToVector(unsigned i) const {
+ Vector<D> 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<D> Δx = Vector<D>::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<D>(vertices[j], Δx));
+ vertices[j].adjacentEdges.push_back(HalfEdge<D>(vertices[i], -Δx));
+ }
+ }
+ }
+
+ std::list<std::reference_wrapper<Vertex<D>>> overlaps(Vertex<D>& v, const State<D>& s,
+ bool excludeSelf = false) {
+ std::list<std::reference_wrapper<Vertex<D>>> o;
+
+ if (s.isEmpty()) {
+ return o;
+ }
+
+ if (!v.isEmpty() && !excludeSelf) {
+ o.push_back(v);
+ }
+
+ for (const HalfEdge<D>& 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<D>& v, const State<D>& s) {
+ if (overlaps(v, s).empty()) {
+ v.state = s;
+ N++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool tryDeletion(Vertex<D>& v) {
+ if (v.isEmpty()) {
+ return false;
+ } else {
+ v.state.remove();
+ N--;
+ return true;
+ }
+ }
+
+ bool tryRandomMove(Rng& r) {
+ Vertex<D>& v = r.pick(vertices);
+ State<D> oldState = v.state;
+
+ if (!tryDeletion(v)) {
+ return false;
+ }
+
+ if (1.0 / (2.0 * D) > r.uniform(0.0, 1.0)) {
+ for (HalfEdge<D>& e : v.adjacentEdges) {
+ if (1 == e.Δx.dot(oldState)) {
+ if (insert(e.neighbor, oldState.flip())) {
+ return true;
+ }
+ break;
+ }
+ }
+ } else {
+ State<D> newState(r);
+ while (newState.dot(oldState) == 1) {
+ newState = State<D>(r);
+ }
+ if (insert(v, newState)) {
+ return true;
+ }
+ }
+ v.state = oldState;
+ N++;
+ return false;
+ }
+
+ bool trySwap(Vertex<D>& v1, Vertex<D>& 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<D>& v1 = r.pick(vertices);
+ Vertex<D>& v2 = r.pick(vertices);
+
+ return trySwap(v1, v2);
+ }
+
+ void setGroundState() {
+ N = 0;
+
+ for (Vertex<D>& 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<D>::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<D>& 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<D>& v = r.pick(vertices);
+ if (v.isEmpty()) {
+ insert(v, State<D>(r));
+ break;
+ }
+ }
+ }
+ } else {
+
+ double pDel = N / (z * maxOccupation());
+
+ if (pDel > r.uniform(0.0, 1.0)) {
+ tryDeletion(r.pick(vertices));
+ }
+ }
+
+ tryRandomMove(r);
+ }
+ }
+
+ void sweepLocal(Rng& r) {
+ for (unsigned i = 0; i < iPow(L, D); i++) {
+ tryRandomMove(r);
+ }
+ }
+
+ void sweepSwap(Rng& r) {
+ for (unsigned i = 0; i < iPow(L, D); i++) {
+ tryRandomSwap(r);
+ }
+ }
+
+ unsigned flipCluster(const Transformation<D>& R, Vertex<D>& v0, Rng& r, bool dry = false) {
+ std::queue<std::reference_wrapper<Vertex<D>>> q;
+ q.push(v0);
+
+ unsigned n = 0;
+
+ while (!q.empty()) {
+ Vertex<D>& v = q.front();
+ q.pop();
+
+ if (!v.marked) {
+ Vector<D> xNew = R.apply(v.position);
+ Vertex<D>& vNew = vertices[vectorToIndex(xNew)];
+
+ v.marked = true;
+ vNew.marked = true;
+
+ State<D> s = R.apply(v.state);
+ State<D> sNew = R.apply(vNew.state);
+
+ std::list<std::reference_wrapper<Vertex<D>>> overlaps1 = overlaps(vNew, s, true);
+ std::list<std::reference_wrapper<Vertex<D>>> overlaps2 = overlaps(v, sNew, true);
+ overlaps1.splice(overlaps1.begin(), overlaps2);
+
+ for (Vertex<D>& vn : overlaps1) {
+ if (!vn.marked) {
+ q.push(vn);
+ }
+ }
+
+ if (!dry) {
+ v.state = sNew;
+ vNew.state = s;
+ }
+
+ n += 1;
+ }
+ }
+
+ return n;
+ }
+
+ void swendsenWang(const Transformation<D>& R, Rng& r) {
+ for (Vertex<D>& v : vertices) {
+ if (!v.marked) {
+ bool dry = 0.5 < r.uniform(0.0, 1.0);
+ unsigned n = flipCluster(R, v, r, dry);
+ if (n > pow(L, D) / 4 && !dry) {
+ orientation = R.apply(orientation);
+ }
+ }
+ }
+
+ for (Vertex<D>& v : vertices) {
+ v.marked = false;
+ }
+ }
+
+ int overlap(const System<D>& s) const {
+ int o = 0;
+
+ for (unsigned i = 0; i < vertices.size(); i++) {
+ State<D> s2 = orientation.apply(s.vertices[vectorToIndex(orientation.inverse().apply(indexToVector(i)))].state);
+ o += vertices[i].state.dot(s2);
+ }
+
+ return o;
+ }
+};
+
+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) {
@@ -42,7 +509,7 @@ int main() {
double Tmax = 0.2;
double δT = 0.02;
- CiamarraSystem<D> s(L);
+ System<D> s(L);
Rng r;
@@ -58,11 +525,8 @@ int main() {
}
std::cerr << "Found state with appropriate density." << std::endl;
- if (!s.compatible()) {
- std::cerr <<"whoops!" << std::endl;
- }
- CiamarraSystem<D> s0 = s;
+ System<D> s0 = s;
std::vector<Matrix<D>> ms = generateTorusMatrices<D>();
@@ -72,9 +536,16 @@ int main() {
n++;
std::cout << i << " " << s.overlap(s0) << std::endl;
}
+ Matrix<D> m = r.pick(ms);
+ Vertex<D>& v = r.pick(s.vertices);
+ unsigned nC = s.flipCluster(Transformation<D>(L, m, v.position - m * v.position), v, r);
+ std::cerr << nC << std::endl;
+ for (Vertex<D>& v : s.vertices) {
+ v.marked = false;
+ }
// s.sweepLocal(r);
// s.sweepSwap(r);
- s.swendsenWang(Transformation<D>(L, ms, r), r);
+// s.swendsenWang(Transformation<D>(L, ms, r), r);
}
return 0;
diff --git a/glass.hpp b/glass.hpp
deleted file mode 100644
index b35964b..0000000
--- a/glass.hpp
+++ /dev/null
@@ -1,677 +0,0 @@
-#include <limits>
-#include <list>
-#include <queue>
-#include <vector>
-
-#include <eigen3/Eigen/Dense>
-
-#include "pcg-cpp/include/pcg_random.hpp"
-#include "randutils/randutils.hpp"
-
-using Rng = randutils::random_generator<pcg32>;
-
-template <int D> using Vector = Eigen::Matrix<int, D, 1>;
-template <int D> using Matrix = Eigen::Matrix<int, D, D>;
-
-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 <int D, typename Derived> Vector<D> mod(const Eigen::MatrixBase<Derived>& v, unsigned b) {
- Vector<D> u;
- for (unsigned i = 0; i < D; i++) {
- u(i) = mod(v(i), b);
- }
- return u;
-}
-
-template <int D> void one_sequences(std::list<std::array<double, D>>& sequences, unsigned level) {
- if (level > 0) {
- unsigned new_level = level - 1;
- for (std::array<double, D>& sequence : sequences) {
- std::array<double, D> new_sequence = sequence;
- new_sequence[new_level] = -1;
- sequences.push_front(new_sequence);
- }
- one_sequences<D>(sequences, new_level);
- }
-}
-
-template <int D> std::vector<Matrix<D>> generateTorusMatrices() {
- std::vector<Matrix<D>> mats;
-
- std::array<double, D> ini_sequence;
- ini_sequence.fill(1);
- std::list<std::array<double, D>> sequences;
- sequences.push_back(ini_sequence);
-
- one_sequences<D>(sequences, D);
-
- sequences.pop_back(); // don't want the identity matrix!
-
- for (std::array<double, D> sequence : sequences) {
- Matrix<D> 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<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)) {
- 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 <int D> class CiamarraState : public Vector<D> {
-public:
- CiamarraState() : Vector<D>(Vector<D>::Zero()) {}
-
- CiamarraState(const Vector<D>& v) : Vector<D>(v) {}
-
- CiamarraState(unsigned a, signed b) : Vector<D>(Vector<D>::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<D> flip() const {
- CiamarraState<D> 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<unsigned>::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<unsigned>::max(); }
-
- void remove() { type = std::numeric_limits<unsigned>::max(); };
-};
-
-template <int D> class Transformation {
-public:
- unsigned L;
- Matrix<D> m;
- Vector<D> v;
-
- Transformation(unsigned L) : L(L) {
- m.setIdentity();
- v.setZero();
- }
-
- Transformation(unsigned L, const Matrix<D>& m, const Vector<D>& v) : L(L), m(m), v(v) {}
-
- Transformation(unsigned L, const std::vector<Matrix<D>>& 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<D> inverse() const {
- return Transformation<D>(L, m.transpose(), -m.transpose() * v);
- }
-
- Vector<D> apply(const Vector<D>& x) const { return mod<D>(v + m * x, L); }
-
- Transformation<D> apply(const Transformation<D>& t) const {
- Transformation<D> tNew(L);
-
- tNew.m = m * t.m;
- tNew.v = apply(t.v);
-
- return tNew;
- }
-
- CiamarraState<D> apply(const CiamarraState<D>& s) const { return CiamarraState<D>(m * s); }
-
- BiroliState apply(const BiroliState& s) const { return s; }
-};
-
-template <int D, typename State> class HalfEdge;
-
-template <int D, typename State> class Vertex {
-public:
- Vector<D> position;
- std::vector<HalfEdge<D, State>> adjacentEdges;
- State state;
- bool marked;
-
- bool isEmpty() const { return state.isEmpty(); }
-};
-
-template <int D, class State> class HalfEdge {
-public:
- Vertex<D, State>& neighbor;
- Vector<D> Δx;
-
- HalfEdge(Vertex<D, State>& n, const Vector<D>& d) : neighbor(n), Δx(d) {}
-};
-
-template <int D, class State> class System {
-public:
- const unsigned L;
- unsigned N;
- std::vector<Vertex<D, State>> vertices;
- Transformation<D> orientation;
-
- unsigned vectorToIndex(const Vector<D>& x) const {
- unsigned i = 0;
- for (unsigned d = 0; d < D; d++) {
- i += x[d] * iPow(L, d);
- }
- return i;
- }
-
- Vector<D> indexToVector(unsigned i) const {
- Vector<D> 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<D> Δx = Vector<D>::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<D, State>(vertices[j], Δx));
- vertices[j].adjacentEdges.push_back(HalfEdge<D, State>(vertices[i], -Δx));
- }
- }
- }
-
- virtual std::list<std::reference_wrapper<Vertex<D, State>>> overlaps(Vertex<D, State>&) { return {}; };
-
- virtual bool insert(Vertex<D, State>& v, const State& s, bool force = false) { return false; };
-
- virtual bool remove(Vertex<D, State>& v) { return false;};
-
- virtual bool randomMove(Rng& r) { return false;};
-
- virtual void swap(Vertex<D, State>& v1, Vertex<D, State>& v2) {};
-
- virtual bool exchange(Vertex<D, State>& v1, Vertex<D, State>& v2) { return false;};
-
- bool randomExchange(Rng& r) {
- Vertex<D, State>& v1 = r.pick(vertices);
- Vertex<D, State>& v2 = r.pick(vertices);
-
- return exchange(v1, v2);
- }
-
- bool compatible() {
- for (Vertex<D, State>& 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<D, State>& 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<D>& R, Vertex<D, State>& v0, bool dry = false) {
- unsigned n = 0;
-
- Vertex<D, State>& v0New = vertices[vectorToIndex(R.apply(v0.position))];
-
- if (&v0New != &v0) {
- std::queue<std::reference_wrapper<Vertex<D, State>>> q;
-
- v0.marked = true;
- v0New.marked = true;
-
- swap(v0, v0New);
-
- for (Vertex<D, State>& vn : overlaps(v0)) {
- if (!vn.marked) {
- q.push(vn);
- }
- }
- for (Vertex<D, State>& vn : overlaps(v0New)) {
- if (!vn.marked) {
- q.push(vn);
- }
- }
-
- while (!q.empty()) {
- Vertex<D, State>& v = q.front();
- q.pop();
-
- if (!v.marked && !overlaps(v).empty()) {
- v.marked = true;
- Vertex<D, State>& vNew = vertices[vectorToIndex(R.apply(v.position))];
-
- if (&vNew != &v) {
- vNew.marked = true;
-
- swap(v, vNew);
-
- for (Vertex<D, State>& vn : overlaps(v)) {
- if (!vn.marked) {
- q.push(vn);
- }
- }
- for (Vertex<D, State>& vn : overlaps(vNew)) {
- if (!vn.marked) {
- q.push(vn);
- }
- }
-
- n += 2;
- } else {
- n += 1;
- }
- }
- if (q.empty()) {
- for (Vertex<D, State>& 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<D, State>& v : vertices) {
- v.marked = false;
- }
-
- return n;
- }
-
- void swendsenWang(const Transformation<D>& R, Rng& r) {
- for (Vertex<D, State>& 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<D, State>& v : vertices) {
- v.marked = false;
- }
- }
-
- virtual int overlap(const System<D, State>& s) const { return 0; };
-};
-
-template <int D> class CiamarraSystem : public System<D, CiamarraState<D>> {
- public:
-
- using System<D, CiamarraState<D>>::System;
- std::list<std::reference_wrapper<Vertex<D, CiamarraState<D>>>>
- overlaps(Vertex<D, CiamarraState<D>>& v, const CiamarraState<D>& s,
- bool excludeSelf = false) override {
- std::list<std::reference_wrapper<Vertex<D, CiamarraState<D>>>> o;
-
- if (s.isEmpty()) {
- return o;
- }
-
- if (!v.isEmpty() && !excludeSelf) {
- o.push_back(v);
- }
-
- for (const HalfEdge<D, CiamarraState<D>>& 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<D, CiamarraState<D>>& v, const CiamarraState<D>& s, bool force = false) override {
- if (force || overlaps(v, s).empty()) {
- v.state = s;
- this->N++;
- return true;
- } else {
- return false;
- }
- }
-
- bool remove(Vertex<D, CiamarraState<D>>& v) override {
- if (v.isEmpty()) {
- return false;
- } else {
- v.state.remove();
- this->N--;
- return true;
- }
- }
-
- bool randomMove(Rng& r) override {
- Vertex<D, CiamarraState<D>>& v = r.pick(this->vertices);
- CiamarraState<D> oldState = v.state;
-
- if (!remove(v)) {
- return false;
- }
-
- if (1.0 / (2.0 * D) > r.uniform(0.0, 1.0)) {
- for (HalfEdge<D, CiamarraState<D>>& e : v.adjacentEdges) {
- if (1 == e.Δx.dot(oldState)) {
- if (insert(e.neighbor, oldState.flip())) {
- return true;
- }
- break;
- }
- }
- } else {
- CiamarraState<D> newState(r);
- while (newState.dot(oldState) == 1) {
- newState = CiamarraState<D>(r);
- }
- if (insert(v, newState)) {
- return true;
- }
- }
- v.state = oldState;
- this->N++;
- return false;
- }
-
- void swap(Vertex<D, CiamarraState<D>>& v1, Vertex<D, CiamarraState<D>>& v2) override {
- std::swap(v1.state, v2.state);
- }
-
- bool exchange(Vertex<D, CiamarraState<D>>& v1, Vertex<D, CiamarraState<D>>& 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<D, CiamarraState<D>>& 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<D>::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<D, CiamarraState<D>>& s) const override {
- int o = 0;
-
- for (unsigned i = 0; i < this->vertices.size(); i++) {
- CiamarraState<D> 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 <int D> class BiroliSystem : public System<D, BiroliState> {
-public:
- using System<D, BiroliState>::System;
-
- bool canReplaceWith(const Vertex<D, BiroliState>& 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<D, BiroliState>& e : v.adjacentEdges) {
- if (e.neighbor.state.type < e.neighbor.state.occupiedNeighbors + Δn) {
- return false;
- }
- }
- }
- return true;
- }
-
- std::list<std::reference_wrapper<Vertex<D, BiroliState>>>
- overlaps(Vertex<D, BiroliState>& v) override {
- std::list<std::reference_wrapper<Vertex<D, BiroliState>>> 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<D, BiroliState>& 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<D, BiroliState>& v, const BiroliState& s, bool force = false) override {
- if (force || (v.isEmpty() && canReplaceWith(v, s))) {
- v.state.type = s.type;
- for (HalfEdge<D, BiroliState>& e : v.adjacentEdges) {
- e.neighbor.state.occupiedNeighbors++;
- }
- this->N++;
- return true;
- } else {
- return false;
- }
- }
-
- bool remove(Vertex<D, BiroliState>& v) override {
- if (v.isEmpty()) {
- return false;
- } else {
- v.state.remove();
- for (HalfEdge<D, BiroliState>& e : v.adjacentEdges) {
- e.neighbor.state.occupiedNeighbors--;
- }
- this->N--;
- return true;
- }
- }
-
- bool randomMove(Rng& r) override {
- Vertex<D, BiroliState>& v = r.pick(this->vertices);
-
- return exchange(v, r.pick(v.adjacentEdges).neighbor);
- }
-
- void swap(Vertex<D, BiroliState>& v1, Vertex<D, BiroliState>& 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<D, BiroliState>& v1, Vertex<D, BiroliState>& v2) override {
- if (canReplaceWith(v1, v2.state) && canReplaceWith(v2, v1.state)) {
- swap(v1, v2);
- return true;
- } else {
- return false;
- }
- }
-
- int overlap(const System<D, BiroliState>& 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;
- }
-};