use stack to maintain unscanned vertices
This commit is contained in:
parent
5674dff7a6
commit
4fee5333a2
3 changed files with 68 additions and 20 deletions
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue