Skip to content

Commit a1ea44e

Browse files
axsketiennedeg
andauthored
fix mincut() (#325)
* s-t cut weight should be adj_cost. fixes #324 * mincut(): simplify cutweight computation * improve performance by 20x using dequeue_pair! * _merge_vertex!: use inplace updates saves another 20% runtime * set u to new root in heuristic merge * add comments --------- Co-authored-by: Etienne dg <[email protected]>
1 parent 5878e7b commit a1ea44e

File tree

1 file changed

+14
-21
lines changed

1 file changed

+14
-21
lines changed

src/traversals/maxadjvisit.jl

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ assumed to be 1.
2626
# in which case we'll return immediately.
2727
(nvg > one(U)) || return (Vector{Int8}([1]), zero(T))
2828

29+
# to avoid reallocating lists in fadjlist, we have some already merged vertices
30+
# still appearing in fadjlist. When iterating neighbors, is_merged makes sure we
31+
# don't consider them
2932
is_merged = falses(nvg)
3033
merged_vertices = IntDisjointSets(U(nvg))
3134
graph_size = nvg
@@ -54,7 +57,6 @@ assumed to be 1.
5457

5558
is_processed = falses(nvg)
5659
@inbounds while graph_size > 1
57-
cutweight = zero(T)
5860
is_processed .= false
5961
is_processed[u] = true
6062
# initialize pq
@@ -66,32 +68,23 @@ assumed to be 1.
6668
for v in fadjlist[u]
6769
(is_merged[v] || v == u) && continue
6870
pq[v] = w[u, v]
69-
cutweight += w[u, v]
7071
end
7172
# Minimum cut phase
73+
local cutweight
7274
while true
7375
last_vertex = u
74-
u, adj_cost = first(pq)
75-
dequeue!(pq)
76+
u, cutweight = dequeue_pair!(pq)
7677
isempty(pq) && break
7778
for v in fadjlist[u]
78-
(is_merged[v] || u == v) && continue
79-
# if the target of e is already marked then decrease cutweight
80-
# otherwise, increase it
81-
ew = w[u, v]
82-
if is_processed[v]
83-
cutweight -= ew
84-
else
85-
cutweight += ew
86-
pq[v] += ew
87-
end
79+
(is_processed[v] || is_merged[v] || u == v) && continue
80+
pq[v] += w[u, v]
8881
end
8982
is_processed[u] = true
90-
# adj_cost is a lower bound on the cut separating the two last vertices
91-
# encountered, so if adj_cost >= bestweight, we can already merge these
83+
# cutweight is a lower bound on the cut separating the two last vertices
84+
# encountered, so if cutweight >= bestweight, we can already merge these
9285
# vertices to save one phase.
93-
if adj_cost >= bestweight
94-
_merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, last_vertex)
86+
if cutweight >= bestweight
87+
u = _merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, last_vertex)
9588
graph_size -= 1
9689
end
9790
end
@@ -105,14 +98,14 @@ assumed to be 1.
10598
end
10699

107100
# merge u and last_vertex
108-
root = _merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, last_vertex)
101+
u = _merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, last_vertex)
109102
graph_size -= 1
110-
u = root # we are sure this vertex was not merged, so the next phase start from it
111103
end
112104
return (convert(Vector{Int8}, parities) .+ one(Int8), bestweight)
113105
end
114106

115107
function _merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, v)
108+
# root is kept, non-root is discarded
116109
root = union!(merged_vertices, u, v)
117110
non_root = (root == u) ? v : u
118111
is_merged[non_root] = true
@@ -122,7 +115,7 @@ function _merge_vertex!(merged_vertices, fadjlist, is_merged, w, u, v)
122115
w[v2, root] = w[root, v2]
123116
end
124117
# update neighbors
125-
fadjlist[root] = union(fadjlist[root], fadjlist[non_root])
118+
union!(fadjlist[root], fadjlist[non_root])
126119
for v in fadjlist[non_root]
127120
if root fadjlist[v]
128121
push!(fadjlist[v], root)

0 commit comments

Comments
 (0)