Lazy updates of vertex duals
This commit is contained in:
		
							parent
							
								
									5500750c13
								
							
						
					
					
						commit
						228da75495
					
				
							
								
								
									
										301
									
								
								cpp/mwmatching.h
								
								
								
								
							
							
						
						
									
										301
									
								
								cpp/mwmatching.h
								
								
								
								
							|  | @ -324,15 +324,11 @@ struct Blossom | ||||||
| 
 | 
 | ||||||
|     // TODO -- delta2_node
 |     // TODO -- delta2_node
 | ||||||
| 
 | 
 | ||||||
|     // TODO -- vertex_dual_offset
 |  | ||||||
| 
 |  | ||||||
| // TODO -- remove
 |  | ||||||
|     /**
 |     /**
 | ||||||
|      * In case of a top-level S-blossom, "best_edge" is the least-slack edge |      * Accumulated pending lazy updates to the dual variables of the vertices | ||||||
|      * that links to a different S-blossom, or "nullptr" if no such edge |      * inside the blossom. | ||||||
|      * has been found. |  | ||||||
|      */ |      */ | ||||||
|     const Edge<WeightType>* best_edge; |     WeightType vertex_dual_offset; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     /** Initialize base class. */ |     /** Initialize base class. */ | ||||||
|  | @ -341,7 +337,7 @@ protected: | ||||||
|         base_vertex(base_vertex), |         base_vertex(base_vertex), | ||||||
|         label(LABEL_NONE), |         label(LABEL_NONE), | ||||||
|         is_nontrivial_blossom(is_nontrivial_blossom), |         is_nontrivial_blossom(is_nontrivial_blossom), | ||||||
|         best_edge(nullptr) |         vertex_dual_offset(0) | ||||||
|     { } |     { } | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | @ -582,16 +578,34 @@ public: | ||||||
|      */ |      */ | ||||||
|     std::vector<BlossomT*> vertex_top_blossom; |     std::vector<BlossomT*> vertex_top_blossom; | ||||||
| 
 | 
 | ||||||
|     // TODO -- start_vertex_dual
 |  | ||||||
| 
 |  | ||||||
| // TODO -- description
 |  | ||||||
|     /**
 |     /**
 | ||||||
|      * Every vertex has a variable in the dual LPP. |      * Modified dual variable of each vertex. | ||||||
|      * |      * | ||||||
|      * "vertex_dual[x]" is the dual variable of vertex "x". |      * Every vertex has a variable in the dual LPP. The true value of the dual | ||||||
|  |      * variable changes through delta steps, but the modified dual variables | ||||||
|  |      * are invariant under delta steps. | ||||||
|  |      * | ||||||
|  |      * For an S-vertex "x": | ||||||
|  |      *   vertex_dual[x] = u(x) + delta_sum | ||||||
|  |      * | ||||||
|  |      * For a T-vertex "x": | ||||||
|  |      *   vertex_dual[x] = u(x) - delta_sum - B(x).vertex_dual_offset | ||||||
|  |      * | ||||||
|  |      * For an unlabeled vertex: | ||||||
|  |      *   vertex_dual[x] = u(x) - B(x).vertex_dual_offset | ||||||
|  |      * | ||||||
|  |      * where u(x) is the true dual variable of vertex "x" | ||||||
|  |      * and B(x) is the top-level blossom that contains vertex "x". | ||||||
|      */ |      */ | ||||||
|     std::vector<WeightType> vertex_dual; |     std::vector<WeightType> vertex_dual; | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Initial value of all vertex dual variables. | ||||||
|  |      * | ||||||
|  |      * This is equal to half of the maximum edge weight. | ||||||
|  |      */ | ||||||
|  |     WeightType init_vertex_dual; | ||||||
|  | 
 | ||||||
|     /** Running sum of applied delta steps. */ |     /** Running sum of applied delta steps. */ | ||||||
|     WeightType delta_sum; |     WeightType delta_sum; | ||||||
| 
 | 
 | ||||||
