ensure all outer vertices are scanned

This commit is contained in:
Maximilian Keßler 2023-11-05 13:06:50 +01:00
parent 14474189c4
commit 1b9f930adf
Signed by: max
GPG key ID: BCC5A619923C0BA5

View file

@ -30,101 +30,113 @@ std::vector<NodeId> path_to_forest_root(Graph const & graph, NodeId id)
return retval; return retval;
} }
NodeId find_outer_vertex(Graph const & graph)
{
for(NodeId id = 0; id < graph.num_nodes(); ++id)
{
if (not graph.node(id).scanned and graph.is_outer(id))
{
return id;
}
}
return invalid_node_id;
}
Graph maximum_matching_from_initial_matching(Graph & graph) Graph maximum_matching_from_initial_matching(Graph & graph)
{ {
graph.reset_forest(); graph.reset_forest();
for(NodeId id = 0; id < graph.num_nodes(); ++id) { NodeId id;
if (graph.is_outer(id)) while((id = find_outer_vertex(graph)) != invalid_node_id)
{
for(NodeId neighbor_id : graph.node(id).neighbors())
{ {
for(NodeId neighbor_id : graph.node(id).neighbors()) if (graph.is_out_of_forest(neighbor_id))
{ {
if (graph.is_out_of_forest(neighbor_id)) // Grow Forest
{ graph.node(neighbor_id).ear_or_root_neighbor = id;
// Grow Forest }
graph.node(neighbor_id).ear_or_root_neighbor = id; else if (graph.is_outer(neighbor_id) and \
} graph.root_of_ear_component(id) != graph.root_of_ear_component(neighbor_id))
else if (graph.is_outer(neighbor_id) and \ {
graph.root_of_ear_component(id) != graph.root_of_ear_component(neighbor_id)) std::vector<NodeId> x_path = path_to_forest_root(graph, id);
{ std::vector<NodeId> y_path = path_to_forest_root(graph, neighbor_id);
std::vector<NodeId> x_path = path_to_forest_root(graph, id);
std::vector<NodeId> y_path = path_to_forest_root(graph, neighbor_id);
if (x_path.back() != y_path.back()) if (x_path.back() != y_path.back())
{
// 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)
{ {
// Paths are disjoint -> augment graph.node(x_path[i]).matched_neighbor = x_path[i+1];
graph.node(x_path.front()).matched_neighbor = y_path.front(); graph.node(x_path[i+1]).matched_neighbor = x_path[i];
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
return maximum_matching(graph);
} }
else for(size_t i = 1; i < y_path.size(); i += 2)
{ {
// Paths are not disjoint -> shrink blossom graph.node(y_path[i]).matched_neighbor = y_path[i+1];
size_t distance_from_x = x_path.size() - 1; graph.node(y_path[i+1]).matched_neighbor = y_path[i];
size_t distance_from_y = y_path.size() - 1; }
while (distance_from_x > 0 and distance_from_y > 0 and \ // Note that since this is tail-recursion, this will not generate
x_path[distance_from_x - 1] == y_path[distance_from_y - 1]) // new stack frames in OPT mode
return maximum_matching(graph);
}
else
{
// 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.root_of_ear_component(x_path[distance_from_x]) != x_path[distance_from_x])
{
++distance_from_x;
++distance_from_y;
};
// found first vertex fixed by root_of_ear_component
NodeId blossom_root_id = x_path[distance_from_x];
for(size_t i = 1; i <= distance_from_x; i += 2)
{
if (graph.root_of_ear_component(graph.ear_or_root_neighbor(x_path[i])) != blossom_root_id)
{ {
--distance_from_x; graph.node(graph.ear_or_root_neighbor(x_path[i])).ear_or_root_neighbor = x_path[i];
--distance_from_y;
} }
// found first vertex of x_path \cap y_path }
while (graph.root_of_ear_component(x_path[distance_from_x]) != x_path[distance_from_x]) for(size_t i = 1; i <= distance_from_y; i += 2)
{
if (graph.root_of_ear_component(graph.ear_or_root_neighbor(y_path[i])) != blossom_root_id)
{ {
++distance_from_x; graph.node(graph.ear_or_root_neighbor(y_path[i])).ear_or_root_neighbor = y_path[i];
++distance_from_y;
};
// found first vertex fixed by root_of_ear_component
NodeId blossom_root_id = x_path[distance_from_x];
for(size_t i = 1; i <= distance_from_x; i += 2)
{
if (graph.root_of_ear_component(graph.ear_or_root_neighbor(x_path[i])) != blossom_root_id)
{
graph.node(graph.ear_or_root_neighbor(x_path[i])).ear_or_root_neighbor = x_path[i];
}
}
for(size_t i = 1; i <= distance_from_y; i += 2)
{
if (graph.root_of_ear_component(graph.ear_or_root_neighbor(y_path[i])) != blossom_root_id)
{
graph.node(graph.ear_or_root_neighbor(y_path[i])).ear_or_root_neighbor = y_path[i];
}
}
if (graph.root_of_ear_component(x_path.front()) != blossom_root_id)
{
graph.node(x_path.front()).ear_or_root_neighbor = y_path.front();
}
if (graph.root_of_ear_component(y_path.front()) != blossom_root_id)
{
graph.node(x_path.front()).ear_or_root_neighbor = x_path.front();
} }
}
if (graph.root_of_ear_component(x_path.front()) != blossom_root_id)
{
graph.node(x_path.front()).ear_or_root_neighbor = y_path.front();
}
if (graph.root_of_ear_component(y_path.front()) != blossom_root_id)
{
graph.node(x_path.front()).ear_or_root_neighbor = x_path.front();
}
// Update root indices // Update root indices
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]).root_of_ear_component = blossom_root_id; graph.node(x_path[i]).root_of_ear_component = blossom_root_id;
} }
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]).root_of_ear_component = blossom_root_id; graph.node(y_path[i]).root_of_ear_component = blossom_root_id;
}
} }
} }
} }
} }
graph.node(id).scanned = true;
} }
return graph; return graph;
}; };