Use tight edges only during delta steps
This commit is contained in:
parent
55a98238aa
commit
7ea1562cc7
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue