Maintain concatenable queue for each blossom
This commit is contained in:
		
							parent
							
								
									5b5c107a5c
								
							
						
					
					
						commit
						22251e64e8
					
				
							
								
								
									
										107
									
								
								cpp/mwmatching.h
								
								
								
								
							
							
						
						
									
										107
									
								
								cpp/mwmatching.h
								
								
								
								
							|  | @ -320,7 +320,8 @@ struct Blossom | ||||||
| 
 | 
 | ||||||
|     // TODO -- tree_blossoms
 |     // TODO -- tree_blossoms
 | ||||||
| 
 | 
 | ||||||
|     // TOOD -- vertex_queue
 |     /** Concatenable queue containing all vertices in the blossom. */ | ||||||
|  |     ConcatenableQueue<WeightType, Blossom*, EdgeId> vertex_queue; | ||||||
| 
 | 
 | ||||||
|     // TODO -- delta2_node
 |     // TODO -- delta2_node
 | ||||||
| 
 | 
 | ||||||
|  | @ -337,13 +338,14 @@ 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), | ||||||
|  |         vertex_queue(this), | ||||||
|         vertex_dual_offset(0) |         vertex_dual_offset(0) | ||||||
|     { } |     { } | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     /** Initialize a trivial (single-vertex) blossom. */ |     /** Initialize a trivial (single-vertex) blossom. */ | ||||||
|     explicit Blossom(VertexId base_vertex) |     explicit Blossom(VertexId x = NO_VERTEX) | ||||||
|       : Blossom(base_vertex, false) |       : Blossom(x, false) | ||||||
|     { } |     { } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -584,18 +586,6 @@ public: | ||||||
| // NOTE - this MUST be a list, because we delete items from it while keeping pointers to other items
 | // NOTE - this MUST be a list, because we delete items from it while keeping pointers to other items
 | ||||||
|     std::list<NonTrivialBlossomT> nontrivial_blossom; |     std::list<NonTrivialBlossomT> nontrivial_blossom; | ||||||
| 
 | 
 | ||||||
|     // TODO -- vertex_queue_node
 |  | ||||||
| 
 |  | ||||||
| // TODO -- remove
 |  | ||||||
|     /**
 |  | ||||||
|      * Every vertex is contained in exactly one top-level blossom |  | ||||||
|      * (possibly the trivial blossom that contains just that vertex). |  | ||||||
|      * |  | ||||||
|      * "vertex_top_blossom[x]" is the top-level blossom that contains |  | ||||||
|      * vertex "x". |  | ||||||
|      */ |  | ||||||
|     std::vector<BlossomT*> vertex_top_blossom; |  | ||||||
| 
 |  | ||||||
|     /**
 |     /**
 | ||||||
|      * Modified dual variable of each vertex. |      * Modified dual variable of each vertex. | ||||||
|      * |      * | ||||||
|  | @ -627,6 +617,10 @@ public: | ||||||
|     /** Running sum of applied delta steps. */ |     /** Running sum of applied delta steps. */ | ||||||
|     WeightType delta_sum; |     WeightType delta_sum; | ||||||
| 
 | 
 | ||||||
|  |     /** For each vertex, a node in its top-level blossom. */ | ||||||
|  |     typedef ConcatenableQueue<WeightType, BlossomT*, EdgeId> VertexQueue; | ||||||
|  |     std::vector<typename VertexQueue::Node> vertex_queue_node; | ||||||
|  | 
 | ||||||
|     // TODO -- delta2_queue
 |     // TODO -- delta2_queue
 | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -673,21 +667,22 @@ public: | ||||||
