diff --git a/Project.toml b/Project.toml index 9b8e7d7..d47ba40 100644 --- a/Project.toml +++ b/Project.toml @@ -11,7 +11,7 @@ OpenBLAS32_jll = "656ef2d0-ae68-5445-9ca0-591084a874a2" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -Cbc_jll = "=200.1000.1200" +Cbc_jll = "=200.1000.1300" LinearAlgebra = "1" MathOptInterface = "1.7" OpenBLAS32_jll = "0.3.10" diff --git a/src/MOI_wrapper/MOI_wrapper.jl b/src/MOI_wrapper/MOI_wrapper.jl index 2264549..18d8c0f 100644 --- a/src/MOI_wrapper/MOI_wrapper.jl +++ b/src/MOI_wrapper/MOI_wrapper.jl @@ -393,12 +393,10 @@ function MOI.copy_to(dest::Optimizer, src::OptimizerCache) end end end - any_sos = false for (S, type) in ((MOI.SOS1{Float64}, 1), (MOI.SOS2{Float64}, 2)) starts, indices, weights = Cint[], Cint[], Float64[] attr = MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S}() for ci in MOI.get(src, attr) - any_sos = true push!(starts, Cint(length(weights))) f = MOI.get(src, MOI.ConstraintFunction(), ci) for x in f.variables @@ -413,12 +411,6 @@ function MOI.copy_to(dest::Optimizer, src::OptimizerCache) Cbc_addSOS(dest, N, starts, indices, weights, Cint(type)) end end - if any_sos && Cbc_getNumIntegers(dest) == 0 - @warn( - "There are known correctness issues using Cbc with SOS " * - "constraints and no binary variables.", - ) - end return _index_map(src) end diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 9344d6d..672a30e 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -11,12 +11,9 @@ import Cbc import MathOptInterface as MOI function runtests() - for name in names(@__MODULE__; all = true) - if startswith("$(name)", "test_") - @testset "$(name)" begin - getfield(@__MODULE__, name)() - end - end + is_test(name) = startswith("$(name)", "test_") + @testset "$name" for name in filter(is_test, names(@__MODULE__; all = true)) + getfield(@__MODULE__, name)() end return end @@ -24,6 +21,7 @@ end function test_SolverName() @test MOI.get(Cbc.Optimizer(), MOI.SolverName()) == "COIN Branch-and-Cut (Cbc)" + return end function test_supports_incremental_interface() @@ -36,10 +34,6 @@ function test_runtests() MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), MOI.instantiate(Cbc.Optimizer; with_bridge_type = Float64), ) - MOI.Bridges.remove_bridge( - model.optimizer, - MOI.Bridges.Variable.ZerosBridge{Float64}, - ) MOI.set(model, MOI.Silent(), true) MOI.Test.runtests( model, @@ -52,11 +46,6 @@ function test_runtests() ], ), exclude = [ - # TODO(odow): upstream bug in Cbc - "test_linear_Indicator_", - "test_linear_SOS1_integration", - "test_linear_SOS2_integration", - "test_solve_SOS2_add_and_delete", # Can't prove infeasible. "test_conic_NormInfinityCone_INFEASIBLE", "test_conic_NormOneCone_INFEASIBLE", @@ -199,193 +188,6 @@ function test_issue_187() return end -# The test_linear_SOS1_integration test with the additional requirement that all -# variables are integer. -function test_SOS1() - model = MOI.Bridges.full_bridge_optimizer( - MOI.Utilities.CachingOptimizer( - MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), - Cbc.Optimizer(), - ), - Float64, - ) - config = MOI.Test.Config() - MOI.set(model, MOI.Silent(), true) - @test MOI.supports_constraint( - model, - MOI.VectorOfVariables, - MOI.SOS1{Float64}, - ) - @test MOI.supports_constraint( - model, - MOI.VariableIndex, - MOI.LessThan{Float64}, - ) - v = MOI.add_variables(model, 3) - MOI.add_constraint.(model, v, MOI.Integer()) - @test MOI.get(model, MOI.NumberOfVariables()) == 3 - vc1 = MOI.add_constraint(model, v[1], MOI.LessThan(1.0)) - @test vc1.value == v[1].value - vc2 = MOI.add_constraint(model, v[2], MOI.LessThan(1.0)) - @test vc2.value == v[2].value - vc3 = MOI.add_constraint(model, v[3], MOI.LessThan(2.0)) - @test vc3.value == v[3].value - c1 = MOI.add_constraint( - model, - MOI.VectorOfVariables([v[1], v[2]]), - MOI.SOS1([1.0, 2.0]), - ) - c2 = MOI.add_constraint( - model, - MOI.VectorOfVariables([v[1], v[3]]), - MOI.SOS1([1.0, 2.0]), - ) - @test MOI.get( - model, - MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.SOS1{Float64}}(), - ) == 2 - #= - To allow for permutations in the sets and variable vectors - we're going to sort according to the weights - =# - cs_sos = MOI.get(model, MOI.ConstraintSet(), c2) - cf_sos = MOI.get(model, MOI.ConstraintFunction(), c2) - p = sortperm(cs_sos.weights) - @test isapprox(cs_sos.weights[p], [1.0, 2.0], config) - @test cf_sos.variables[p] == v[[1, 3]] - objf = - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2.0, 1.0, 1.0], v), 0.0) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - objf, - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - @test MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE - @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status - @test MOI.get(model, MOI.ResultCount()) >= 1 - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - @test isapprox(MOI.get(model, MOI.ObjectiveValue()), 3, config) - @test isapprox(MOI.get(model, MOI.VariablePrimal(), v), [0, 1, 2], config) - MOI.delete(model, c1) - MOI.delete(model, c2) - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status - @test MOI.get(model, MOI.ResultCount()) >= 1 - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - @test isapprox(MOI.get(model, MOI.ObjectiveValue()), 5, config) - @test isapprox(MOI.get(model, MOI.VariablePrimal(), v), [1, 1, 2], config) - return -end - -# The test_linear_SOS2_integration test with the additional requirement that all -# variables are integer. -function test_SOS2() - model = MOI.Bridges.full_bridge_optimizer( - MOI.Utilities.CachingOptimizer( - MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), - Cbc.Optimizer(), - ), - Float64, - ) - config = MOI.Test.Config() - MOI.set(model, MOI.Silent(), true) - @test MOI.supports_constraint( - model, - MOI.VectorOfVariables, - MOI.SOS1{Float64}, - ) - @test MOI.supports_constraint( - model, - MOI.VectorOfVariables, - MOI.SOS2{Float64}, - ) - v = MOI.add_variables(model, 10) - @test MOI.get(model, MOI.NumberOfVariables()) == 10 - bin_constraints = [] - for i in 1:8 - vc = MOI.add_constraint(model, v[i], MOI.Interval(0.0, 2.0)) - @test vc.value == v[i].value - push!(bin_constraints, MOI.add_constraint(model, v[i], MOI.ZeroOne())) - @test bin_constraints[i].value == v[i].value - end - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, 2.0, 3.0, -1.0], v[[1, 2, 3, 9]]), - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.( - [5.0, 4.0, 7.0, 2.0, 1.0, -1.0], - v[[4, 5, 6, 7, 8, 10]], - ), - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.add_constraint( - model, - MOI.VectorOfVariables(v[[1, 2, 3]]), - MOI.SOS1([1.0, 2.0, 3.0]), - ) - vv = MOI.VectorOfVariables(v[[4, 5, 6, 7, 8]]) - sos2 = MOI.SOS2([5.0, 4.0, 7.0, 2.0, 1.0]) - c = MOI.add_constraint(model, vv, sos2) - #= - To allow for permutations in the sets and variable vectors - we're going to sort according to the weights - =# - cs_sos = MOI.get(model, MOI.ConstraintSet(), c) - cf_sos = MOI.get(model, MOI.ConstraintFunction(), c) - p = sortperm(cs_sos.weights) - @test isapprox(cs_sos.weights[p], [1.0, 2.0, 4.0, 5.0, 7.0], config) - @test cf_sos.variables[p] == v[[8, 7, 5, 4, 6]] - objf = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, 1.0], [v[9], v[10]]), - 0.0, - ) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - objf, - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - @test MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE - @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status - @test MOI.get(model, MOI.ResultCount()) >= 1 - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - @test isapprox(MOI.get(model, MOI.ObjectiveValue()), 15.0, config) - @test isapprox( - MOI.get(model, MOI.VariablePrimal(), v), - [0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 3.0, 12.0], - config, - ) - for cref in bin_constraints - MOI.delete(model, cref) - end - MOI.add_constraint.(model, v, MOI.Integer()) - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status - @test MOI.get(model, MOI.ResultCount()) >= 1 - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - @test isapprox(MOI.get(model, MOI.ObjectiveValue()), 30.0, config) - @test isapprox( - MOI.get(model, MOI.VariablePrimal(), v), - [0.0, 0.0, 2.0, 2.0, 0.0, 2.0, 0.0, 0.0, 6.0, 24.0], - config, - ) - return -end - """ test_VariablePrimalStart()