Permalink
Browse files

changed w type in max matching (#5)

* changed w type in max matching

* test default weights

* split cutoff, tests

* added tests

* fix stuff
  • Loading branch information...
matbesancon committed Jan 12, 2018
1 parent 8f64632 commit 6765fbfb77aff24b96fda1f3453f60a8bb058105
Showing with 119 additions and 70 deletions.
  1. +29 −16 src/lp.jl
  2. +20 −11 src/maximum_weight_matching.jl
  3. +70 −43 test/runtests.jl
@@ -20,18 +20,11 @@ The returned object is of type `MatchingResult`.
"""
function maximum_weight_maximal_matching end
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::Dict{Edge,T}, cutoff::R) where {T<:Real, R<:Real}
wnew = Dict{Edge,T}()
for (e,x) in w
if x >= cutoff
wnew[e] = x
end
end
return maximum_weight_maximal_matching(g, solver, wnew)
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
return maximum_weight_maximal_matching(g, solver, cutoff_weights(w, cutoff))
end
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::Dict{Edge,T}) where {T<:Real}
function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolver, w::AbstractMatrix{T}) where {T<:Real}
# TODO support for graphs with zero degree nodes
# TODO apply separately on each connected component
bpmap = bipartite_map(g)
@@ -44,10 +37,15 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
nedg = 0
edgemap = Dict{Edge,Int}()
for (e,_) in w
nedg += 1
edgemap[e] = nedg
edgemap[reverse(e)] = nedg
for j in 1:size(w,2)
for i in 1:size(w,1)
if w[i,j] > 0.0
nedg += 1
edgemap[Edge(i,j)] = nedg
edgemap[Edge(j,i)] = nedg
end
end
end
model = Model(solver=solver)
@@ -78,7 +76,7 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
end
end
@objective(model, Max, sum(c * x[edgemap[e]] for (e,c) = w))
@objective(model, Max, sum(w[src(e),dst(e)] * x[edgemap[e]] for e in keys(edgemap)))
status = solve(model)
status != :Optimal && error("JuMP solver failed to find optimal solution.")
@@ -90,7 +88,7 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
mate = fill(-1, nv(g))
for e in edges(g)
if haskey(w, e)
if w[src(e),dst(e)] > zero(T)
inmatch = convert(Bool, sol[edgemap[e]])
if inmatch
mate[src(e)] = dst(e)
@@ -101,3 +99,18 @@ function maximum_weight_maximal_matching(g::Graph, solver::AbstractMathProgSolve
return MatchingResult(cost, mate)
end
"""
cutoff_weights copies the weight matrix with all elements below cutoff set to 0
"""
function cutoff_weights(w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real}
wnew = copy(w)
for j in 1:size(w,2)
for i in 1:size(w,1)
if wnew[i,j] < cutoff
wnew[i,j] = zero(T)
end
end
end
wnew
end
@@ -23,30 +23,30 @@ function maximum_weight_matching end
function maximum_weight_matching(g::Graph,
solver::AbstractMathProgSolver,
w::Dict{Edge,T} = Dict{Edge,Int64}(i => 1 for i in collect(edges(g)))) where {T <:Real}
w::AbstractMatrix{T} = default_weights(g)) where {T <:Real}
model = Model(solver = solver)
n = nv(g)
edge_list = collect(edges(g))
# put the edge weights in w in the right order to be compatible with edge_list
for edge in keys(w)
redge = reverse(edge)
if !is_ordered(edge) && !haskey(w, redge) # replace i=>j by j=>i if necessary.
w[redge] = w[edge]
for j in 1:n
for i in 1:n
if i > j && w[i,j] > zero(T) && w[j,i] < w[i,j]
w[j,i] = w[i,j]
end
if Edge(i,j) ∉ edge_list
w[i,j] = zero(T)
end
end
end
if setdiff(edge_list, keys(w)) != [] # If some edges do not have a key in w.
error("Some edge weights are missing, check that keys i => j in w satisfy i <= j")
end
if is_bipartite(g)
@variable(model, x[edge_list] >= 0) # no need to enforce integrality
else
@variable(model, x[edge_list] >= 0, Int) # requires MIP solver
end
@objective(model, Max, sum(x[edge]*w[edge] for edge in edge_list))
@objective(model, Max, sum(x[e]*w[src(e),dst(e)] for e in edge_list))
@constraint(model, c1[i=1:n],
sum(x[Edge(i,j)] for j=filter(l -> l > i, neighbors(g,i))) +
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}}})
end
return mate
end
function default_weights(g::G) where {G<:AbstractGraph}
m = spzeros(nv(g),nv(g))
for e in edges(g)
m[src(e),dst(e)] = 1
end
return m
end
@@ -4,12 +4,36 @@ using LightGraphsMatching
using Base.Test
using Cbc: CbcSolver
g =CompleteBipartiteGraph(2,2)
w =Dict{Edge,Float64}()
w[Edge(1,3)] = 10.
w[Edge(1,4)] = 1.
w[Edge(2,3)] = 2.
w[Edge(2,4)] = 11.
g = CompleteGraph(4)
w = LightGraphsMatching.default_weights(g)
@test all((w + w') .≈ ones(4,4) - eye(4,4))
w1 = [
1 3
5 1
]
w0 = [
0 3
5 0
]
@test all(w0 .≈ LightGraphsMatching.cutoff_weights(w1, 2))
g = CompleteGraph(3)
w = [
1 2 1
1 1 1
3 1 1
]
match = maximum_weight_matching(g, CbcSolver(), w)
@test match.mate[1] == 3
@test match.weight == 3
g = CompleteBipartiteGraph(2,2)
w = zeros(4,4)
w[1,3] = 10.
w[1,4] = 1.
w[2,3] = 2.
w[2,4] = 11.
match = maximum_weight_maximal_matching(g, CbcSolver(), w)
@test match.weight == 21
@test match.mate[1] == 3
@@ -18,11 +42,11 @@ match = maximum_weight_maximal_matching(g, CbcSolver(), w)
@test match.mate[4] == 2
g =CompleteBipartiteGraph(2,4)
w =Dict{Edge,Float64}()
w[Edge(1,3)] = 10
w[Edge(1,4)] = 0.5
w[Edge(2,3)] = 11
w[Edge(2,4)] = 1
w =zeros(6,6)
w[1,3] = 10
w[1,4] = 0.5
w[2,3] = 11
w[2,4] = 1
match = maximum_weight_maximal_matching(g, CbcSolver(), w)
@test match.weight == 11.5
@test match.mate[1] == 4
@@ -31,13 +55,13 @@ match = maximum_weight_maximal_matching(g, CbcSolver(), w)
@test match.mate[3] == 2
g =CompleteBipartiteGraph(2,6)
w =Dict{Edge,Float64}()
w[Edge(1,3)] = 10
w[Edge(1,4)] = 0.5
w[Edge(2,3)] = 11
w[Edge(2,4)] = 1
w[Edge(2,5)] = -1
w[Edge(2,6)] = -1
w =zeros(8,8)
w[1,3] = 10
w[1,4] = 0.5
w[2,3] = 11
w[2,4] = 1
w[2,5] = -1
w[2,6] = -1
match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
@test match.weight == 11.5
@test match.mate[1] == 4
@@ -46,12 +70,12 @@ match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
@test match.mate[3] == 2
g =CompleteBipartiteGraph(4,2)
w =Dict{Edge,Float64}()
w[Edge(3,5)] = 10
w[Edge(3,6)] = 0.5
w[Edge(2,5)] = 11
w[Edge(1,6)] = 1
w[Edge(1,5)] = -1
w = zeros(6,6)
w[3,5] = 10
w[3,6] = 0.5
w[2,5] = 11
w[1,6] = 1
w[1,5] = -1
match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
@test match.weight == 12
@@ -63,24 +87,24 @@ match = maximum_weight_maximal_matching(g,CbcSolver(),w,0)
@test match.mate[6] == 1
g = CompleteGraph(3)
w =Dict{Edge,Float64}()
w[Edge(1,2)] = 1
@test_throws ErrorException maximum_weight_matching(g,CbcSolver(),w)
w[Edge(3,2)] = 1
w[Edge(1,3)] = 1
w = zeros(3,3)
w[1,2] = 1
w[3,2] = 1
w[1,3] = 1
match = maximum_weight_matching(g,CbcSolver(),w)
@test match.weight == 1
g = Graph(4)
w =Dict{Edge,Float64}()
add_edge!(g, 1,3)
add_edge!(g, 1,4)
add_edge!(g, 2,4)
w[Edge(1,3)] = 1
w[Edge(1,4)] = 3
w[Edge(2,4)] = 1
w =zeros(4,4)
w[1,3] = 1
w[1,4] = 3
w[2,4] = 1
match = maximum_weight_matching(g,CbcSolver(),w)
@test match.weight == 3
@test match.mate[1] == 4
@@ -100,22 +124,25 @@ match = maximum_weight_matching(g,CbcSolver())
@test match.mate[3] == 4
@test match.mate[4] == 3
w =Dict{Edge,Float64}()
w[Edge(1,2)] = 1
w[Edge(2,3)] = 1
w[Edge(1,3)] = 1
w[Edge(3,4)] = 1
w = zeros(4,4)
w[1,2] = 1
w[2,3] = 1
w[1,3] = 1
w[3,4] = 1
match = maximum_weight_matching(g,CbcSolver(), w)
@test match.weight == 2
@test match.mate[1] == 2
@test match.mate[2] == 1
@test match.mate[3] == 4
@test match.mate[4] == 3
w[Edge(1,2)] = 1
w[Edge(2,3)] = 1
w[Edge(1,3)] = 5
w[Edge(3,4)] = 1
w = zeros(4,4)
w[1,2] = 1
w[2,3] = 1
w[1,3] = 5
w[3,4] = 1
match = maximum_weight_matching(g,CbcSolver(),w)
@test match.weight == 5
@test match.mate[1] == 3

0 comments on commit 6765fbf

Please sign in to comment.