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.
|
Marks the blossoms as unlabeled.
|
||||||
Updates delta tracking accordingly.
|
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:
|
for blossom in tree_blossoms:
|
||||||
assert blossom.label != _LABEL_NONE
|
assert blossom.label != _LABEL_NONE
|
||||||
|
@ -1098,9 +1098,9 @@ class _MatchingContext:
|
||||||
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*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,
|
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:
|
Returns:
|
||||||
Alternating path as an ordered list of edges between top-level
|
Alternating path as an ordered list of edges between top-level
|
||||||
|
@ -1180,7 +1180,7 @@ class _MatchingContext:
|
||||||
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*log(n)) per stage.
|
This function takes total time O(n * log(n)) per stage.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Check that the path is odd-length.
|
# Check that the path is odd-length.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue