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 <iostream>
#include <stack>
using namespace ED;
@ -82,6 +83,7 @@ std::vector<NodeId> path_to_forest_root(Graph const & graph, NodeId id)
return retval;
}
__attribute__((noinline))
NodeId find_outer_vertex(Graph const & graph)
{
for(NodeId id = 0; id < graph.num_nodes(); ++id)
@ -94,12 +96,35 @@ NodeId find_outer_vertex(Graph const & graph)
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)
{
graph.reset_forest();
NodeId id;
while((id = find_outer_vertex(graph)) != invalid_node_id)
// Over the course of the algorithm, this will maintain all outer vertices
// 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())
{
//check_integrity(graph);
@ -109,6 +134,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
//std::cout << "Grow forest" << std::endl;
// Grow Forest
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))
{
@ -136,6 +163,7 @@ void maximum_matching_from_initial_matching(Graph & graph)
// 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);
break;
}
else
@ -158,6 +186,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
};
// 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)
@ -172,6 +202,8 @@ void maximum_matching_from_initial_matching(Graph & graph)
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();
@ -185,14 +217,26 @@ void maximum_matching_from_initial_matching(Graph & graph)
// ρ(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)

View file

@ -176,24 +176,6 @@ std::ostream & operator<<(std::ostream & output, Graph const & graph)
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()
{
NodeId cur_id = 0;

View file

@ -260,6 +260,28 @@ NodeId Graph::rho(const NodeId id) const
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
#endif /* GRAPH_HPP */