1
0
Fork 0

Simplify slack handling in delta2 tracking

This commit is contained in:
Joris van Rantwijk 2024-05-31 00:24:22 +02:00
parent 9ee26584ab
commit 3a77749425
1 changed files with 25 additions and 25 deletions

View File

@ -613,7 +613,24 @@ class _MatchingContext:
blossom.vertex_set.clear()
del blossom.vertex_set
def edge_slack_2x_info(
def edge_pseudo_slack_2x(self, e: int) -> float:
"""Return 2 times the pseudo-slack of the specified edge.
The pseudo-slack of an edge ignores pending changes to vertex duals.
For an edge between two S-vertices (in different top-level blossoms),
the true slack is the pseudo-slack minus 2 times the running sum
of delta steps.
For an edge between an S-vertex and unlabeled vertex,
the true slack is the pseudo-slack minus the running sum of delta
steps, plus the pending offset of the top-level blossom that contains
the unlabeled vertex.
"""
(x, y, w) = self.graph.edges[e]
return self.vertex_dual_2x[x] + self.vertex_dual_2x[y] - 2 * w
def edge_slack_2x(
self,
x: int,
y: int,
@ -645,13 +662,6 @@ class _MatchingContext:
dual_2x += by.vertex_dual_offset
return dual_2x - 2 * w
def edge_slack_2x(self, e: int) -> float:
"""Return 2 times the slack of the edge with index "e"."""
(x, y, w) = self.graph.edges[e]
bx = self.vertex_set_node[x].find()
by = self.vertex_set_node[y].find()
return self.edge_slack_2x_info(x, y, bx, by, w)
#
# Least-slack edge tracking:
#
@ -689,36 +699,26 @@ class _MatchingContext:
for blossom in self.trivial_blossom + self.nontrivial_blossom:
blossom.delta2_node = None
def lset_add_vertex_edge(
self,
y: int,
by: _Blossom,
e: int,
slack: float
) -> None:
def lset_add_vertex_edge(self, y: int, by: _Blossom, e: int) -> None:
"""Add edge "e" from an S-vertex to unlabeled vertex or T-vertex "y".
This function takes time O(log(n)).
"""
# TODO -- Simplify: We don't need to know the true slack of the edge,
# only the pseudo-slack based on raw vertex duals and weight.
prio = self.edge_pseudo_slack_2x(e)
best_edge = self.vertex_best_edge[y]
if best_edge != -1:
best_slack = self.edge_slack_2x(best_edge)
if slack >= best_slack:
best_prio = self.edge_pseudo_slack_2x(best_edge)
if prio >= best_prio:
return
self.vertex_best_edge[y] = e
(p, q, w) = self.graph.edges[e]
prio = self.vertex_dual_2x[p] + self.vertex_dual_2x[q] - 2 * w
prev_min = by.vertex_set.min_prio()
self.vertex_set_node[y].set_prio(prio)
if (by.label == _LABEL_NONE) and (prio < prev_min):
prio = slack + self.delta_sum_2x
prio += by.vertex_dual_offset
if by.delta2_node is None:
by.delta2_node = self.delta2_queue.insert(prio, by)
elif prio < by.delta2_node.prio:
@ -1476,7 +1476,7 @@ class _MatchingContext:
# Check whether this edge is tight (has zero slack).
# Only tight edges may be part of an alternating tree.
slack = self.edge_slack_2x_info(x, y, bx, by, w)
slack = self.edge_slack_2x(x, y, bx, by, w)
if slack <= 0:
if ylabel == _LABEL_NONE:
# Assign label T to the blossom that contains "y".
@ -1509,7 +1509,7 @@ class _MatchingContext:
# any S-vertex. We do this for T-vertices and unlabeled
# vertices. Edges which already have zero slack are still
# tracked.
self.lset_add_vertex_edge(y, by, e, slack)
self.lset_add_vertex_edge(y, by, e)
# No further S vertices to scan, and no augmenting path found.
return None