#include #include #include #include "pcg-cpp/include/pcg_random.hpp" #include "randutils/randutils.hpp" template using Vector = Eigen::Matrix; template using Matrix = Eigen::Matrix; using Rng = randutils::random_generator; 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 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; } 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; } Transformation inverse() const { return Transformation(L, m.transpose(), -m.transpose() * v); } }; template concept State = requires(T v) { { v.empty() } -> std::same_as; {v.remove()}; }; template class HalfEdge; template class Vertex { public: Vector position; Vector initialPosition; S state; std::vector> adjacentEdges; bool marked; bool empty() const { return state.empty(); } }; template class HalfEdge { public: Vertex& neighbor; Vector Δx; HalfEdge(Vertex& n, const Vector& d) : neighbor(n), Δx(d) {} };