Reorganize code that handles labeling
This commit is contained in:
parent
39eaea451e
commit
5500750c13
176
cpp/mwmatching.h
176
cpp/mwmatching.h
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue