Skip to content
This repository has been archived by the owner on Oct 22, 2021. It is now read-only.

Commit

Permalink
changed w type in max matching (#5)
Browse files Browse the repository at this point in the history
* changed w type in max matching

* test default weights

* split cutoff, tests

* added tests

* fix stuff
  • Loading branch information
matbesancon authored Jan 12, 2018
1 parent 8f64632 commit 6765fbf
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 70 deletions.
45 changes: 29 additions & 16 deletions src/lp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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.")
Expand All @@ -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)
Expand All @@ -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
31 changes: 20 additions & 11 deletions src/maximum_weight_matching.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand All @@ -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
113 changes: 70 additions & 43 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 6765fbf

Please sign in to comment.