Skip to content

Commit 40cdca3

Browse files
authored
Add more tests for BoykovKolmorogovAlgorithm (#51)
* Add tests for BoykovKolmorogovAlgorithm * Update test/boykov_kolmogorov.jl * Update contact email
1 parent 03755d3 commit 40cdca3

File tree

3 files changed

+155
-5
lines changed

3 files changed

+155
-5
lines changed

src/boykov_kolmogorov.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Return the maximum flow in the network, the flow matrix and the partition
1212
Min-Cut/Max-Flow Algorithms for Energy Minimization in Vision.
1313
1414
### Author
15-
- Júlio Hoffimann Mendes (juliohm@stanford.edu)
15+
- Júlio Hoffimann Mendes (julio.hoffimann@gmail.com)
1616
"""
1717
function boykov_kolmogorov_impl end
1818
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax

test/boykov_kolmogorov.jl

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,155 @@
11
@testset "Boykov Kolmogorov" begin
2+
@testset "Lattice graph" begin
3+
# image size
4+
sz = (9, 9)
5+
6+
# number of pixels
7+
npix = prod(sz)
8+
9+
# lattice graph
10+
G = DiGraph(npix+2)
11+
C = spzeros(npix+2, npix+2)
12+
13+
# connect all pixels in the 9x9 image
14+
# with its immediate 4 neighbors
15+
for i in 1:sz[1]-1, j in 1:sz[2]
16+
u = LinearIndices(sz)[i,j]
17+
v = LinearIndices(sz)[i+1,j]
18+
add_edge!(G, u, v)
19+
add_edge!(G, v, u)
20+
end
21+
for i in 1:sz[1], j in 1:sz[2]-1
22+
u = LinearIndices(sz)[i,j]
23+
v = LinearIndices(sz)[i,j+1]
24+
add_edge!(G, u, v)
25+
add_edge!(G, v, u)
26+
end
27+
28+
# create capacity for flow in the 4x4
29+
# subimage located at the top left
30+
for i in 1:3, j in 1:4
31+
u = LinearIndices(sz)[i,j]
32+
v = LinearIndices(sz)[i+1,j]
33+
C[u,v] = C[v,u] = 1
34+
end
35+
for i in 1:4, j in 1:3
36+
u = LinearIndices(sz)[i,j]
37+
v = LinearIndices(sz)[i,j+1]
38+
C[u,v] = C[v,u] = 1
39+
end
40+
41+
# create capacity for flow in the 4x4
42+
# subimage located at the bottom right
43+
for i in 6:8, j in 6:9
44+
u = LinearIndices(sz)[i,j]
45+
v = LinearIndices(sz)[i+1,j]
46+
C[u,v] = C[v,u] = 1
47+
end
48+
for i in 6:9, j in 6:8
49+
u = LinearIndices(sz)[i,j]
50+
v = LinearIndices(sz)[i,j+1]
51+
C[u,v] = C[v,u] = 1
52+
end
53+
54+
# create source node and connect it to the
55+
# leftmost column of the image
56+
# create target node and connect it to the
57+
# rightmost column of the image
58+
s = npix + 1
59+
t = npix + 2
60+
for i in 1:sz[1]
61+
u = LinearIndices(sz)[i,1]
62+
add_edge!(G, s, u)
63+
C[s,u] = C[u,s] = Inf
64+
end
65+
for i in 1:sz[1]
66+
u = LinearIndices(sz)[i,sz[2]]
67+
add_edge!(G, u, t)
68+
C[u,t] = C[t,u] = Inf
69+
end
70+
71+
# now we are ready to start the flow
72+
flow, _, labels = maximum_flow(G, s, t, C, algorithm=BoykovKolmogorovAlgorithm())
73+
74+
# because the two subimages are not connected
75+
# we must have zero flow from source to target
76+
@test flow == 0
77+
78+
# the final cut represents the two disconnected
79+
# subimages filled with water of different color
80+
COLOR = reshape(labels[1:end-2], sz)
81+
@test COLOR == [
82+
1 1 1 1 0 0 0 0 2
83+
1 1 1 1 0 0 0 0 2
84+
1 1 1 1 0 0 0 0 2
85+
1 1 1 1 0 0 0 0 2
86+
1 0 0 0 0 0 0 0 2
87+
1 0 0 0 0 2 2 2 2
88+
1 0 0 0 0 2 2 2 2
89+
1 0 0 0 0 2 2 2 2
90+
1 0 0 0 0 2 2 2 2
91+
]
92+
93+
# now let's create a bridge connecting the two
94+
# subimages to allow flow from source to target
95+
for (I1, I2) in [[(4,4), (5,4)], [(5,4), (5,5)],
96+
[(5,5), (5,6)], [(5,6), (6,6)]]
97+
u = LinearIndices(sz)[I1...]
98+
v = LinearIndices(sz)[I2...]
99+
C[u,v] = C[v,u] = 1
100+
end
101+
102+
flow, _, labels = maximum_flow(G, s, t, C, algorithm=BoykovKolmogorovAlgorithm())
103+
104+
# because there is only one bridge,
105+
# the maximum flow allowed is one unit
106+
@test flow == 1
107+
108+
# the final cut is unchanged compared to the previous one
109+
COLOR = reshape(labels[1:end-2], sz)
110+
@test COLOR == [
111+
1 1 1 1 0 0 0 0 2
112+
1 1 1 1 0 0 0 0 2
113+
1 1 1 1 0 0 0 0 2
114+
1 1 1 1 0 0 0 0 2
115+
1 0 0 0 0 0 0 0 2
116+
1 0 0 0 0 2 2 2 2
117+
1 0 0 0 0 2 2 2 2
118+
1 0 0 0 0 2 2 2 2
119+
1 0 0 0 0 2 2 2 2
120+
]
121+
122+
# finally let's create a second bridge to increase
123+
# the maximum flow from one to two units
124+
for (I1, I2) in [[(4,4), (4,5)], [(4,5), (5,5)],
125+
[(5,5), (6,5)], [(6,5), (6,6)]]
126+
u = LinearIndices(sz)[I1...]
127+
v = LinearIndices(sz)[I2...]
128+
C[u,v] = C[v,u] = 1
129+
end
130+
131+
flow, _, labels = maximum_flow(G, s, t, C, algorithm=BoykovKolmogorovAlgorithm())
132+
133+
# the maximum flow is now doubled
134+
@test flow == 2
135+
136+
# the final cut is slightly different
137+
# near the corners of the two subimages
138+
COLOR = reshape(labels[1:end-2], sz)
139+
@test COLOR == [
140+
1 1 1 1 0 0 0 0 2
141+
1 1 1 1 0 0 0 0 2
142+
1 1 1 1 0 0 0 0 2
143+
1 1 1 0 0 0 0 0 2
144+
1 0 0 0 0 0 0 0 2
145+
1 0 0 0 0 0 2 2 2
146+
1 0 0 0 0 2 2 2 2
147+
1 0 0 0 0 2 2 2 2
148+
1 0 0 0 0 2 2 2 2
149+
]
150+
end
151+
152+
@testset "Find path" begin
2153
# construct graph
3154
gg = lg.DiGraph(3)
4155
lg.add_edge!(gg, 1, 2)
@@ -7,9 +158,8 @@
7158
# source and sink terminals
8159
source, target = 1, 3
9160

10-
11161
for g in testdigraphs(gg)
12-
# default capacity
162+
# default capacity
13163
capacity_matrix = LightGraphsFlows.DefaultCapacity(g)
14164
residual_graph = @inferred(LightGraphsFlows.residual(g))
15165
T = eltype(g)
@@ -19,12 +169,11 @@
19169
TREE[target] = T(2)
20170
PARENT = zeros(T, 3)
21171
A = [T(source), T(target)]
22-
# see https://github.com/JuliaLang/julia/issues/21077
23-
# @show("testing $g with eltype $T, residual_graph type is $(eltype(residual_graph)), flow_matrix type is $(eltype(flow_matrix)), capacity_matrix type is $(eltype(capacity_matrix))")
24172
path = LightGraphsFlows.find_path!(
25173
residual_graph, source, target, flow_matrix,
26174
capacity_matrix, PARENT, TREE, A)
27175

28176
@test path == [1, 2, 3]
177+
end
29178
end
30179
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import SimpleTraits
55
const lg = LightGraphs
66

77
using LinearAlgebra: diag
8+
using SparseArrays: spzeros
89

910
using JuMP
1011
import GLPK

0 commit comments

Comments
 (0)