1
0
Fork 0

Reorganize code that handles labeling

This commit is contained in:
Joris van Rantwijk 2024-11-14 23:31:11 +01:00
parent 39eaea451e
commit 5500750c13
1 changed files with 127 additions and 49 deletions

View File

@ -856,6 +856,70 @@ public:
return std::make_tuple(NO_EDGE, 0); return std::make_tuple(NO_EDGE, 0);
} }
/* ********** Managing blossom labels: ********** */
/**
* Change an unlabeled top-level blossom into an S-blossom.
*
* For a blossom with "j" vertices and "k" incident edges,
* this function takes time O(j * log(n) + k).
*
* This function is called at most once per blossom per stage.
* It therefore takes total time O(n * log(n) + m) per stage.
*/
void assign_blossom_label_s(BlossomT* blossom)
{
assert(! blossom->parent);
assert(blossom->label == LABEL_NONE);
blossom->label = LABEL_S;
// Add new S-vertices to the scan queue.
for_vertices_in_blossom(blossom,
[this](VertexId x) {
scan_queue.push_back(x);
});
}
/**
* Change an unlabeled top-level blossom into a T-blossom.
*
* This function takes time O(log(n)).
*/
void assign_blossom_label_t(BlossomT* blossom)
{
assert(! blossom->parent);
assert(blossom->label == LABEL_NONE);
blossom->label = LABEL_T;
}
/**
* Change a top-level T-blossom into an unlabeled blossom.
*
* This function takes time O(log(n)).
*/
void remove_blossom_label_t(BlossomT* blossom)
{
assert(! blossom->parent);
assert(blossom->label == LABEL_T);
blossom->label = LABEL_NONE;
}
/**
* Change a top-level S-blossom into an S-subblossom.
*
* This function takes time O(1).
*/
void change_s_blossom_to_subblossom(BlossomT* blossom)
{
assert(! blossom->parent);
assert(blossom->label == LABEL_S);
blossom->label = LABEL_NONE;
}
/* ********** Creating and expanding blossoms: ********** */ /* ********** Creating and expanding blossoms: ********** */
/** /**
@ -985,6 +1049,21 @@ public:
assert(vertex_top_blossom[edge.second] == subblossoms[pos]); assert(vertex_top_blossom[edge.second] == subblossoms[pos]);
} }
// Blossom must start and end with an S-blossom.
assert(subblossoms.front()->label == LABEL_S);
for (BlossomT* sub : subblossoms) {
// Mark vertices inside former T-blossoms as S-vertices.
if (sub->label == LABEL_T) {
remove_blossom_label_t(sub);
assign_blossom_label_s(sub);
}
// Remove labels from sub-blossoms.
change_s_blossom_to_subblossom(sub);
}
// Create the new blossom object. // Create the new blossom object.
nontrivial_blossom.emplace_back(subblossoms, path.edges); nontrivial_blossom.emplace_back(subblossoms, path.edges);
NonTrivialBlossomT* blossom = &nontrivial_blossom.back(); NonTrivialBlossomT* blossom = &nontrivial_blossom.back();
@ -1000,20 +1079,8 @@ public:
}); });
// Assign label S to the new blossom and link to the alternating tree. // Assign label S to the new blossom and link to the alternating tree.
assert(subblossoms.front()->label == LABEL_S);
blossom->label = LABEL_S; blossom->label = LABEL_S;
blossom->tree_edge = subblossoms.front()->tree_edge; blossom->tree_edge = subblossoms.front()->tree_edge;
// Consider vertices inside former T-sub-blossoms which now
// became S-vertices; add them to the queue.
for (BlossomT* sub : subblossoms) {
if (sub->label == LABEL_T) {
for_vertices_in_blossom(sub,
[this](VertexId x) {
scan_queue.push_back(x);
});
}
}
} }
/** Erase the specified non-trivial blossom. */ /** Erase the specified non-trivial blossom. */
@ -1039,6 +1106,9 @@ public:
assert(blossom->parent == nullptr); assert(blossom->parent == nullptr);
assert(blossom->label == LABEL_T); assert(blossom->label == LABEL_T);
// Remove label from blossom.
remove_blossom_label_t(blossom);
// Convert sub-blossoms into top-level blossoms. // Convert sub-blossoms into top-level blossoms.
for (const auto& sub : blossom->subblossoms) { for (const auto& sub : blossom->subblossoms) {
BlossomT* sub_blossom = sub.blossom; BlossomT* sub_blossom = sub.blossom;
@ -1061,7 +1131,7 @@ public:
BlossomT* entry = vertex_top_blossom[blossom->tree_edge.second]; BlossomT* entry = vertex_top_blossom[blossom->tree_edge.second];
// Assign label T to that blossom and link to the alternating tree. // Assign label T to that blossom and link to the alternating tree.
entry->label = LABEL_T; assign_blossom_label_t(entry);
entry->tree_edge = blossom->tree_edge; entry->tree_edge = blossom->tree_edge;
// Find the position of this sub-blossom within the expanding blossom. // Find the position of this sub-blossom within the expanding blossom.
@ -1079,12 +1149,12 @@ public:
while (sub_it != sub_begin) { while (sub_it != sub_begin) {
// Assign label S to the next node on the path. // Assign label S to the next node on the path.
--sub_it; --sub_it;
assign_label_s(sub_it->edge.first); extend_tree_t_to_s(sub_it->edge.first);
// Assign label T to the next node on the path. // Assign label T to the next node on the path.
assert(sub_it != sub_begin); assert(sub_it != sub_begin);
--sub_it; --sub_it;
sub_it->blossom->label = LABEL_T; assign_blossom_label_t(sub_it->blossom);
sub_it->blossom->tree_edge = flip_vertex_pair(sub_it->edge); sub_it->blossom->tree_edge = flip_vertex_pair(sub_it->edge);
} }
@ -1094,7 +1164,7 @@ public:
auto sub_end = blossom->subblossoms.end(); auto sub_end = blossom->subblossoms.end();
while (sub_it != sub_end) { while (sub_it != sub_end) {
// Assign label S to the next node on the path. // Assign label S to the next node on the path.
assign_label_s(sub_it->edge.second); extend_tree_t_to_s(sub_it->edge.second);
++sub_it; ++sub_it;
// Assign label T to the next node on the path. // Assign label T to the next node on the path.
@ -1106,7 +1176,7 @@ public:
BlossomT *sub_blossom = (sub_it == sub_end) ? BlossomT *sub_blossom = (sub_it == sub_end) ?
blossom->subblossoms.front().blossom : blossom->subblossoms.front().blossom :
sub_it->blossom; sub_it->blossom;
sub_blossom->label = LABEL_T; assign_blossom_label_t(sub_blossom);
sub_blossom->tree_edge = tree_edge; sub_blossom->tree_edge = tree_edge;
} }
} }
@ -1306,26 +1376,25 @@ public:
} }
} }
/* ********** Labels and alternating tree: ********** */ /* ********** Alternating tree: ********** */
/** /**
* Assign label S to the unlabeled blossom that contains vertex "x". * Assign label S to the unlabeled blossom that contains vertex "x".
* *
* If vertex "x" is matched, it becomes attached to the alternating tree * The newly labeled S-blossom is added to the alternating tree
* via its matched edge. If vertex "x" is unmatched, it becomes the root * via its matched edge. All vertices in the newly labeled S-blossom
* of an alternating tree. * are added to the scan queue.
* *
* All vertices in the newly labeled blossom are added to the scan queue. * All vertices in the newly labeled blossom are added to the scan queue.
* *
* @pre "x" is an unlabeled vertex, either unmatched or matched to * @pre "x" is an unlabeled vertex.
* a T-vertex via a tight edge. * @pre "x" is matched to a T-vertex via a tight edge.
*/ */
void assign_label_s(VertexId x) void extend_tree_t_to_s(VertexId x)
{ {
// Assign label S to the blossom that contains vertex "x". // Assign label S to the blossom that contains vertex "x".
BlossomT* bx = vertex_top_blossom[x]; BlossomT* bx = top_level_blossom(x);
assert(bx->label == LABEL_NONE); assign_blossom_label_s(bx);
bx->label = LABEL_S;
VertexId y = vertex_mate[x]; VertexId y = vertex_mate[x];
if (y == NO_VERTEX) { if (y == NO_VERTEX) {
@ -1339,57 +1408,52 @@ public:
} else { } else {
// Vertex "x" is matched to T-vertex "y". // Vertex "x" is matched to T-vertex "y".
assert(vertex_top_blossom[y]->label == LABEL_T); BlossomT* by = top_level_blossom(y);
assert(by->label == LABEL_T);
// Attach the blossom to the alternating tree via vertex "y". // Attach the blossom to the alternating tree via vertex "y".
bx->tree_edge = std::make_pair(y, x); bx->tree_edge = std::make_pair(y, x);
} }
// Add all vertices inside the newly labeled S-blossom to the queue.
for_vertices_in_blossom(bx,
[this](VertexId v) {
scan_queue.push_back(v);
});
} }
/** /**
* Assign label T to the unlabeled blossom that contains vertex "y". * Assign label T to the unlabeled blossom that contains vertex "y".
* *
* Attach it to the alternating tree via edge (x, y). * The newly labeled T-blossom is added to the alternating tree.
* Then immediately assign label S to the mate of vertex "y". * Directly afterwards, label S is assigned to the blossom that has
* a matched edge to the base of the newly labeled T-blossom.
* That newly labeled S-blossom is also added to the alternating tree.
* *
* Note that this function may expand blossoms that contain vertex "y". * Note that this function may expand blossoms that contain vertex "y".
* *
* @pre "x" is an S-vertex. * @pre "x" is an S-vertex.
* @pre "y" is an unlabeled, matched vertex. * @pre "y" is an unlabeled, matched vertex.
* @pre The top-level blossom that contains "y" has a matched base vertex.
* @pre There is a tight edge between vertices "x" and "y". * @pre There is a tight edge between vertices "x" and "y".
*/ */
void assign_label_t(VertexId x, VertexId y) void extend_tree_s_to_t(VertexId x, VertexId y)
{ {
assert(vertex_top_blossom[x]->label == LABEL_S); assert(top_level_blossom(x)->label == LABEL_S);
BlossomT* by = vertex_top_blossom[y];
assert(by->label == LABEL_NONE);
// If "y" is part of a zero-dual blossom, expand it. // If "y" is part of a zero-dual blossom, expand it.
// This would otherwise likely happen through a zero-delta4 step, // This would otherwise likely happen through a zero-delta4 step,
// so we can just do it now and avoid a substage. // so we can just do it now and avoid a substage.
BlossomT* by = top_level_blossom(y);
NonTrivialBlossomT* ntb = by->nontrivial(); NonTrivialBlossomT* ntb = by->nontrivial();
while (ntb != nullptr && ntb->dual_var == 0) { while (ntb != nullptr && ntb->dual_var == 0) {
expand_unlabeled_blossom(ntb); expand_unlabeled_blossom(ntb);
by = vertex_top_blossom[y]; by = top_level_blossom(y);
assert(by->label == LABEL_NONE);
ntb = by->nontrivial(); ntb = by->nontrivial();
} }
// Assign label T to the top-level blossom that contains vertex "y". // Assign label T to the top-level blossom that contains vertex "y".
by->label = LABEL_T; assign_blossom_label_t(by);
by->tree_edge = std::make_pair(x, y); by->tree_edge = std::make_pair(x, y);
// Assign label S to the blossom that is mated to the T-blossom. // Assign label S to the blossom that is mated to the T-blossom.
VertexId z = vertex_mate[by->base_vertex]; VertexId z = vertex_mate[by->base_vertex];
assert(z != NO_VERTEX); assert(z != NO_VERTEX);
assign_label_s(z); extend_tree_t_to_s(z);
} }
/** /**
@ -1401,12 +1465,19 @@ public:
* If the edge connects two different alternating trees, an augmenting * If the edge connects two different alternating trees, an augmenting
* path has been discovered. In this case the matching is augmented. * path has been discovered. In this case the matching is augmented.
* *
* @pre "x" and "y" are S-vertices in different top-level blossoms.
* @pre There is a tight edge between vertices "x" and "y".
*
* @return True if the matching was augmented; otherwise false. * @return True if the matching was augmented; otherwise false.
*/ */
bool add_s_to_s_edge(VertexId x, VertexId y) bool add_s_to_s_edge(VertexId x, VertexId y)
{ {
assert(vertex_top_blossom[x]->label == LABEL_S); BlossomT* bx = top_level_blossom(x);
assert(vertex_top_blossom[y]->label == LABEL_S); BlossomT* by = top_level_blossom(y);
assert(bx->label == LABEL_S);
assert(by->label == LABEL_S);
assert(bx != by);
// Trace back through the alternating trees from "x" and "y". // Trace back through the alternating trees from "x" and "y".
AlternatingPath path = trace_alternating_paths(x, y); AlternatingPath path = trace_alternating_paths(x, y);
@ -1615,7 +1686,14 @@ public:
// Assign label S to all unmatched vertices and put them in the queue. // Assign label S to all unmatched vertices and put them in the queue.
for (VertexId x = 0; x < graph.num_vertex; ++x) { for (VertexId x = 0; x < graph.num_vertex; ++x) {
if (vertex_mate[x] == NO_VERTEX) { if (vertex_mate[x] == NO_VERTEX) {
assign_label_s(x);
// Assign label S.
BlossomT* bx = top_level_blossom(x);
assert(bx->base_vertex == x);
assign_blossom_label_s(bx);
// Mark blossom as the root of an alternating tree.
bx->tree_edge = std::make_pair(NO_VERTEX, x);
} }
} }
@ -1656,7 +1734,7 @@ public:
if (vertex_top_blossom[x]->label != LABEL_S) { if (vertex_top_blossom[x]->label != LABEL_S) {
std::swap(x, y); std::swap(x, y);
} }
assign_label_t(x, y); extend_tree_s_to_t(x, y);
} else if (delta.kind == 3) { } else if (delta.kind == 3) {
// Use the S-to-S edge that got unlocked by the delta update. // Use the S-to-S edge that got unlocked by the delta update.