Lazy delta updates of S-blossom duals
This commit is contained in:
		
							parent
							
								
									de03796d99
								
							
						
					
					
						commit
						b2e055b357
					
				|  | @ -444,7 +444,13 @@ class _NonTrivialBlossom(_Blossom): | |||
| 
 | ||||
|         # Every non-trivial blossom has a variable in the dual LPP. | ||||
|         # | ||||
|         # If this is a top-level S-blossom, | ||||
|         # "dual_var" is the value of the dual variable minus 2 times | ||||
|         # the running sum of delta steps. | ||||
|         # | ||||
|         # In all other cases, | ||||
|         # "dual_var" is the current value of the dual variable. | ||||
|         # | ||||
|         # New blossoms start with dual variable 0. | ||||
|         self.dual_var: float = 0 | ||||
| 
 | ||||
|  | @ -542,7 +548,7 @@ class _MatchingContext: | |||
|         # | ||||
|         # For an S-vertex "x", | ||||
|         # "vertex_dual_2x[x]" is 2 times the dual variable of vertex "x" | ||||
|         # plus two times the running sum of delta updates. | ||||
|         # plus two times the running sum of delta steps. | ||||
|         # | ||||
|         # For a T-vertex "x", ... TODO | ||||
|         self.vertex_dual_2x: list[float] | ||||
|  | @ -553,13 +559,13 @@ class _MatchingContext: | |||
| 
 | ||||
|         # Queue containing edges between S-vertices in different top-level | ||||
|         # blossoms. The priority of an edge is its slack plus two times the | ||||
|         # running sum of delta updates. | ||||
|         # running sum of delta steps. | ||||
|         self.delta3_queue: PriorityQueue[int] = PriorityQueue() | ||||
|         self.delta3_set: set[int] = set() | ||||
| 
 | ||||
|         # Queue containing top-level non-trivial T-blossoms. | ||||
|         # The priority of a blossom is its dual plus two times the running | ||||
|         # sum of delta updates. | ||||
|         # sum of delta steps. | ||||
|         self.delta4_queue: PriorityQueue[_NonTrivialBlossom] = PriorityQueue() | ||||
| 
 | ||||
|         # For each T-vertex or unlabeled vertex "x", | ||||
|  | @ -677,34 +683,36 @@ class _MatchingContext: | |||
|     # | ||||
| 
 | ||||
|     def assign_blossom_label_s(self, blossom: _Blossom) -> None: | ||||
|         """Assign label S to an unlabeled top-level blossom. | ||||
| 
 | ||||
|         All vertices in the newly labeled blossom are added to the scan queue. | ||||
|         Dual variables are adjusted. | ||||
|         """ | ||||
| 
 | ||||
|         """Assign label S to an unlabeled top-level blossom.""" | ||||
|         assert blossom.parent is None | ||||
|         assert blossom.label == _LABEL_NONE | ||||
| 
 | ||||
|         # Assign label S. | ||||
|         blossom.label = _LABEL_S | ||||
| 
 | ||||
|         if isinstance(blossom, _NonTrivialBlossom): | ||||
|             blossom.dual_var -= self.delta_sum_2x | ||||
| 
 | ||||
|     def remove_blossom_label_s(self, blossom: _Blossom) -> None: | ||||
|         """Remove label S from a top-level S-blossom.""" | ||||
|         assert blossom.parent is None | ||||
|         assert blossom.label == _LABEL_S | ||||
|         blossom.label = _LABEL_NONE | ||||
| 
 | ||||
|         if isinstance(blossom, _NonTrivialBlossom): | ||||
|             blossom.dual_var += self.delta_sum_2x | ||||
| 
 | ||||
|     def assign_vertex_label_s(self, blossom: _Blossom) -> None: | ||||
|         """Adjust after assigning label S to previously unlabeled vertices.""" | ||||
| 
 | ||||
|         # Adjust the vertex dual variables of the new S-vertices. | ||||
|         vertices = blossom.vertices() | ||||
|         for x in vertices: | ||||
|             self.vertex_dual_2x[x] += self.delta_sum_2x | ||||
| 
 | ||||
|         # Add all vertices inside the newly labeled S-blossom to the queue. | ||||
|         # Add the new S-vertices to the scan queue. | ||||
|         self.scan_queue.extend(vertices) | ||||
| 
 | ||||
|     def remove_blossom_label_s(self, blossom: _Blossom) -> None: | ||||
|         """Remove label S from a top-level S-blossom.""" | ||||
| 
 | ||||
