From 497d601ffc32ee84152970ff116c737fbfa02031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Mon, 6 Nov 2023 18:45:08 +0100 Subject: [PATCH] use union-find structure for rho --- src/edmonds.cpp | 54 ++++++++++++++++-------------------------- src/graph_attributes.h | 21 ++++++++++++---- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/edmonds.cpp b/src/edmonds.cpp index e2de33b..fa378ba 100644 --- a/src/edmonds.cpp +++ b/src/edmonds.cpp @@ -8,7 +8,7 @@ using namespace ED; namespace Edmonds { -void check_integrity(GraphAttributes const & attrs) +void check_integrity(GraphAttributes & attrs) { for(NodeId id = 0; id < attrs.num_nodes(); ++id) { @@ -22,13 +22,13 @@ void check_integrity(GraphAttributes const & attrs) if (attrs.is_out_of_forest(id)) { assert(attrs.phi[id] == id); - assert(attrs.rho[id] == id); + assert(attrs.rho(id) == id); } else { // check for a path to the root, i.e. ρ(node) NodeId cur_node = id; - while(cur_node != attrs.rho[cur_node]) + while(cur_node != attrs.rho(cur_node)) { // If the condition was true, then cur_node is outer, part of a blossom // and we want to follow its path @@ -36,8 +36,8 @@ void check_integrity(GraphAttributes const & attrs) // and point to vertices that have the same rho assert(attrs.mu[cur_node] != cur_node); assert(attrs.phi[cur_node] != cur_node); - assert(attrs.rho[attrs.mu[cur_node]] == attrs.rho[cur_node]); - assert(attrs.rho[attrs.phi[cur_node]] == attrs.rho[cur_node]); + assert(attrs.rho(attrs.mu[cur_node]) == attrs.rho(cur_node)); + assert(attrs.rho(attrs.phi[cur_node]) == attrs.rho(cur_node)); // now, walk along the matched edge cur_node = attrs.mu[cur_node]; @@ -46,7 +46,7 @@ void check_integrity(GraphAttributes const & attrs) // - not be the identity // - result in a node that has the same rho assert(attrs.phi[cur_node] != cur_node); - assert(attrs.rho[attrs.phi[cur_node]] == attrs.rho[cur_node]); + assert(attrs.rho(attrs.phi[cur_node]) == attrs.rho(cur_node)); cur_node = attrs.mu[attrs.phi[cur_node]]; } @@ -54,7 +54,7 @@ void check_integrity(GraphAttributes const & attrs) if (not attrs.is_outer(id)) { - assert(attrs.rho[id] == id); + assert(attrs.rho(id) == id); } } } @@ -103,7 +103,7 @@ __attribute__((noinline)) void augment(GraphAttributes & attrs, std::vector const & x_path, std::vector const & y_path, std::stack & outer_unvisited_nodes) { - //std::cout << "Augment" << std::endl; + std::cout << "Augment" << std::endl; // Paths are disjoint -> augment attrs.mu[x_path.front()] = y_path.front(); attrs.mu[y_path.front()] = x_path.front(); @@ -124,7 +124,7 @@ void augment(GraphAttributes & attrs, std::vector const & x_path, std::v } __attribute__((noinline)) -std::tuple find_blossom_root_id(GraphAttributes const & attrs, std::vector const & x_path, std::vector const & y_path) +std::tuple find_blossom_root_id(GraphAttributes & attrs, std::vector const & x_path, std::vector const & y_path) { size_t distance_from_x = x_path.size() - 1; size_t distance_from_y = y_path.size() - 1; @@ -135,7 +135,7 @@ std::tuple find_blossom_root_id(GraphAttributes co --distance_from_y; } // found first vertex of x_path \cap y_path - while (attrs.rho[x_path[distance_from_x]] != x_path[distance_from_x]) + while (attrs.rho(x_path[distance_from_x]) != x_path[distance_from_x]) { ++distance_from_x; ++distance_from_y; @@ -153,7 +153,7 @@ void update_phialong_blossom_paths(GraphAttributes & attrs, std::vector // Update φ along the paths to encode the ear decomposition for (size_t i = 1; i <= distance_from_x; i += 2) { - if (attrs.rho[attrs.phi[x_path[i]]] != blossom_root_id) + if (attrs.rho(attrs.phi[x_path[i]]) != blossom_root_id) { attrs.phi[attrs.phi[x_path[i]]] = x_path[i]; } @@ -161,36 +161,23 @@ void update_phialong_blossom_paths(GraphAttributes & attrs, std::vector for (size_t i = 1; i <= distance_from_y; i += 2) { - if (attrs.rho[attrs.phi[y_path[i]]] != blossom_root_id) + if (attrs.rho(attrs.phi[y_path[i]]) != blossom_root_id) { attrs.phi[attrs.phi[y_path[i]]] = y_path[i]; } } // Link x and y - if (attrs.rho[x_path.front()] != blossom_root_id) + if (attrs.rho(x_path.front()) != blossom_root_id) { attrs.phi[x_path.front()] = y_path.front(); } - if (attrs.rho[y_path.front()] != blossom_root_id) + if (attrs.rho(y_path.front()) != blossom_root_id) { attrs.phi[y_path.front()] = x_path.front(); } } -__attribute__((noinline)) -void contract_rho(GraphAttributes & attrs, NodeId blossom_root_id) -{ - // Iterating over whole attrs. - for (NodeId node_id = 0; node_id < attrs.num_nodes(); ++node_id) - { - if (attrs.rho[attrs.rho[node_id]] == blossom_root_id) - { - attrs.rho[node_id] = blossom_root_id; - } - } -} - __attribute__((noinline)) void update_rho(GraphAttributes & attrs, std::vector const & x_path, std::vector const & y_path, std::tuple const & blossom_root_description, @@ -205,7 +192,7 @@ void update_rho(GraphAttributes & attrs, std::vector const & x_path, std auto const [blossom_root_id, distance_from_x, distance_from_y] = blossom_root_description; for (size_t i = 0; i <= distance_from_x; ++i) { - attrs.rho[x_path[i]] = blossom_root_id; + attrs.rho_[x_path[i]] = blossom_root_id; if (not attrs.scanned[x_path[i]]) { outer_unvisited_nodes.push(x_path[i]); @@ -213,20 +200,19 @@ void update_rho(GraphAttributes & attrs, std::vector const & x_path, std } for (size_t i = 0; i <= distance_from_y; ++i) { - attrs.rho[y_path[i]] = blossom_root_id; + attrs.rho_[y_path[i]] = blossom_root_id; if (not attrs.scanned[y_path[i]]) { outer_unvisited_nodes.push(y_path[i]); } } - contract_rho(attrs, blossom_root_id); } __attribute__((noinline)) void contract_blossom(GraphAttributes & attrs, std::vector const & x_path, std::vector const & y_path, std::stack & outer_unvisited_nodes) { - //std::cout << "Contract blossom" << std::endl; + std::cout << "Contract blossom" << std::endl; std::tuple const blossom_root_description = find_blossom_root_id(attrs, x_path, y_path); update_phialong_blossom_paths(attrs, x_path, y_path, blossom_root_description); @@ -253,16 +239,16 @@ void maximum_matching_from_initial_matching(Graph const & graph, GraphAttributes for(NodeId neighbor_id : graph.node(id).neighbors()) { check_integrity(attrs); - //std::cout << "Check passed" << std::endl; + std::cout << "Check passed" << std::endl; if (attrs.is_out_of_forest(neighbor_id)) { - //std::cout << "Grow forest" << std::endl; + std::cout << "Grow forest" << std::endl; // Grow Forest attrs.phi[neighbor_id] = id; assert(attrs.mu[neighbor_id] != neighbor_id); outer_unvisited_nodes.push(attrs.mu[neighbor_id]); } - else if (attrs.is_outer(neighbor_id) and attrs.rho[id] != attrs.rho[neighbor_id]) + else if (attrs.is_outer(neighbor_id) and attrs.rho(id) != attrs.rho(neighbor_id)) { std::vector x_path = path_to_forest_root(attrs, id); std::vector y_path = path_to_forest_root(attrs, neighbor_id); diff --git a/src/graph_attributes.h b/src/graph_attributes.h index 4575123..2c1c038 100644 --- a/src/graph_attributes.h +++ b/src/graph_attributes.h @@ -20,10 +20,12 @@ namespace ED void reset_forest(); + NodeId rho(NodeId id); + void reset_matching(); std::vector phi; - std::vector rho; + std::vector rho_; std::vector mu; std::vector scanned; }; @@ -31,7 +33,7 @@ namespace ED inline GraphAttributes::GraphAttributes(const ED::NodeId num_nodes): phi(num_nodes), - rho(num_nodes), + rho_(num_nodes), mu(num_nodes), scanned(num_nodes) { @@ -41,7 +43,7 @@ namespace ED inline NodeId GraphAttributes::num_nodes() const { - assert(phi.size() == rho.size()); + assert(phi.size() == rho_.size()); assert(phi.size() == mu.size()); assert(phi.size() == scanned.size()); return phi.size(); @@ -68,10 +70,21 @@ namespace ED void GraphAttributes::reset_forest() { std::iota(phi.begin(), phi.end(), 0); - std::iota(rho.begin(), rho.end(), 0); + std::iota(rho_.begin(), rho_.end(), 0); std::fill(scanned.begin(), scanned.end(), false); } + inline + NodeId GraphAttributes::rho(NodeId id) + { + while(rho_[id] != id) + { + rho_[id] = rho_[rho_[id]]; + id = rho_[id]; + } + return id; + } + inline void GraphAttributes::reset_matching() {