diff --git a/src/edmonds.cpp b/src/edmonds.cpp index d11461d..0e7712c 100644 --- a/src/edmonds.cpp +++ b/src/edmonds.cpp @@ -64,6 +64,7 @@ void check_integrity(Graph const & graph) * @note This assumes that the values of μ, φ and ρ represent a special * blossom forest on the graph when this method is called. * **/ +__attribute__((noinline)) std::vector path_to_forest_root(Graph const & graph, NodeId id) { std::vector retval; @@ -96,6 +97,114 @@ void collect_exposed_vertices(Graph & graph, std::stack & container) } } +__attribute__((noinline)) +void augment(Graph & graph, std::vector const & x_path, std::vector const & y_path, + std::stack & outer_unvisited_nodes) +{ + //std::cout << "Augment" << std::endl; + // Paths are disjoint -> augment + graph.node(x_path.front()).matched_neighbor = y_path.front(); + graph.node(y_path.front()).matched_neighbor = x_path.front(); + + // TODO: put this into own method? + for(size_t i = 1; i < x_path.size(); i += 2) + { + graph.node(x_path[i]).matched_neighbor = x_path[i+1]; + graph.node(x_path[i+1]).matched_neighbor = x_path[i]; + } + for(size_t i = 1; i < y_path.size(); i += 2) + { + graph.node(y_path[i]).matched_neighbor = y_path[i+1]; + graph.node(y_path[i+1]).matched_neighbor = y_path[i]; + } + // Note that since this is tail-recursion, this will not generate + // new stack frames in OPT mode + graph.reset_forest(); + collect_exposed_vertices(graph, outer_unvisited_nodes); +} + +void contract_blossom(Graph & graph, std::vector const & x_path, std::vector const & y_path, + std::stack & outer_unvisited_nodes) +{ + //std::cout << "Contract blossom" << std::endl; + // Paths are not disjoint -> shrink blossom + size_t distance_from_x = x_path.size() - 1; + size_t distance_from_y = y_path.size() - 1; + while (distance_from_x > 0 and distance_from_y > 0 and \ + x_path[distance_from_x - 1] == y_path[distance_from_y - 1]) + { + --distance_from_x; + --distance_from_y; + } +// found first vertex of x_path \cap y_path + while (graph.rho(x_path[distance_from_x]) != x_path[distance_from_x]) + { + ++distance_from_x; + ++distance_from_y; + }; +// found first vertex fixed by rho + NodeId blossom_root_id = x_path[distance_from_x]; + +// Update φ along the paths to encode the ear decomposition + for (size_t i = 1; i <= distance_from_x; i += 2) + { + if (graph.rho(graph.phi(x_path[i])) != blossom_root_id) + { + graph.node(graph.phi(x_path[i])).phi = x_path[i]; + } + } + for (size_t i = 1; i <= distance_from_y; i += 2) + { + if (graph.rho(graph.phi(y_path[i])) != blossom_root_id) + { + graph.node(graph.phi(y_path[i])).phi = y_path[i]; + } + } + +// Link x and y + if (graph.rho(x_path.front()) != blossom_root_id) + { + graph.node(x_path.front()).phi = y_path.front(); + } + if (graph.rho(y_path.front()) != blossom_root_id) + { + graph.node(y_path.front()).phi = x_path.front(); + } + +// Update root indices. We have to do this for all vertices v with +// ρ(v) in the paths from x or y to r +// We update ρ(v) first for the paths themselves, and then 'contract' ρ +// by updating ρ(v) to r for all vertices where ρ(ρ(v)) = r +// Also, while walking along the paths, we can add all vertices (which are now outer) +// to the stack. + for (size_t i = 0; i <= distance_from_x; ++i) + { + graph.node(x_path[i]).rho = blossom_root_id; + if (not graph.node(x_path[i]).scanned) + { + outer_unvisited_nodes.push(x_path[i]); + } + } + for (size_t i = 0; i <= distance_from_y; ++i) + { + graph.node(y_path[i]).rho = blossom_root_id; + if (not graph.node(y_path[i]).scanned) + { + outer_unvisited_nodes.push(y_path[i]); + } + } + +// Iterating over whole graph. + for (NodeId node_id = 0; node_id < graph.num_nodes(); ++node_id) + { + if (graph.rho(graph.rho(node_id)) == blossom_root_id) + { + graph.node(node_id).rho = blossom_root_id; + } + } +//check_integrity(graph); +} + void maximum_matching_from_initial_matching(Graph & graph) { graph.reset_forest(); @@ -131,107 +240,12 @@ void maximum_matching_from_initial_matching(Graph & graph) if (x_path.back() != y_path.back()) { - //std::cout << "Augment" << std::endl; - // Paths are disjoint -> augment - graph.node(x_path.front()).matched_neighbor = y_path.front(); - graph.node(y_path.front()).matched_neighbor = x_path.front(); - - // TODO: put this into own method? - for(size_t i = 1; i < x_path.size(); i += 2) - { - graph.node(x_path[i]).matched_neighbor = x_path[i+1]; - graph.node(x_path[i+1]).matched_neighbor = x_path[i]; - } - for(size_t i = 1; i < y_path.size(); i += 2) - { - graph.node(y_path[i]).matched_neighbor = y_path[i+1]; - graph.node(y_path[i+1]).matched_neighbor = y_path[i]; - } - // Note that since this is tail-recursion, this will not generate - // new stack frames in OPT mode - graph.reset_forest(); - collect_exposed_vertices(graph, outer_unvisited_nodes); + augment(graph, x_path, y_path, outer_unvisited_nodes); break; } else { - //std::cout << "Contract blossom" << std::endl; - // Paths are not disjoint -> shrink blossom - size_t distance_from_x = x_path.size() - 1; - size_t distance_from_y = y_path.size() - 1; - while (distance_from_x > 0 and distance_from_y > 0 and \ - x_path[distance_from_x - 1] == y_path[distance_from_y - 1]) - { - --distance_from_x; - --distance_from_y; - } - // found first vertex of x_path \cap y_path - while (graph.rho(x_path[distance_from_x]) != x_path[distance_from_x]) - { - ++distance_from_x; - ++distance_from_y; - }; - // found first vertex fixed by rho - NodeId blossom_root_id = x_path[distance_from_x]; - - // Update φ along the paths to encode the ear decomposition - for(size_t i = 1; i <= distance_from_x; i += 2) - { - if (graph.rho(graph.phi(x_path[i])) != blossom_root_id) - { - graph.node(graph.phi(x_path[i])).phi = x_path[i]; - } - } - for(size_t i = 1; i <= distance_from_y; i += 2) - { - if (graph.rho(graph.phi(y_path[i])) != blossom_root_id) - { - graph.node(graph.phi(y_path[i])).phi = y_path[i]; - } - } - - // Link x and y - if (graph.rho(x_path.front()) != blossom_root_id) - { - graph.node(x_path.front()).phi = y_path.front(); - } - if (graph.rho(y_path.front()) != blossom_root_id) - { - graph.node(y_path.front()).phi = x_path.front(); - } - - // Update root indices. We have to do this for all vertices v with - // ρ(v) in the paths from x or y to r - // We update ρ(v) first for the paths themselves, and then 'contract' ρ - // by updating ρ(v) to r for all vertices where ρ(ρ(v)) = r - // Also, while walking along the paths, we can add all vertices (which are now outer) - // to the stack. - for(size_t i = 0; i <= distance_from_x; ++i) - { - graph.node(x_path[i]).rho = blossom_root_id; - if(not graph.node(x_path[i]).scanned) - { - outer_unvisited_nodes.push(x_path[i]); - } - } - for(size_t i = 0; i <= distance_from_y; ++i) - { - graph.node(y_path[i]).rho = blossom_root_id; - if(not graph.node(y_path[i]).scanned) - { - outer_unvisited_nodes.push(y_path[i]); - } - } - - // Iterating over whole graph. - for(NodeId node_id = 0; node_id < graph.num_nodes(); ++node_id) - { - if (graph.rho(graph.rho(node_id)) == blossom_root_id) - { - graph.node(node_id).rho = blossom_root_id; - } - } - //check_integrity(graph); + contract_blossom(graph, x_path, y_path, outer_unvisited_nodes); } } }