diff --git a/src/MOI_wrapper/objective.jl b/src/MOI_wrapper/objective.jl index 31c56fc1..51c059ec 100644 --- a/src/MOI_wrapper/objective.jl +++ b/src/MOI_wrapper/objective.jl @@ -1,7 +1,12 @@ -# objective function & sense +# Objective function & sense. +# +# SCIP only supports affine objectives. For quadratic or nonlinear objectives, +# the solver will depend on bridges with auxiliary variables. Single variable +# objectives are also accepted, but the type is not correctly remembered. MOI.supports(::Optimizer, ::MOI.ObjectiveSense) = true MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SAF}) = true +MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SVF}) = true function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SAF}, obj::SAF) allow_modification(o) @@ -24,6 +29,11 @@ function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SAF}, obj::SAF) return nothing end +function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SVF}, obj::SVF) + aff_obj = SAF([AFF_TERM(1.0, obj.variable)], 0.0) + return MOI.set(o, MOI.ObjectiveFunction{SAF}(), aff_obj) +end + function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{SAF}) terms = AFF_TERM[] for vr = keys(o.mscip.vars) @@ -35,6 +45,16 @@ function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{SAF}) return SAF(terms, constant) end +function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{SVF}) + aff_obj = MOI.get(o, MOI.ObjectiveFunction{SAF}()) + if (length(aff_obj.terms) != 1 + || aff_obj.terms[1].coefficient != 1.0 + || aff_obj.constant != 0.0) + error("Objective is not single variable: $aff_obj !") + end + return SVF(aff_obj.terms[1].variable_index) +end + function MOI.set(o::Optimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense) allow_modification(o) if sense == MOI.MIN_SENSE diff --git a/test/MINLPTests/run_minlptests.jl b/test/MINLPTests/run_minlptests.jl index e9d9dd1c..a6bdebf0 100644 --- a/test/MINLPTests/run_minlptests.jl +++ b/test/MINLPTests/run_minlptests.jl @@ -19,6 +19,11 @@ const DUALTOL = NaN # to disable the query end @testset "MINLPTests - nlp cvx" begin + @testset "nlp_cvx_001_010" begin + MINLPTests.nlp_cvx_001_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + @testset "nlp_cvx_002_010" begin MINLPTests.nlp_cvx_002_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; termination_target = MOI.OPTIMAL) @@ -29,6 +34,16 @@ end termination_target = MOI.OPTIMAL) end + @testset "nlp_cvx_101_012" begin + MINLPTests.nlp_cvx_101_012(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + + @testset "nlp_cvx_102_010" begin + MINLPTests.nlp_cvx_102_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + @testset "nlp_cvx_102_011" begin MINLPTests.nlp_cvx_102_011(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; termination_target = MOI.OPTIMAL) @@ -39,6 +54,16 @@ end termination_target = MOI.OPTIMAL) end + @testset "nlp_cvx_103_010" begin + MINLPTests.nlp_cvx_103_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + + @testset "nlp_cvx_103_011" begin + MINLPTests.nlp_cvx_103_011(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + @testset "nlp_cvx_103_012" begin MINLPTests.nlp_cvx_103_012(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; termination_target = MOI.OPTIMAL) @@ -49,6 +74,16 @@ end termination_target = MOI.OPTIMAL) end + @testset "nlp_cvx_103_014" begin + MINLPTests.nlp_cvx_103_014(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + + @testset "nlp_cvx_104_010" begin + MINLPTests.nlp_cvx_104_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + @testset "nlp_cvx_105_010" begin MINLPTests.nlp_cvx_105_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; termination_target = MOI.OPTIMAL) @@ -79,6 +114,16 @@ end termination_target = MOI.OPTIMAL) end + @testset "nlp_cvx_202_010" begin + MINLPTests.nlp_cvx_202_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + + @testset "nlp_cvx_202_011" begin + MINLPTests.nlp_cvx_202_011(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + @testset "nlp_cvx_202_012" begin MINLPTests.nlp_cvx_202_012(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; termination_target = MOI.OPTIMAL) @@ -104,6 +149,11 @@ end termination_target = MOI.OPTIMAL) end + @testset "nlp_cvx_205_010" begin + MINLPTests.nlp_cvx_205_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; + termination_target = MOI.OPTIMAL) + end + # Wrong solution?! # @testset "nlp_cvx_206_010" begin # MINLPTests.nlp_cvx_206_010(OPTIMIZER, OBJTOL, PRIMALTOL, DUALTOL; diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index ffec23a9..8bec3ab4 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -366,3 +366,25 @@ end # fail to delete them in wrong order @test_throws ErrorException MOI.delete(optimizer, x) end + +@testset "single variable objective" begin + optimizer = SCIP.Optimizer() + + # Happy Path: add objective and retrieve it. + x = MOI.add_variable(optimizer) + obj = MOI.SingleVariable(x) + MOI.set(optimizer, MOI.ObjectiveFunction{MOI.SingleVariable}(), obj) + MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) + @test MOI.get(optimizer, MOI.ObjectiveFunction{MOI.SingleVariable}()) == obj + @test MOI.get(optimizer, MOI.ObjectiveSense()) == MOI.MAX_SENSE + + MOI.empty!(optimizer) + + # Error with type mismatch + x = MOI.add_variable(optimizer) + y = MOI.add_variable(optimizer) + aff_obj = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 3.0) + MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), aff_obj) + MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) + @test_throws ErrorException MOI.get(optimizer, MOI.ObjectiveFunction{MOI.SingleVariable}()) +end