|         assert blossom.parent is None | ||||
|         assert blossom.label == _LABEL_S | ||||
| 
 | ||||
|         # Remove label. | ||||
|         blossom.label = _LABEL_NONE | ||||
|     def remove_vertex_label_s(self, blossom: _Blossom) -> None: | ||||
|         """Adjust after removing labels from S-vertices.""" | ||||
| 
 | ||||
|         # Adjust the vertex dual variables of the former S-vertices. | ||||
|         for x in blossom.vertices(): | ||||
|  | @ -751,12 +759,11 @@ class _MatchingContext: | |||
| 
 | ||||
|         # Remove blossom labels. | ||||
|         for blossom in self.trivial_blossom + self.nontrivial_blossom: | ||||
|             if blossom.parent is None: | ||||
|                 if blossom.label == _LABEL_S: | ||||
|                     self.remove_blossom_label_s(blossom) | ||||
|                 elif blossom.label == _LABEL_T: | ||||
|                     self.remove_blossom_label_t(blossom) | ||||
|             blossom.label = _LABEL_NONE | ||||
|             if blossom.label == _LABEL_S: | ||||
|                 self.remove_blossom_label_s(blossom) | ||||
|                 self.remove_vertex_label_s(blossom) | ||||
|             elif blossom.label == _LABEL_T: | ||||
|                 self.remove_blossom_label_t(blossom) | ||||
|             blossom.tree_edge = None | ||||
| 
 | ||||
|         # Clear the scan queue. | ||||
|  | @ -881,18 +888,20 @@ class _MatchingContext: | |||
|         # Blossom must start and end with an S-sub-blossom. | ||||
|         assert subblossoms[0].label == _LABEL_S | ||||
| 
 | ||||
|         # Relabel the T-sub-blossoms to S-sub-blossoms. | ||||
|         # This also adds new S-vertices to the scan queue. | ||||
|         # Remove blossom labels. | ||||
|         # Mark vertices inside former T-blossoms as S-vertices. | ||||
|         for sub in subblossoms: | ||||
|             if sub.label == _LABEL_T: | ||||
|             if sub.label == _LABEL_S: | ||||
|                 self.remove_blossom_label_s(sub) | ||||
|             elif sub.label == _LABEL_T: | ||||
|                 self.remove_blossom_label_t(sub) | ||||
|                 self.assign_blossom_label_s(sub) | ||||
|                 self.assign_vertex_label_s(sub) | ||||
| 
 | ||||
|         # Create the new blossom object. | ||||
|         blossom = _NonTrivialBlossom(subblossoms, path.edges) | ||||
| 
 | ||||
|         # Assign label S to the new blossom and link it to the tree. | ||||
|         blossom.label = _LABEL_S | ||||
|         self.assign_blossom_label_s(blossom) | ||||
|         blossom.tree_edge = subblossoms[0].tree_edge | ||||
| 
 | ||||
|         # Insert into the blossom array. | ||||
|  | @ -1185,6 +1194,7 @@ class _MatchingContext: | |||
|         # Assign label S to the blossom that contains vertex "x". | ||||
|         bx = self.vertex_top_blossom[x] | ||||
|         self.assign_blossom_label_s(bx) | ||||
|         self.assign_vertex_label_s(bx) | ||||
| 
 | ||||
|         y = self.vertex_mate[x] | ||||
|         if y == -1: | ||||
|  | @ -1325,7 +1335,7 @@ class _MatchingContext: | |||
|                 elif ylabel == _LABEL_S: | ||||
|                     # Update tracking of least-slack edges between S-blossoms. | ||||
|                     # Priority is edge slack plus 2 times the running sum of | ||||
|                     # delta updates. | ||||
|                     # delta steps. | ||||
|                     if e not in self.delta3_set: | ||||
|                         if self.graph.integer_weights: | ||||
|                             # If all edge weights are integers, the slack of | ||||
|  | @ -1443,10 +1453,7 @@ class _MatchingContext: | |||
|         for blossom in self.nontrivial_blossom: | ||||
|             if blossom.parent is None: | ||||
|                 blabel = blossom.label | ||||
|                 if blabel == _LABEL_S: | ||||
|                     # S-blossom: add 2*delta to dual variable. | ||||
|                     blossom.dual_var += delta_2x | ||||
|                 elif blabel == _LABEL_T: | ||||
|                 if blabel == _LABEL_T: | ||||
|                     # T-blossom: subtract 2*delta from dual variable. | ||||
|                     blossom.dual_var -= delta_2x | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue