Minor cleanup in scanning and delta steps
This commit is contained in:
parent
f35a640e43
commit
0e76e6472b
|
@ -1078,7 +1078,7 @@ class _MatchingContext:
|
|||
Marks the blossoms as unlabeled.
|
||||
Updates delta tracking accordingly.
|
||||
|
||||
This function takes time O((n+m) * log(n)).
|
||||
This function takes time O((n + m) * log(n)).
|
||||
"""
|
||||
for blossom in tree_blossoms:
|
||||
assert blossom.label != _LABEL_NONE
|
||||
|
@ -1098,9 +1098,9 @@ class _MatchingContext:
|
|||
discovers an augmenting path. In this case it returns an alternating
|
||||
path that starts and ends in an unmatched vertex.
|
||||
|
||||
This function takes time O(k*log(n)) to discover a blossom,
|
||||
This function takes time O(k * log(n)) to discover a blossom,
|
||||
where "k" is the number of sub-blossoms,
|
||||
or time O(n*log(n)) to discover an augmenting path.
|
||||
or time O(n * log(n)) to discover an augmenting path.
|
||||
|
||||
Returns:
|
||||
Alternating path as an ordered list of edges between top-level
|
||||
|
@ -1180,7 +1180,7 @@ class _MatchingContext:
|
|||
Assign label S to the new blossom.
|
||||
Relabel all T-sub-blossoms as S and add their vertices to the queue.
|
||||
|
||||
This function takes total time O(n*log(n)) per stage.
|
||||
This function takes total time O(n * log(n)) per stage.
|
||||
"""
|
||||
|
||||
# Check that the path is odd-length.
|
||||
|
@ -1635,14 +1635,22 @@ class _MatchingContext:
|
|||
|
||||
return True
|
||||
|
||||
def substage_scan(self) -> None:
|
||||
"""Scan queued S-vertices and consider their incident edges.
|
||||
def scan_new_s_vertices(self) -> None:
|
||||
"""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
|
||||
tree or find blossoms or augmenting paths, even if the edges
|
||||
are tight. An edge that is already tight may be used later through
|
||||
a zero-delta step.
|
||||
are tight. If there are such tight edges, they will be used later
|
||||
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
|
||||
|
@ -1688,7 +1696,7 @@ class _MatchingContext:
|
|||
# Delta steps:
|
||||
#
|
||||
|
||||
def substage_calc_dual_delta(
|
||||
def calc_dual_delta_step(
|
||||
self
|
||||
) -> tuple[int, float, int, Optional[_NonTrivialBlossom]]:
|
||||
"""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
|
||||
weights are integers.
|
||||
|
||||
This function assumes that there is at least one S-vertex.
|
||||
This function takes total time O(m * log(n)) for all calls
|
||||
within a stage.
|
||||
This function takes time O((1 + k) * log(n)),
|
||||
where "k" is the number of intra-blossom edges removed from
|
||||
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:
|
||||
Tuple (delta_type, delta_2x, delta_edge, delta_blossom).
|
||||
|
@ -1788,12 +1800,6 @@ class _MatchingContext:
|
|||
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".
|
||||
# The substage tries to find an augmenting path.
|
||||
# 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
|
||||
|
||||
# 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.
|
||||
(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.
|
||||
# This implicitly updates the dual variables as needed, because
|
||||
|
|
|
@ -24,22 +24,22 @@ def patch_matching_code() -> None:
|
|||
import mwmatching
|
||||
|
||||
orig_make_blossom = mwmatching._MatchingContext.make_blossom
|
||||
orig_substage_calc_dual_delta = (
|
||||
mwmatching._MatchingContext.substage_calc_dual_delta)
|
||||
orig_calc_dual_delta_step = (
|
||||
mwmatching._MatchingContext.calc_dual_delta_step)
|
||||
|
||||
def stub_make_blossom(*args: Any, **kwargs: Any) -> Any:
|
||||
count_make_blossom[0] += 1
|
||||
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
|
||||
ret = orig_substage_calc_dual_delta(*args, **kwargs)
|
||||
ret = orig_calc_dual_delta_step(*args, **kwargs)
|
||||
return ret
|
||||
|
||||
mwmatching._MatchingContext.make_blossom = ( # type: ignore
|
||||
stub_make_blossom)
|
||||
mwmatching._MatchingContext.substage_calc_dual_delta = ( # type: ignore
|
||||
stub_substage_calc_dual_delta)
|
||||
mwmatching._MatchingContext.calc_dual_delta_step = ( # type: ignore
|
||||
stub_calc_dual_delta_step)
|
||||
|
||||
|
||||
def run_max_weight_matching(
|
||||
|
|
Loading…
Reference in New Issue