From fd366dad8257684d0adb34ad38edf1482631db60 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 14 Mar 2022 12:14:39 +1300 Subject: [PATCH] Use a CachingOptimizer for the MIP solver and test Cbc (#62) --- Project.toml | 6 ++++-- src/MOI_wrapper.jl | 37 +++++++++++++++++++------------------ test/runtests.jl | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/Project.toml b/Project.toml index 3e2127f..afa655b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,13 +1,14 @@ name = "Pavito" uuid = "cd433a01-47d1-575d-afb7-6db927ee8d8f" repo = "https://github.com/jump-dev/Pavito.jl.git" -version = "0.3.3" +version = "0.3.4" [deps] MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" [compat] +Cbc = "0.9, 1" GLPK = "0.15, 1" Ipopt = "0.8, 0.9, 1" JuMP = "0.22, 0.23" @@ -16,6 +17,7 @@ MathOptInterface = "0.10.3, 1" julia = "1.6" [extras] +Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" @@ -23,4 +25,4 @@ MINLPTests = "ee0a3090-8ee9-5cdb-b8cb-8eeba3165522" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["GLPK", "Ipopt", "JuMP", "MINLPTests", "Test"] +test = ["Cbc", "GLPK", "Ipopt", "JuMP", "MINLPTests", "Test"] diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 7e889fc..f506689 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -335,24 +335,25 @@ end # utilities: function _mip(model::Optimizer) - if isnothing(model.mip_optimizer) - if isnothing(model.mip_solver) - error("No MIP solver specified (set `mip_solver` attribute)\n") - end - - model.mip_optimizer = - MOI.instantiate(model.mip_solver, with_bridge_type = Float64) - - supports_lazy = - MOI.supports(model.mip_optimizer, MOI.LazyConstraintCallback()) - if isnothing(model.mip_solver_drives) - model.mip_solver_drives = supports_lazy - elseif model.mip_solver_drives && !supports_lazy - error( - "MIP solver (`mip_solver`) does not support lazy constraint " * - "callbacks (cannot set `mip_solver_drives` attribute to `true`)", - ) - end + if model.mip_optimizer !== nothing + return model.mip_optimizer + end + if model.mip_solver === nothing + error("No MIP solver specified (set `mip_solver` attribute)\n") + end + model.mip_optimizer = MOI.Utilities.CachingOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), + MOI.instantiate(model.mip_solver, with_bridge_type = Float64), + ) + supports_lazy = + MOI.supports(model.mip_optimizer, MOI.LazyConstraintCallback()) + if model.mip_solver_drives === nothing + model.mip_solver_drives = supports_lazy + elseif model.mip_solver_drives && !supports_lazy + error( + "MIP solver (`mip_solver`) does not support lazy constraint " * + "callbacks (cannot set `mip_solver_drives` attribute to `true`)", + ) end return model.mip_optimizer end diff --git a/test/runtests.jl b/test/runtests.jl index 73c40e3..c24eb15 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,6 +6,7 @@ using Test +import Cbc import GLPK import Ipopt import MathOptInterface @@ -15,6 +16,14 @@ const MOI = MathOptInterface include("MOI_wrapper.jl") include("jump_tests.jl") +# !!! info +# We test with both Cbc and GLPK because they have very different +# implementations of the MOI API: GLPK supports incremental modification and +# supports lazy constraints, whereas Cbc supports copy_to and does not +# support lazy constraints. In addition, Cbc uses MatrixOfConstraints to +# simplify the copy process, needing an additional cache if we modify after +# the solve. + @testset "MOI" begin TestMOIWrapper.runtests( MOI.OptimizerWithAttributes( @@ -28,6 +37,14 @@ include("jump_tests.jl") ) end +@testset "Cbc" begin + TestMOIWrapper._run_moi_tests( + false, # mip_solver_drives + MOI.OptimizerWithAttributes(Cbc.Optimizer, MOI.Silent() => true), + MOI.OptimizerWithAttributes(Ipopt.Optimizer, MOI.Silent() => true), + ) +end + @testset "JuMP" begin TestJuMP.runtests( MOI.OptimizerWithAttributes(