From a06ff64534815cbf702a3847a19443612d307b80 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Fri, 30 Sep 2022 10:55:55 +0200 Subject: Changed rbmp to use blossom algorithm. --- blossom5-v2.05.src/PMrepair.cpp | 431 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 blossom5-v2.05.src/PMrepair.cpp (limited to 'blossom5-v2.05.src/PMrepair.cpp') diff --git a/blossom5-v2.05.src/PMrepair.cpp b/blossom5-v2.05.src/PMrepair.cpp new file mode 100644 index 0000000..978b38f --- /dev/null +++ b/blossom5-v2.05.src/PMrepair.cpp @@ -0,0 +1,431 @@ +#include +#include +#include +#include "PMimplementation.h" + + +struct PerfectMatching::LCATreeX : LCATree +{ + LCATreeX(int size) : LCATree(size) { rev_mapping = new Node*[size]; } + ~LCATreeX() { delete [] rev_mapping; } + Node** rev_mapping; +}; + +void PerfectMatching::StartUpdate() +{ + Node* i0; + Node* i; + Node* j; + Node* b; + + while ((i=removed_first)) + { + removed_first = i->tree_sibling_next; + blossoms->Delete(i); + removed_num --; + } + + Edge* a; + Edge* selfloop_first = NULL; + Edge* selfloop_last = NULL; + + for (i0=nodes; i0is_processed = 0; + if (i0->is_outer) continue; + + i0->is_tree_root = 0; + i0->blossom_ptr = NULL; + i = i0; + while ( 1 ) + { + j = i->blossom_parent; + j->is_processed = 0; + if (j->is_outer) { j->first_tree_child = i; break; } + if (j->is_marked) break; + if ((a=j->blossom_selfloops)) + { + if (selfloop_last) selfloop_last->next[1] = a; + else selfloop_first = a; + selfloop_last = a; + a->next[1] = NULL; + } + j->blossom_ptr = i; + i = j; + } + b = (i->blossom_parent->is_outer) ? i->blossom_parent : i->blossom_parent->blossom_grandparent; +#ifdef LCA_REPAIRS + if (!b->is_marked) + { + b->lca_size = 1; + b->is_marked = 1; + } +#endif + while ( 1 ) + { +#ifdef LCA_REPAIRS + b->lca_size ++; +#endif + ARC_TO_EDGE_PTR(i->blossom_sibling)->y_saved = i->y; + i->y += i->blossom_parent->y; + if (!i->is_blossom) break; + i->is_marked = 1; + j = i; + i = i->blossom_ptr; + j->blossom_grandparent = b; + } + i->blossom_grandparent = b; + } + +#ifdef LCA_REPAIRS + for (i0=nodes; i0is_outer) continue; + b = i0->blossom_grandparent; + if (!b->is_marked) continue; + b->is_marked = 0; + LCATreeX* lca = new LCATreeX(b->lca_size); + b->blossom_ptr = b->first_tree_child; + i = b; + while ( 1 ) + { + if (i->blossom_ptr) i = i->blossom_ptr; + else + { + while ( 1 ) + { + if (i->is_outer) break; + i->lca_preorder = lca->Add(i, i->blossom_parent); + lca->rev_mapping[i->lca_preorder] = i; + i = ARC_HEAD(i->blossom_sibling); + if (i != i->blossom_parent->blossom_ptr) break; + i = i->blossom_parent; + } + if (i->is_outer) + { + lca->AddRoot(i); + break; + } + } + } + b->lca = lca; + } +#endif + + while ((a=selfloop_first)) + { + selfloop_first = a->next[1]; + do + { + Edge* a_next = a->next[0]; + +#ifdef LCA_REPAIRS + int _i = a->head0[1]->lca_preorder; + int _j = a->head0[0]->lca_preorder; + Node* b = a->head0[1]->blossom_grandparent; + b->lca->GetPenultimateNodes(_i, _j); + i = b->lca->rev_mapping[_i]; + j = b->lca->rev_mapping[_j]; +#else + GetRealEndpoints(a, i, j); +#endif + ADD_EDGE(i, a, 0); + ADD_EDGE(j, a, 1); + a->slack -= 2*i->blossom_eps; + a = a_next; + } while ( a ); + } + + /* + for (i0=nodes; i0is_outer) continue; + b = i0->blossom_grandparent; + if (b->lca) + { + delete b->lca; + b->lca = NULL; + } + } + */ + + nodes[node_num].first_tree_child = NULL; +} + +void PerfectMatching::FinishUpdate() +{ + Node* i0; + Node* i; + Node* j; + Edge* a; + EdgeIterator I; + int dir; + Tree* t; + + for (i0=nodes; i0is_outer) continue; + +#ifdef LCA_REPAIRS + if (i0->blossom_grandparent->lca) + { + delete i0->blossom_grandparent->lca; + i0->blossom_grandparent->lca = NULL; + } +#endif + + ////////////////////////////////////////////////////////////// + if (!i0->blossom_grandparent->is_removed) + { + i = i0; + do + { + i->y = ARC_TO_EDGE_PTR(i->blossom_sibling)->y_saved; + i->is_marked = 0; + i->blossom_selfloops = NULL; + i = i->blossom_parent; + } while (i->is_marked); + continue; + } + ////////////////////////////////////////////////////////////// + + i = i0->blossom_parent; + while ( 1 ) + { + if (i->is_removed && !i->is_outer) break; + REAL y_parent = (i->is_outer) ? 0 : i->blossom_parent->y; + for (dir=0; dir<2; dir++) + { + if (!i->first[dir]) continue; + i->first[dir]->prev[dir]->next[dir] = NULL; + Edge* a_next; + for (a=i->first[dir]; a; a=a_next) + { + a_next = a->next[dir]; + j = a->head0[1-dir]; + ADD_EDGE(j, a, dir); + a->slack += j->blossom_parent->y - y_parent; + } + i->first[dir] = NULL; + } + if (i->is_removed) break; + + j = i->blossom_parent; + i->is_removed = 1; + i->tree_sibling_next = removed_first; + removed_first = i; + i = j; + } + i0->y = ARC_TO_EDGE_PTR(i0->blossom_sibling)->y_saved; + i0->is_outer = 1; + i0->flag = 2; + i0->is_tree_root = 1; + } + + Node* blossom_list = nodes[node_num].first_tree_child; + + + + for (i=nodes; iis_tree_root) continue; + i->first_tree_child = nodes[node_num].first_tree_child; + nodes[node_num].first_tree_child = i; + REAL slack_min = PM_INFTY; + FOR_ALL_EDGES(i, a, dir, I) + { + if (slack_min > a->slack) slack_min = a->slack; + } + i->y += slack_min; + FOR_ALL_EDGES(i, a, dir, I) a->slack -= slack_min; + } + + tree_num = 0; + for (i=nodes[node_num].first_tree_child; i!=blossom_list; i=i->first_tree_child) + { + tree_num ++; + if (!i->is_tree_root) continue; + FOR_ALL_EDGES(i, a, dir, I) + { + j = a->head[dir]; + if (a->slack <= 0 && j->is_tree_root) + { + i->is_tree_root = j->is_tree_root = 0; + i->match = EDGE_DIR_TO_ARC(a, dir); + j->match = EDGE_DIR_TO_ARC(a, 1-dir); + tree_num -= 2; + break; + } + } + } + for ( ; i; i=i->first_tree_child) + { + if (i->is_removed) { i->is_tree_root = 0; continue; } + tree_num ++; + } + + if (tree_num > tree_num_max) + { + if (trees) free(trees); + tree_num_max = tree_num; + trees = (Tree*) malloc(tree_num_max*sizeof(Tree)); + } + t = trees; + + Node* last_root = &nodes[node_num]; + Node* i_next; + for (i=nodes; i; i=i_next) + { + if (!i->is_blossom) i_next = (ifirst_tree_child; + if (!i->is_tree_root) continue; + + i->flag = 0; + i->first_tree_child = NULL; + i->tree_sibling_prev = last_root; + last_root->tree_sibling_next = i; + last_root = i; + i->tree = t; + t->root = i; + t->eps = 0; + t->first[0] = t->first[1] = NULL; + t->pq_current = NULL; + t->pq00.Reset(); + t->pq0.Reset(); + t->pq_blossoms.Reset(); + t ++; + } + + assert(t == trees + tree_num); + last_root->tree_sibling_next = NULL; + + while ((i=removed_first)) + { + removed_first = i->tree_sibling_next; + blossoms->Delete(i); + blossom_num --; + } +} + +PerfectMatching::REAL PerfectMatching::GetTwiceSum(NodeId i) +{ + assert(i>=0 && ihead0[dir]; + if (i->is_outer) + { + if (!i->is_tree_root) + { + i->is_tree_root = 1; + i = ARC_HEAD(i->match); + assert(!i->is_tree_root && i->is_outer); + i->is_tree_root = 1; + if (i->is_blossom) + { + i->first_tree_child = nodes[node_num].first_tree_child; + nodes[node_num].first_tree_child = i; + } + } + return; + } + if (i->blossom_grandparent->is_removed) return; + } + + Node* b = i->blossom_grandparent; + assert(b->is_outer); + + if (!b->is_tree_root) + { + b->is_tree_root = 1; + i = ARC_HEAD(b->match); + assert(!i->is_tree_root && i->is_outer); + i->is_tree_root = 1; + if (i->is_blossom) + { + i->first_tree_child = nodes[node_num].first_tree_child; + nodes[node_num].first_tree_child = i; + } + } + + b->is_removed = 1; + b->tree_sibling_next = removed_first; + removed_first = b; +} + +PerfectMatching::EdgeId PerfectMatching::AddNewEdge(NodeId _i, NodeId _j, REAL cost, bool do_not_add_if_positive_slack) +{ + assert(_i>=0 && _i=0 && _j= edge_num_max) ReallocateEdges(); + Node* i = nodes + _i; + Node* j = nodes + _j; + Edge* a = edges + edge_num; + + a->slack = cost*COST_FACTOR; + a->head0[0] = j; + a->head0[1] = i; + Node* bi = (i->is_outer) ? i : i->blossom_grandparent; + Node* bj = (j->is_outer) ? j : j->blossom_grandparent; + if (bi == bj) + { +#ifdef LCA_REPAIRS + int _i = i->lca_preorder; + int _j = j->lca_preorder; + bi->lca->GetPenultimateNodes(_i, _j); + i = bi->lca->rev_mapping[_i]; + j = bi->lca->rev_mapping[_j]; +#else + GetRealEndpoints(a, i, j); +#endif + a->slack += i->blossom_parent->y + j->blossom_parent->y; + } + else + { + i = bi; + j = bj; + } + a->slack -= a->head0[0]->y + a->head0[1]->y; + + if (a->slack >= 0 && do_not_add_if_positive_slack) return -1; + + ADD_EDGE(i, a, 0); + ADD_EDGE(j, a, 1); + PriorityQueue::ResetItem(a); + + if (a->slack < 0) + { + ProcessNegativeEdge(a); + } + + return edge_num ++; +} + +void PerfectMatching::UpdateCost(EdgeId e, REAL delta_cost) +{ + assert(e>=0 && eslack += delta_cost*COST_FACTOR; + if (a->slack == 0) return; + if (a->slack > 0) + { + Node* i = a->head[1]; + Node* j = a->head[0]; + if (i->is_outer) + { + if (ARC_TO_EDGE_PTR(i->match) != a && ARC_TO_EDGE_PTR(j->match) != a) return; + } + else + { + if (ARC_TO_EDGE_PTR(i->blossom_sibling) != a && ARC_TO_EDGE_PTR(j->blossom_sibling) != a) return; + } + } + ProcessNegativeEdge(a); +} + -- cgit v1.2.3-70-g09d2