|      */ |      */ | ||||||
|     explicit MatchingContext(const std::vector<EdgeT>& edges_in) |     explicit MatchingContext(const std::vector<EdgeT>& edges_in) | ||||||
|       : graph(edges_in), |       : graph(edges_in), | ||||||
|  |         trivial_blossom(graph.num_vertex), | ||||||
|  |         vertex_queue_node(graph.num_vertex), | ||||||
|         delta3_node(edges_in.size()) |         delta3_node(edges_in.size()) | ||||||
|     { |     { | ||||||
|         // Initially all vertices are unmatched.
 |         // Initially all vertices are unmatched.
 | ||||||
|         vertex_mate.resize(graph.num_vertex, NO_VERTEX); |         vertex_mate.resize(graph.num_vertex, NO_VERTEX); | ||||||
| 
 | 
 | ||||||
|         // Create a trivial blossom for each vertex.
 |         // Initialize a trivial blossom for each vertex.
 | ||||||
|         trivial_blossom.reserve(graph.num_vertex); |  | ||||||
|         for (VertexId x = 0; x < graph.num_vertex; ++x) { |         for (VertexId x = 0; x < graph.num_vertex; ++x) { | ||||||
|             trivial_blossom.emplace_back(x); |             trivial_blossom[x].base_vertex = x; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Initially all vertices are trivial top-level blossoms.
 |         // Insert each vertex as the only element in its own blossom.
 | ||||||
|         vertex_top_blossom.reserve(graph.num_vertex); |  | ||||||
|         for (VertexId x = 0; x < graph.num_vertex; ++x) { |         for (VertexId x = 0; x < graph.num_vertex; ++x) { | ||||||
|             vertex_top_blossom.push_back(&trivial_blossom[x]); |             trivial_blossom[x].vertex_queue.insert( | ||||||
|  |                 &vertex_queue_node[x], 0, x); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Vertex duals are initialized to half the maximum edge weight.
 |         // Vertex duals are initialized to half the maximum edge weight.
 | ||||||
|  | @ -721,8 +716,7 @@ public: | ||||||
|      */ |      */ | ||||||
|     BlossomT* top_level_blossom(VertexId x) const |     BlossomT* top_level_blossom(VertexId x) const | ||||||
|     { |     { | ||||||
|         // TODO
 |         return vertex_queue_node[x].find(); | ||||||
|         return vertex_top_blossom[x]; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* **********  Least slack edge tracking:  ********** */ |     /* **********  Least slack edge tracking:  ********** */ | ||||||
|  | @ -818,7 +812,7 @@ public: | ||||||
|         WeightType best_slack = 0; |         WeightType best_slack = 0; | ||||||
| 
 | 
 | ||||||
|         for (VertexId x = 0; x < graph.num_vertex; ++x) { |         for (VertexId x = 0; x < graph.num_vertex; ++x) { | ||||||
|             if (vertex_top_blossom[x]->label == LABEL_NONE) { |             if (top_level_blossom(x)->label == LABEL_NONE) { | ||||||
|                 const EdgeT* edge = vertex_best_edge[x]; |                 const EdgeT* edge = vertex_best_edge[x]; | ||||||
|                 if (edge != nullptr) { |                 if (edge != nullptr) { | ||||||
|                     WeightType slack = edge_slack(*edge); |                     WeightType slack = edge_slack(*edge); | ||||||
|  | @ -1095,13 +1089,12 @@ public: | ||||||
|      * discovers an augmenting path. In this case it returns an alternating |      * discovers an augmenting path. In this case it returns an alternating | ||||||
|      * path that starts and ends in an unmatched vertex. |      * path that starts and ends in an unmatched vertex. | ||||||
|      * |      * | ||||||
|      * This function takes time O(k) to discover a blossom, where "k" is the |      * This function takes time O(k * log(n)) to discover a blossom, | ||||||
|      * number of sub-blossoms, or time O(n) to discover an augmenting path. |      * where "k" is the number of sub-blossoms, | ||||||
|  |      * or time O(n * log(n)) to discover an augmenting path. | ||||||
|      */ |      */ | ||||||
|     AlternatingPath trace_alternating_paths(VertexId x, VertexId y) |     AlternatingPath trace_alternating_paths(VertexId x, VertexId y) | ||||||
|     { |     { | ||||||
|         assert(vertex_top_blossom[x] != vertex_top_blossom[y]); |  | ||||||
| 
 |  | ||||||
|         // Initialize a path containing only the edge (x, y).
 |         // Initialize a path containing only the edge (x, y).
 | ||||||
|         AlternatingPath path; |         AlternatingPath path; | ||||||
|         path.edges.emplace_back(x, y); |         path.edges.emplace_back(x, y); | ||||||
|  | @ -1120,7 +1113,7 @@ public: | ||||||
|             if (x != NO_VERTEX) { |             if (x != NO_VERTEX) { | ||||||
| 
 | 
 | ||||||
|                 // Stop if we found a common ancestor.
 |                 // Stop if we found a common ancestor.
 | ||||||
|                 BlossomT* bx = vertex_top_blossom[x]; |                 BlossomT* bx = top_level_blossom(x); | ||||||
|                 if (vertex_marker[bx->base_vertex]) { |                 if (vertex_marker[bx->base_vertex]) { | ||||||
|                     first_common = bx; |                     first_common = bx; | ||||||
|                     break; |                     break; | ||||||
|  | @ -1141,7 +1134,7 @@ public: | ||||||
|             if (y != NO_VERTEX) { |             if (y != NO_VERTEX) { | ||||||
| 
 | 
 | ||||||
|                 // Stop if we found a common ancestor.
 |                 // Stop if we found a common ancestor.
 | ||||||
|                 BlossomT* by = vertex_top_blossom[y]; |                 BlossomT* by = top_level_blossom(y); | ||||||
|                 if (vertex_marker[by->base_vertex]) { |                 if (vertex_marker[by->base_vertex]) { | ||||||
|                     first_common = by; |                     first_common = by; | ||||||
|                     break; |                     break; | ||||||
|  | @ -1168,11 +1161,11 @@ public: | ||||||
|         // If we found a common ancestor, trim the paths so they end there.
 |         // If we found a common ancestor, trim the paths so they end there.
 | ||||||
|         if (first_common) { |         if (first_common) { | ||||||
|             assert(first_common->label == LABEL_S); |             assert(first_common->label == LABEL_S); | ||||||
|             while (vertex_top_blossom[path.edges.front().first] |             while (top_level_blossom(path.edges.front().first) | ||||||
|                    != first_common) { |                    != first_common) { | ||||||
|                 path.edges.pop_front(); |                 path.edges.pop_front(); | ||||||
|             } |             } | ||||||
|             while (vertex_top_blossom[path.edges.back().second] |             while (top_level_blossom(path.edges.back().second) | ||||||
|                    != first_common) { |                    != first_common) { | ||||||
|                 path.edges.pop_back(); |                 path.edges.pop_back(); | ||||||
|             } |             } | ||||||
|  | @ -1190,7 +1183,7 @@ public: | ||||||
|      * Assign label S to the new blossom. |      * Assign label S to the new blossom. | ||||||
|      * Relabel all T-sub-blossoms as S and add their vertices to the queue. |      * Relabel all T-sub-blossoms as S and add their vertices to the queue. | ||||||
|      * |      * | ||||||
|      * This function takes total time O(n**2) per stage. |      * This function takes total time O((n + m) * log(n)) per stage. | ||||||
|      */ |      */ | ||||||
|     void make_blossom(const AlternatingPath& path) |     void make_blossom(const AlternatingPath& path) | ||||||
|     { |     { | ||||||
|  | @ -1201,14 +1194,14 @@ public: | ||||||
|         std::vector<BlossomT*> subblossoms; |         std::vector<BlossomT*> subblossoms; | ||||||
|         subblossoms.reserve(path.edges.size()); |         subblossoms.reserve(path.edges.size()); | ||||||
|         for (VertexPair edge : path.edges) { |         for (VertexPair edge : path.edges) { | ||||||
|             subblossoms.push_back(vertex_top_blossom[edge.first]); |             subblossoms.push_back(top_level_blossom(edge.first)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Check that the path is cyclic.
 |         // Check that the path is cyclic.
 | ||||||
|         VertexId pos = 0; |         VertexId pos = 0; | ||||||
|         for (VertexPair edge : path.edges) { |         for (VertexPair edge : path.edges) { | ||||||
|             pos = (pos + 1) % subblossoms.size(); |             pos = (pos + 1) % subblossoms.size(); | ||||||
|             assert(vertex_top_blossom[edge.second] == subblossoms[pos]); |             assert(top_level_blossom(edge.second) == subblossoms[pos]); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Blossom must start and end with an S-blossom.
 |         // Blossom must start and end with an S-blossom.
 | ||||||
|  | @ -1238,10 +1231,13 @@ public: | ||||||
|             sub->parent = blossom; |             sub->parent = blossom; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Mark vertices as belonging to the new blossom.
 |         // Merge concatenable queues.
 | ||||||
|         for_vertices_in_blossom(blossom, [this,blossom](VertexId x) { | // TODO -- avoid temporary array
 | ||||||
|             vertex_top_blossom[x] = blossom; |         std::vector<VertexQueue*> subqueues; | ||||||
|         }); |         for (BlossomT* sub : subblossoms) { | ||||||
|  |             subqueues.push_back(&sub->vertex_queue); | ||||||
|  |         } | ||||||
|  |         blossom->vertex_queue.merge(subqueues.begin(), subqueues.end()); | ||||||
| 
 | 
 | ||||||
|         // 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.
 | ||||||
|         blossom->label = LABEL_S; |         blossom->label = LABEL_S; | ||||||
|  | @ -1271,6 +1267,10 @@ public: | ||||||
|         assert(blossom->parent == nullptr); |         assert(blossom->parent == nullptr); | ||||||
|         assert(blossom->label == LABEL_NONE); |         assert(blossom->label == LABEL_NONE); | ||||||
| 
 | 
 | ||||||
|  |         // Split concatenable queue, thus reconstructing the separate
 | ||||||
|  |         // concatenable queues of the sub-blossoms.
 | ||||||
|  |         blossom->vertex_queue.split(); | ||||||
|  | 
 | ||||||
|         // Prepare to push pending delta updates down to the sub-blossoms.
 |         // Prepare to push pending delta updates down to the sub-blossoms.
 | ||||||
|         WeightType vertex_dual_offset = blossom->vertex_dual_offset; |         WeightType vertex_dual_offset = blossom->vertex_dual_offset; | ||||||
|         blossom->vertex_dual_offset = 0; |         blossom->vertex_dual_offset = 0; | ||||||
|  | @ -1281,10 +1281,6 @@ public: | ||||||
|             assert(sub_blossom->parent == blossom); |             assert(sub_blossom->parent == blossom); | ||||||
|             assert(sub_blossom->label == LABEL_NONE); |             assert(sub_blossom->label == LABEL_NONE); | ||||||
|             sub_blossom->parent = nullptr; |             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.
 |             // Push pending delta updates to sub-blossom.
 | ||||||
|             assert(sub_blossom->vertex_dual_offset == 0); |             assert(sub_blossom->vertex_dual_offset == 0); | ||||||
|  | @ -1326,7 +1322,7 @@ public: | ||||||
| 
 | 
 | ||||||
|         // Find the sub-blossom that was attached to the parent node
 |         // Find the sub-blossom that was attached to the parent node
 | ||||||
|         // in the alternating tree.
 |         // in the alternating tree.
 | ||||||
|         BlossomT* entry = vertex_top_blossom[blossom->tree_edge.second]; |         BlossomT* entry = top_level_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.
 | ||||||
|         assign_blossom_label_t(entry); |         assign_blossom_label_t(entry); | ||||||
|  | @ -1469,8 +1465,6 @@ public: | ||||||
|      * from sub-blossom "entry" to the base vertex of the blossom. |      * from sub-blossom "entry" to the base vertex of the blossom. | ||||||
|      * |      * | ||||||
|      * Recursively handle sub-blossoms as needed. |      * Recursively handle sub-blossoms as needed. | ||||||
|      * |  | ||||||
|      * This function takes time O(n). |  | ||||||
|      */ |      */ | ||||||
|     void augment_blossom(NonTrivialBlossomT* blossom, BlossomT* entry) |     void augment_blossom(NonTrivialBlossomT* blossom, BlossomT* entry) | ||||||
|     { |     { | ||||||
|  | @ -1505,14 +1499,18 @@ public: | ||||||
|     /**
 |     /**
 | ||||||
|      * Augment the matching through the specified augmenting path. |      * Augment the matching through the specified augmenting path. | ||||||
|      * |      * | ||||||
|      * This function takes time O(n). |      * This function takes time O(n * log(n)). | ||||||
|      */ |      */ | ||||||
|     void augment_matching(const AlternatingPath& path) |     void augment_matching(const AlternatingPath& path) | ||||||
|     { |     { | ||||||
|         // Check that the path starts and ends in an unmatched blossom.
 |         // Check that the path starts and ends in an unmatched blossom.
 | ||||||
|         assert(path.edges.size() % 2 == 1); |         assert(path.edges.size() % 2 == 1); | ||||||
|         assert(vertex_mate[vertex_top_blossom[path.edges.front().first]->base_vertex] == NO_VERTEX); |         assert(vertex_mate[ | ||||||
|         assert(vertex_mate[vertex_top_blossom[path.edges.back().second]->base_vertex] == NO_VERTEX); |             top_level_blossom(path.edges.front().first)->base_vertex] | ||||||
|  |             == NO_VERTEX); | ||||||
|  |         assert(vertex_mate[ | ||||||
|  |             top_level_blossom(path.edges.back().second)->base_vertex] | ||||||
|  |             == NO_VERTEX); | ||||||
| 
 | 
 | ||||||
|         // Process the unmatched edges on the augmenting path.
 |         // Process the unmatched edges on the augmenting path.
 | ||||||
|         auto edge_it = path.edges.begin(); |         auto edge_it = path.edges.begin(); | ||||||
|  | @ -1522,13 +1520,13 @@ public: | ||||||
|             VertexId y = edge_it->second; |             VertexId y = edge_it->second; | ||||||
| 
 | 
 | ||||||
|             // Augment any non-trivial blossoms that touch this edge.
 |             // Augment any non-trivial blossoms that touch this edge.
 | ||||||
|             BlossomT* bx = vertex_top_blossom[x]; |             BlossomT* bx = top_level_blossom(x); | ||||||
|             NonTrivialBlossomT* bx_ntb = bx->nontrivial(); |             NonTrivialBlossomT* bx_ntb = bx->nontrivial(); | ||||||
|             if (bx_ntb != nullptr) { |             if (bx_ntb != nullptr) { | ||||||
|                 augment_blossom(bx_ntb, &trivial_blossom[x]); |                 augment_blossom(bx_ntb, &trivial_blossom[x]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             BlossomT* by = vertex_top_blossom[y]; |             BlossomT* by = top_level_blossom(y); | ||||||
|             NonTrivialBlossomT* by_ntb = by->nontrivial(); |             NonTrivialBlossomT* by_ntb = by->nontrivial(); | ||||||
|             if (by_ntb != nullptr) { |             if (by_ntb != nullptr) { | ||||||
|                 augment_blossom(by_ntb, &trivial_blossom[y]); |                 augment_blossom(by_ntb, &trivial_blossom[y]); | ||||||
|  | @ -1557,8 +1555,6 @@ public: | ||||||
|      * via its matched edge. All vertices in the newly labeled S-blossom |      * via its matched edge. All vertices in the newly labeled S-blossom | ||||||
|      * are added to the scan queue. |      * 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. |      * @pre "x" is an unlabeled vertex. | ||||||
|      * @pre "x" is matched to a T-vertex via a tight edge. |      * @pre "x" is matched to a T-vertex via a tight edge. | ||||||
|      */ |      */ | ||||||
|  | @ -1658,9 +1654,10 @@ public: | ||||||
|         // Otherwise the path is an augmenting path.
 |         // Otherwise the path is an augmenting path.
 | ||||||
|         // Note that an alternating starts and ends in the same blossom,
 |         // Note that an alternating starts and ends in the same blossom,
 | ||||||
|         // but not necessarily in the same vertex within that blossom.
 |         // but not necessarily in the same vertex within that blossom.
 | ||||||
|  | // TODO -- directly check whether both blossoms are in the same tree
 | ||||||
|         VertexId p = path.edges.front().first; |         VertexId p = path.edges.front().first; | ||||||
|         VertexId q = path.edges.back().second; |         VertexId q = path.edges.back().second; | ||||||
|         if (vertex_top_blossom[p] == vertex_top_blossom[q]) { |         if (top_level_blossom(p) == top_level_blossom(q)) { | ||||||
|             make_blossom(path); |             make_blossom(path); | ||||||
|             return false; |             return false; | ||||||
|         } else { |         } else { | ||||||
|  | @ -1873,7 +1870,7 @@ public: | ||||||
|                 // unlocked through the delta update.
 |                 // unlocked through the delta update.
 | ||||||
|                 VertexId x = delta.edge.first; |                 VertexId x = delta.edge.first; | ||||||
|                 VertexId y = delta.edge.second; |                 VertexId y = delta.edge.second; | ||||||
|                 if (vertex_top_blossom[x]->label != LABEL_S) { |                 if (top_level_blossom(x)->label != LABEL_S) { | ||||||
|                     std::swap(x, y); |                     std::swap(x, y); | ||||||
|                 } |                 } | ||||||
|                 extend_tree_s_to_t(x, y); |                 extend_tree_s_to_t(x, y); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue