1
0
Fork 0

Minor cleanup in scanning and delta steps

This commit is contained in:
Joris van Rantwijk 2024-06-30 16:13:40 +02:00
parent f35a640e43
commit 0e76e6472b
2 changed files with 33 additions and 27 deletions

View File

@ -1635,14 +1635,22 @@ class _MatchingContext:
return True return True
def substage_scan(self) -> None: def scan_new_s_vertices(self) -> None:
"""Scan queued S-vertices and consider their incident edges. """Scan the incident edges of newly labeled S-vertices.
Edges are added to delta2 tracking or delta3 tracking depending
on the state of the vertex on the opposite side of the edge.
Edges are inserted in delta2 and delta3 tracking.
This function does not yet use the edges to extend the alternating This function does not yet use the edges to extend the alternating
tree or find blossoms or augmenting paths, even if the edges tree or find blossoms or augmenting paths, even if the edges
are tight. An edge that is already tight may be used later through are tight. If there are such tight edges, they will be used later
a zero-delta step. through zero-delta steps.
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.
""" """
edges = self.graph.edges edges = self.graph.edges
@ -1688,7 +1696,7 @@ class _MatchingContext:
# Delta steps: # Delta steps:
# #
def substage_calc_dual_delta( def calc_dual_delta_step(
self self
) -> tuple[int, float, int, Optional[_NonTrivialBlossom]]: ) -> tuple[int, float, int, Optional[_NonTrivialBlossom]]:
"""Calculate a delta step in the dual LPP problem. """Calculate a delta step in the dual LPP problem.
@ -1701,9 +1709,13 @@ class _MatchingContext:
Multiplication by 2 ensures that the result is an integer if all edge Multiplication by 2 ensures that the result is an integer if all edge
weights are integers. weights are integers.
This function assumes that there is at least one S-vertex. This function takes time O((1 + k) * log(n)),
This function takes total time O(m * log(n)) for all calls where "k" is the number of intra-blossom edges removed from
within a stage. the delta3 queue.
Since each edge can be inserted into the delta3 queue at most
once per stage, this function takes total time O((n + m) * log(n))
per stage.
Returns: Returns:
Tuple (delta_type, delta_2x, delta_edge, delta_blossom). Tuple (delta_type, delta_2x, delta_edge, delta_blossom).
@ -1788,12 +1800,6 @@ class _MatchingContext:
False if no further improvement is possible. False if no further improvement is possible.
""" """
# 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 all(y >= 0 for y in self.vertex_mate):
return False
# Each pass through the following loop is a "substage". # Each pass through the following loop is a "substage".
# The substage tries to find an augmenting path. # The substage tries to find an augmenting path.
# If an augmenting path is found, we augment the matching and end # If an augmenting path is found, we augment the matching and end
@ -1806,11 +1812,11 @@ class _MatchingContext:
self._check_alternating_tree_consistency() # TODO -- remove this self._check_alternating_tree_consistency() # TODO -- remove this
# Consider the incident edges of newly labeled S-vertices. # Consider the incident edges of newly labeled S-vertices.
self.substage_scan() self.scan_new_s_vertices()
# Calculate delta step in the dual LPP problem. # Calculate delta step in the dual LPP problem.
(delta_type, delta_2x, delta_edge, delta_blossom (delta_type, delta_2x, delta_edge, delta_blossom
) = self.substage_calc_dual_delta() ) = self.calc_dual_delta_step()
# Update the running sum of delta steps. # Update the running sum of delta steps.
# This implicitly updates the dual variables as needed, because # This implicitly updates the dual variables as needed, because

View File

@ -24,22 +24,22 @@ def patch_matching_code() -> None:
import mwmatching import mwmatching
orig_make_blossom = mwmatching._MatchingContext.make_blossom orig_make_blossom = mwmatching._MatchingContext.make_blossom
orig_substage_calc_dual_delta = ( orig_calc_dual_delta_step = (
mwmatching._MatchingContext.substage_calc_dual_delta) mwmatching._MatchingContext.calc_dual_delta_step)
def stub_make_blossom(*args: Any, **kwargs: Any) -> Any: def stub_make_blossom(*args: Any, **kwargs: Any) -> Any:
count_make_blossom[0] += 1 count_make_blossom[0] += 1
return orig_make_blossom(*args, **kwargs) return orig_make_blossom(*args, **kwargs)
def stub_substage_calc_dual_delta(*args: Any, **kwargs: Any) -> Any: def stub_calc_dual_delta_step(*args: Any, **kwargs: Any) -> Any:
count_delta_step[0] += 1 count_delta_step[0] += 1
ret = orig_substage_calc_dual_delta(*args, **kwargs) ret = orig_calc_dual_delta_step(*args, **kwargs)
return ret return ret
mwmatching._MatchingContext.make_blossom = ( # type: ignore mwmatching._MatchingContext.make_blossom = ( # type: ignore
stub_make_blossom) stub_make_blossom)
mwmatching._MatchingContext.substage_calc_dual_delta = ( # type: ignore mwmatching._MatchingContext.calc_dual_delta_step = ( # type: ignore
stub_substage_calc_dual_delta) stub_calc_dual_delta_step)
def run_max_weight_matching( def run_max_weight_matching(