use stack to maintain unscanned vertices

This commit is contained in:
Maximilian Keßler 2023-11-05 21:14:48 +01:00
parent 5674dff7a6
commit 4fee5333a2
Signed by: max
GPG key ID: BCC5A619923C0BA5
3 changed files with 68 additions and 20 deletions

View file

@ -1,5 +1,6 @@
#include "edmonds.h" #include "edmonds.h"
#include <iostream> #include <iostream>
#include <stack>
using namespace ED; using namespace ED;
@ -82,6 +83,7 @@ std::vector<NodeId> path_to_forest_root(Graph const & graph, NodeId id)
return retval; return retval;
} }
__attribute__((noinline))
NodeId find_outer_vertex(Graph const & graph) NodeId find_outer_vertex(Graph const & graph)
{ {
for(NodeId id = 0; id < graph.num_nodes(); ++id) for(NodeId id = 0; id < graph.num_nodes(); ++id)
@ -94,12 +96,35 @@ NodeId find_outer_vertex(Graph const & graph)
return invalid_node_id; return invalid_node_id;
} }
void collect_exposed_vertices(Graph & graph, std::stack<NodeId> & container)
{
std::stack<NodeId>().swap(container);
for(NodeId id = 0; id < graph.num_nodes(); id++)
{
if (graph.matched_neighbor(id) == id)
{
container.push(id);
graph.node(id).scanned = true;
}
}
}
void maximum_matching_from_initial_matching(Graph & graph) void maximum_matching_from_initial_matching(Graph & graph)
{ {
graph.reset_forest(); graph.reset_forest();
NodeId id; // Over the course of the algorithm, this will maintain all outer vertices
while((id = find_outer_vertex(graph)) != invalid_node_id) // that have not been scanned yet.
// Note that at the beginning, this is exactly the exposed edges.
// Throughout the algorithm, we push new ids whenever there are new outer vertices.
// Also note that we separately mark each node whether it has been collected to this stack.
// When this stack runs out, then we know that all vertices marked 'scanned' have already been processed,
// but also all vertices not marked 'scanned' are not outer vertices, so we can in fact terminate.
std::stack<NodeId> outer_unvisited_nodes;
collect_exposed_vertices(graph, outer_unvisited_nodes);
while(not outer_unvisited_nodes.empty())
{ {
NodeId const id = outer_unvisited_nodes.top();
outer_unvisited_nodes.pop();
for(NodeId neighbor_id : graph.node(id).neighbors()) for(NodeId neighbor_id : graph.node(id).neighbors())
{ {
//check_integrity(graph); //check_integrity(graph);
@ -109,6 +134,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
//std::cout << "Grow forest" << std::endl; //std::cout << "Grow forest" << std::endl;
// Grow Forest // Grow Forest
graph.node(neighbor_id).phi = id; graph.node(neighbor_id).phi = id;
assert(graph.matched_neighbor(neighbor_id) != neighbor_id);
outer_unvisited_nodes.push(graph.matched_neighbor(neighbor_id));
} }
else if (graph.is_outer(neighbor_id) and graph.rho(id) != graph.rho(neighbor_id)) else if (graph.is_outer(neighbor_id) and graph.rho(id) != graph.rho(neighbor_id))
{ {
@ -136,6 +163,7 @@ void maximum_matching_from_initial_matching(Graph & graph)
// Note that since this is tail-recursion, this will not generate // Note that since this is tail-recursion, this will not generate
// new stack frames in OPT mode // new stack frames in OPT mode
graph.reset_forest(); graph.reset_forest();
collect_exposed_vertices(graph, outer_unvisited_nodes);
break; break;
} }
else else
@ -158,6 +186,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
}; };
// found first vertex fixed by rho // found first vertex fixed by rho
NodeId blossom_root_id = x_path[distance_from_x]; 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) for(size_t i = 1; i <= distance_from_x; i += 2)
{ {
if (graph.rho(graph.phi(x_path[i])) != blossom_root_id) if (graph.rho(graph.phi(x_path[i])) != blossom_root_id)
@ -172,6 +202,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
graph.node(graph.phi(y_path[i])).phi = y_path[i]; graph.node(graph.phi(y_path[i])).phi = y_path[i];
} }
} }
// Link x and y
if (graph.rho(x_path.front()) != blossom_root_id) if (graph.rho(x_path.front()) != blossom_root_id)
{ {
graph.node(x_path.front()).phi = y_path.front(); graph.node(x_path.front()).phi = y_path.front();
@ -185,14 +217,26 @@ void maximum_matching_from_initial_matching(Graph & graph)
// ρ(v) in the paths from x or y to r // ρ(v) in the paths from x or y to r
// We update ρ(v) first for the paths themselves, and then 'contract' ρ // We update ρ(v) first for the paths themselves, and then 'contract' ρ
// by updating ρ(v) to r for all vertices where ρ(ρ(v)) = r // 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) for(size_t i = 0; i <= distance_from_x; ++i)
{ {
graph.node(x_path[i]).rho = blossom_root_id; 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) for(size_t i = 0; i <= distance_from_y; ++i)
{ {
graph.node(y_path[i]).rho = blossom_root_id; 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) for(NodeId node_id = 0; node_id < graph.num_nodes(); ++node_id)
{ {
if (graph.rho(graph.rho(node_id)) == blossom_root_id) if (graph.rho(graph.rho(node_id)) == blossom_root_id)

View file

@ -176,24 +176,6 @@ std::ostream & operator<<(std::ostream & output, Graph const & graph)
return output; return output;
} }
bool Graph::is_outer(NodeId const id) const {
return matched_neighbor(id) == id or \
phi(matched_neighbor(id)) != matched_neighbor(id);
}
bool Graph::is_inner(NodeId const id) const
{
return phi(id) != id and \
phi(matched_neighbor(id)) == matched_neighbor(id);
}
bool Graph::is_out_of_forest(const ED::NodeId id) const
{
return matched_neighbor(id) != id and \
phi(id) == id and \
phi(matched_neighbor(id)) == matched_neighbor(id);
}
void Graph::reset_forest() void Graph::reset_forest()
{ {
NodeId cur_id = 0; NodeId cur_id = 0;

View file

@ -260,6 +260,28 @@ NodeId Graph::rho(const NodeId id) const
return _nodes[id].rho; return _nodes[id].rho;
} }
inline
bool Graph::is_outer(NodeId const id) const {
return matched_neighbor(id) == id or \
phi(matched_neighbor(id)) != matched_neighbor(id);
}
inline
bool Graph::is_inner(NodeId const id) const
{
return phi(id) != id and \
phi(matched_neighbor(id)) == matched_neighbor(id);
}
inline
bool Graph::is_out_of_forest(const ED::NodeId id) const
{
return matched_neighbor(id) != id and \
phi(id) == id and \
phi(matched_neighbor(id)) == matched_neighbor(id);
}
} // namespace ED } // namespace ED
#endif /* GRAPH_HPP */ #endif /* GRAPH_HPP */