|  | @ -658,7 +672,7 @@ public: | ||||||
|         for (const EdgeT& edge : graph.edges) { |         for (const EdgeT& edge : graph.edges) { | ||||||
|             max_weight = std::max(max_weight, edge.weight); |             max_weight = std::max(max_weight, edge.weight); | ||||||
|         } |         } | ||||||
|         WeightType init_vertex_dual = max_weight * (weight_factor / 2); |         init_vertex_dual = max_weight * (weight_factor / 2); | ||||||
|         vertex_dual.resize(graph.num_vertex, init_vertex_dual); |         vertex_dual.resize(graph.num_vertex, init_vertex_dual); | ||||||
| 
 | 
 | ||||||
|         delta_sum = 0; |         delta_sum = 0; | ||||||
|  | @ -682,7 +696,7 @@ public: | ||||||
|      * |      * | ||||||
|      * This function takes time O(log(n)). |      * This function takes time O(log(n)). | ||||||
|      */ |      */ | ||||||
|     BlossomT* top_level_blossom(VertexId x) |     BlossomT* top_level_blossom(VertexId x) const | ||||||
|     { |     { | ||||||
|         // TODO
 |         // TODO
 | ||||||
|         return vertex_top_blossom[x]; |         return vertex_top_blossom[x]; | ||||||
|  | @ -701,8 +715,7 @@ public: | ||||||
|         const EdgeT& edge = graph.edges[e]; |         const EdgeT& edge = graph.edges[e]; | ||||||
|         VertexId x = edge.vt.first; |         VertexId x = edge.vt.first; | ||||||
|         VertexId y = edge.vt.second; |         VertexId y = edge.vt.second; | ||||||
|         // TODO -- remove delta_sum here
 |         return vertex_dual[x] + vertex_dual[y] - weight_factor * edge.weight; | ||||||
|         return vertex_dual[x] + vertex_dual[y] - weight_factor * edge.weight + 2 * delta_sum; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| // TODO -- delete
 | // TODO -- delete
 | ||||||
|  | @ -710,7 +723,28 @@ public: | ||||||
|     { |     { | ||||||
|         VertexId x = edge.vt.first; |         VertexId x = edge.vt.first; | ||||||
|         VertexId y = edge.vt.second; |         VertexId y = edge.vt.second; | ||||||
|         return vertex_dual[x] + vertex_dual[y] - weight_factor * edge.weight; |         BlossomT* bx = top_level_blossom(x); | ||||||
|  |         BlossomT* by = top_level_blossom(y); | ||||||
|  | 
 | ||||||
|  |         WeightType ux = vertex_dual[x]; | ||||||
|  |         if (bx->label == LABEL_S) { | ||||||
|  |             ux -= delta_sum; | ||||||
|  |         } else if (bx->label == LABEL_T) { | ||||||
|  |             ux += delta_sum + bx->vertex_dual_offset; | ||||||
|  |         } else { | ||||||
|  |             ux += bx->vertex_dual_offset; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         WeightType uy = vertex_dual[y]; | ||||||
|  |         if (by->label == LABEL_S) { | ||||||
|  |             uy -= delta_sum; | ||||||
|  |         } else if (by->label == LABEL_T) { | ||||||
|  |             uy += delta_sum + by->vertex_dual_offset; | ||||||
|  |         } else { | ||||||
|  |             uy += by->vertex_dual_offset; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return ux + uy - weight_factor * edge.weight; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -724,14 +758,6 @@ public: | ||||||
|             vertex_best_edge[x] = nullptr; |             vertex_best_edge[x] = nullptr; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (BlossomT& blossom : trivial_blossom) { |  | ||||||
|             blossom.best_edge = nullptr; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for (NonTrivialBlossomT& blossom : nontrivial_blossom) { |  | ||||||
|             blossom.best_edge = nullptr; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         delta3_queue.clear(); |         delta3_queue.clear(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -874,9 +900,27 @@ public: | ||||||
| 
 | 
 | ||||||
|         blossom->label = LABEL_S; |         blossom->label = LABEL_S; | ||||||
| 
 | 
 | ||||||
|         // Add new S-vertices to the scan queue.
 |         // Unlabeled vertices and S-vertices use different rules for
 | ||||||
|  |         // modified vertex duals. Calculate the adjustment that must be
 | ||||||
|  |         // applied to modified vertex duals to preserve the true vertex duals
 | ||||||
|  |         // while switching labels.
 | ||||||
|  |         //
 | ||||||
|  |         // Unlabeled vertex: vertex_dual[x] = u(x) - B(x).vertex_dual_offset
 | ||||||
|  |         // S-vertex:         vertex_dual[x] = u(x) + delta_sum
 | ||||||
|  |         //
 | ||||||
|  |         // For S-blossoms, "vertex_dual_offset" is always 0.
 | ||||||
|  |         //
 | ||||||
|  |         WeightType dual_fixup = delta_sum + blossom->vertex_dual_offset; | ||||||
|  |         blossom->vertex_dual_offset = 0; | ||||||
|  | 
 | ||||||
|  |         // Loop over newly labeled S-vertices.
 | ||||||
|         for_vertices_in_blossom(blossom, |         for_vertices_in_blossom(blossom, | ||||||
|             [this](VertexId x) { |             [this,dual_fixup](VertexId x) { | ||||||
|  | 
 | ||||||
|  |                 // Apply adjustment to modified dual variable.
 | ||||||
|  |                 vertex_dual[x] += dual_fixup; | ||||||
|  | 
 | ||||||
|  |                 // Add new S-vertices to the scan queue.
 | ||||||
|                 scan_queue.push_back(x); |                 scan_queue.push_back(x); | ||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
|  | @ -892,6 +936,45 @@ public: | ||||||
|         assert(blossom->label == LABEL_NONE); |         assert(blossom->label == LABEL_NONE); | ||||||
| 
 | 
 | ||||||
|         blossom->label = LABEL_T; |         blossom->label = LABEL_T; | ||||||
|  | 
 | ||||||
|  |         // Unlabeled vertices and T-vertices use different rules for
 | ||||||
|  |         // modified vertex duals. Adjust the dual offset to preserve the
 | ||||||
|  |         // true vertex duals while switching labels.
 | ||||||
|  |         //
 | ||||||
|  |         // Unlabeled vertex:
 | ||||||
|  |         //   vertex_dual[x] = u(x) - B(x).vertex_dual_offset
 | ||||||
|  |         //
 | ||||||
|  |         // T-vertex:
 | ||||||
|  |         //   vertex_dual[x] = u(x) - delta_sum - B(x).vertex_dual_offset
 | ||||||
|  |         //
 | ||||||
|  |         blossom->vertex_dual_offset -= delta_sum; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Change a top-level S-blossom into an unlabeled blossom. | ||||||
|  |      * | ||||||
|  |      * For a blossom with "j" vertices and "k" incident edges, | ||||||
|  |      * this function takes time O((j + k) * log(n)). | ||||||
|  |      * | ||||||
|  |      * This function is called at most once per blossom per stage. | ||||||
|  |      * It therefore takes total time O((n + m) * log(n)) per stage. | ||||||
|  |      */ | ||||||
|  |     void remove_blossom_label_s(BlossomT* blossom) | ||||||
|  |     { | ||||||
|  |         assert(! blossom->parent); | ||||||
|  |         assert(blossom->label == LABEL_S); | ||||||
|  | 
 | ||||||
|  |         blossom->label = LABEL_NONE; | ||||||
|  | 
 | ||||||
|  |         // Unlabeled vertices and S-vertices use different rules for
 | ||||||
|  |         // modified vertex duals. Adjust the modified vertex duals
 | ||||||
|  |         // match the true vertex duals.
 | ||||||
|  |         assert(blossom->vertex_dual_offset == 0); | ||||||
|  |         WeightType dual_fixup = -delta_sum; | ||||||
|  |         for_vertices_in_blossom(blossom, | ||||||
|  |             [this,dual_fixup](VertexId x) { | ||||||
|  |                 vertex_dual[x] += dual_fixup; | ||||||
|  |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -905,6 +988,23 @@ public: | ||||||
|         assert(blossom->label == LABEL_T); |         assert(blossom->label == LABEL_T); | ||||||
| 
 | 
 | ||||||
|         blossom->label = LABEL_NONE; |         blossom->label = LABEL_NONE; | ||||||
|  | 
 | ||||||
|  |         // Unlabeled vertices and T-vertices use different rules for
 | ||||||
|  |         // modified vertex duals. Adjust the dual offset to preserve the
 | ||||||
|  |         // true vertex duals while switching labels.
 | ||||||
|  |         blossom->vertex_dual_offset += 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); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -1096,6 +1196,48 @@ public: | ||||||
|         nontrivial_blossom.erase(blossom_it); |         nontrivial_blossom.erase(blossom_it); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Expand the specified unlabeled blossom but do not yet delete it. | ||||||
|  |      * | ||||||
|  |      * This function takes time O(n). | ||||||
|  |      */ | ||||||
|  |     void expand_unlabeled_blossom_core(NonTrivialBlossomT* blossom) | ||||||
|  |     { | ||||||
|  |         assert(blossom->parent == nullptr); | ||||||
|  |         assert(blossom->label == LABEL_NONE); | ||||||
|  | 
 | ||||||
|  |         // Prepare to push pending delta updates down to the sub-blossoms.
 | ||||||
|  |         WeightType vertex_dual_offset = blossom->vertex_dual_offset; | ||||||
|  |         blossom->vertex_dual_offset = 0; | ||||||
|  | 
 | ||||||
|  |         // Convert sub-blossoms into top-level blossoms.
 | ||||||
|  |         for (const auto& sub : blossom->subblossoms) { | ||||||
|  |             BlossomT* sub_blossom = sub.blossom; | ||||||
|  |             assert(sub_blossom->parent == blossom); | ||||||
|  |             assert(sub_blossom->label == LABEL_NONE); | ||||||
|  |             sub_blossom->parent = nullptr; | ||||||
|  |             for_vertices_in_blossom(sub_blossom, | ||||||
|  |                 [this,sub_blossom](VertexId x) { | ||||||
|  |                     vertex_top_blossom[x] = sub_blossom; | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |             // Push pending delta updates to sub-blossom.
 | ||||||
|  |             assert(sub_blossom->vertex_dual_offset == 0); | ||||||
|  |             sub_blossom->vertex_dual_offset = vertex_dual_offset; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Expand and delete the specified unlabeled blossom. | ||||||
|  |      * | ||||||
|  |      * This function takes time O(n). | ||||||
|  |      */ | ||||||
|  |     void expand_unlabeled_blossom(NonTrivialBlossomT* blossom) | ||||||
|  |     { | ||||||
|  |         expand_unlabeled_blossom_core(blossom); | ||||||
|  |         erase_nontrivial_blossom(blossom); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Expand the specified T-blossom. |      * Expand the specified T-blossom. | ||||||
|      * |      * | ||||||
|  | @ -1109,17 +1251,8 @@ public: | ||||||
|         // Remove label from blossom.
 |         // Remove label from blossom.
 | ||||||
|         remove_blossom_label_t(blossom); |         remove_blossom_label_t(blossom); | ||||||
| 
 | 
 | ||||||
|         // Convert sub-blossoms into top-level blossoms.
 |         // Expand the unlabeled blossom.
 | ||||||
|         for (const auto& sub : blossom->subblossoms) { |         expand_unlabeled_blossom_core(blossom); | ||||||
|             BlossomT* sub_blossom = sub.blossom; |  | ||||||
|             assert(sub_blossom->parent == blossom); |  | ||||||
|             assert(sub_blossom->label == LABEL_NONE); |  | ||||||
|             sub_blossom->parent = nullptr; |  | ||||||
|             for_vertices_in_blossom(sub_blossom, |  | ||||||
|                 [this,sub_blossom](VertexId x) { |  | ||||||
|                     vertex_top_blossom[x] = sub_blossom; |  | ||||||
|                 }); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // The expanded blossom was part of an alternating tree.
 |         // The expanded blossom was part of an alternating tree.
 | ||||||
|         // We must now reconstruct the part of the alternating tree
 |         // We must now reconstruct the part of the alternating tree
 | ||||||
|  | @ -1185,32 +1318,6 @@ public: | ||||||
|         erase_nontrivial_blossom(blossom); |         erase_nontrivial_blossom(blossom); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |  | ||||||
|      * Expand the specified unlabeled blossom. |  | ||||||
|      * |  | ||||||
|      * This function takes time O(n). |  | ||||||
|      */ |  | ||||||
|     void expand_unlabeled_blossom(NonTrivialBlossomT* blossom) |  | ||||||
|     { |  | ||||||
|         assert(blossom->parent == nullptr); |  | ||||||
|         assert(blossom->label == LABEL_NONE); |  | ||||||
| 
 |  | ||||||
|         // Convert sub-blossoms into top-level blossoms.
 |  | ||||||
|         for (const auto& sub : blossom->subblossoms) { |  | ||||||
|             BlossomT* sub_blossom = sub.blossom; |  | ||||||
|             assert(sub_blossom->parent == blossom); |  | ||||||
|             assert(sub_blossom->label == LABEL_NONE); |  | ||||||
|             sub_blossom->parent = nullptr; |  | ||||||
|             for_vertices_in_blossom(sub_blossom, |  | ||||||
|                 [this,sub_blossom](VertexId x) { |  | ||||||
|                     vertex_top_blossom[x] = sub_blossom; |  | ||||||
|                 }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Delete the expanded blossom.
 |  | ||||||
|         erase_nontrivial_blossom(blossom); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* **********  Augmenting:  ********** */ |     /* **********  Augmenting:  ********** */ | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -1573,13 +1680,10 @@ public: | ||||||
|         delta.blossom = nullptr; |         delta.blossom = nullptr; | ||||||
| 
 | 
 | ||||||
|         // Compute delta1: minimum dual variable of any S-vertex.
 |         // Compute delta1: minimum dual variable of any S-vertex.
 | ||||||
|  |         // All unmatched vertices have the same dual value, and this is
 | ||||||
|  |         // the minimum value among all S-vertices.
 | ||||||
|         delta.kind = 1; |         delta.kind = 1; | ||||||
|         delta.value = std::numeric_limits<WeightType>::max(); |         delta.value = init_vertex_dual - delta_sum; | ||||||
|         for (VertexId x = 0; x < graph.num_vertex; ++x) { |  | ||||||
|             if (vertex_top_blossom[x]->label == LABEL_S) { |  | ||||||
|                 delta.value = std::min(delta.value, vertex_dual[x]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // Compute delta2: minimum slack of any edge between an S-vertex and
 |         // Compute delta2: minimum slack of any edge between an S-vertex and
 | ||||||
|         // an unlabeled vertex.
 |         // an unlabeled vertex.
 | ||||||
|  | @ -1618,18 +1722,6 @@ public: | ||||||
|     /** Apply a delta step to the dual LPP variables. */ |     /** Apply a delta step to the dual LPP variables. */ | ||||||
|     void substage_apply_delta_step(WeightType delta) |     void substage_apply_delta_step(WeightType delta) | ||||||
|     { |     { | ||||||
|         // Apply delta to dual variables of all vertices.
 |  | ||||||
|         for (VertexId x = 0; x < graph.num_vertex; ++x) { |  | ||||||
|             BlossomLabel xlabel = vertex_top_blossom[x]->label; |  | ||||||
|             if (xlabel == LABEL_S) { |  | ||||||
|                 // S-vertex: subtract delta from dual variable.
 |  | ||||||
|                 vertex_dual[x] -= delta; |  | ||||||
|             } else if (xlabel == LABEL_T) { |  | ||||||
|                 // T-vertex: add delta to dual variable.
 |  | ||||||
|                 vertex_dual[x] += delta; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Apply delta to dual variables of top-level non-trivial blossoms.
 |         // Apply delta to dual variables of top-level non-trivial blossoms.
 | ||||||
|         for (NonTrivialBlossomT& blossom : nontrivial_blossom) { |         for (NonTrivialBlossomT& blossom : nontrivial_blossom) { | ||||||
|             if (blossom.parent == nullptr) { |             if (blossom.parent == nullptr) { | ||||||
|  | @ -1658,10 +1750,10 @@ public: | ||||||
| 
 | 
 | ||||||
|         // Remove blossom labels.
 |         // Remove blossom labels.
 | ||||||
|         for (BlossomT& blossom : trivial_blossom) { |         for (BlossomT& blossom : trivial_blossom) { | ||||||
|             blossom.label = LABEL_NONE; |             reset_blossom_label(&blossom); | ||||||
|         } |         } | ||||||
|         for (BlossomT& blossom : nontrivial_blossom) { |         for (BlossomT& blossom : nontrivial_blossom) { | ||||||
|             blossom.label = LABEL_NONE; |             reset_blossom_label(&blossom); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Reset least-slack edge tracking.
 |         // Reset least-slack edge tracking.
 | ||||||
|  | @ -1766,6 +1858,42 @@ public: | ||||||
|         return augmented; |         return augmented; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Remove alternating trees and apply lazy updates to dual variables. | ||||||
|  |      * | ||||||
|  |      * This function takes time O((n + m) * log(n)). | ||||||
|  |      * It is called once, at the end of the algorithm. | ||||||
|  |      */ | ||||||
|  |     void cleanup() | ||||||
|  |     { | ||||||
|  |         assert(scan_queue.empty()); | ||||||
|  | 
 | ||||||
|  |         auto cleanup_blossom = [this](BlossomT* blossom) { | ||||||
|  |             assert(blossom->label == LABEL_NONE); | ||||||
|  | 
 | ||||||
|  |             // Unwind lazy delta updates to vertex dual variables.
 | ||||||
|  |             if (blossom->vertex_dual_offset != 0) { | ||||||
|  |                 WeightType dual_fixup = blossom->vertex_dual_offset; | ||||||
|  |                 blossom->vertex_dual_offset = 0; | ||||||
|  |                 for_vertices_in_blossom(blossom, | ||||||
|  |                     [this,dual_fixup](VertexId x) { | ||||||
|  |                         vertex_dual[x] += dual_fixup; | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         for (BlossomT& blossom : trivial_blossom) { | ||||||
|  |             cleanup_blossom(&blossom); | ||||||
|  |         } | ||||||
|  |         for (BlossomT& blossom : nontrivial_blossom) { | ||||||
|  |             cleanup_blossom(&blossom); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // TODO -- check delta2_queue empty
 | ||||||
|  |         assert(delta3_queue.empty()); | ||||||
|  |         // TODO -- check delta4_queue empty
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** Run the matching algorithm. */ |     /** Run the matching algorithm. */ | ||||||
|     void run() |     void run() | ||||||
|     { |     { | ||||||
|  | @ -1777,6 +1905,9 @@ public: | ||||||
|         // This loop runs through at most (n/2 + 1) iterations.
 |         // This loop runs through at most (n/2 + 1) iterations.
 | ||||||
|         // Each iteration takes time O(n**2).
 |         // Each iteration takes time O(n**2).
 | ||||||
|         while (run_stage()) ; |         while (run_stage()) ; | ||||||
|  | 
 | ||||||
|  |         // Clean up and unwind lazy updates to dual variables.
 | ||||||
|  |         cleanup(); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue