1
0
Fork 0

Lazy updates of blossom duals

This commit is contained in:
Joris van Rantwijk 2024-11-16 14:23:13 +01:00
parent 228da75495
commit 2271df1897
1 changed files with 75 additions and 43 deletions

View File

@ -410,8 +410,24 @@ struct NonTrivialBlossom : public Blossom<WeightType>
*/ */
std::list<SubBlossom> subblossoms; std::list<SubBlossom> subblossoms;
// TODO -- description /**
/** Dual LPP variable for this blossom. */ * Modified dual variable of this blossom.
*
* Every non-trivial blossom has a variable in the dual LPP. The true
* value of the dual variable changes through delta steps, but the
* modified dual variable is invariant under delta steps.
*
* For an S-blossom "b":
* b.dual_var = z(b) - 2 * delta_sum
*
* For a T-blossom "b":
* b.dual_var = z(b) + 2 * delta_sum
*
* For an unlabeled blossom or non-top-level blossom "b":
* b.dual_var = z(b)
*
* where z(b) is the true dual variable of blossom "b".
*/
WeightType dual_var; WeightType dual_var;
// TODO -- delta4_node // TODO -- delta4_node
@ -900,6 +916,14 @@ public:
blossom->label = LABEL_S; blossom->label = LABEL_S;
// Unlabeled blossoms and S-blossoms use different rules
// for modified blossom duals. Adjust the modified dual variable
// to preserve the true blossom dual while switching labels.
NonTrivialBlossomT* ntb = blossom->nontrivial();
if (ntb) {
ntb->dual_var -= 2 * delta_sum;
}
// Unlabeled vertices and S-vertices use different rules for // Unlabeled vertices and S-vertices use different rules for
// modified vertex duals. Calculate the adjustment that must be // modified vertex duals. Calculate the adjustment that must be
// applied to modified vertex duals to preserve the true vertex duals // applied to modified vertex duals to preserve the true vertex duals
@ -937,6 +961,14 @@ public:
blossom->label = LABEL_T; blossom->label = LABEL_T;
// Unlabeled blossoms and T-blossoms use different rules
// for modified blossom duals. Adjust the modified dual variable
// to preserve the true blossom dual while switching labels.
NonTrivialBlossomT* ntb = blossom->nontrivial();
if (ntb) {
ntb->dual_var += 2 * delta_sum;
}
// Unlabeled vertices and T-vertices use different rules for // Unlabeled vertices and T-vertices use different rules for
// modified vertex duals. Adjust the dual offset to preserve the // modified vertex duals. Adjust the dual offset to preserve the
// true vertex duals while switching labels. // true vertex duals while switching labels.
@ -966,9 +998,13 @@ public:
blossom->label = LABEL_NONE; blossom->label = LABEL_NONE;
// Unlabeled vertices and S-vertices use different rules for // Adjust modified blossom dual to preserve true blossom dual.
// modified vertex duals. Adjust the modified vertex duals NonTrivialBlossomT* ntb = blossom->nontrivial();
// match the true vertex duals. if (ntb) {
ntb->dual_var += 2 * delta_sum;
}
// Adjust modified vertex duals to preserve true vertex dual.
assert(blossom->vertex_dual_offset == 0); assert(blossom->vertex_dual_offset == 0);
WeightType dual_fixup = -delta_sum; WeightType dual_fixup = -delta_sum;
for_vertices_in_blossom(blossom, for_vertices_in_blossom(blossom,
@ -989,22 +1025,14 @@ public:
blossom->label = LABEL_NONE; blossom->label = LABEL_NONE;
// Unlabeled vertices and T-vertices use different rules for // Adjust modified blossom dual to preserve true blossom dual.
// modified vertex duals. Adjust the dual offset to preserve the NonTrivialBlossomT* ntb = blossom->nontrivial();
// true vertex duals while switching labels. if (ntb) {
blossom->vertex_dual_offset += delta_sum; ntb->dual_var -= 2 * delta_sum;
} }
/** Remove blossom label. */ // Adjust dual offset to preserve true vertex duals.
void reset_blossom_label(BlossomT* blossom) blossom->vertex_dual_offset += delta_sum;
{
if (! blossom->parent) {
if (blossom->label == LABEL_S) {
remove_blossom_label_s(blossom);
} else if (blossom->label == LABEL_T) {
remove_blossom_label_t(blossom);
}
}
} }
/** /**
@ -1018,6 +1046,25 @@ public:
assert(blossom->label == LABEL_S); assert(blossom->label == LABEL_S);
blossom->label = LABEL_NONE; blossom->label = LABEL_NONE;
// The subblossom becomes unlabeled.
// Adjust its modified blossom dual to preserve the true blossom dual.
NonTrivialBlossomT* ntb = blossom->nontrivial();
if (ntb) {
ntb->dual_var += 2 * delta_sum;
}
}
/** Remove blossom label. */
void reset_blossom_label(BlossomT* blossom)
{
if (! blossom->parent) {
if (blossom->label == LABEL_S) {
remove_blossom_label_s(blossom);
} else if (blossom->label == LABEL_T) {
remove_blossom_label_t(blossom);
}
}
} }
/* ********** Creating and expanding blossoms: ********** */ /* ********** Creating and expanding blossoms: ********** */
@ -1168,6 +1215,9 @@ public:
nontrivial_blossom.emplace_back(subblossoms, path.edges); nontrivial_blossom.emplace_back(subblossoms, path.edges);
NonTrivialBlossomT* blossom = &nontrivial_blossom.back(); NonTrivialBlossomT* blossom = &nontrivial_blossom.back();
// Initialize modified blossom dual to set true dual to 0.
blossom->dual_var = -2 * delta_sum;
// Link the subblossoms to the their new parent. // Link the subblossoms to the their new parent.
for (BlossomT* sub : subblossoms) { for (BlossomT* sub : subblossoms) {
sub->parent = blossom; sub->parent = blossom;
@ -1708,9 +1758,10 @@ public:
// Compute delta4: half minimum dual of a top-level T-blossom. // Compute delta4: half minimum dual of a top-level T-blossom.
for (NonTrivialBlossomT& blossom : nontrivial_blossom) { for (NonTrivialBlossomT& blossom : nontrivial_blossom) {
if ((! blossom.parent) && (blossom.label == LABEL_T)) { if ((! blossom.parent) && (blossom.label == LABEL_T)) {
if (blossom.dual_var / 2 <= delta.value) { WeightType true_dual_var = blossom.dual_var - 2 * delta_sum;
if (true_dual_var / 2 <= delta.value) {
delta.kind = 4; delta.kind = 4;
delta.value = blossom.dual_var / 2; delta.value = true_dual_var / 2;
delta.blossom = &blossom; delta.blossom = &blossom;
} }
} }
@ -1719,23 +1770,6 @@ public:
return delta; return delta;
} }
/** Apply a delta step to the dual LPP variables. */
void substage_apply_delta_step(WeightType delta)
{
// Apply delta to dual variables of top-level non-trivial blossoms.
for (NonTrivialBlossomT& blossom : nontrivial_blossom) {
if (blossom.parent == nullptr) {
if (blossom.label == LABEL_S) {
// S-blossom: add 2*delta to dual variable.
blossom.dual_var += 2 * delta;
} else if (blossom.label == LABEL_T) {
// T-blossom: subtract 2*delta from dual variable.
blossom.dual_var -= 2 * delta;
}
}
}
}
/* ********** Main algorithm: ********** */ /* ********** Main algorithm: ********** */
/** /**
@ -1812,10 +1846,8 @@ public:
// Calculate delta step in the dual LPP problem. // Calculate delta step in the dual LPP problem.
DeltaStep delta = calc_dual_delta_step(); DeltaStep delta = calc_dual_delta_step();
// Apply the delta step to the dual variables. // Update the running sum of delta steps. This implicitly updates
substage_apply_delta_step(delta.value); // the dual variables of vertices and blossoms.
// Update the running sum of delta steps.
delta_sum += delta.value; delta_sum += delta.value;
if (delta.kind == 2) { if (delta.kind == 2) {