From 02bff5563d5a0150bde4ae3de9222a1837aefa98 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Mon, 10 Oct 2022 20:49:04 +0200 Subject: Merged Graph and AztecDiamond classes. --- rbmp.hpp | 162 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 93 insertions(+), 69 deletions(-) (limited to 'rbmp.hpp') diff --git a/rbmp.hpp b/rbmp.hpp index 02ca5ad..15b7e97 100644 --- a/rbmp.hpp +++ b/rbmp.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "randutils/randutils.hpp" #include "pcg-cpp/include/pcg_random.hpp" @@ -10,97 +11,120 @@ #include "blossom5-v2.05.src/PerfectMatching.h" using Rng = randutils::random_generator; +using Real = long double; - -class Graph { +class AztecDiamond { public: -class Edge; -class HalfEdge; - -class Coordinate { - std::array r; - public: - void operator=(const std::array& rp) { - r = rp; - } - void operator+=(const Coordinate& x) { - r[0] += x.r[0]; - r[1] += x.r[1]; - } - void operator-=(const Coordinate& x) { - r[0] -= x.r[0]; - r[1] -= x.r[1]; - } - int operator[](unsigned i) const { - return r[i]; - } -}; + using Coordinate = std::array; -class Vertex { -public: - unsigned index; - std::vector> neighbors; - Coordinate coordinate; + typedef struct Vertex { + unsigned index; + Coordinate coordinate; + } Vertex; - void addEdge(HalfEdge& e) { - neighbors.push_back(e); - } -}; + typedef struct Edge { + Vertex* tail; + Vertex* head; + double weight; + std::stack weights; + Real probability = 0; + } Edge; -class HalfEdge { private: - Vertex* tail; - Vertex* head; + std::tuple face(unsigned i, unsigned j) { + unsigned x0 = n - i; + unsigned x = x0 + 2 * (j % i); + unsigned y = x0 + 2 * (j / i); -public: - const Edge& edge; + Edge& e1 = edges[2 * n * y + x]; + Edge& e2 = edges[2 * n * y + x + 1]; + Edge& e3 = edges[2 * n * (y + 1) + x]; + Edge& e4 = edges[2 * n * (y + 1) + x + 1]; - HalfEdge(const Edge& e) : edge(e) {} - void setVertices(Vertex& vt, Vertex& vh) { - tail = &vt; - head = &vh; + return {e1, e2, e3, e4}; } - const Vertex& getHead() const { - return *head; - } - const Vertex& getTail() const { - return *tail; - } -}; -class Edge { public: - std::array halfedges; - double weight; - - Edge() : halfedges{*this, *this} {}; - void setVertices(Vertex& red, Vertex& blue) { - halfedges[0].setVertices(red, blue); - halfedges[1].setVertices(blue, red); - red.addEdge(halfedges[0]); - blue.addEdge(halfedges[1]); - } -}; + unsigned n; std::vector vertices; std::vector edges; - Graph(int n, Rng& r) : vertices(2 * n * (n + 1)), edges(pow(2 * n, 2)) { + AztecDiamond(int n, Rng& r) : n(n), vertices(2 * n * (n + 1)), edges(pow(2 * n, 2)) { unsigned M = vertices.size() / 2; for (int i = 0; i < M; i++) { vertices[i].index = i; - vertices[i].coordinate = {2 * (i % (n + 1)), 2 * (i / (n + 1)) + 1}; vertices[M + i].index = M + i; + vertices[i].coordinate = {2 * (i % (n + 1)), 2 * (i / (n + 1)) + 1}; vertices[M + i].coordinate = {2 * (i % n) + 1, 2 * (i / n)}; } for (unsigned i = 0; i < edges.size(); i++) { - Vertex& redVertex = vertices[(1 + (i % (2 * n))) / 2 + (n + 1) * ((i / 4) / n)]; - Vertex& blueVertex = vertices[M + (i % (2 * n)) / 2 + n * (((i + 2 * n) / 4) / n)]; - edges[i].setVertices(redVertex, blueVertex); + edges[i].tail = &vertices[(1 + (i % (2 * n))) / 2 + (n + 1) * ((i / 4) / n)]; + edges[i].head = &vertices[M + (i % (2 * n)) / 2 + n * (((i + 2 * n) / 4) / n)]; edges[i].weight = r.variate(1); } } -}; -bool edgeMatched(PerfectMatching& pm, const Graph::Edge& e) { - return e.halfedges[0].getTail().index == pm.GetMatch(e.halfedges[0].getHead().index); -} + void computeWeights() { + for (unsigned i = n; i > 0; i--) { +#pragma omp parallel for + for (unsigned j = 0; j < pow(i, 2); j++) { + auto [e1, e2, e3, e4] = face(i, j); + + Real w = e1.weights.top(); + Real x = e2.weights.top(); + Real y = e3.weights.top(); + Real z = e4.weights.top(); + + Real cellFactor = w * z + x * y; + + e1.weights.push(z / cellFactor); + e2.weights.push(y / cellFactor); + e3.weights.push(x / cellFactor); + e4.weights.push(w / cellFactor); + } + } + + // This process computes one extra weight per edge. + for (Edge& e : edges) { + e.weights.pop(); + } + } + + Real computeProbabilities() { // destroys *all* weights + Real partitionFunction = 1; + + for (unsigned i = 1; i <= n; i++) { +#pragma omp parallel for + for (unsigned j = 0; j < pow(i, 2); j++) { + auto [e1, e2, e3, e4] = face(i, j); + + Real p = e1.probability; + Real q = e2.probability; + Real r = e3.probability; + Real s = e4.probability; + + Real w = e1.weights.top(); + Real x = e2.weights.top(); + Real y = e3.weights.top(); + Real z = e4.weights.top(); + + Real cellFactor = w * z + x * y; + Real deficit = 1 - p - q - r - s; + + e1.probability = s + deficit * w * z / cellFactor; + e2.probability = r + deficit * x * y / cellFactor; + e3.probability = q + deficit * x * y / cellFactor; + e4.probability = p + deficit * w * z / cellFactor; + + e1.weights.pop(); + e2.weights.pop(); + e3.weights.pop(); + e4.weights.pop(); + + partitionFunction *= cellFactor; + } + } + + return partitionFunction; + } +}; -- cgit v1.2.3-54-g00ecf