diff options
Diffstat (limited to 'lib/src')
-rw-r--r-- | lib/src/graph.cpp | 143 | ||||
-rw-r--r-- | lib/src/network.cpp | 83 | ||||
-rw-r--r-- | lib/src/problem.cpp | 84 |
3 files changed, 170 insertions, 140 deletions
diff --git a/lib/src/graph.cpp b/lib/src/graph.cpp index a5063de..1475c40 100644 --- a/lib/src/graph.cpp +++ b/lib/src/graph.cpp @@ -34,23 +34,21 @@ graph::graph(unsigned Nx, unsigned Ny) { vertices[i].r.x = (double)((1 + i / (Nx / 2)) % 2 + 2 * (i % (Nx / 2))); vertices[i].r.y = (double)(i / (Nx / 2)); signed f = (1 + i / (Nx / 2)) % 2 == 1 ? 1 : -1; - vertices[i].nd = {i, (i + Nx / 2) % nv, Nx / 2 * (i / (Nx / 2)) + ((i + f) % (Nx / 2)), (nv + i - Nx / 2) % nv}; - vertices[i].polygon = { - {vertices[i].r.x - 1.0, vertices[i].r.y}, - {vertices[i].r.x, vertices[i].r.y - 1.0}, - {vertices[i].r.x + 1.0, vertices[i].r.y}, - {vertices[i].r.x, vertices[i].r.y + 1.0} - }; + vertices[i].nd = {i, (i + Nx / 2) % nv, Nx / 2 * (i / (Nx / 2)) + ((i + f) % (Nx / 2)), + (nv + i - Nx / 2) % nv}; + vertices[i].polygon = {{vertices[i].r.x - 1.0, vertices[i].r.y}, + {vertices[i].r.x, vertices[i].r.y - 1.0}, + {vertices[i].r.x + 1.0, vertices[i].r.y}, + {vertices[i].r.x, vertices[i].r.y + 1.0}}; dual_vertices[i].r.x = (double)((i / (Nx / 2)) % 2 + 2 * (i % (Nx / 2))); dual_vertices[i].r.y = (double)(i / (Nx / 2)); - dual_vertices[i].nd = {i, (i + Nx / 2) % nv, Nx / 2 * (i / (Nx / 2)) + ((i + f) % (Nx / 2)), (nv + i - Nx / 2) % nv}; - dual_vertices[i].polygon = { - {dual_vertices[i].r.x - 1.0, vertices[i].r.y}, - {dual_vertices[i].r.x, vertices[i].r.y - 1.0}, - {dual_vertices[i].r.x + 1.0, vertices[i].r.y}, - {dual_vertices[i].r.x, vertices[i].r.y + 1.0} - }; + dual_vertices[i].nd = {i, (i + Nx / 2) % nv, Nx / 2 * (i / (Nx / 2)) + ((i + f) % (Nx / 2)), + (nv + i - Nx / 2) % nv}; + dual_vertices[i].polygon = {{dual_vertices[i].r.x - 1.0, vertices[i].r.y}, + {dual_vertices[i].r.x, vertices[i].r.y - 1.0}, + {dual_vertices[i].r.x + 1.0, vertices[i].r.y}, + {dual_vertices[i].r.x, vertices[i].r.y + 1.0}}; } for (unsigned y = 0; y < Ny; y++) { @@ -66,7 +64,8 @@ graph::graph(unsigned Nx, unsigned Ny) { unsigned dv1 = (Nx * y) / 2 + ((x + (y + 1) % 2) / 2) % (Nx / 2); unsigned dv2 = ((Nx * (y + 1)) / 2 + ((x + y % 2) / 2) % (Nx / 2)) % nv; - dual_edges.push_back({{dv1, dv2}, {0.5 + (double)x, 0.5 + (double)y}, {crossed_x, crossed_y}}); + dual_edges.push_back( + {{dv1, dv2}, {0.5 + (double)x, 0.5 + (double)y}, {crossed_x, crossed_y}}); } } @@ -102,29 +101,23 @@ graph::graph(unsigned Nx, unsigned Ny) { dual_vertices[vi].ne.push_back(i); } } - } -class eulerException: public std::exception -{ - virtual const char* what() const throw() - { - return "The voronoi tessellation generated has the incorrect Euler characteristic for a torus and is malformed."; +class eulerException : public std::exception { + virtual const char* what() const throw() { + return "The voronoi tessellation generated has the incorrect Euler characteristic for a torus " + "and is malformed."; } } eulerex; -class clippingException: public std::exception -{ - virtual const char* what() const throw() - { +class clippingException : public std::exception { + virtual const char* what() const throw() { return "An interior site has a clipped edge and the tesselation is malformed."; } } clippingex; -class triangleException: public std::exception -{ - virtual const char* what() const throw() - { +class triangleException : public std::exception { + virtual const char* what() const throw() { return "A dual-centered triangle has an impossible geometry and the tesselation is malformed."; } } triex; @@ -147,29 +140,45 @@ unsigned get_triangle_signature(unsigned j1, unsigned j2, unsigned j3) { if ((j1 == j2) && (j2 == j3)) { return 0; - } else if (((j1 == j2) && (x2 < x3) && (y2 == y3)) || ((j1 == j3) && (x3 < x2) && (y2 == y3)) || ((j2 == j3) && (x3 < x1) && (y1 == y3))) { + } else if (((j1 == j2) && (x2 < x3) && (y2 == y3)) || ((j1 == j3) && (x3 < x2) && (y2 == y3)) || + ((j2 == j3) && (x3 < x1) && (y1 == y3))) { return 1; - } else if (((j1 == j2) && (x2 > x3) && (y2 == y3)) || ((j1 == j3) && (x3 > x2) && (y2 == y3)) || ((j2 == j3) && (x3 > x1) && (y1 == y3))) { + } else if (((j1 == j2) && (x2 > x3) && (y2 == y3)) || ((j1 == j3) && (x3 > x2) && (y2 == y3)) || + ((j2 == j3) && (x3 > x1) && (y1 == y3))) { return 2; - } else if (((j1 == j2) && (y2 < y3) && (x2 == x3)) || ((j1 == j3) && (y3 < y2) && (x2 == x3)) || ((j2 == j3) && (y3 < y1) && (x1 == x3))) { + } else if (((j1 == j2) && (y2 < y3) && (x2 == x3)) || ((j1 == j3) && (y3 < y2) && (x2 == x3)) || + ((j2 == j3) && (y3 < y1) && (x1 == x3))) { return 3; - } else if (((j1 == j2) && (y2 > y3) && (x2 == x3)) || ((j1 == j3) && (y3 > y2) && (x2 == x3)) || ((j2 == j3) && (y3 > y1) && (x1 == x3))) { + } else if (((j1 == j2) && (y2 > y3) && (x2 == x3)) || ((j1 == j3) && (y3 > y2) && (x2 == x3)) || + ((j2 == j3) && (y3 > y1) && (x1 == x3))) { return 4; - } else if (((j1 == j2) && (x2 < x3) && (y2 < y3)) || ((j1 == j3) && (x3 < x2) && (y3 < y2)) || ((j2 == j3) && (x3 < x1) && (y3 < y1))) { + } else if (((j1 == j2) && (x2 < x3) && (y2 < y3)) || ((j1 == j3) && (x3 < x2) && (y3 < y2)) || + ((j2 == j3) && (x3 < x1) && (y3 < y1))) { return 5; - } else if (((j1 == j2) && (x2 < x3) && (y2 > y3)) || ((j1 == j3) && (x3 < x2) && (y3 > y2)) || ((j2 == j3) && (x3 < x1) && (y3 > y1))) { + } else if (((j1 == j2) && (x2 < x3) && (y2 > y3)) || ((j1 == j3) && (x3 < x2) && (y3 > y2)) || + ((j2 == j3) && (x3 < x1) && (y3 > y1))) { return 6; - } else if (((j1 == j2) && (x2 > x3) && (y2 < y3)) || ((j1 == j3) && (x3 > x2) && (y3 < y2)) || ((j2 == j3) && (x3 > x1) && (y3 < y1))) { + } else if (((j1 == j2) && (x2 > x3) && (y2 < y3)) || ((j1 == j3) && (x3 > x2) && (y3 < y2)) || + ((j2 == j3) && (x3 > x1) && (y3 < y1))) { return 7; - } else if (((j1 == j2) && (x2 > x3) && (y2 > y3)) || ((j1 == j3) && (x3 > x2) && (y3 > y2)) || ((j2 == j3) && (x3 > x1) && (y3 > y1))) { + } else if (((j1 == j2) && (x2 > x3) && (y2 > y3)) || ((j1 == j3) && (x3 > x2) && (y3 > y2)) || + ((j2 == j3) && (x3 > x1) && (y3 > y1))) { return 8; - } else if (((x1 == x2) && (x2 < x3) && ((y1 < y3) || (y2 < y3))) || ((x1 == x3) && (x3 < x2) && ((y1 < y2) || (y3 < y2))) || ((x2 == x3) && (x2 < x1) && ((y2 < y1) || (y3 < y1)))) { + } else if (((x1 == x2) && (x2 < x3) && ((y1 < y3) || (y2 < y3))) || + ((x1 == x3) && (x3 < x2) && ((y1 < y2) || (y3 < y2))) || + ((x2 == x3) && (x2 < x1) && ((y2 < y1) || (y3 < y1)))) { return 9; - } else if (((x1 == x2) && (x2 > x3) && ((y1 < y3) || (y2 < y3))) || ((x1 == x3) && (x3 > x2) && ((y1 < y2) || (y3 < y2))) || ((x2 == x3) && (x2 > x1) && ((y2 < y1) || (y3 < y1)))) { + } else if (((x1 == x2) && (x2 > x3) && ((y1 < y3) || (y2 < y3))) || + ((x1 == x3) && (x3 > x2) && ((y1 < y2) || (y3 < y2))) || + ((x2 == x3) && (x2 > x1) && ((y2 < y1) || (y3 < y1)))) { return 10; - } else if (((x1 == x2) && (x2 < x3) && ((y1 > y3) || (y2 > y3))) || ((x1 == x3) && (x3 < x2) && ((y1 > y2) || (y3 > y2))) || ((x2 == x3) && (x2 < x1) && ((y2 > y1) || (y3 > y1)))) { + } else if (((x1 == x2) && (x2 < x3) && ((y1 > y3) || (y2 > y3))) || + ((x1 == x3) && (x3 < x2) && ((y1 > y2) || (y3 > y2))) || + ((x2 == x3) && (x2 < x1) && ((y2 > y1) || (y3 > y1)))) { return 11; - } else if (((x1 == x2) && (x2 > x3) && ((y1 > y3) || (y2 > y3))) || ((x1 == x3) && (x3 > x2) && ((y1 > y2) || (y3 > y2))) || ((x2 == x3) && (x2 > x1) && ((y2 > y1) || (y3 > y1)))) { + } else if (((x1 == x2) && (x2 > x3) && ((y1 > y3) || (y2 > y3))) || + ((x1 == x3) && (x3 > x2) && ((y1 > y2) || (y3 > y2))) || + ((x2 == x3) && (x2 > x1) && ((y2 > y1) || (y3 > y1)))) { return 12; } else { throw triex; @@ -200,7 +209,7 @@ void graph::helper(unsigned nv, std::mt19937& rng) { // the coordinates of the lattice, from which a delaunay triangulation // and corresponding voronoi tessellation will be built. Everyone is in the // rectangle (0, 0) (Lx, Ly) - for (vertex &v : vertices) { + for (vertex& v : vertices) { v = {{L.x * d(rng), L.y * d(rng)}}; } @@ -243,7 +252,7 @@ void graph::helper(unsigned nv, std::mt19937& rng) { ep = ep->next; } // for each edge on the site's cell - while(e) { + while (e) { // assess whether the edge needs to be added. only neighboring // sites whose index is larger than ours are given edges, so we // don't double up later @@ -275,7 +284,8 @@ void graph::helper(unsigned nv, std::mt19937& rng) { if (it1 == known_vertices.end()) { vi1 = dual_vertices.size(); - dual_vertices.push_back({{mod(e->pos[0].x, L.x), mod(e->pos[0].y, L.y)},{i1},{},{{site->p.x, site->p.y}}}); + dual_vertices.push_back( + {{mod(e->pos[0].x, L.x), mod(e->pos[0].y, L.y)}, {i1}, {}, {{site->p.x, site->p.y}}}); known_vertices[t1] = vi1; } else { vi1 = it1->second; @@ -284,7 +294,7 @@ void graph::helper(unsigned nv, std::mt19937& rng) { } vertices[i1].nd.push_back(vi1); - + if (i1 < i2 || (i1 == i2 && !self_bonded)) { if (i1 == i2) { self_bonded = true; @@ -292,12 +302,11 @@ void graph::helper(unsigned nv, std::mt19937& rng) { bool crossed_x = x2 != 1; bool crossed_y = y2 != 1; edges.push_back({{i1, i2}, - {mod((site->p.x + neighbor->p.x) / 2, L.x), - mod((site->p.y + neighbor->p.y) / 2, L.y)}, - {crossed_x, crossed_y} - }); + {mod((site->p.x + neighbor->p.x) / 2, L.x), + mod((site->p.y + neighbor->p.y) / 2, L.y)}, + {crossed_x, crossed_y}}); - jcv_graphedge *en; + jcv_graphedge* en; if (e->next == NULL) { en = site->edges; } else { @@ -322,20 +331,21 @@ void graph::helper(unsigned nv, std::mt19937& rng) { if (it2 == known_vertices.end()) { vi2 = dual_vertices.size(); - dual_vertices.push_back({{mod(e->pos[1].x, L.x), mod(e->pos[1].y, L.y)},{}}); + dual_vertices.push_back({{mod(e->pos[1].x, L.x), mod(e->pos[1].y, L.y)}, {}}); known_vertices[t2] = vi2; } else { vi2 = it2->second; } - bool dcrossed_x = (unsigned)floor(e->pos[0].x / L.x) != (unsigned)floor(e->pos[1].x / L.x); - bool dcrossed_y = (unsigned)floor(e->pos[0].y / L.y) != (unsigned)floor(e->pos[1].y / L.y); + bool dcrossed_x = + (unsigned)floor(e->pos[0].x / L.x) != (unsigned)floor(e->pos[1].x / L.x); + bool dcrossed_y = + (unsigned)floor(e->pos[0].y / L.y) != (unsigned)floor(e->pos[1].y / L.y); dual_edges.push_back({{vi1, vi2}, - {mod((e->pos[0].x + e->pos[1].x) / 2, L.x), - mod((e->pos[0].y + e->pos[1].y) / 2, L.y)}, - {dcrossed_x, dcrossed_y} - }); + {mod((e->pos[0].x + e->pos[1].x) / 2, L.x), + mod((e->pos[0].y + e->pos[1].y) / 2, L.y)}, + {dcrossed_x, dcrossed_y}}); } ep = e; @@ -348,7 +358,7 @@ void graph::helper(unsigned nv, std::mt19937& rng) { throw eulerex; } - for (vertex &v : dual_vertices) { + for (vertex& v : dual_vertices) { if (fabs(v.polygon[0].x - v.polygon[1].x) > L.x / 2) { if (v.polygon[0].x < L.x / 2) { v.polygon[0].x += L.x; @@ -434,33 +444,31 @@ void graph::helper(unsigned nv, std::mt19937& rng) { jcv_diagram_free(&diagram); } -graph::coordinate reverse(const graph::coordinate &x) { - return {x.y, x.x}; -} +graph::coordinate reverse(const graph::coordinate& x) { return {x.y, x.x}; } graph const graph::rotate() { graph g2(*this); - for (graph::vertex &v : g2.vertices) { + for (graph::vertex& v : g2.vertices) { v.r = reverse(v.r); - for (graph::coordinate &r : v.polygon) { + for (graph::coordinate& r : v.polygon) { r = reverse(r); } } - for (graph::edge &e : g2.edges) { + for (graph::edge& e : g2.edges) { e.r = reverse(e.r); e.crossings = {e.crossings[1], e.crossings[0]}; } - for (graph::vertex &v : g2.dual_vertices) { + for (graph::vertex& v : g2.dual_vertices) { v.r = reverse(v.r); - for (graph::coordinate &r : v.polygon) { + for (graph::coordinate& r : v.polygon) { r = reverse(r); } } - for (graph::edge &e : g2.dual_edges) { + for (graph::edge& e : g2.dual_edges) { e.r = reverse(e.r); e.crossings = {e.crossings[1], e.crossings[0]}; } @@ -469,4 +477,3 @@ graph const graph::rotate() { return g2; } - diff --git a/lib/src/network.cpp b/lib/src/network.cpp index 0cf50c7..eef7e9a 100644 --- a/lib/src/network.cpp +++ b/lib/src/network.cpp @@ -11,7 +11,8 @@ network::network(const graph& G, cholmod_common* c) void network::set_thresholds(double beta, std::mt19937& rng) { if (beta == 0.0) { - /* zero beta doesn't make any sense computationally, we interpret it as "infinity" */ + /* zero beta doesn't make any sense computationally, we interpret it as + * "infinity" */ for (long double& threshold : thresholds) { threshold = 1.0; } @@ -104,7 +105,8 @@ std::set<unsigned> network::get_cycle_edges(unsigned v0) const { return cycle_edges; } -bool network::find_cycle_helper(std::array<unsigned, 2>& sig, const std::set<unsigned>& cycle_edges, unsigned vPrev, unsigned vCur, unsigned vEnd) const { +bool network::find_cycle_helper(std::array<unsigned, 2>& sig, const std::set<unsigned>& cycle_edges, + unsigned vPrev, unsigned vCur, unsigned vEnd) const { for (unsigned ei : G.dual_vertices[vCur].ne) { if (fuses[ei]) { auto it = cycle_edges.find(ei); @@ -113,13 +115,17 @@ bool network::find_cycle_helper(std::array<unsigned, 2>& sig, const std::set<uns unsigned vn = e[0] == vCur ? e[1] : e[0]; if (vn != vPrev) { if (vn == vEnd) { - if (G.dual_edges[ei].crossings[0]) sig[0]++; - if (G.dual_edges[ei].crossings[1]) sig[1]++; + if (G.dual_edges[ei].crossings[0]) + sig[0]++; + if (G.dual_edges[ei].crossings[1]) + sig[1]++; return true; } else { if (this->find_cycle_helper(sig, cycle_edges, vCur, vn, vEnd)) { - if (G.dual_edges[ei].crossings[0]) sig[0]++; - if (G.dual_edges[ei].crossings[1]) sig[1]++; + if (G.dual_edges[ei].crossings[0]) + sig[0]++; + if (G.dual_edges[ei].crossings[1]) + sig[1]++; return true; } } @@ -131,7 +137,8 @@ bool network::find_cycle_helper(std::array<unsigned, 2>& sig, const std::set<uns return false; } -std::array<unsigned, 2> network::find_cycle(const std::set<unsigned>& cycle_edges, unsigned v0, unsigned v1) const { +std::array<unsigned, 2> network::find_cycle(const std::set<unsigned>& cycle_edges, unsigned v0, + unsigned v1) const { std::array<unsigned, 2> sig = {0, 0}; this->find_cycle_helper(sig, cycle_edges, v0, v0, v1); return sig; @@ -158,7 +165,8 @@ std::set<unsigned> network::get_cluster_edges(unsigned v0) const { return cluster_edges; } -void network::get_tie_flaps_helper(std::set<unsigned>& added_edges, unsigned v0, unsigned vCur) const { +void network::get_tie_flaps_helper(std::set<unsigned>& added_edges, unsigned v0, + unsigned vCur) const { for (unsigned ei : G.vertices[vCur].ne) { if (!backbone[ei]) { auto it = added_edges.find(ei); @@ -219,7 +227,8 @@ void network::update_backbone(const std::vector<double>& c) { // Now, we create a crossing signature for each cycle. First, we do it // for the new cycle that would form by removing the stem. - std::array<unsigned, 2> base_sig = this->find_cycle(cedges, G.dual_edges[i].v[0], G.dual_edges[i].v[1]); + std::array<unsigned, 2> base_sig = + this->find_cycle(cedges, G.dual_edges[i].v[0], G.dual_edges[i].v[1]); if (G.dual_edges[i].crossings[0]) base_sig[0]++; if (G.dual_edges[i].crossings[1]) @@ -229,9 +238,12 @@ void network::update_backbone(const std::vector<double>& c) { // previous step. std::list<std::array<unsigned, 2>> all_sigs = {base_sig}; for (unsigned e : cedges) { - std::array<unsigned, 2> new_sig_1 = this->find_cycle(cedges, G.dual_edges[i].v[0], G.dual_edges[e].v[0]); - std::array<unsigned, 2> new_sig_2 = this->find_cycle(cedges, G.dual_edges[i].v[1], G.dual_edges[e].v[1]); - std::array<unsigned, 2> new_sig = {new_sig_1[0] + new_sig_2[0], new_sig_1[1] + new_sig_2[1]}; + std::array<unsigned, 2> new_sig_1 = + this->find_cycle(cedges, G.dual_edges[i].v[0], G.dual_edges[e].v[0]); + std::array<unsigned, 2> new_sig_2 = + this->find_cycle(cedges, G.dual_edges[i].v[1], G.dual_edges[e].v[1]); + std::array<unsigned, 2> new_sig = {new_sig_1[0] + new_sig_2[0], + new_sig_1[1] + new_sig_2[1]}; if (G.dual_edges[i].crossings[0]) new_sig[0]++; @@ -248,10 +260,10 @@ void network::update_backbone(const std::vector<double>& c) { // Now, having found all cycles involving the candidate stem, we check // if any of them spans the torus and therefore can carry current. if (std::any_of(all_sigs.begin(), all_sigs.end(), - [done_x, done_y](std::array<unsigned, 2> c) { - return (c[0] % 2 == 0 && c[1] % 2 == 0) || - ((c[0] % 2 == 0 && done_x) || (c[1] % 2 == 0 && done_y)); - })) { + [done_x, done_y](std::array<unsigned, 2> c) { + return (c[0] % 2 == 0 && c[1] % 2 == 0) || + ((c[0] % 2 == 0 && done_x) || (c[1] % 2 == 0 && done_y)); + })) { // If it does, we remove it from the backbone! seen_pairs[{G.dual_edges[i].v[0], G.dual_edges[i].v[1]}] = true; backbone[i] = true; @@ -297,6 +309,7 @@ void network::update_backbone(const std::vector<double>& c) { // Now, we will check for bow ties! std::set<unsigned> bb_verts; + // First we get a list of all vertices that remain in the backbone. for (unsigned i = 0; i < G.edges.size(); i++) { if (!backbone[i]) { bb_verts.insert(G.edges[i].v[0]); @@ -307,6 +320,10 @@ void network::update_backbone(const std::vector<double>& c) { for (unsigned v : bb_verts) { bool found_pair = false; unsigned d1, d2, p1, p2; + // For each vertex, we check to see if two of the faces adjacent to the + // vertex are in the same component of the dual lattice and if so, we make + // sure they do not belong to a contiguously connected series of such + // faces. for (unsigned i = 0; i < G.vertices[v].nd.size(); i++) { for (unsigned j = 2; j < G.vertices[v].nd.size() - 1; j++) { unsigned l = (i + j) % G.vertices[v].nd.size(); @@ -316,12 +333,11 @@ void network::update_backbone(const std::vector<double>& c) { auto it_search = seen_pairs.find({G.vertices[v].nd[il], G.vertices[v].nd[ig]}); if (it_search == seen_pairs.end()) { bool any_intervening1 = false; - bool any_intervening_e_1 = false; bool any_intervening2 = false; - bool any_intervening_e_2 = false; unsigned ie1 = 0; unsigned ie2 = 0; + // yuck, think of something more elegant? for (unsigned k = il + 1; k < ig; k++) { if (!C.same_component(G.vertices[v].nd[i], G.vertices[v].nd[k])) { any_intervening1 = true; @@ -330,7 +346,7 @@ void network::update_backbone(const std::vector<double>& c) { } for (unsigned k = (ig + 1); k % G.vertices[v].nd.size() != il; k++) { if (!C.same_component(G.vertices[v].nd[i], - G.vertices[v].nd[k % G.vertices[v].nd.size()])) { + G.vertices[v].nd[k % G.vertices[v].nd.size()])) { any_intervening2 = true; break; } @@ -349,6 +365,9 @@ void network::update_backbone(const std::vector<double>& c) { } } } + + // If all these conditions are true, we process the pair. The same + // cycle analysis as in the lollipop case is done. if ((any_intervening1 && any_intervening2) || (any_intervening1 && ie2 > 1) || (any_intervening2 && ie1 > 1)) { found_pair = true; @@ -367,13 +386,14 @@ void network::update_backbone(const std::vector<double>& c) { base_sig[1]++; } - // Then, we do it for each of the existing cycles we found in the - // previous step. std::list<std::array<unsigned, 2>> all_sigs = {base_sig}; for (unsigned e : cedges) { - std::array<unsigned, 2> new_sig_1 = this->find_cycle(cedges, d1, G.dual_edges[e].v[0]); - std::array<unsigned, 2> new_sig_2 = this->find_cycle(cedges, d2, G.dual_edges[e].v[1]); - std::array<unsigned, 2> new_sig = {new_sig_1[0] + new_sig_2[0], new_sig_1[1] + new_sig_2[1]}; + std::array<unsigned, 2> new_sig_1 = + this->find_cycle(cedges, d1, G.dual_edges[e].v[0]); + std::array<unsigned, 2> new_sig_2 = + this->find_cycle(cedges, d2, G.dual_edges[e].v[1]); + std::array<unsigned, 2> new_sig = {new_sig_1[0] + new_sig_2[0], + new_sig_1[1] + new_sig_2[1]}; for (unsigned k = p1; k < p2; k++) { if (G.dual_edges[G.vertices[v].ne[k]].crossings[0]) @@ -390,15 +410,20 @@ void network::update_backbone(const std::vector<double>& c) { } if (std::any_of(all_sigs.begin(), all_sigs.end(), - [done_x, done_y](std::array<unsigned, 2> c) { - return ((c[0] % 2 == 0 && c[1] % 2 == 0) || - (c[0] % 2 == 0 && done_x)) || - (c[1] % 2 == 0 && done_y); - })) { + [done_x, done_y](std::array<unsigned, 2> c) { + return ((c[0] % 2 == 0 && c[1] % 2 == 0) || + (c[0] % 2 == 0 && done_x)) || + (c[1] % 2 == 0 && done_y); + })) { + // one of our pairs qualifies for trimming! seen_pairs[{d1, d2}] = true; + // We separate the flaps of the bowtie (there may be more than + // two!) into distinct sets. std::list<std::set<unsigned>> flaps = this->get_tie_flaps(v); + // All the bonds in each flap without current are removed from + // the backbone. for (const std::set<unsigned>& flap : flaps) { std::array<double, 2> total_current = {0.0, 0.0}; for (unsigned e : flap) { diff --git a/lib/src/problem.cpp b/lib/src/problem.cpp index 0645244..ab87b0c 100644 --- a/lib/src/problem.cpp +++ b/lib/src/problem.cpp @@ -1,15 +1,12 @@ #include "problem.hpp" -class nanException: public std::exception -{ - virtual const char* what() const throw() - { - return "The linear problem returned NaN."; - } +class nanException : public std::exception { + virtual const char* what() const throw() { return "The linear problem returned NaN."; } } nanex; -problem::problem(const graph& G, unsigned axis, cholmod_sparse *vcmat, cholmod_common *c) : G(G), axis(axis), voltcurmat(vcmat), c(c) { +problem::problem(const graph& G, unsigned axis, cholmod_sparse* vcmat, cholmod_common* c) + : G(G), axis(axis), voltcurmat(vcmat), c(c) { b = CHOL_F(zeros)(G.vertices.size(), 1, CHOLMOD_REAL, c); for (unsigned i = 0; i < G.edges.size(); i++) { graph::coordinate v0 = G.vertices[G.edges[i].v[0]].r; @@ -23,19 +20,20 @@ problem::problem(const graph& G, unsigned axis, cholmod_sparse *vcmat, cholmod_c ind = v0.x < v1.x ? 0 : 1; } - ((double *)b->x)[G.edges[i].v[ind]] += 1.0; - ((double *)b->x)[G.edges[i].v[!ind]] -= 1.0; + ((double*)b->x)[G.edges[i].v[ind]] += 1.0; + ((double*)b->x)[G.edges[i].v[!ind]] -= 1.0; } } unsigned nnz = G.vertices.size() + G.edges.size(); - cholmod_triplet *t = CHOL_F(allocate_triplet)(G.vertices.size(), G.vertices.size(), nnz, 1, CHOLMOD_REAL, c); + cholmod_triplet* t = + CHOL_F(allocate_triplet)(G.vertices.size(), G.vertices.size(), nnz, 1, CHOLMOD_REAL, c); for (unsigned i = 0; i < G.vertices.size(); i++) { - ((CHOL_INT *)t->i)[i] = i; - ((CHOL_INT *)t->j)[i] = i; - ((double *)t->x)[i] = 0.0; + ((CHOL_INT*)t->i)[i] = i; + ((CHOL_INT*)t->j)[i] = i; + ((double*)t->x)[i] = 0.0; } unsigned terms = G.vertices.size(); @@ -46,8 +44,8 @@ problem::problem(const graph& G, unsigned axis, cholmod_sparse *vcmat, cholmod_c unsigned v0 = G.edges[i].v[0]; unsigned v1 = G.edges[i].v[1]; - ((double *)t->x)[v0]++; - ((double *)t->x)[v1]++; + ((double*)t->x)[v0]++; + ((double*)t->x)[v1]++; unsigned s0 = v0 < v1 ? v0 : v1; unsigned s1 = v0 < v1 ? v1 : v0; @@ -55,22 +53,22 @@ problem::problem(const graph& G, unsigned axis, cholmod_sparse *vcmat, cholmod_c auto it = known_edges.find({s0, s1}); if (it == known_edges.end()) { - ((CHOL_INT *)t->i)[terms] = s1; - ((CHOL_INT *)t->j)[terms] = s0; - ((double *)t->x)[terms] = -1.0; + ((CHOL_INT*)t->i)[terms] = s1; + ((CHOL_INT*)t->j)[terms] = s0; + ((double*)t->x)[terms] = -1.0; known_edges[{s0, s1}] = terms; terms++; } else { - ((double *)t->x)[it->second] -= 1.0; + ((double*)t->x)[it->second] -= 1.0; } } - ((double *)t->x)[0]++; + ((double*)t->x)[0]++; t->nnz = terms; - cholmod_sparse *laplacian = CHOL_F(triplet_to_sparse)(t, terms, c); + cholmod_sparse* laplacian = CHOL_F(triplet_to_sparse)(t, terms, c); CHOL_F(free_triplet)(&t, c); factor = CHOL_F(analyze)(laplacian, c); CHOL_F(factorize)(laplacian, factor, c); @@ -79,19 +77,20 @@ problem::problem(const graph& G, unsigned axis, cholmod_sparse *vcmat, cholmod_c sol.currents.resize(G.edges.size()); } -problem::problem(const graph& G, unsigned axis, cholmod_common *c) : problem(G, axis, NULL, c) { - cholmod_triplet *t = CHOL_F(allocate_triplet)(G.edges.size(), G.vertices.size(), 2 * G.edges.size(), 0, CHOLMOD_REAL, c); +problem::problem(const graph& G, unsigned axis, cholmod_common* c) : problem(G, axis, NULL, c) { + cholmod_triplet* t = CHOL_F(allocate_triplet)(G.edges.size(), G.vertices.size(), + 2 * G.edges.size(), 0, CHOLMOD_REAL, c); t->nnz = 2 * G.edges.size(); for (unsigned i = 0; i < G.edges.size(); i++) { - ((CHOL_INT *)t->i)[2 * i] = i; - ((CHOL_INT *)t->j)[2 * i] = G.edges[i].v[0]; - ((double *)t->x)[2 * i] = 1.0; + ((CHOL_INT*)t->i)[2 * i] = i; + ((CHOL_INT*)t->j)[2 * i] = G.edges[i].v[0]; + ((double*)t->x)[2 * i] = 1.0; - ((CHOL_INT *)t->i)[2 * i + 1] = i; - ((CHOL_INT *)t->j)[2 * i + 1] = G.edges[i].v[1]; - ((double *)t->x)[2 * i + 1] = -1.0; + ((CHOL_INT*)t->i)[2 * i + 1] = i; + ((CHOL_INT*)t->j)[2 * i + 1] = G.edges[i].v[1]; + ((double*)t->x)[2 * i + 1] = -1.0; } voltcurmat = CHOL_F(triplet_to_sparse)(t, 2 * G.edges.size(), c); @@ -103,7 +102,7 @@ problem::problem(const problem& other) : G(other.G), axis(other.axis), c(other.c b = CHOL_F(copy_dense)(other.b, c); factor = CHOL_F(copy_factor)(other.factor, c); voltcurmat = CHOL_F(copy_sparse)(other.voltcurmat, c); -} +} problem::~problem() { CHOL_F(free_dense)(&b, c); @@ -112,13 +111,13 @@ problem::~problem() { } void problem::solve(std::vector<bool>& fuses) { - cholmod_dense *x = CHOL_F(solve)(CHOLMOD_A, factor, b, c); + cholmod_dense* x = CHOL_F(solve)(CHOLMOD_A, factor, b, c); - if (((double *)x->x)[0] != ((double *)x->x)[0]) { + if (((double*)x->x)[0] != ((double*)x->x)[0]) { throw nanex; } - cholmod_dense *y = CHOL_F(allocate_dense)(G.edges.size(), 1, G.edges.size(), CHOLMOD_REAL, c); + cholmod_dense* y = CHOL_F(allocate_dense)(G.edges.size(), 1, G.edges.size(), CHOLMOD_REAL, c); double alpha[2] = {1, 0}; double beta[2] = {0, 0}; @@ -130,7 +129,7 @@ void problem::solve(std::vector<bool>& fuses) { if (fuses[i]) { sol.currents[i] = 0; } else { - sol.currents[i] = ((double *)y->x)[i]; + sol.currents[i] = ((double*)y->x)[i]; graph::coordinate v0 = G.vertices[G.edges[i].v[0]].r; graph::coordinate v1 = G.vertices[G.edges[i].v[1]].r; @@ -166,15 +165,15 @@ void problem::break_edge(unsigned e, bool unbreak) { unsigned n = factor->n; - cholmod_sparse *update_mat = CHOL_F(allocate_sparse)(n, n, 2, true, true, 0, CHOLMOD_REAL, c); + cholmod_sparse* update_mat = CHOL_F(allocate_sparse)(n, n, 2, true, true, 0, CHOLMOD_REAL, c); unsigned s1, s2; s1 = v0 < v1 ? v0 : v1; s2 = v0 < v1 ? v1 : v0; - CHOL_INT *pp = (CHOL_INT *)update_mat->p; - CHOL_INT *ii = (CHOL_INT *)update_mat->i; - double *xx = (double *)update_mat->x; + CHOL_INT* pp = (CHOL_INT*)update_mat->p; + CHOL_INT* ii = (CHOL_INT*)update_mat->i; + double* xx = (double*)update_mat->x; for (unsigned i = 0; i <= s1; i++) { pp[i] = 0; @@ -189,8 +188,8 @@ void problem::break_edge(unsigned e, bool unbreak) { xx[0] = 1; xx[1] = -1; - cholmod_sparse *perm_update_mat = CHOL_F(submatrix)( - update_mat, (CHOL_INT *)factor->Perm, factor->n, NULL, -1, true, true, c); + cholmod_sparse* perm_update_mat = + CHOL_F(submatrix)(update_mat, (CHOL_INT*)factor->Perm, factor->n, NULL, -1, true, true, c); CHOL_F(updown)(unbreak, perm_update_mat, factor, c); @@ -208,8 +207,7 @@ void problem::break_edge(unsigned e, bool unbreak) { ind = r0.x < r1.x ? unbreak : !unbreak; } - ((double *)b->x)[G.edges[e].v[ind]] -= 1.0; - ((double *)b->x)[G.edges[e].v[!ind]] += 1.0; + ((double*)b->x)[G.edges[e].v[ind]] -= 1.0; + ((double*)b->x)[G.edges[e].v[!ind]] += 1.0; } } - |