1
0
Fork 0

Use tight edges only during delta steps

This commit is contained in:
Joris van Rantwijk 2024-11-09 21:23:38 +01:00
parent 55a98238aa
commit 7ea1562cc7
1 changed files with 35 additions and 61 deletions

View File

@ -619,9 +619,8 @@ public:
*/
std::vector<const EdgeT*> vertex_best_edge;
// TODO -- rename to scan_queue
/** Queue of S-vertices to be scanned. */
std::deque<VertexId> queue;
std::vector<VertexId> scan_queue;
// TODO -- delete
/** Markers placed while tracing an alternating path. */
@ -1005,7 +1004,7 @@ public:
if (sub->label == LABEL_T) {
for_vertices_in_blossom(sub,
[this](VertexId x) {
queue.push_back(x);
scan_queue.push_back(x);
});
}
}
@ -1343,7 +1342,7 @@ public:
// Add all vertices inside the newly labeled S-blossom to the queue.
for_vertices_in_blossom(bx,
[this](VertexId v) {
queue.push_back(v);
scan_queue.push_back(v);
});
}
@ -1422,27 +1421,31 @@ public:
}
/**
* Scan queued S-vertices to expand the alternating trees.
* Scan the incident edges of newly labeled S-vertices.
*
* The scan proceeds until either an augmenting path is found,
* or the queue of S-vertices becomes empty.
* If an augmenting path is found, it is used to augment the matching.
* Edges are added to delta2 tracking or delta3 tracking depending
* on the state of the vertex on the opposite side of the edge.
*
* New blossoms may be created during the scan.
* This function does not yet use the edges to extend the alternating
* tree or find blossoms or augmenting paths, even if the edges
* are tight. If there are such tight edges, they will be used later
* through zero-delta steps.
*
* @return True if the matching was augmented; otherwise false.
* If there are "j" new S-vertices with a total of "k" incident edges,
* this function takes time O((j + k) * log(n)).
*
* Since each vertex can become an S-vertex at most once per stage,
* this function takes total time O((n + m) * log(n)) per stage.
*/
bool substage_scan()
void scan_new_s_vertices()
{
// Process the queue of S-vertices to be scanned.
// This loop runs through O(n) iterations per stage.
while (! queue.empty()) {
for (VertexId x : scan_queue) {
// Take one vertex from the queue.
VertexId x = queue.front();
queue.pop_front();
assert(vertex_top_blossom[x]->label == LABEL_S);
// Double-check that "x" is an S-vertex.
BlossomT* bx = top_level_blossom(x);
assert(bx->label == LABEL_S);
// Scan the edges that are incident on "x".
// This loop runs through O(m) iterations per stage.
@ -1451,50 +1454,26 @@ public:
VertexId y = (edge.vt.first != x) ? edge.vt.first
: edge.vt.second;
// Note: The top-level blossom of vertex "x" may change
// during this loop, so we need to refresh it in each pass.
BlossomT* bx = vertex_top_blossom[x];
// Ignore edges that are internal to a blossom.
if (bx == vertex_top_blossom[y]) {
BlossomT* by = top_level_blossom(y);
if (bx == by) {
continue;
}
BlossomLabel ylabel = vertex_top_blossom[y]->label;
// Check whether this edge is tight (has zero slack).
// Only tight edges may be part of an alternating tree.
WeightType slack = edge_slack(edge);
if (slack <= 0) {
if (ylabel == LABEL_NONE) {
// Found a tight edge to an unlabeled blossom.
// Assign label T to the blossom that contains "y".
assign_label_t(x, y);
} else if (ylabel == LABEL_S) {
// Found a tight edge between two S-blossoms.
// Find either a new blossom or an augmenting path.
bool augmented = add_s_to_s_edge(x, y);
if (augmented) {
return true;
}
}
} else if (ylabel == LABEL_S) {
// Found a non-tight edge between two S-blossoms.
// Pass it to the least-slack edge tracker.
if (by->label == LABEL_S) {
// Edge between S-vertices in different top-level blossoms.
// Add to delta3 tracking.
delta3_add_edge(e);
}
if (ylabel != LABEL_S) {
// Found an to a T-vertex or unlabeled vertex "y".
// Pass it to the least-slack edge tracker.
// Tight edges must also be tracked in this way.
} else {
// Edge to T-vertex or unlabeled vertex.
// Add to delta2 tracking.
WeightType slack = edge_slack(edge);
lset_add_vertex_edge(y, &edge, slack);
}
}
}
// No further S vertices to scan, and no augmenting path found.
return false;
scan_queue.clear();
}
/* ********** Delta steps: ********** */
@ -1602,6 +1581,8 @@ public:
*/
void reset_stage()
{
assert(scan_queue.empty());
// Remove blossom labels.
for (BlossomT& blossom : trivial_blossom) {
blossom.label = LABEL_NONE;
@ -1610,9 +1591,6 @@ public:
blossom.label = LABEL_NONE;
}
// Clear the S-vertex queue.
queue.clear();
// Reset least-slack edge tracking.
lset_reset();
}
@ -1642,7 +1620,7 @@ public:
// Stop if all vertices are matched.
// No further improvement is possible in that case.
// This avoids messy calculations of delta steps without any S-vertex.
if (queue.empty()) {
if (scan_queue.empty()) {
return false;
}
@ -1656,12 +1634,8 @@ public:
bool augmented = false;
while (true) {
// Grow alternating trees.
// End the stage if an augmenting path is found.
augmented = substage_scan();
if (augmented) {
break;
}
// Consider the incident edges of newly labeled S-vertices.
scan_new_s_vertices();
// Calculate delta step in the dual LPP problem.
DeltaStep delta = substage_calc_dual_delta();