diff --git a/Project.toml b/Project.toml index 2221c8c..5783ce8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GraphsMatching" uuid = "c3af3a8c-b79e-4b01-bf44-c718d7e0e0d6" authors = ["JuliaGraphs"] -version = "0.1.0" +version = "0.2.0" [deps] BlossomV = "6c721016-9dae-5d90-abf6-67daaccb2332" @@ -14,10 +14,10 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] BlossomV = "0.4" -Graphs = "1.4.0" -Hungarian = "0.4" -JuMP = "0.20" -MathOptInterface = "0.9" +Graphs = "1.4, 1.7" +Hungarian = "0.4, 0.6" +JuMP = "1" +MathOptInterface = "1" julia = "1" [extras] diff --git a/src/lp.jl b/src/lp.jl index 640d979..c92d0de 100644 --- a/src/lp.jl +++ b/src/lp.jl @@ -1,8 +1,8 @@ -function maximum_weight_maximal_matching_lp(g::Graph, solver::JuMP.OptimizerFactory, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real} - return maximum_weight_maximal_matching_lp(g, solver, cutoff_weights(w, cutoff)) +function maximum_weight_maximal_matching_lp(g::Graph, optimizer, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real} + return maximum_weight_maximal_matching_lp(g, optimizer, cutoff_weights(w, cutoff)) end -function maximum_weight_maximal_matching_lp(g::Graph, solver::JuMP.OptimizerFactory, w::AbstractMatrix{T}) where {T<:Real} +function maximum_weight_maximal_matching_lp(g::Graph, optimizer, 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) @@ -26,7 +26,7 @@ function maximum_weight_maximal_matching_lp(g::Graph, solver::JuMP.OptimizerFact end end - model = Model(solver) + model = Model(optimizer) @variable(model, x[1:length(w)] >= 0) for i in v1 diff --git a/src/maximum_weight_matching.jl b/src/maximum_weight_matching.jl index e73e372..2d9dfca 100644 --- a/src/maximum_weight_matching.jl +++ b/src/maximum_weight_matching.jl @@ -22,10 +22,10 @@ Returns MatchingResult containing: function maximum_weight_matching end function maximum_weight_matching(g::Graph, - solver::JuMP.OptimizerFactory, + optimizer, w::AbstractMatrix{U} = default_weights(g)) where {U <:Real} - model = Model(with_optimizer(solver)) + model = Model(optimizer) n = nv(g) edge_list = collect(edges(g)) @@ -40,7 +40,7 @@ function maximum_weight_matching(g::Graph, end end end - + if is_bipartite(g) @variable(model, x[edge_list] >= 0) # no need to enforce integrality else diff --git a/src/maximum_weight_maximal_matching.jl b/src/maximum_weight_maximal_matching.jl index c39ec75..afd54e1 100644 --- a/src/maximum_weight_maximal_matching.jl +++ b/src/maximum_weight_maximal_matching.jl @@ -11,16 +11,13 @@ Forces the maximum_weight_maximal_matching function to use a linear programming struct LPAlgorithm <: AbstractMaximumWeightMaximalMatchingAlgorithm end function maximum_weight_maximal_matching( - g::Graph, - w::AbstractMatrix{T}, - algorithm::LPAlgorithm, - solver = nothing + g::Graph, + w::AbstractMatrix{T}, + algorithm::LPAlgorithm, + optimizer = nothing ) where {T<:Real} - if ! isa(solver, JuMP.OptimizerFactory) - error("The keyword argument solver must be an JuMP.OptimizerFactory, as accepted by JuMP.") - end - return maximum_weight_maximal_matching_lp(g, solver, w) + return maximum_weight_maximal_matching_lp(g, optimizer, w) end """ @@ -30,10 +27,10 @@ Forces the maximum_weight_maximal_matching function to use the Hungarian algorit struct HungarianAlgorithm <: AbstractMaximumWeightMaximalMatchingAlgorithm end function maximum_weight_maximal_matching( - g::Graph, - w::AbstractMatrix{T}, - algorithm::HungarianAlgorithm, - solver = nothing + g::Graph, + w::AbstractMatrix{T}, + algorithm::HungarianAlgorithm, + optimizer = nothing ) where {T<:Real} return maximum_weight_maximal_matching_hungarian(g, w) end @@ -50,24 +47,24 @@ Edges in `g` not present in `w` will not be considered for the matching. A `cutoff` keyword argument can be given, to reduce computational times excluding edges with weights lower than the cutoff. -Finally, a specific algorithm can be chosen (`algorithm` keyword argument); -each algorithm has specific dependencies. For instance: +Finally, a specific algorithm can be chosen (`algorithm` keyword argument); +each algorithm has specific dependencies. For instance: -- If `algorithm=HungarianAlgorithm()` (the default), the package Hungarian.jl is used. - This algorithm is always polynomial in time, with complexity O(n³). -- If `algorithm=LPAlgorithm()`, the package JuMP.jl and one of its supported solvers is required. +- If `algorithm=HungarianAlgorithm()` (the default), the package Hungarian.jl is used. + This algorithm is always polynomial in time, with complexity O(n³). +- If `algorithm=LPAlgorithm()`, the package JuMP.jl and one of its supported solvers is required. In this case, the algorithm relies on a linear relaxation on of the matching problem, which is - guaranteed to have integer solution on bipartite graphs. A solver must be provided with - the `solver` keyword parameter. + guaranteed to have integer solution on bipartite graphs. A solver must be provided with + the `optimizer` keyword parameter. The returned object is of type `MatchingResult`. """ function maximum_weight_maximal_matching( - g::Graph, - w::AbstractMatrix{T}; + g::Graph, + w::AbstractMatrix{T}; cutoff = nothing, - algorithm::AbstractMaximumWeightMaximalMatchingAlgorithm = HungarianAlgorithm(), - solver = nothing + algorithm::AbstractMaximumWeightMaximalMatchingAlgorithm = HungarianAlgorithm(), + optimizer = nothing ) where {T<:Real} if cutoff != nothing && ! isa(cutoff, Real) @@ -75,9 +72,9 @@ function maximum_weight_maximal_matching( end if cutoff != nothing - return maximum_weight_maximal_matching(g, cutoff_weights(w, cutoff), algorithm, solver) + return maximum_weight_maximal_matching(g, cutoff_weights(w, cutoff), algorithm, optimizer) else - return maximum_weight_maximal_matching(g, w, algorithm, solver) + return maximum_weight_maximal_matching(g, w, algorithm, optimizer) end end @@ -96,4 +93,4 @@ function cutoff_weights(w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real wnew end -@deprecate maximum_weight_maximal_matching(g::Graph, solver::JuMP.OptimizerFactory, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real} maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), cutoff=cutoff, solver=solver) +@deprecate maximum_weight_maximal_matching(g::Graph, optimizer, w::AbstractMatrix{T}, cutoff::R) where {T<:Real, R<:Real} maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), cutoff=cutoff, optimizer=optimizer) diff --git a/test/runtests.jl b/test/runtests.jl index f4a0f8d..0beb14f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,7 +14,7 @@ using LinearAlgebra: I 1 1 1 3 1 1 ] - match = maximum_weight_matching(g, with_optimizer(Cbc.Optimizer, logLevel=0), w) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0), w) @test match.mate[1] == 3 @test match.weight ≈ 3 @@ -23,7 +23,7 @@ using LinearAlgebra: I w[1,2] = 1 w[3,2] = 1 w[1,3] = 1 - match = maximum_weight_matching(g,with_optimizer(Cbc.Optimizer, logLevel=0),w) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0),w) @test match.weight ≈ 1 @@ -37,7 +37,7 @@ using LinearAlgebra: I w[1,4] = 3 w[2,4] = 1 - match = maximum_weight_matching(g,with_optimizer(Cbc.Optimizer, logLevel=0),w) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0),w) @test match.weight ≈ 3 @test match.mate[1] == 4 @test match.mate[2] == -1 @@ -49,7 +49,7 @@ using LinearAlgebra: I add_edge!(g, 2,3) add_edge!(g, 3,1) add_edge!(g, 3,4) - match = maximum_weight_matching(g,with_optimizer(Cbc.Optimizer, logLevel=0)) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0)) @test match.weight ≈ 2 @test match.mate[1] == 2 @test match.mate[2] == 1 @@ -62,7 +62,7 @@ using LinearAlgebra: I w[1,3] = 1 w[3,4] = 1 - match = maximum_weight_matching(g,with_optimizer(Cbc.Optimizer, logLevel=0), w) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0), w) @test match.weight ≈ 2 @test match.mate[1] == 2 @test match.mate[2] == 1 @@ -75,7 +75,7 @@ using LinearAlgebra: I w[1,3] = 5 w[3,4] = 1 - match = maximum_weight_matching(g,with_optimizer(Cbc.Optimizer, logLevel=0),w) + match = maximum_weight_matching(g, optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0),w) @test match.weight ≈ 5 @test match.mate[1] == 3 @test match.mate[2] == -1 @@ -92,7 +92,7 @@ end w[1,4] = 1. w[2,3] = 2. w[2,4] = 11. - match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), solver=with_optimizer(Cbc.Optimizer, logLevel=0)) + match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), optimizer=optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0)) @test match.weight ≈ 21 @test match.mate[1] == 3 @test match.mate[3] == 1 @@ -105,7 +105,7 @@ end w[1,4] = 0.5 w[2,3] = 11 w[2,4] = 1 - match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), solver=with_optimizer(Cbc.Optimizer, logLevel=0)) + match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), optimizer=optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0)) @test match.weight ≈ 11.5 @test match.mate[1] == 4 @test match.mate[4] == 1 @@ -120,7 +120,7 @@ end w[2,4] = 1 w[2,5] = -1 w[2,6] = -1 - match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), solver=with_optimizer(Cbc.Optimizer, logLevel=0), cutoff=0) + match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), optimizer=optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0), cutoff=0) @test match.weight ≈ 11.5 @test match.mate[1] == 4 @test match.mate[4] == 1 @@ -135,7 +135,7 @@ end w[1,6] = 1 w[1,5] = -1 - match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), solver=with_optimizer(Cbc.Optimizer, logLevel=0), cutoff=0) + match = maximum_weight_maximal_matching(g, w, algorithm=LPAlgorithm(), optimizer=optimizer_with_attributes(Cbc.Optimizer, "LogLevel" => 0), cutoff=0) @test match.weight ≈ 12 @test match.mate[1] == 6 @test match.mate[2] == 5 @@ -143,8 +143,8 @@ end @test match.mate[4] == -1 @test match.mate[5] == 2 @test match.mate[6] == 1 - - + + g = complete_bipartite_graph(2, 2) w = zeros(4, 4) w[1, 3] = 10. @@ -178,10 +178,10 @@ end add_edge!(g, 2, 4) w = zeros(4, 4) w[1, 3] = 1 - w[1, 4] = 3 + w[1, 4] = 3 w[2, 4] = 1 match = maximum_weight_maximal_matching(g, w, algorithm=HungarianAlgorithm()) - @test match.weight ≈ 2 + @test match.weight ≈ 2 end