Skip to content

Commit 6765fbf

Browse files
authored
changed w type in max matching (#5)
* changed w type in max matching * test default weights * split cutoff, tests * added tests * fix stuff
1 parent 8f64632 commit 6765fbf

File tree

3 files changed

+119
-70
lines changed

3 files changed

+119
-70
lines changed

src/lp.jl

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,11 @@ The returned object is of type `MatchingResult`.
2020
"""
2121
function maximum_weight_maximal_matching end
2222

23-
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::Dict{Edge,T}, cutoff::R) where {T<:Real, R<:Real}
24-
wnew = Dict{Edge,T}()
25-
for (e,x) in w
26-
if x >= cutoff
27-
wnew[e] = x
28-
end
29-
end
30-
return maximum_weight_maximal_matching(g, solver, wnew)
23+
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
24+
return maximum_weight_maximal_matching(g, solver, cutoff_weights(w, cutoff))
3125
end
3226

33-
34-
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::Dict{Edge,T}) where {T<:Real}
27+
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}) where {T<:Real}
3528
# TODO support for graphs with zero degree nodes
3629
# TODO apply separately on each connected component
3730
bpmap = bipartite_map(g)
@@ -44,10 +37,15 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
4437

4538
nedg = 0
4639
edgemap = Dict{Edge,Int}()
47-
for (e,_) in w
48-
nedg += 1
49-
edgemap[e] = nedg
50-
edgemap[reverse(e)] = nedg
40+
41+
for j in 1:size(w,2)
42+
for i in 1:size(w,1)
43+
if w[i,j] > 0.0
44+
nedg += 1
45+
edgemap[Edge(i,j)] = nedg
46+
edgemap[Edge(j,i)] = nedg
47+
end
48+
end
5149
end
5250

5351
model = Model(solver=solver)
@@ -78,7 +76,7 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
7876
end
7977
end
8078

81-
@objective(model, Max, sum(c * x[edgemap[e]] for (e,c) = w))
79+
@objective(model, Max, sum(w[src(e),dst(e)] * x[edgemap[e]] for e in keys(edgemap)))
8280

8381
status = solve(model)
8482
status != :Optimal && error("JuMP solver failed to find optimal solution.")
@@ -90,7 +88,7 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
9088

9189
mate = fill(-1, nv(g))
9290
for e in edges(g)
93-
if haskey(w, e)
91+
if w[src(e),dst(e)] > zero(T)
9492
inmatch = convert(Bool, sol[edgemap[e]])
9593
if inmatch
9694
mate[src(e)] = dst(e)
@@ -101,3 +99,18 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
10199

102100
return MatchingResult(cost, mate)
103101
end
102+
103+
"""
104+
cutoff_weights copies the weight matrix with all elements below cutoff set to 0
105+
"""
106+
function cutoff_weights(w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
107+
wnew = copy(w)
108+
for j in 1:size(w,2)
109+
for i in 1:size(w,1)
110+
if wnew[i,j] < cutoff
111+
wnew[i,j] = zero(T)
112+
end
113+
end
114+
end
115+
wnew
116+
end

src/maximum_weight_matching.jl

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,30 @@ function maximum_weight_matching end
2323

2424
function maximum_weight_matching(g::Graph,
2525
solver::AbstractMathProgSolver,
26-
w::Dict{Edge,T} = Dict{Edge,Int64}(i => 1 for i in collect(edges(g)))) where {T <:Real}
26+
w::AbstractMatrix{T} = default_weights(g)) where {T <:Real}
2727

2828
model = Model(solver = solver)
2929
n = nv(g)
3030
edge_list = collect(edges(g))
3131

3232
# put the edge weights in w in the right order to be compatible with edge_list
33-
for edge in keys(w)
34-
redge = reverse(edge)
35-
if !is_ordered(edge) && !haskey(w, redge) # replace i=>j by j=>i if necessary.
36-
w[redge] = w[edge]
33+
for j in 1:n
34+
for i in 1:n
35+
if i > j && w[i,j] > zero(T) && w[j,i] < w[i,j]
36+
w[j,i] = w[i,j]
37+
end
38+
if Edge(i,j) edge_list
39+
w[i,j] = zero(T)
40+
end
3741
end
3842
end
39-
40-
if setdiff(edge_list, keys(w)) != [] # If some edges do not have a key in w.
41-
error("Some edge weights are missing, check that keys i => j in w satisfy i <= j")
42-
end
43-
43+
4444
if is_bipartite(g)
4545
@variable(model, x[edge_list] >= 0) # no need to enforce integrality
4646
else
4747
@variable(model, x[edge_list] >= 0, Int) # requires MIP solver
4848
end
49-
@objective(model, Max, sum(x[edge]*w[edge] for edge in edge_list))
49+
@objective(model, Max, sum(x[e]*w[src(e),dst(e)] for e in edge_list))
5050
@constraint(model, c1[i=1:n],
5151
sum(x[Edge(i,j)] for j=filter(l -> l > i, neighbors(g,i))) +
5252
sum(x[Edge(j,i)] for j=filter(l -> l <= i, neighbors(g,i)))
@@ -71,3 +71,12 @@ function dict_to_arr(n::Int64, solution::JuMP.JuMPArray{T,1,Tuple{Array{E,1}}})
7171
end
7272
return mate
7373
end
74+
75+
76+
function default_weights(g::G) where {G<:AbstractGraph}
77+
m = spzeros(nv(g),nv(g))
78+
for e in edges(g)
79+
m[src(e),dst(e)] = 1
80+
end
81+
return m
82+
end

test/runtests.jl

Lines changed: 70 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,36 @@ using LightGraphsMatching
44
using Base.Test
55
using Cbc: CbcSolver
66

7-
g =CompleteBipartiteGraph(2,2)
8-
w =Dict{Edge,Float64}()
9-
w[Edge(1,3)] = 10.
10-
w[Edge(1,4)] = 1.
11-
w[Edge(2,3)] = 2.
12-
w[Edge(2,4)] = 11.
7+
g = CompleteGraph(4)
8+
w = LightGraphsMatching.default_weights(g)
9+
@test all((w + w') .≈ ones(4,4) - eye(4,4))
10+
11+
w1 = [
12+
1 3
13+
5 1
14+
]
15+
w0 = [
16+
0 3
17+
5 0
18+
]
19+
@test all(w0 .≈ LightGraphsMatching.cutoff_weights(w1, 2))
20+
21+
g = CompleteGraph(3)
22+
w = [
23+
1 2 1
24+
1 1 1
25+
3 1 1
26+
]
27+
match = maximum_weight_matching(g, CbcSolver(), w)
28+
@test match.mate[1] == 3
29+
@test match.weight == 3
30+
31+
g = CompleteBipartiteGraph(2,2)
32+
w = zeros(4,4)
33+
w[1,3] = 10.
34+
w[1,4] = 1.
35+
w[2,3] = 2.
36+
w[2,4] = 11.
1337
match = maximum_weight_maximal_matching(g, CbcSolver(), w)
1438
@test match.weight == 21
1539
@test match.mate[1] == 3
@@ -18,11 +42,11 @@ match = maximum_weight_maximal_matching(g, CbcSolver(), w)
1842
@test match.mate[4] == 2
1943

2044
g =CompleteBipartiteGraph(2,4)
21-
w =Dict{Edge,Float64}()
22-
w[Edge(1,3)] = 10
23-
w[Edge(1,4)] = 0.5
24-
w[Edge(2,3)] = 11
25-
w[Edge(2,4)] = 1
45+
w =zeros(6,6)
46+
w[1,3] = 10
47+
w[1,4] = 0.5
48+
w[2,3] = 11
49+
w[2,4] = 1
2650
match = maximum_weight_maximal_matching(g, CbcSolver(), w)
2751
@test match.weight == 11.5
2852
@test match.mate[1] == 4
@@ -31,13 +55,13 @@ match = maximum_weight_maximal_matching(g, CbcSolver(), w)
3155
@test match.mate[3] == 2
3256

3357
g =CompleteBipartiteGraph(2,6)
34-
w =Dict{Edge,Float64}()
35-
w[Edge(1,3)] = 10
36-
w[Edge(1,4)] = 0.5
37-
w[Edge(2,3)] = 11
38-
w[Edge(2,4)] = 1
39-
w[Edge(2,5)] = -1
40-
w[Edge(2,6)] = -1
58+
w =zeros(8,8)
59+
w[1,3] = 10
60+
w[1,4] = 0.5
61+
w[2,3] = 11
62+
w[2,4] = 1
63+
w[2,5] = -1
64+
w[2,6] = -1
4165
match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
4266
@test match.weight == 11.5
4367
@test match.mate[1] == 4
@@ -46,12 +70,12 @@ match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
4670
@test match.mate[3] == 2
4771

4872
g =CompleteBipartiteGraph(4,2)
49-
w =Dict{Edge,Float64}()
50-
w[Edge(3,5)] = 10
51-
w[Edge(3,6)] = 0.5
52-
w[Edge(2,5)] = 11
53-
w[Edge(1,6)] = 1
54-
w[Edge(1,5)] = -1
73+
w = zeros(6,6)
74+
w[3,5] = 10
75+
w[3,6] = 0.5
76+
w[2,5] = 11
77+
w[1,6] = 1
78+
w[1,5] = -1
5579

5680
match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
5781
@test match.weight == 12
@@ -63,24 +87,24 @@ match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
6387
@test match.mate[6] == 1
6488

6589
g = CompleteGraph(3)
66-
w =Dict{Edge,Float64}()
67-
w[Edge(1,2)] = 1
68-
@test_throws ErrorException maximum_weight_matching(g,CbcSolver(),w)
69-
70-
w[Edge(3,2)] = 1
71-
w[Edge(1,3)] = 1
90+
w = zeros(3,3)
91+
w[1,2] = 1
92+
w[3,2] = 1
93+
w[1,3] = 1
7294
match = maximum_weight_matching(g,CbcSolver(),w)
7395
@test match.weight == 1
7496

7597

7698
g = Graph(4)
77-
w =Dict{Edge,Float64}()
7899
add_edge!(g, 1,3)
79100
add_edge!(g, 1,4)
80101
add_edge!(g, 2,4)
81-
w[Edge(1,3)] = 1
82-
w[Edge(1,4)] = 3
83-
w[Edge(2,4)] = 1
102+
103+
w =zeros(4,4)
104+
w[1,3] = 1
105+
w[1,4] = 3
106+
w[2,4] = 1
107+
84108
match = maximum_weight_matching(g,CbcSolver(),w)
85109
@test match.weight == 3
86110
@test match.mate[1] == 4
@@ -100,22 +124,25 @@ match = maximum_weight_matching(g,CbcSolver())
100124
@test match.mate[3] == 4
101125
@test match.mate[4] == 3
102126

103-
w =Dict{Edge,Float64}()
104-
w[Edge(1,2)] = 1
105-
w[Edge(2,3)] = 1
106-
w[Edge(1,3)] = 1
107-
w[Edge(3,4)] = 1
127+
w = zeros(4,4)
128+
w[1,2] = 1
129+
w[2,3] = 1
130+
w[1,3] = 1
131+
w[3,4] = 1
132+
108133
match = maximum_weight_matching(g,CbcSolver(), w)
109134
@test match.weight == 2
110135
@test match.mate[1] == 2
111136
@test match.mate[2] == 1
112137
@test match.mate[3] == 4
113138
@test match.mate[4] == 3
114139

115-
w[Edge(1,2)] = 1
116-
w[Edge(2,3)] = 1
117-
w[Edge(1,3)] = 5
118-
w[Edge(3,4)] = 1
140+
w = zeros(4,4)
141+
w[1,2] = 1
142+
w[2,3] = 1
143+
w[1,3] = 5
144+
w[3,4] = 1
145+
119146
match = maximum_weight_matching(g,CbcSolver(),w)
120147
@test match.weight == 5
121148
@test match.mate[1] == 3

0 commit comments

Comments
 (0)