From fce47834f13ccca311ebe93c8b6c1e9919a4c3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Wed, 8 Sep 2021 22:36:15 +0200 Subject: [PATCH 01/16] up to MOI 10 --- Project.toml | 2 +- src/MOI_wrapper.jl | 26 ++++++------ src/MOI_wrapper/indicator_constraints.jl | 20 +++++---- src/MOI_wrapper/objective.jl | 8 ++-- src/MOI_wrapper/results.jl | 4 +- src/MOI_wrapper/variable.jl | 42 +++++++++---------- test/MOI_additional.jl | 53 ++++++++++++------------ test/MOI_conshdlr.jl | 4 +- test/MOI_nonlinear_exprs.jl | 2 +- test/MOI_wrapper_bridged.jl | 4 +- test/MOI_wrapper_direct.jl | 6 +-- test/sepa.jl | 4 +- 12 files changed, 87 insertions(+), 88 deletions(-) diff --git a/Project.toml b/Project.toml index bacc0b72..47b9db86 100644 --- a/Project.toml +++ b/Project.toml @@ -10,7 +10,7 @@ SCIP_jll = "e5ac4fe4-a920-5659-9bf8-f9f73e9e79ce" [compat] Ipopt_jll = "^3.13.2" -MathOptInterface = "^0.9.6" +MathOptInterface = "0.10" SCIP_jll = "^0.1.2" julia = "1" diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 9efb401c..7e8ec439 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -6,7 +6,6 @@ const MOIU = MOI.Utilities const VI = MOI.VariableIndex const CI = MOI.ConstraintIndex # supported functions -const SVF = MOI.SingleVariable const SAF = MOI.ScalarAffineFunction{Float64} const SQF = MOI.ScalarQuadraticFunction{Float64} const VAF = MOI.VectorAffineFunction{Float64} @@ -44,8 +43,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer scip_data = SCIPData(scip, Dict(), Dict(), 0, 0, Dict(), Dict(), Dict()) - o = new(scip_data, PtrMap(), ConsTypeMap(), Dict(), Dict(), Dict(), - nothing) + o = new(scip_data, PtrMap(), ConsTypeMap(), Dict(), Dict(), Dict(), nothing) finalizer(free_scip, o) # Set all parameters given as keyword arguments, replacing the @@ -53,7 +51,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer # allowed in Julia identifiers. for (key, value) in kwargs name = replace(String(key),"_" => "/") - MOI.set(o, Param(name), value) + MOI.set(o, MOI.RawOptimizerAttribute(name), value) end return o end @@ -135,16 +133,16 @@ end MOI.get(::Optimizer, ::MOI.SolverName) = "SCIP" -MOIU.supports_default_copy_to(model::Optimizer, copy_names::Bool) = !copy_names +MOIU.supports_default_copy_to(::Optimizer, copy_names::Bool) = !copy_names # Keep SCIP-specific alias for backwards-compatibility. -const Param = MOI.RawParameter +const Param = MOI.RawOptimizerAttribute -function MOI.get(o::Optimizer, param::MOI.RawParameter) +function MOI.get(o::Optimizer, param::MOI.RawOptimizerAttribute) return get_parameter(o.inner, param.name) end -function MOI.set(o::Optimizer, param::MOI.RawParameter, value) +function MOI.set(o::Optimizer, param::MOI.RawOptimizerAttribute, value) o.params[param.name] = value set_parameter(o.inner, param.name, value) return nothing @@ -153,11 +151,11 @@ end MOI.supports(o::Optimizer, ::MOI.Silent) = true function MOI.get(o::Optimizer, ::MOI.Silent) - return MOI.get(o, MOI.RawParameter("display/verblevel")) == 0 + return MOI.get(o, MOI.RawOptimizerAttribute("display/verblevel")) == 0 end function MOI.set(o::Optimizer, ::MOI.Silent, value) - param = MOI.RawParameter("display/verblevel") + param = MOI.RawOptimizerAttribute("display/verblevel") if value MOI.set(o, param, 0) # no output at all else @@ -168,7 +166,7 @@ end MOI.supports(o::Optimizer, ::MOI.TimeLimitSec) = true function MOI.get(o::Optimizer, ::MOI.TimeLimitSec) - raw_value = MOI.get(o, MOI.RawParameter("limits/time")) + raw_value = MOI.get(o, MOI.RawOptimizerAttribute("limits/time")) if raw_value == SCIPinfinity(o) return nothing else @@ -178,9 +176,9 @@ end function MOI.set(o::Optimizer, ::MOI.TimeLimitSec, value) if value === nothing - MOI.set(o, MOI.RawParameter("limits/time"), SCIPinfinity(o)) + MOI.set(o, MOI.RawOptimizerAttribute("limits/time"), SCIPinfinity(o)) else - MOI.set(o, MOI.RawParameter("limits/time"), value) + MOI.set(o, MOI.RawOptimizerAttribute("limits/time"), value) end end @@ -224,7 +222,7 @@ function MOI.get(o::Optimizer, ::MOI.NumberOfConstraints{F,S}) where {F,S} return haskey(o.constypes, (F, S)) ? length(o.constypes[F, S]) : 0 end -function MOI.get(o::Optimizer, ::MOI.ListOfConstraints) +function MOI.get(o::Optimizer, ::MOI.ListOfConstraintTypesPresent) return collect(keys(o.constypes)) end diff --git a/src/MOI_wrapper/indicator_constraints.jl b/src/MOI_wrapper/indicator_constraints.jl index f02b7427..9c5a668a 100644 --- a/src/MOI_wrapper/indicator_constraints.jl +++ b/src/MOI_wrapper/indicator_constraints.jl @@ -1,8 +1,8 @@ # Indicator constraints -MOI.supports_constraint(::Optimizer, ::Type{<:MOI.VectorAffineFunction}, ::Type{<:MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, <:MOI.LessThan}}) = true +MOI.supports_constraint(::Optimizer, ::Type{<:MOI.VectorAffineFunction}, ::Type{<:MOI.Indicator{MOI.ACTIVATE_ON_ONE, <:MOI.LessThan}}) = true -function MOI.add_constraint(o::Optimizer, func::MOI.VectorAffineFunction{T}, set::MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}) where {T<:Real, LT<:MOI.LessThan} +function MOI.add_constraint(o::Optimizer, func::MOI.VectorAffineFunction{T}, set::MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}) where {T<:Real, LT<:MOI.LessThan} allow_modification(o) first_index_terms = [v.scalar_term for v in func.terms if v.output_index == 1] scalar_index_terms = [v.scalar_term for v in func.terms if v.output_index != 1] @@ -14,21 +14,21 @@ function MOI.add_constraint(o::Optimizer, func::MOI.VectorAffineFunction{T}, set # a^T x + b <= c ===> a^T <= c - b cr = add_indicator_constraint(o.inner, y, x, a, MOI.constant(set.set) - b) - ci = CI{MOI.VectorAffineFunction{T}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}}(cr.val) + ci = CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}(cr.val) register!(o, ci) register!(o, cons(o, ci), cr) return ci end -function MOI.delete(o::Optimizer, ci::CI{MOI.VectorAffineFunction{T}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} +function MOI.delete(o::Optimizer, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} allow_modification(o) - delete!(o.constypes[MOI.VectorAffineFunction{T}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}], ConsRef(ci.value)) + delete!(o.constypes[MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) delete(o.inner, ConsRef(ci.value)) return nothing end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{MOI.VectorAffineFunction{T}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} indicator_cons = cons(o, ci)::Ptr{SCIP_CONS} bin_var = SCIPgetBinaryVarIndicator(indicator_cons)::Ptr{SCIP_VAR} slack_var = SCIPgetSlackVarIndicator(indicator_cons)::Ptr{SCIP_VAR} @@ -46,7 +46,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{MOI.VectorAffine return VAF(vcat(ind_terms, vec_terms), [0.0, 0.0]) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{MOI.VectorAffineFunction{T}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} indicator_cons = cons(o, ci)::Ptr{SCIP_CONS} linear_cons = SCIPgetLinearConsIndicator(indicator_cons)::Ptr{SCIP_CONS} @@ -54,5 +54,9 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{MOI.VectorAffineFunct rhs = SCIPgetRhsLinear(o, linear_cons) lhs == -SCIPinfinity(o) || error("Have lower bound on indicator constraint!") - return MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(rhs)) + return MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(rhs)) +end + +function MOI.get(o::Optimizer, ::MOI.ListOfConstraintIndices{F, S}) where {F <: MOI.VectorAffineFunction{Float64}, S <: MOI.Indicator{MOI.ACTIVATE_ON_ONE, MOI.LessThan{Float64}}} + return Vector{F, S}(o.constypes[F,S]) end diff --git a/src/MOI_wrapper/objective.jl b/src/MOI_wrapper/objective.jl index f9f51e9c..8b3b1aa1 100644 --- a/src/MOI_wrapper/objective.jl +++ b/src/MOI_wrapper/objective.jl @@ -6,7 +6,7 @@ MOI.supports(::Optimizer, ::MOI.ObjectiveSense) = true MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SAF}) = true -MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SVF}) = true +MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{VI}) = true function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SAF}, obj::SAF) allow_modification(o) @@ -30,7 +30,7 @@ function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SAF}, obj::SAF) end # Note that SCIP always uses a scalar affine function internally! -function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SVF}, obj::SVF) +function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{VI}, obj::VI) aff_obj = SAF([AFF_TERM(1.0, obj.variable)], 0.0) return MOI.set(o, MOI.ObjectiveFunction{SAF}(), aff_obj) end @@ -47,14 +47,14 @@ function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{SAF}) end # Note that SCIP always uses a scalar affine function internally! -function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{SVF}) +function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{VI}) 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) + return aff_obj.terms[1].variable_index end function MOI.set(o::Optimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense) diff --git a/src/MOI_wrapper/results.jl b/src/MOI_wrapper/results.jl index f685fea1..cefff48d 100644 --- a/src/MOI_wrapper/results.jl +++ b/src/MOI_wrapper/results.jl @@ -86,7 +86,7 @@ function MOI.get(o::Optimizer, attr::MOI.VariablePrimal, vi::VI) return SCIPgetSolVal(o, sols[attr.N], var(o, vi)) end -function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{SVF,<:BOUNDS}) +function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{VI,<:BOUNDS}) assert_solved(o) MOI.check_result_index_bounds(o, attr) sols = unsafe_wrap(Array{Ptr{SCIP_SOL}}, SCIPgetSols(o), SCIPgetNSols(o)) @@ -110,7 +110,7 @@ function MOI.get(o::Optimizer, ::MOI.RelativeGap) return SCIPgetGap(o) end -function MOI.get(o::Optimizer, ::MOI.SolveTime) +function MOI.get(o::Optimizer, ::MOI.SolveTimeSec) return SCIPgetSolvingTime(o) end diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index a73e746e..b4b6303f 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -40,14 +40,13 @@ end ## variable types (binary, integer) -MOI.supports_constraint(o::Optimizer, ::Type{SVF}, ::Type{<:VAR_TYPES}) = true +MOI.supports_constraint(o::Optimizer, ::Type{VI}, ::Type{<:VAR_TYPES}) = true scip_vartype(::Type{MOI.ZeroOne}) = SCIP_VARTYPE_BINARY scip_vartype(::Type{MOI.Integer}) = SCIP_VARTYPE_INTEGER -function MOI.add_constraint(o::Optimizer, func::SVF, set::S) where {S <: VAR_TYPES} +function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where {S <: VAR_TYPES} allow_modification(o) - vi = func.variable v = var(o, vi) infeasible = Ref{SCIP_Bool}() @SCIP_CALL SCIPchgVarType(o, v, scip_vartype(S), infeasible) @@ -74,11 +73,11 @@ function MOI.add_constraint(o::Optimizer, func::SVF, set::S) where {S <: VAR_TYP end end # use var index for cons index of this type - i = func.variable.value - return register!(o, CI{SVF, S}(i)) + i = vi.value + return register!(o, CI{VI, S}(i)) end -function MOI.delete(o::Optimizer, ci::CI{SVF,S}) where {S <: VAR_TYPES} +function MOI.delete(o::Optimizer, ci::CI{VI,S}) where {S <: VAR_TYPES} allow_modification(o) vi = VI(ci.value) @@ -100,18 +99,17 @@ function MOI.delete(o::Optimizer, ci::CI{SVF,S}) where {S <: VAR_TYPES} end # but do delete the constraint reference - delete!(o.constypes[SVF, S], ConsRef(ci.value)) + delete!(o.constypes[VI, S], ConsRef(ci.value)) return nothing end ## variable bounds -MOI.supports_constraint(o::Optimizer, ::Type{SVF}, ::Type{<:BOUNDS}) = true +MOI.supports_constraint(o::Optimizer, ::Type{VI}, ::Type{<:BOUNDS}) = true -function MOI.add_constraint(o::Optimizer, func::SVF, set::S) where S <: BOUNDS +function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where S <: BOUNDS allow_modification(o) - vi = func.variable v = var(o, vi) inf = SCIPinfinity(o) @@ -154,25 +152,25 @@ function MOI.add_constraint(o::Optimizer, func::SVF, set::S) where S <: BOUNDS end # use var index for cons index of this type - i = func.variable.value - return register!(o, CI{SVF, S}(i)) + i = vi.value + return register!(o, CI{VI, S}(i)) end -function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{SVF, S}) where S <: Union{MOI.Interval{Float64}, MOI.EqualTo{Float64}} +function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{VI, S}) where S <: Union{MOI.Interval{Float64}, MOI.EqualTo{Float64}} @SCIP_CALL SCIPchgVarLb(o, v, lb) @SCIP_CALL SCIPchgVarUb(o, v, ub) end -function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{SVF, MOI.GreaterThan{Float64}}) +function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{VI, MOI.GreaterThan{Float64}}) @SCIP_CALL SCIPchgVarLb(o, v, lb) end -function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{SVF, MOI.LessThan{Float64}}) +function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{VI, MOI.LessThan{Float64}}) @SCIP_CALL SCIPchgVarUb(o, v, ub) end -function MOI.delete(o::Optimizer, ci::CI{SVF,S}) where S <: BOUNDS +function MOI.delete(o::Optimizer, ci::CI{VI,S}) where S <: BOUNDS allow_modification(o) # Don't actually delete any SCIP constraint, just reset bounds @@ -187,12 +185,12 @@ function MOI.delete(o::Optimizer, ci::CI{SVF,S}) where S <: BOUNDS # but do delete the constraint reference haskey(o.binbounds, vi) && delete!(o.binbounds, vi) - delete!(o.constypes[SVF, S], ConsRef(ci.value)) + delete!(o.constypes[VI, S], ConsRef(ci.value)) return nothing end -function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SVF,S}, set::S) where {S <: BOUNDS} +function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{VI,S}, set::S) where {S <: BOUNDS} allow_modification(o) v = var(o, VI(ci.value)) # cons index is actually var index lb, ub = bounds(set) @@ -209,15 +207,15 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SVF,S}, set::S) end # TODO: is actually wrong for unbounded variables? -function MOI.is_valid(o::Optimizer, ci::CI{SVF,<:BOUNDS}) +function MOI.is_valid(o::Optimizer, ci::CI{VI,<:BOUNDS}) return haskey(o.inner.vars, VarRef(ci.value)) end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SVF, S}) where S <: BOUNDS - return SVF(VI(ci.value)) +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, S}) where S <: BOUNDS + return VI(ci.value) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SVF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, S}) where S <: BOUNDS vi = VI(ci.value) v = var(o, vi) lb, ub = SCIPvarGetLbOriginal(v), SCIPvarGetUbOriginal(v) diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index cbe9135f..481f2c3f 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -3,14 +3,13 @@ const MOI = MathOptInterface const VI = MOI.VariableIndex const CI = MOI.ConstraintIndex -const SVF = MOI.SingleVariable function var_bounds(o::SCIP.Optimizer, vi::VI) - return MOI.get(o, MOI.ConstraintSet(), CI{SVF,MOI.Interval{Float64}}(vi.value)) + return MOI.get(o, MOI.ConstraintSet(), CI{VI,MOI.Interval{Float64}}(vi.value)) end function chg_bounds(o::SCIP.Optimizer, vi::VI, set::S) where S - ci = CI{SVF,S}(vi.value) + ci = CI{VI,S}(vi.value) MOI.set(o, MOI.ConstraintSet(), ci, set) return nothing end @@ -369,7 +368,7 @@ end x3 = MOI.add_variable(optimizer) y = MOI.add_variable(optimizer) t = MOI.add_constraint(optimizer, y, MOI.ZeroOne()) - iset = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)) + iset = MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)) ind_func = MOI.VectorAffineFunction( [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, y)), MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x1)), @@ -449,27 +448,27 @@ end @testset "set_parameter" begin # bool optimizer = SCIP.Optimizer(branching_preferbinary=true) - @test MOI.get(optimizer, MOI.RawParameter("branching/preferbinary")) == true + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/preferbinary")) == true # int optimizer = SCIP.Optimizer(conflict_minmaxvars=1) - @test MOI.get(optimizer, MOI.RawParameter("conflict/minmaxvars")) == 1 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("conflict/minmaxvars")) == 1 # long int optimizer = SCIP.Optimizer(heuristics_alns_maxnodes=2) - @test MOI.get(optimizer, MOI.RawParameter("heuristics/alns/maxnodes")) == 2 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/maxnodes")) == 2 # real optimizer = SCIP.Optimizer(branching_scorefac=0.15) - @test MOI.get(optimizer, MOI.RawParameter("branching/scorefac")) == 0.15 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/scorefac")) == 0.15 # char optimizer = SCIP.Optimizer(branching_scorefunc='s') - @test MOI.get(optimizer, MOI.RawParameter("branching/scorefunc")) == 's' + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/scorefunc")) == 's' # string optimizer = SCIP.Optimizer(heuristics_alns_rewardfilename="abc.txt") - @test MOI.get(optimizer, MOI.RawParameter("heuristics/alns/rewardfilename")) == "abc.txt" + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/rewardfilename")) == "abc.txt" # invalid @test_throws ErrorException SCIP.Optimizer(some_invalid_param_name=true) @@ -479,31 +478,31 @@ end optimizer = SCIP.Optimizer() # bool - MOI.set(optimizer, MOI.RawParameter("branching/preferbinary"), true) - @test MOI.get(optimizer, MOI.RawParameter("branching/preferbinary")) == true + MOI.set(optimizer, MOI.RawOptimizerAttribute("branching/preferbinary"), true) + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/preferbinary")) == true # int - MOI.set(optimizer, MOI.RawParameter("conflict/minmaxvars"), 1) - @test MOI.get(optimizer, MOI.RawParameter("conflict/minmaxvars")) == 1 + MOI.set(optimizer, MOI.RawOptimizerAttribute("conflict/minmaxvars"), 1) + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("conflict/minmaxvars")) == 1 # long int - MOI.set(optimizer, MOI.RawParameter("heuristics/alns/maxnodes"), 2) - @test MOI.get(optimizer, MOI.RawParameter("heuristics/alns/maxnodes")) == 2 + MOI.set(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/maxnodes"), 2) + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/maxnodes")) == 2 # real - MOI.set(optimizer, MOI.RawParameter("branching/scorefac"), 0.15) - @test MOI.get(optimizer, MOI.RawParameter("branching/scorefac")) == 0.15 + MOI.set(optimizer, MOI.RawOptimizerAttribute("branching/scorefac"), 0.15) + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/scorefac")) == 0.15 # char - MOI.set(optimizer, MOI.RawParameter("branching/scorefunc"), 's') - @test MOI.get(optimizer, MOI.RawParameter("branching/scorefunc")) == 's' + MOI.set(optimizer, MOI.RawOptimizerAttribute("branching/scorefunc"), 's') + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("branching/scorefunc")) == 's' # string - MOI.set(optimizer, MOI.RawParameter("heuristics/alns/rewardfilename"), "abc.txt") - @test MOI.get(optimizer, MOI.RawParameter("heuristics/alns/rewardfilename")) == "abc.txt" + MOI.set(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/rewardfilename"), "abc.txt") + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("heuristics/alns/rewardfilename")) == "abc.txt" # invalid - @test_throws ErrorException MOI.set(optimizer, MOI.RawParameter("some/invalid/param/name"), true) + @test_throws ErrorException MOI.set(optimizer, MOI.RawOptimizerAttribute("some/invalid/param/name"), true) end @testset "Silent" begin @@ -513,17 +512,17 @@ end # "loud" by default @test MOI.get(optimizer, MOI.Silent()) == false - @test MOI.get(optimizer, MOI.RawParameter("display/verblevel")) == 4 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("display/verblevel")) == 4 # make it silent MOI.set(optimizer, MOI.Silent(), true) @test MOI.get(optimizer, MOI.Silent()) == true - @test MOI.get(optimizer, MOI.RawParameter("display/verblevel")) == 0 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("display/verblevel")) == 0 # but a user can override it - MOI.set(optimizer, MOI.RawParameter("display/verblevel"), 1) + MOI.set(optimizer, MOI.RawOptimizerAttribute("display/verblevel"), 1) @test MOI.get(optimizer, MOI.Silent()) == false - @test MOI.get(optimizer, MOI.RawParameter("display/verblevel")) == 1 + @test MOI.get(optimizer, MOI.RawOptimizerAttribute("display/verblevel")) == 1 end @testset "Query results (before/after solve)" begin diff --git a/test/MOI_conshdlr.jl b/test/MOI_conshdlr.jl index 2b1c78f5..9c9fae78 100644 --- a/test/MOI_conshdlr.jl +++ b/test/MOI_conshdlr.jl @@ -166,9 +166,9 @@ end optimizer = SCIP.Optimizer(display_verblevel=0, presolving_maxrounds=0) allow_dual_reductions = if SCIP.SCIPmajorVersion() < 7 - MOI.RawParameter("misc/allowdualreds") + MOI.RawOptimizerAttribute("misc/allowdualreds") else - MOI.RawParameter("misc/allowstrongdualreds") + MOI.RawOptimizerAttribute("misc/allowstrongdualreds") end MOI.set(optimizer, allow_dual_reductions, SCIP.FALSE) diff --git a/test/MOI_nonlinear_exprs.jl b/test/MOI_nonlinear_exprs.jl index b8607543..ba27ef93 100644 --- a/test/MOI_nonlinear_exprs.jl +++ b/test/MOI_nonlinear_exprs.jl @@ -118,7 +118,7 @@ end @testset "add nonlinear constraint after solve" begin optimizer = SCIP.Optimizer() - MOI.set(optimizer, MOI.RawParameter("display/verblevel"), 0) + MOI.set(optimizer, MOI.RawOptimizerAttribute("display/verblevel"), 0) x, y = MOI.add_variables(optimizer, 2) diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index ee653a8b..37e2bf41 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -4,8 +4,8 @@ const MOIB = MOI.Bridges const MOIT = MOI.Test const BRIDGED = MOIB.full_bridge_optimizer(SCIP.Optimizer(display_verblevel=0), Float64) -const CONFIG = MOIT.TestConfig(atol=1e-5, rtol=1e-5, duals=false, infeas_certificates=false) -const CONFIG3 = MOIT.TestConfig(atol=1e-3, rtol=1e-2, duals=false, infeas_certificates=false) +const CONFIG = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[MOI.ConstraintDual]) +const CONFIG3 = MOIT.Config(atol=1e-3, rtol=1e-2, exclude=Any[MOI.ConstraintDual]) @testset "MOI Continuous Linear" begin excluded = [ diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index 2d74bd0c..171b8fea 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -70,7 +70,7 @@ function indicator4_test(model::MOI.ModelLike, config) @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.ZeroOne) @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.Interval{Float64}) @test MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) - @test MOI.supports_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, MOI.LessThan{Float64}}) + @test MOI.supports_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, MOI.LessThan{Float64}}) x1 = MOI.add_variable(model) x2 = MOI.add_variable(model) z1 = MOI.add_variable(model) @@ -83,7 +83,7 @@ function indicator4_test(model::MOI.ModelLike, config) ], [0.0, -1.0] ) - iset1 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(7.0)) + iset1 = MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(7.0)) MOI.add_constraint(model, f1, iset1) f2 = MOI.VectorAffineFunction( @@ -93,7 +93,7 @@ function indicator4_test(model::MOI.ModelLike, config) ], [0.0, 1.0], ) - iset2 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(10.0)) + iset2 = MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(10.0)) MOI.add_constraint(model, f2, iset2) diff --git a/test/sepa.jl b/test/sepa.jl index f2a9285b..0a3875c8 100644 --- a/test/sepa.jl +++ b/test/sepa.jl @@ -10,8 +10,8 @@ const MOI = MathOptInterface # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, From 1d68a9e2764c8585cadf4f32fb0ed3c0e9f23783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 9 Sep 2021 11:17:14 +0200 Subject: [PATCH 02/16] fix deprecations --- README.md | 2 +- src/MOI_wrapper/indicator_constraints.jl | 4 +-- src/MOI_wrapper/linear_constraints.jl | 2 +- src/MOI_wrapper/objective.jl | 4 +-- src/MOI_wrapper/quadratic_constraints.jl | 6 ++-- src/MOI_wrapper/results.jl | 8 +++--- src/MOI_wrapper/sepa.jl | 2 +- test/MOI_additional.jl | 36 ++++++++++++------------ test/MOI_conshdlr.jl | 30 ++++++++++---------- test/MOI_wrapper_direct.jl | 4 +-- test/cutcallback.jl | 12 ++++---- test/sepa.jl | 12 ++++---- 12 files changed, 61 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index da923c5e..bf911925 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ features through MathOptInterface. However, the focus is on keeping the wrapper simple and avoiding duplicate storage of model data. As a consequence, we do not currently support some features such as retrieving -constraints by name (`SingleVariable`-set constraints are not stored as SCIP +constraints by name (`VariableIndex`-set constraints are not stored as SCIP constraints explicitly). Support for more constraint types (quadratic/SOC, SOS1/2, nonlinear expression) diff --git a/src/MOI_wrapper/indicator_constraints.jl b/src/MOI_wrapper/indicator_constraints.jl index 9c5a668a..e9330bd8 100644 --- a/src/MOI_wrapper/indicator_constraints.jl +++ b/src/MOI_wrapper/indicator_constraints.jl @@ -7,8 +7,8 @@ function MOI.add_constraint(o::Optimizer, func::MOI.VectorAffineFunction{T}, set first_index_terms = [v.scalar_term for v in func.terms if v.output_index == 1] scalar_index_terms = [v.scalar_term for v in func.terms if v.output_index != 1] length(first_index_terms) == 1 || error("There should be exactly one term in output_index 1, found $(length(first_index_terms))") - y = VarRef(first_index_terms[1].variable_index.value) - x = [VarRef(vi.variable_index.value) for vi in scalar_index_terms] + y = VarRef(first_index_terms[1].variable.value) + x = [VarRef(vi.variable.value) for vi in scalar_index_terms] a = [vi.coefficient for vi in scalar_index_terms] b = func.constants[2] # a^T x + b <= c ===> a^T <= c - b diff --git a/src/MOI_wrapper/linear_constraints.jl b/src/MOI_wrapper/linear_constraints.jl index 348e1b31..8eb38e39 100644 --- a/src/MOI_wrapper/linear_constraints.jl +++ b/src/MOI_wrapper/linear_constraints.jl @@ -9,7 +9,7 @@ function MOI.add_constraint(o::Optimizer, func::SAF, set::S) where {S <: BOUNDS} allow_modification(o) - varrefs = [VarRef(t.variable_index.value) for t in func.terms] + varrefs = [VarRef(t.variable.value) for t in func.terms] coefs = [t.coefficient for t in func.terms] lhs, rhs = bounds(set) diff --git a/src/MOI_wrapper/objective.jl b/src/MOI_wrapper/objective.jl index 8b3b1aa1..b8ea4e31 100644 --- a/src/MOI_wrapper/objective.jl +++ b/src/MOI_wrapper/objective.jl @@ -18,7 +18,7 @@ function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{SAF}, obj::SAF) # set new objective coefficients, summing coefficients for t in obj.terms - v = var(o, t.variable_index) + v = var(o, t.variable) oldcoef = SCIPvarGetObj(v) newcoef = oldcoef + t.coefficient @SCIP_CALL SCIPchgVarObj(o, v, newcoef) @@ -54,7 +54,7 @@ function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{VI}) || aff_obj.constant != 0.0) error("Objective is not single variable: $aff_obj !") end - return aff_obj.terms[1].variable_index + return aff_obj.terms[1].variable end function MOI.set(o::Optimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense) diff --git a/src/MOI_wrapper/quadratic_constraints.jl b/src/MOI_wrapper/quadratic_constraints.jl index 9eb081bb..c0d54360 100644 --- a/src/MOI_wrapper/quadratic_constraints.jl +++ b/src/MOI_wrapper/quadratic_constraints.jl @@ -10,12 +10,12 @@ function MOI.add_constraint(o::Optimizer, func::SQF, set::S) where {S <: BOUNDS} allow_modification(o) # affine terms - linrefs = [VarRef(t.variable_index.value) for t in func.affine_terms] + linrefs = [VarRef(t.variable.value) for t in func.affine_terms] lincoefs = [t.coefficient for t in func.affine_terms] # quadratic terms - quadrefs1 = [VarRef(t.variable_index_1.value) for t in func.quadratic_terms] - quadrefs2 = [VarRef(t.variable_index_2.value) for t in func.quadratic_terms] + quadrefs1 = [VarRef(t.variable_1.value) for t in func.quadratic_terms] + quadrefs2 = [VarRef(t.variable_2.value) for t in func.quadratic_terms] # Divide coefficients by 2 iff they come from the diagonal: # Take coef * x * y as-is, but turn coef * x^2 into coef/2 * x^2. factor = 1.0 .- 0.5 * (quadrefs1 .== quadrefs2) diff --git a/src/MOI_wrapper/results.jl b/src/MOI_wrapper/results.jl index cefff48d..fcda7eb4 100644 --- a/src/MOI_wrapper/results.jl +++ b/src/MOI_wrapper/results.jl @@ -24,7 +24,7 @@ function MOI.get(o::Optimizer, ::MOI.TerminationStatus) end function MOI.get(o::Optimizer, attr::MOI.PrimalStatus) - return if 1 <= attr.N <= MOI.get(o, MOI.ResultCount()) + return if 1 <= attr.result_index <= MOI.get(o, MOI.ResultCount()) MOI.FEASIBLE_POINT else MOI.NO_SOLUTION @@ -83,21 +83,21 @@ function MOI.get(o::Optimizer, attr::MOI.VariablePrimal, vi::VI) assert_solved(o) MOI.check_result_index_bounds(o, attr) sols = unsafe_wrap(Array{Ptr{SCIP_SOL}}, SCIPgetSols(o), SCIPgetNSols(o)) - return SCIPgetSolVal(o, sols[attr.N], var(o, vi)) + return SCIPgetSolVal(o, sols[attr.result_index], var(o, vi)) end function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{VI,<:BOUNDS}) assert_solved(o) MOI.check_result_index_bounds(o, attr) sols = unsafe_wrap(Array{Ptr{SCIP_SOL}}, SCIPgetSols(o), SCIPgetNSols(o)) - return SCIPgetSolVal(o, sols[attr.N], var(o, VI(ci.value))) + return SCIPgetSolVal(o, sols[attr.result_index], var(o, VI(ci.value))) end function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{SAF,<:BOUNDS}) assert_solved(o) MOI.check_result_index_bounds(o, attr) sols = unsafe_wrap(Array{Ptr{SCIP_SOL}}, SCIPgetSols(o), SCIPgetNSols(o)) - return SCIPgetActivityLinear(o, cons(o, ci), sols[attr.N]) + return SCIPgetActivityLinear(o, cons(o, ci), sols[attr.result_index]) end function MOI.get(o::Optimizer, ::MOI.ObjectiveBound) diff --git a/src/MOI_wrapper/sepa.jl b/src/MOI_wrapper/sepa.jl index d7392538..15e91114 100644 --- a/src/MOI_wrapper/sepa.jl +++ b/src/MOI_wrapper/sepa.jl @@ -79,7 +79,7 @@ MOI.supports(::Optimizer, ::MOI.UserCutCallback) = true function MOI.submit(o::Optimizer, cb_data::MOI.UserCut{CutCbData}, func::SAF, set::S) where S <: BOUNDS - varrefs = [VarRef(t.variable_index.value) for t in func.terms] + varrefs = [VarRef(t.variable.value) for t in func.terms] coefs = [t.coefficient for t in func.terms] lhs, rhs = bounds(set) diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index 481f2c3f..fcb4c588 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -216,7 +216,7 @@ end MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0,1.0], [y,z]), 0.0)) MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) - ceq = MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.EqualTo(1.0)) + ceq = MOI.add_constraint(optimizer, x, MOI.EqualTo(1.0)) csoc = MOI.add_constraint(optimizer, MOI.VectorOfVariables([x, y, z]), MOI.SecondOrderCone(3)) @@ -245,8 +245,8 @@ end x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.Interval(0.0, 1.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.GreaterThan(2.0)) + MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0)) + MOI.add_constraint(optimizer, y, MOI.GreaterThan(2.0)) MOI.add_constraint(optimizer, MOI.VectorOfVariables([x, y]), MOI.SecondOrderCone(2)) MOI.optimize!(optimizer) @@ -260,7 +260,7 @@ end @test_throws ErrorException MOI.add_constraint( optimizer, MOI.VectorOfVariables([x, y]), MOI.SecondOrderCone(2)) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) + MOI.add_constraint(optimizer, x, MOI.GreaterThan(0.0)) MOI.add_constraint(optimizer, MOI.VectorOfVariables([x, y]), MOI.SecondOrderCone(2)) # no error @@ -270,9 +270,9 @@ end optimizer = SCIP.Optimizer(display_verblevel=0) x, y, z = MOI.add_variables(optimizer, 3) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.LessThan(1.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.LessThan(1.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(z), MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, x, MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, y, MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, z, MOI.LessThan(1.0)) c = MOI.add_constraint(optimizer, MOI.VectorOfVariables([x,y,z]), MOI.SOS1([1.0,2.0,3.0])) @@ -298,9 +298,9 @@ end optimizer = SCIP.Optimizer(display_verblevel=0) x, y, z = MOI.add_variables(optimizer, 3) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.LessThan(1.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.LessThan(1.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(z), MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, x, MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, y, MOI.LessThan(1.0)) + MOI.add_constraint(optimizer, z, MOI.LessThan(1.0)) c = MOI.add_constraint(optimizer, MOI.VectorOfVariables([x,y,z]), MOI.SOS2([1.0,2.0,3.0])) @@ -331,8 +331,8 @@ end optimizer = SCIP.Optimizer(display_verblevel=0) x1, x2, z1, z2 = MOI.add_variables(optimizer, 4) - MOI.add_constraint(optimizer, MOI.SingleVariable(z1), MOI.LessThan(4.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(z2), MOI.GreaterThan(-8.0)) + MOI.add_constraint(optimizer, z1, MOI.LessThan(4.0)) + MOI.add_constraint(optimizer, z2, MOI.GreaterThan(-8.0)) c1 = MOI.add_constraint(optimizer, MOI.VectorOfVariables([x1, z1]), SCIP.AbsolutePowerSet(2.0)) @@ -427,10 +427,10 @@ end # Happy Path: add objective and retrieve it. x = MOI.add_variable(optimizer) - obj = MOI.SingleVariable(x) - MOI.set(optimizer, MOI.ObjectiveFunction{MOI.SingleVariable}(), obj) + obj = x + MOI.set(optimizer, MOI.ObjectiveFunction{MOI.VariableIndex}(), obj) MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) - @test MOI.get(optimizer, MOI.ObjectiveFunction{MOI.SingleVariable}()) == obj + @test MOI.get(optimizer, MOI.ObjectiveFunction{MOI.VariableIndex}()) == obj @test MOI.get(optimizer, MOI.ObjectiveSense()) == MOI.MAX_SENSE @test MOI.get(optimizer, MOI.ObjectiveFunctionType()) == MOI.ScalarAffineFunction{Float64} @@ -442,7 +442,7 @@ end 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}()) + @test_throws ErrorException MOI.get(optimizer, MOI.ObjectiveFunction{MOI.VariableIndex}()) end @testset "set_parameter" begin @@ -530,8 +530,8 @@ end atol, rtol = 1e-6, 1e-6 x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.GreaterThan(0.0)) + MOI.add_constraint(optimizer, x, MOI.GreaterThan(0.0)) + MOI.add_constraint(optimizer, y, MOI.GreaterThan(0.0)) c = MOI.add_constraint( optimizer, diff --git a/test/MOI_conshdlr.jl b/test/MOI_conshdlr.jl index 9c9fae78..1cc93a32 100644 --- a/test/MOI_conshdlr.jl +++ b/test/MOI_conshdlr.jl @@ -7,8 +7,8 @@ const MOI = MathOptInterface # add two binary variables: x, y x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # maximize 2x + y MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), @@ -38,9 +38,9 @@ end # add three binary variables x, y, z = MOI.add_variables(optimizer, 3) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(z), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) + MOI.add_constraint(optimizer, z, MOI.ZeroOne()) # maximize 2x + 3y + 2z MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), @@ -72,9 +72,9 @@ end # add three binary variables x, y, z = MOI.add_variables(optimizer, 3) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(z), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) + MOI.add_constraint(optimizer, z, MOI.ZeroOne()) # maximize 2x + 3y + 2z MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), @@ -104,9 +104,9 @@ end # add three binary variables x, y, z = MOI.add_variables(optimizer, 3) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(z), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) + MOI.add_constraint(optimizer, z, MOI.ZeroOne()) # maximize 2x + 3y + 2z MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), @@ -135,8 +135,8 @@ end # add three integer variables, in {0, 1, 2} x, y, z = MOI.add_variables(optimizer, 3) for v in [x, y, z] - MOI.add_constraint(optimizer, MOI.SingleVariable(v), MOI.Integer()) - MOI.add_constraint(optimizer, MOI.SingleVariable(v), MOI.Interval(0.0, 2.0)) + MOI.add_constraint(optimizer, v, MOI.Integer()) + MOI.add_constraint(optimizer, v, MOI.Interval(0.0, 2.0)) end # maximize 2x + y @@ -176,8 +176,8 @@ end # add binary variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # maximize 2x + y MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index 171b8fea..f538c50b 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -67,8 +67,8 @@ function indicator4_test(model::MOI.ModelLike, config) @test MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}()) @test MOI.supports(model, MOI.ObjectiveSense()) - @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.ZeroOne) - @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.Interval{Float64}) + @test MOI.supports_constraint(model, MOI.VariableIndex, MOI.ZeroOne) + @test MOI.supports_constraint(model, MOI.VariableIndex, MOI.Interval{Float64}) @test MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) @test MOI.supports_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, MOI.LessThan{Float64}}) x1 = MOI.add_variable(model) diff --git a/test/cutcallback.jl b/test/cutcallback.jl index 6d270eba..632bd9a5 100644 --- a/test/cutcallback.jl +++ b/test/cutcallback.jl @@ -14,8 +14,8 @@ const MOI = MathOptInterface # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, @@ -69,8 +69,8 @@ end # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, @@ -120,8 +120,8 @@ end # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, diff --git a/test/sepa.jl b/test/sepa.jl index 0a3875c8..853d8388 100644 --- a/test/sepa.jl +++ b/test/sepa.jl @@ -50,8 +50,8 @@ end # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, @@ -97,8 +97,8 @@ end # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, @@ -144,8 +144,8 @@ end # add variables x, y = MOI.add_variables(optimizer, 2) - MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.ZeroOne()) - MOI.add_constraint(optimizer, MOI.SingleVariable(y), MOI.ZeroOne()) + MOI.add_constraint(optimizer, x, MOI.ZeroOne()) + MOI.add_constraint(optimizer, y, MOI.ZeroOne()) # add constraint: x + y ≤ 1.5 MOI.add_constraint(optimizer, From 0d98a63c46d86f17cd53a4775588ff9ca9491df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 23 Sep 2021 15:34:45 +0200 Subject: [PATCH 03/16] fix SAF-EqualTo tests --- src/MOI_wrapper.jl | 18 +++++++++++++++++ src/MOI_wrapper/abspower_constraints.jl | 5 +++-- src/MOI_wrapper/constraints.jl | 4 ++++ src/MOI_wrapper/indicator_constraints.jl | 3 +++ src/MOI_wrapper/linear_constraints.jl | 3 +++ src/MOI_wrapper/quadratic_constraints.jl | 25 +++++++++++++----------- src/MOI_wrapper/soc_constraints.jl | 3 +++ src/MOI_wrapper/sos_constraints.jl | 4 ++++ src/MOI_wrapper/variable.jl | 5 +++++ test/MOI_wrapper_bridged.jl | 2 +- 10 files changed, 58 insertions(+), 14 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 7e8ec439..0a1cbcc2 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -135,6 +135,13 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "SCIP" MOIU.supports_default_copy_to(::Optimizer, copy_names::Bool) = !copy_names +function _throw_if_invalid(o::Optimizer, ci::CI{F, S}) where {F, S} + if !in(ConsRef(ci.value), o.constypes[F, S]) + throw(MOI.InvalidIndex(ci)) + end + return nothing +end + # Keep SCIP-specific alias for backwards-compatibility. const Param = MOI.RawOptimizerAttribute @@ -226,6 +233,17 @@ function MOI.get(o::Optimizer, ::MOI.ListOfConstraintTypesPresent) return collect(keys(o.constypes)) end +function MOI.get(o::Optimizer, ::MOI.ListOfConstraintIndices{F, S}) where {F, S} + list_indices = Vector{CI{F,S}}() + if !haskey(o.constypes, (F, S)) + return list_indices + end + for cref in o.constypes[F, S] + push!(list_indices, CI{F,S}(cref.val)) + end + return list_indices +end + function set_start_values(o::Optimizer) if isempty(o.start) # no primal start values are given diff --git a/src/MOI_wrapper/abspower_constraints.jl b/src/MOI_wrapper/abspower_constraints.jl index 36480f1f..3f2b7c27 100644 --- a/src/MOI_wrapper/abspower_constraints.jl +++ b/src/MOI_wrapper/abspower_constraints.jl @@ -47,6 +47,7 @@ function MOI.add_constraint(o::Optimizer, func::VECTOR, set::ABSPOWER) end function MOI.delete(o::Optimizer, ci::CI{VECTOR, ABSPOWER}) + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[VECTOR, ABSPOWER], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -55,6 +56,7 @@ function MOI.delete(o::Optimizer, ci::CI{VECTOR, ABSPOWER}) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, ABSPOWER}) + _throw_if_invalid(o, ci) c = cons(o, ci)::Ptr{SCIP_CONS} lvar = SCIPgetLinearVarAbspower(o, c) nlvar = SCIPgetNonlinearVarAbspower(o, c) @@ -62,13 +64,12 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, ABSPOWER end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VECTOR, ABSPOWER}) + _throw_if_invalid(o, ci) c = cons(o, ci)::Ptr{SCIP_CONS} - n = SCIPgetExponentAbspower(o, c) a = SCIPgetOffsetAbspower(o, c) coef = SCIPgetCoefLinearAbspower(o, c) lhs = SCIPgetLhsAbspower(o, c) rhs = SCIPgetRhsAbspower(o, c) - return AbsolutePowerSet(n, a, coef, lhs, rhs) end diff --git a/src/MOI_wrapper/constraints.jl b/src/MOI_wrapper/constraints.jl index 0ff432d0..483c7a48 100644 --- a/src/MOI_wrapper/constraints.jl +++ b/src/MOI_wrapper/constraints.jl @@ -8,3 +8,7 @@ function MOI.set(o::Optimizer, ::MOI.ConstraintName, ci::CI, name::String) @SCIP_CALL SCIPchgConsName(o, cons(o, ci), name) return nothing end + +function MOI.is_valid(o::Optimizer, c::MOI.ConstraintIndex) + return haskey(o.inner.conss, SCIP.ConsRef(c.value)) +end diff --git a/src/MOI_wrapper/indicator_constraints.jl b/src/MOI_wrapper/indicator_constraints.jl index e9330bd8..7f264545 100644 --- a/src/MOI_wrapper/indicator_constraints.jl +++ b/src/MOI_wrapper/indicator_constraints.jl @@ -21,6 +21,7 @@ function MOI.add_constraint(o::Optimizer, func::MOI.VectorAffineFunction{T}, set end function MOI.delete(o::Optimizer, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -29,6 +30,7 @@ function MOI.delete(o::Optimizer, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indica end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} + _throw_if_invalid(o, ci) indicator_cons = cons(o, ci)::Ptr{SCIP_CONS} bin_var = SCIPgetBinaryVarIndicator(indicator_cons)::Ptr{SCIP_VAR} slack_var = SCIPgetSlackVarIndicator(indicator_cons)::Ptr{SCIP_VAR} @@ -47,6 +49,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{MOI.VectorAffine end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{MOI.VectorAffineFunction{T}, MOI.Indicator{MOI.ACTIVATE_ON_ONE, LT}}) where {T<:Real, LT<:MOI.LessThan} + _throw_if_invalid(o, ci) indicator_cons = cons(o, ci)::Ptr{SCIP_CONS} linear_cons = SCIPgetLinearConsIndicator(indicator_cons)::Ptr{SCIP_CONS} diff --git a/src/MOI_wrapper/linear_constraints.jl b/src/MOI_wrapper/linear_constraints.jl index 8eb38e39..2b031ea7 100644 --- a/src/MOI_wrapper/linear_constraints.jl +++ b/src/MOI_wrapper/linear_constraints.jl @@ -24,6 +24,7 @@ function MOI.add_constraint(o::Optimizer, func::SAF, set::S) where {S <: BOUNDS} end function MOI.delete(o::Optimizer, ci::CI{SAF, S}) where {S <: BOUNDS} + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[SAF, S], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -45,6 +46,7 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SAF,S}, set::S) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where S <: BOUNDS + _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsLinear(o, c) vars = unsafe_wrap(Array{Ptr{SCIP_VAR}}, SCIPgetVarsLinear(o, c), nvars) @@ -56,6 +58,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where S end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SAF, S}) where S <: BOUNDS + _throw_if_invalid(o, ci) lhs = SCIPgetLhsLinear(o, cons(o, ci)) rhs = SCIPgetRhsLinear(o, cons(o, ci)) return from_bounds(S, lhs, rhs) diff --git a/src/MOI_wrapper/quadratic_constraints.jl b/src/MOI_wrapper/quadratic_constraints.jl index c0d54360..5b363965 100644 --- a/src/MOI_wrapper/quadratic_constraints.jl +++ b/src/MOI_wrapper/quadratic_constraints.jl @@ -35,6 +35,7 @@ function MOI.add_constraint(o::Optimizer, func::SQF, set::S) where {S <: BOUNDS} end function MOI.delete(o::Optimizer, ci::CI{SQF, S}) where {S <: BOUNDS} + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[SQF, S], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -55,18 +56,13 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SQF,S}, set::S) return nothing end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SQF, S}) where S <: BOUNDS - lhs = SCIPgetLhsQuadratic(o, cons(o, ci)) - rhs = SCIPgetRhsQuadratic(o, cons(o, ci)) - return from_bounds(S, lhs, rhs) -end - function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S <: BOUNDS + _throw_if_invalid(o, ci) c = cons(o, ci) - + affterms = AFF_TERM[] quadterms = QUAD_TERM[] - + # variables that appear only linearly nlin = SCIPgetNLinearVarsQuadratic(o, c) linvars = unsafe_wrap(Vector{Ptr{SCIP_VAR}}, SCIPgetLinearVarsQuadratic(o, c), nlin) @@ -74,7 +70,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S for i=1:nlin push!(affterms, AFF_TERM(lincoefs[i], VI(ref(o, linvars[i]).val))) end - + # variables that appear squared, and linearly nquadvarterms = SCIPgetNQuadVarTermsQuadratic(o, c) quadvarterms = unsafe_wrap(Vector{SCIP_QUADVARTERM}, SCIPgetQuadVarTermsQuadratic(o, c), nquadvarterms) @@ -84,7 +80,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S # multiply quadratic coefficients by 2! push!(quadterms, QUAD_TERM(2.0 * term.sqrcoef, vi, vi)) end - + # bilinear terms (pair of different variables) nbilinterms = SCIPgetNBilinTermsQuadratic(o, c) bilinterms = unsafe_wrap(Vector{SCIP_BILINTERM}, SCIPgetBilinTermsQuadratic(o, c), nbilinterms) @@ -92,10 +88,17 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S # keep coefficients as they are! push!(quadterms, QUAD_TERM(term.coef, VI(ref(o, term.var1).val), VI(ref(o, term.var2).val))) end - + return SQF(affterms, quadterms, 0.0) end +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SQF, S}) where S <: BOUNDS + _throw_if_invalid(o, ci) + lhs = SCIPgetLhsQuadratic(o, cons(o, ci)) + rhs = SCIPgetRhsQuadratic(o, cons(o, ci)) + return from_bounds(S, lhs, rhs) +end + function MOI.get(o::Optimizer, ::MOI.ConstraintPrimal, ci::CI{SQF, S}) where S <: BOUNDS activity = Ref{Cdouble}() @SCIP_CALL SCIPgetActivityQuadratic(o, cons(o, ci), SCIPgetBestSol(o), activity) diff --git a/src/MOI_wrapper/soc_constraints.jl b/src/MOI_wrapper/soc_constraints.jl index 6357c338..f317ce8e 100644 --- a/src/MOI_wrapper/soc_constraints.jl +++ b/src/MOI_wrapper/soc_constraints.jl @@ -21,6 +21,7 @@ function MOI.add_constraint(o::Optimizer, func::VECTOR, set::SOC) end function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOC}) + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[VECTOR, SOC], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -29,6 +30,7 @@ function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOC}) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOC}) + _throw_if_invalid(o, ci) c = cons(o, ci)::Ptr{SCIP_CONS} nvars::Int = SCIPgetNLhsVarsSOC(o, c) vars = unsafe_wrap(Array{Ptr{SCIP_VAR}}, SCIPgetLhsVarsSOC(o, c), nvars) @@ -39,6 +41,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOC}) end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VECTOR, SOC}) + _throw_if_invalid(o, ci) c = cons(o, ci)::Ptr{SCIP_CONS} nvars::Int = SCIPgetNLhsVarsSOC(o, c) return MOI.SecondOrderCone(nvars + 1) diff --git a/src/MOI_wrapper/sos_constraints.jl b/src/MOI_wrapper/sos_constraints.jl index 3c96583c..acf5764e 100644 --- a/src/MOI_wrapper/sos_constraints.jl +++ b/src/MOI_wrapper/sos_constraints.jl @@ -14,6 +14,7 @@ function MOI.add_constraint(o::Optimizer, func::VECTOR, set::SOS1) end function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOS1}) + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[VECTOR, SOS1], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -51,6 +52,7 @@ function MOI.add_constraint(o::Optimizer, func::VECTOR, set::SOS2) end function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOS2}) + _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[VECTOR, SOS2], ConsRef(ci.value)) delete!(o.reference, cons(o, ci)) @@ -59,6 +61,7 @@ function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOS2}) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOS2}) + _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsSOS2(o, c) vars = unsafe_wrap(Array{Ptr{SCIP_VAR}}, SCIPgetVarsSOS2(o, c), nvars) @@ -66,6 +69,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOS2}) end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VECTOR, SOS2}) + _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsSOS2(o, c) weights = unsafe_wrap(Array{Float64}, SCIPgetWeightsSOS2(o, c), nvars) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index b4b6303f..c81944eb 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -78,6 +78,7 @@ function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where {S <: VAR_TYPES} end function MOI.delete(o::Optimizer, ci::CI{VI,S}) where {S <: VAR_TYPES} + _throw_if_invalid(o, ci) allow_modification(o) vi = VI(ci.value) @@ -171,6 +172,7 @@ end function MOI.delete(o::Optimizer, ci::CI{VI,S}) where S <: BOUNDS + _throw_if_invalid(o, ci) allow_modification(o) # Don't actually delete any SCIP constraint, just reset bounds @@ -212,6 +214,9 @@ function MOI.is_valid(o::Optimizer, ci::CI{VI,<:BOUNDS}) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, S}) where S <: BOUNDS + if !MOI.is_valid(o, ci) + throw(MOI.InvalidIndex(ci)) + end return VI(ci.value) end diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index 37e2bf41..3681160b 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -4,7 +4,7 @@ const MOIB = MOI.Bridges const MOIT = MOI.Test const BRIDGED = MOIB.full_bridge_optimizer(SCIP.Optimizer(display_verblevel=0), Float64) -const CONFIG = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[MOI.ConstraintDual]) +const CONFIG = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[MOI.ConstraintDual, MOI.ConstraintName]) const CONFIG3 = MOIT.Config(atol=1e-3, rtol=1e-2, exclude=Any[MOI.ConstraintDual]) @testset "MOI Continuous Linear" begin From c318481e197222447fc0afe2acc6869aff569d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 23 Sep 2021 18:23:57 +0200 Subject: [PATCH 04/16] added getters --- src/MOI_wrapper/variable.jl | 46 +++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index c81944eb..2beb4012 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -92,11 +92,13 @@ function MOI.delete(o::Optimizer, ci::CI{VI,S}) where {S <: VAR_TYPES} @SCIP_CALL SCIPchgVarType(o, var(o, vi), SCIP_VARTYPE_CONTINUOUS, infeasible) # TODO: warn if infeasible[] == TRUE? - # Can only change bounds after chaging the var type. + # Can only change bounds after changing the var type. if reset_bounds - bounds = o.binbounds[vi] - @SCIP_CALL SCIPchgVarLb(o, v, bounds.lower) - @SCIP_CALL SCIPchgVarUb(o, v, bounds.upper) + bounds = get(o.binbounds, vi, nothing) + if bounds !== nothing + @SCIP_CALL SCIPchgVarLb(o, v, bounds.lower) + @SCIP_CALL SCIPchgVarUb(o, v, bounds.upper) + end end # but do delete the constraint reference @@ -231,6 +233,42 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, S}) where S <: BO return from_bounds(S, lb, ub) end +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, MOI.ZeroOne}) + vi = VI(ci.value) + v = var(o, vi) + if SCIPvarGetType(v) == SCIP_VARTYPE_BINARY + return MOI.ZeroOne() + end + throw(MOI.InvalidIndex(ci)) +end + +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, MOI.Integer}) + vi = VI(ci.value) + v = var(o, vi) + if SCIPvarGetType(v) == SCIP_VARTYPE_INTEGER + return MOI.Integer() + end + throw(MOI.InvalidIndex(ci)) +end + +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, MOI.ZeroOne}) + vi = VI(ci.value) + v = var(o, vi) + if SCIPvarGetType(v) == SCIP_VARTYPE_BINARY + return vi + end + throw(MOI.InvalidIndex(ci)) +end + +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, MOI.Integer}) + vi = VI(ci.value) + v = var(o, vi) + if SCIPvarGetType(v) == SCIP_VARTYPE_INTEGER + return vi + end + throw(MOI.InvalidIndex(ci)) +end + # (partial) warm starts MOI.supports(::Optimizer, ::MOI.VariablePrimalStart, ::Type{VI}) = true From 7c432bbbc439f8e59a05a190c348dccc17a09621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 24 Sep 2021 00:03:00 +0200 Subject: [PATCH 05/16] more fixes --- src/MOI_wrapper/constraints.jl | 8 +++++ src/MOI_wrapper/linear_constraints.jl | 8 +++-- src/MOI_wrapper/quadratic_constraints.jl | 8 ++--- src/MOI_wrapper/sepa.jl | 2 +- src/MOI_wrapper/sos_constraints.jl | 2 ++ src/MOI_wrapper/variable.jl | 28 +++++++++++---- test/MOI_wrapper_bridged.jl | 44 +++++++++++++++++++++++- 7 files changed, 85 insertions(+), 15 deletions(-) diff --git a/src/MOI_wrapper/constraints.jl b/src/MOI_wrapper/constraints.jl index 483c7a48..bf7c37d8 100644 --- a/src/MOI_wrapper/constraints.jl +++ b/src/MOI_wrapper/constraints.jl @@ -12,3 +12,11 @@ end function MOI.is_valid(o::Optimizer, c::MOI.ConstraintIndex) return haskey(o.inner.conss, SCIP.ConsRef(c.value)) end + +# function MOI.get(::Optimizer, ::MOI.ListOfConstraintAttributesSet{F, S}) where {F, S} +# return [MOI.ConstraintName()] +# end + +# function MOI.get(::Optimizer, ::MOI.ListOfConstraintAttributesSet{<:Union{SAF, SQF}, S}) where {S} +# return Any[MOI.ConstraintName(), MOI.ConstraintPrimal()] +# end diff --git a/src/MOI_wrapper/linear_constraints.jl b/src/MOI_wrapper/linear_constraints.jl index 2b031ea7..e0b02243 100644 --- a/src/MOI_wrapper/linear_constraints.jl +++ b/src/MOI_wrapper/linear_constraints.jl @@ -45,7 +45,7 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SAF,S}, set::S) return nothing end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsLinear(o, c) @@ -57,13 +57,17 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where S return SAF(terms, 0.0) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SAF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SAF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) lhs = SCIPgetLhsLinear(o, cons(o, ci)) rhs = SCIPgetRhsLinear(o, cons(o, ci)) return from_bounds(S, lhs, rhs) end +function MOI.get(o::Optimizer, ::MOI.ConstraintPrimal, ci::CI{SAF, S}) where {S <: BOUNDS} + return SCIPgetActivityLinear(o, cons(o, ci), SCIPgetBestSol(o)) +end + function MOI.modify(o::Optimizer, ci::CI{SAF, <:BOUNDS}, change::MOI.ScalarCoefficientChange{Float64}) allow_modification(o) diff --git a/src/MOI_wrapper/quadratic_constraints.jl b/src/MOI_wrapper/quadratic_constraints.jl index 5b363965..f6a9a6a1 100644 --- a/src/MOI_wrapper/quadratic_constraints.jl +++ b/src/MOI_wrapper/quadratic_constraints.jl @@ -56,7 +56,7 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SQF,S}, set::S) return nothing end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) c = cons(o, ci) @@ -89,17 +89,17 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where S push!(quadterms, QUAD_TERM(term.coef, VI(ref(o, term.var1).val), VI(ref(o, term.var2).val))) end - return SQF(affterms, quadterms, 0.0) + return SQF(quadterms, affterms, 0.0) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SQF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SQF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) lhs = SCIPgetLhsQuadratic(o, cons(o, ci)) rhs = SCIPgetRhsQuadratic(o, cons(o, ci)) return from_bounds(S, lhs, rhs) end -function MOI.get(o::Optimizer, ::MOI.ConstraintPrimal, ci::CI{SQF, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintPrimal, ci::CI{SQF, S}) where {S <: BOUNDS} activity = Ref{Cdouble}() @SCIP_CALL SCIPgetActivityQuadratic(o, cons(o, ci), SCIPgetBestSol(o), activity) return activity[] diff --git a/src/MOI_wrapper/sepa.jl b/src/MOI_wrapper/sepa.jl index 15e91114..91d594cd 100644 --- a/src/MOI_wrapper/sepa.jl +++ b/src/MOI_wrapper/sepa.jl @@ -78,7 +78,7 @@ end MOI.supports(::Optimizer, ::MOI.UserCutCallback) = true function MOI.submit(o::Optimizer, cb_data::MOI.UserCut{CutCbData}, - func::SAF, set::S) where S <: BOUNDS + func::SAF, set::S) where {S <: BOUNDS} varrefs = [VarRef(t.variable.value) for t in func.terms] coefs = [t.coefficient for t in func.terms] diff --git a/src/MOI_wrapper/sos_constraints.jl b/src/MOI_wrapper/sos_constraints.jl index acf5764e..377f5e37 100644 --- a/src/MOI_wrapper/sos_constraints.jl +++ b/src/MOI_wrapper/sos_constraints.jl @@ -23,6 +23,7 @@ function MOI.delete(o::Optimizer, ci::CI{VECTOR, SOS1}) end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOS1}) + _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsSOS1(o, c) vars = unsafe_wrap(Array{Ptr{SCIP_VAR}}, SCIPgetVarsSOS1(o, c), nvars) @@ -30,6 +31,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VECTOR, SOS1}) end function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VECTOR, SOS1}) + _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsSOS1(o, c) weights = unsafe_wrap(Array{Float64}, SCIPgetWeightsSOS1(o, c), nvars) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index 2beb4012..908287f6 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -111,7 +111,7 @@ end MOI.supports_constraint(o::Optimizer, ::Type{VI}, ::Type{<:BOUNDS}) = true -function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where S <: BOUNDS +function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where {S <: BOUNDS} allow_modification(o) v = var(o, vi) inf = SCIPinfinity(o) @@ -142,7 +142,8 @@ function MOI.add_constraint(o::Optimizer, vi::VI, set::S) where S <: BOUNDS @debug "Overwriting existing bounds [0.0,1.0] with [$newlb,$newub] for binary variable at $(vi.value)!" end else # general case (non-binary variable) - error("Already have bounds [$oldlb,$oldub] for variable at $(vi.value)!") + # TODO find initially-set bound constraint + throw(MOI.LowerBoundAlreadySet{S,S}(vi)) end end @@ -173,7 +174,7 @@ function reset_bounds(o::Optimizer, v, lb, ub, ci::CI{VI, MOI.LessThan{Float64}} end -function MOI.delete(o::Optimizer, ci::CI{VI,S}) where S <: BOUNDS +function MOI.delete(o::Optimizer, ci::CI{VI,S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) allow_modification(o) @@ -211,18 +212,24 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{VI,S}, set::S) w end # TODO: is actually wrong for unbounded variables? -function MOI.is_valid(o::Optimizer, ci::CI{VI,<:BOUNDS}) - return haskey(o.inner.vars, VarRef(ci.value)) +function MOI.is_valid(o::Optimizer, ci::CI{VI,S}) where {S <: BOUNDS} + if !haskey(o.inner.vars, VarRef(ci.value)) + return false + end + return ConsRef(ci.value) in o.constypes[VI, S] end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{VI, S}) where {S <: BOUNDS} if !MOI.is_valid(o, ci) throw(MOI.InvalidIndex(ci)) end return VI(ci.value) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, S}) where S <: BOUNDS +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, S}) where {S <: BOUNDS} + if !MOI.is_valid(o, ci) + throw(MOI.InvalidIndex(ci)) + end vi = VI(ci.value) v = var(o, vi) lb, ub = SCIPvarGetLbOriginal(v), SCIPvarGetUbOriginal(v) @@ -233,6 +240,13 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, S}) where S <: BO return from_bounds(S, lb, ub) end +function MOI.is_valid(o::Optimizer, ci::CI{VI,S}) where {S <: Union{MOI.ZeroOne, MOI.Integer}} + if !haskey(o.inner.vars, VarRef(ci.value)) + return false + end + return ConsRef(ci.value) in o.constypes[VI, S] +end + function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{VI, MOI.ZeroOne}) vi = VI(ci.value) v = var(o, vi) diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index 3681160b..7719eb52 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -15,7 +15,49 @@ const CONFIG3 = MOIT.Config(atol=1e-3, rtol=1e-2, exclude=Any[MOI.ConstraintDual "linear13", # TODO: support MOI.FEASIBILITY_SENSE "linear14", # needs MOI.delete (of variables in constraints) ] - MOIT.contlineartest(BRIDGED, CONFIG, excluded) + + excluded = [ + "Semicontinuous", + "ScalarAffineFunction_Semiinteger", + "ScalarAffineFunction_ZeroOne", + "ScalarQuadraticFunction_Semiinteger", + "ScalarQuadraticFunction_ZeroOne", + "VectorAffineFunction_GeometricMeanCone", + "Indicator_GreaterThan", + "Indicator_LessThan", + "VectorAffineFunction_NormOneCone", + "VectorQuadraticFunction_NormOneCone", + "VectorAffineFunction_RotatedSecondOrderCone", + "VectorAffineFunction_SOS", + "VectorQuadraticFunction_SOS", + "VectorAffineFunction_SecondOrderCone", + "GeometricMeanCone", + "RotatedSecondOrderCone", + "SecondOrderCone", + "Indicator_ACTIVATE_ON_ZERO", + "test_constraint_ZeroOne_bounds", # accessing variable from string name + "test_constraint_get_ConstraintIndex", + "test_model_ListOfConstraintAttributesSet", + "BoundAlreadySet", # see TODO, + "ListOfConstraintIndices", # MathOptInterface.ListOfModelAttributesSet + "ListOfConstraintTypesPresent", + "ScalarAffineFunction_ConstraintName", # get(::SCIP.Optimizer, ::Type{MathOptInterface.ConstraintIndex}, ::String) + "ScalarFunctionConstantNotZero", + "UnsupportedAttribute", # test_model_copy_to_UnsupportedAttribute: MOI.copy_to(model, BadVariableAttributeModel()) + "UnsupportedConstraint", + ] + MOIT.runtests( + BRIDGED, + CONFIG, + warn_unsupported=true, + exclude = excluded, + ) + +# test_constraint_Indicator_ACTIVATE_ON_ZERO: Error During Test at /home/mbesancon/.julia/packages/MathOptInterface/Evu1m/src/Test/test_constraint.jl:868 +# Test threw exception +# Expression: MOI.get(model, MOI.ConstraintSet(), c) == s +# ArgumentError: Bridge of type `MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}` does not support accessing the attribute `MathOptInterface.ConstraintSet()`. If you encountered this error unexpectedly, it probably means your model has been reformulated using the bridge, and you are attempting to query an attribute that we haven't implemented yet for this bridge. Please open an issue at https://github.com/jump-dev/MathOptInterface.jl/issues/new and provide a reproducible example explaining what you were trying to do. + end @testset "MOI Continuous Conic" begin From 5fd0c949c4b52140357c8f5678de63794f919578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 24 Sep 2021 18:35:40 +0200 Subject: [PATCH 06/16] fix tests --- src/MOI_wrapper.jl | 4 +- src/MOI_wrapper/constraints.jl | 14 +++- src/MOI_wrapper/linear_constraints.jl | 18 ++--- src/MOI_wrapper/objective.jl | 6 +- src/MOI_wrapper/results.jl | 2 +- src/MOI_wrapper/variable.jl | 12 ++- test/MOI_additional.jl | 57 ++------------ test/MOI_wrapper_bridged.jl | 109 ++++---------------------- test/MOI_wrapper_cached.jl | 32 +++++--- test/MOI_wrapper_direct.jl | 96 ++++++++--------------- test/runtests.jl | 49 ++++++++++++ 11 files changed, 158 insertions(+), 241 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 0a1cbcc2..cef757a7 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -219,7 +219,7 @@ function MOI.empty!(o::Optimizer) end function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kws...) - return MOIU.automatic_copy_to(dest, src; kws...) + return MOIU.default_copy_to(dest, src; kws...) end MOI.get(o::Optimizer, ::MOI.Name) = SCIPgetProbName(o) @@ -273,6 +273,8 @@ function MOI.optimize!(o::Optimizer) return nothing end +MOI.supports_incremental_interface(::Optimizer) = true + include(joinpath("MOI_wrapper", "variable.jl")) include(joinpath("MOI_wrapper", "constraints.jl")) include(joinpath("MOI_wrapper", "linear_constraints.jl")) diff --git a/src/MOI_wrapper/constraints.jl b/src/MOI_wrapper/constraints.jl index bf7c37d8..ea960170 100644 --- a/src/MOI_wrapper/constraints.jl +++ b/src/MOI_wrapper/constraints.jl @@ -9,7 +9,19 @@ function MOI.set(o::Optimizer, ::MOI.ConstraintName, ci::CI, name::String) return nothing end -function MOI.is_valid(o::Optimizer, c::MOI.ConstraintIndex) +function MOI.set(o::Optimizer, ::MOI.ConstraintName, ci::CI{VI}, name::String) + throw(MOI.VariableIndexConstraintNameError()) + return nothing +end + +function MOI.is_valid(o::Optimizer, c::CI{F, S}) where {F, S} + cons_set = get(o.constypes, (F, S), nothing) + if cons_set === nothing + return false + end + if !in(ConsRef(c.value), cons_set) + return false + end return haskey(o.inner.conss, SCIP.ConsRef(c.value)) end diff --git a/src/MOI_wrapper/linear_constraints.jl b/src/MOI_wrapper/linear_constraints.jl index e0b02243..711f505e 100644 --- a/src/MOI_wrapper/linear_constraints.jl +++ b/src/MOI_wrapper/linear_constraints.jl @@ -2,7 +2,7 @@ MOI.supports_constraint(o::Optimizer, ::Type{SAF}, ::Type{<:BOUNDS}) = true -function MOI.add_constraint(o::Optimizer, func::SAF, set::S) where {S <: BOUNDS} +function MOI.add_constraint(o::Optimizer, func::F, set::S) where {F <: SAF, S <: BOUNDS} if func.constant != 0.0 error("SCIP does not support linear constraints with a constant offset.") end @@ -17,13 +17,13 @@ function MOI.add_constraint(o::Optimizer, func::SAF, set::S) where {S <: BOUNDS} rhs = rhs === nothing ? SCIPinfinity(o) : rhs cr = add_linear_constraint(o.inner, varrefs, coefs, lhs, rhs) - ci = CI{SAF, S}(cr.val) + ci = CI{F, S}(cr.val) register!(o, ci) register!(o, cons(o, ci), cr) return ci end -function MOI.delete(o::Optimizer, ci::CI{SAF, S}) where {S <: BOUNDS} +function MOI.delete(o::Optimizer, ci::CI{<:SAF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) allow_modification(o) delete!(o.constypes[SAF, S], ConsRef(ci.value)) @@ -32,7 +32,7 @@ function MOI.delete(o::Optimizer, ci::CI{SAF, S}) where {S <: BOUNDS} return nothing end -function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SAF,S}, set::S) where {S <: BOUNDS} +function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{<:SAF,S}, set::S) where {S <: BOUNDS} allow_modification(o) lhs, rhs = bounds(set) @@ -45,7 +45,7 @@ function MOI.set(o::SCIP.Optimizer, ::MOI.ConstraintSet, ci::CI{SAF,S}, set::S) return nothing end -function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where {S <: BOUNDS} +function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{<:SAF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) c = cons(o, ci) nvars::Int = SCIPgetNVarsLinear(o, c) @@ -57,18 +57,14 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SAF, S}) where { return SAF(terms, 0.0) end -function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{SAF, S}) where {S <: BOUNDS} +function MOI.get(o::Optimizer, ::MOI.ConstraintSet, ci::CI{<:SAF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) lhs = SCIPgetLhsLinear(o, cons(o, ci)) rhs = SCIPgetRhsLinear(o, cons(o, ci)) return from_bounds(S, lhs, rhs) end -function MOI.get(o::Optimizer, ::MOI.ConstraintPrimal, ci::CI{SAF, S}) where {S <: BOUNDS} - return SCIPgetActivityLinear(o, cons(o, ci), SCIPgetBestSol(o)) -end - -function MOI.modify(o::Optimizer, ci::CI{SAF, <:BOUNDS}, +function MOI.modify(o::Optimizer, ci::CI{<:SAF, <:BOUNDS}, change::MOI.ScalarCoefficientChange{Float64}) allow_modification(o) @SCIP_CALL SCIPchgCoefLinear(o, cons(o, ci), var(o, change.variable), change.new_coefficient) diff --git a/src/MOI_wrapper/objective.jl b/src/MOI_wrapper/objective.jl index b8ea4e31..18c014db 100644 --- a/src/MOI_wrapper/objective.jl +++ b/src/MOI_wrapper/objective.jl @@ -31,7 +31,7 @@ end # Note that SCIP always uses a scalar affine function internally! function MOI.set(o::Optimizer, ::MOI.ObjectiveFunction{VI}, obj::VI) - aff_obj = SAF([AFF_TERM(1.0, obj.variable)], 0.0) + aff_obj = SAF([AFF_TERM(1.0, obj)], 0.0) return MOI.set(o, MOI.ObjectiveFunction{SAF}(), aff_obj) end @@ -52,7 +52,7 @@ function MOI.get(o::Optimizer, ::MOI.ObjectiveFunction{VI}) 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 !") + throw(InexactError(:get, VI, aff_obj)) end return aff_obj.terms[1].variable end @@ -63,7 +63,7 @@ function MOI.set(o::Optimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSens @SCIP_CALL SCIPsetObjsense(o, SCIP_OBJSENSE_MINIMIZE) elseif sense == MOI.MAX_SENSE @SCIP_CALL SCIPsetObjsense(o, SCIP_OBJSENSE_MAXIMIZE) - elseif sense == MOI.FEASIBLITY_SENSE + elseif sense == MOI.FEASIBILITY_SENSE @warn "FEASIBLITY_SENSE not supported by SCIP.jl" maxlog=1 end return nothing diff --git a/src/MOI_wrapper/results.jl b/src/MOI_wrapper/results.jl index fcda7eb4..a973978f 100644 --- a/src/MOI_wrapper/results.jl +++ b/src/MOI_wrapper/results.jl @@ -93,7 +93,7 @@ function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{VI,<:BOUNDS}) return SCIPgetSolVal(o, sols[attr.result_index], var(o, VI(ci.value))) end -function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{SAF,<:BOUNDS}) +function MOI.get(o::Optimizer, attr::MOI.ConstraintPrimal, ci::CI{<:SAF,<:BOUNDS}) assert_solved(o) MOI.check_result_index_bounds(o, attr) sols = unsafe_wrap(Array{Ptr{SCIP_SOL}}, SCIPgetSols(o), SCIPgetNSols(o)) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index 908287f6..b8a214fc 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -30,8 +30,14 @@ function MOI.delete(o::Optimizer, vi::VI) if length(o.inner.conss) > 0 error("Can not delete variable while model contains constraints!") end - allow_modification(o) + if !haskey(o.inner.vars, VarRef(vi.value)) + throw(MOI.InvalidIndex(vi)) + end + # TODO still necessary? + if !haskey(o.reference, var(o, vi)) + throw(MOI.InvalidIndex(vi)) + end haskey(o.binbounds, vi) && delete!(o.binbounds, vi) delete!(o.reference, var(o, vi)) delete(o.inner, VarRef(vi.value)) @@ -216,6 +222,10 @@ function MOI.is_valid(o::Optimizer, ci::CI{VI,S}) where {S <: BOUNDS} if !haskey(o.inner.vars, VarRef(ci.value)) return false end + cons_set = get(o.constypes, (VI, S), nothing) + if cons_set === nothing + return false + end return ConsRef(ci.value) in o.constypes[VI, S] end diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index fcb4c588..05823751 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -124,21 +124,21 @@ end x = MOI.add_variable(optimizer) b = MOI.add_constraint(optimizer, x, MOI.Interval(2.0, 3.0)) @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) - @test_throws ErrorException MOI.add_constraint(optimizer, x, MOI.Interval(3.0, 4.0)) + @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.Interval(3.0, 4.0)) # Should work: variable with lower bound, but only once! MOI.empty!(optimizer) x = MOI.add_variable(optimizer) b = MOI.add_constraint(optimizer, x, MOI.GreaterThan(2.0)) @test var_bounds(optimizer, x) == MOI.Interval(2.0, inf) - @test_throws ErrorException MOI.add_constraint(optimizer, x, MOI.GreaterThan(3.0)) + @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.GreaterThan(3.0)) # Should work: variable with lower bound, but only once! MOI.empty!(optimizer) x = MOI.add_variable(optimizer) b = MOI.add_constraint(optimizer, x, MOI.LessThan(2.0)) @test var_bounds(optimizer, x) == MOI.Interval(-inf, 2.0) - @test_throws ErrorException MOI.add_constraint(optimizer, x, MOI.LessThan(3.0)) + @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.LessThan(3.0)) # Should work: fixed variable, but only once! MOI.empty!(optimizer) @@ -155,51 +155,6 @@ end @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) end -@testset "Changing bounds for variable." begin - optimizer = SCIP.Optimizer() - inf = SCIP.SCIPinfinity(optimizer) - - # change interval bounds - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.Interval(2.0, 3.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) - chg_bounds(optimizer, x, MOI.Interval(4.0, 5.0)) - @test var_bounds(optimizer, x) == MOI.Interval(4.0, 5.0) - - # change lower bound - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.GreaterThan(2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, inf) - chg_bounds(optimizer, x, MOI.GreaterThan(4.0)) - @test var_bounds(optimizer, x) == MOI.Interval(4.0, inf) - - # change upper bound - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.LessThan(3.0)) - @test var_bounds(optimizer, x) == MOI.Interval(-inf, 3.0) - chg_bounds(optimizer, x, MOI.LessThan(5.0)) - @test var_bounds(optimizer, x) == MOI.Interval(-inf, 5.0) - - # change fixed value - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(2.5)) - @test var_bounds(optimizer, x) == MOI.Interval(2.5, 2.5) - chg_bounds(optimizer, x, MOI.EqualTo(4.5)) - @test var_bounds(optimizer, x) == MOI.Interval(4.5, 4.5) - - # change mixed - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.GreaterThan(2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, inf) - chg_bounds(optimizer, x, MOI.LessThan(4.0)) - @test var_bounds(optimizer, x) == MOI.Interval(-inf, 4.0) -end - @testset "Second Order Cone Constraint" begin # Derived from MOI's problem SOC1 # max 0x + 1y + 1z @@ -442,7 +397,7 @@ end 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.VariableIndex}()) + @test_throws InexactError MOI.get(optimizer, MOI.ObjectiveFunction{MOI.VariableIndex}()) end @testset "set_parameter" begin @@ -551,7 +506,7 @@ end @test_throws ErrorException MOI.get(optimizer, MOI.ConstraintPrimal(), c) @test_throws ErrorException MOI.get(optimizer, MOI.ObjectiveBound()) @test_throws ErrorException MOI.get(optimizer, MOI.RelativeGap()) - @test MOI.get(optimizer, MOI.SolveTime()) ≈ 0.0 atol=atol rtol=rtol + @test MOI.get(optimizer, MOI.SolveTimeSec()) ≈ 0.0 atol=atol rtol=rtol @test_throws ErrorException MOI.get(optimizer, MOI.SimplexIterations()) @test MOI.get(optimizer, MOI.NodeCount()) == 0 @@ -566,7 +521,7 @@ end @test MOI.get(optimizer, MOI.ConstraintPrimal(), c) ≈ 1.0 atol=atol rtol=rtol @test MOI.get(optimizer, MOI.ObjectiveBound()) ≈ 2.0 atol=atol rtol=rtol @test MOI.get(optimizer, MOI.RelativeGap()) ≈ 0.0 atol=atol rtol=rtol - @test MOI.get(optimizer, MOI.SolveTime()) < 1.0 + @test MOI.get(optimizer, MOI.SolveTimeSec()) < 1.0 @test MOI.get(optimizer, MOI.SimplexIterations()) <= 3 # conservative @test MOI.get(optimizer, MOI.NodeCount()) <= 1 # conservative end diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index 7719eb52..701a8ba3 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -4,102 +4,23 @@ const MOIB = MOI.Bridges const MOIT = MOI.Test const BRIDGED = MOIB.full_bridge_optimizer(SCIP.Optimizer(display_verblevel=0), Float64) -const CONFIG = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[MOI.ConstraintDual, MOI.ConstraintName]) -const CONFIG3 = MOIT.Config(atol=1e-3, rtol=1e-2, exclude=Any[MOI.ConstraintDual]) - -@testset "MOI Continuous Linear" begin - excluded = [ - "linear1", # needs MOI.delete (of variables in constraints) - "linear5", # needs MOI.delete (of variables in constraints) - "linear11", # broken in SCIP (#2556) - "linear13", # TODO: support MOI.FEASIBILITY_SENSE - "linear14", # needs MOI.delete (of variables in constraints) - ] - - excluded = [ - "Semicontinuous", - "ScalarAffineFunction_Semiinteger", - "ScalarAffineFunction_ZeroOne", - "ScalarQuadraticFunction_Semiinteger", - "ScalarQuadraticFunction_ZeroOne", - "VectorAffineFunction_GeometricMeanCone", - "Indicator_GreaterThan", - "Indicator_LessThan", - "VectorAffineFunction_NormOneCone", - "VectorQuadraticFunction_NormOneCone", - "VectorAffineFunction_RotatedSecondOrderCone", - "VectorAffineFunction_SOS", - "VectorQuadraticFunction_SOS", - "VectorAffineFunction_SecondOrderCone", - "GeometricMeanCone", - "RotatedSecondOrderCone", - "SecondOrderCone", - "Indicator_ACTIVATE_ON_ZERO", - "test_constraint_ZeroOne_bounds", # accessing variable from string name - "test_constraint_get_ConstraintIndex", - "test_model_ListOfConstraintAttributesSet", - "BoundAlreadySet", # see TODO, - "ListOfConstraintIndices", # MathOptInterface.ListOfModelAttributesSet - "ListOfConstraintTypesPresent", - "ScalarAffineFunction_ConstraintName", # get(::SCIP.Optimizer, ::Type{MathOptInterface.ConstraintIndex}, ::String) - "ScalarFunctionConstantNotZero", - "UnsupportedAttribute", # test_model_copy_to_UnsupportedAttribute: MOI.copy_to(model, BadVariableAttributeModel()) - "UnsupportedConstraint", - ] +const CONFIG_BRIDGED = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[ + MOI.ConstraintDual, MOI.ConstraintName, MOI.VariableName, MOI.DualObjectiveValue, MOI.VariableBasisStatus, MOI.ConstraintBasisStatus, +]) + +@testset "MOI unit tests" begin + excluded = copy(MOI_BASE_EXCLUDED) + append!(excluded, [ + "test_linear_Interval_inactive", + "test_linear_integration", + "test_model_ordered_indices", # TODO should fix? ListOf in order of creation + "test_quadratic_duplicate_terms", + "test_quadratic_nonhomogeneous", + ]) MOIT.runtests( BRIDGED, - CONFIG, - warn_unsupported=true, + CONFIG_BRIDGED, + warn_unsupported=false, exclude = excluded, ) - -# test_constraint_Indicator_ACTIVATE_ON_ZERO: Error During Test at /home/mbesancon/.julia/packages/MathOptInterface/Evu1m/src/Test/test_constraint.jl:868 -# Test threw exception -# Expression: MOI.get(model, MOI.ConstraintSet(), c) == s -# ArgumentError: Bridge of type `MathOptInterface.Bridges.Constraint.IndicatorActiveOnFalseBridge{Float64, MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}` does not support accessing the attribute `MathOptInterface.ConstraintSet()`. If you encountered this error unexpectedly, it probably means your model has been reformulated using the bridge, and you are attempting to query an attribute that we haven't implemented yet for this bridge. Please open an issue at https://github.com/jump-dev/MathOptInterface.jl/issues/new and provide a reproducible example explaining what you were trying to do. - -end - -@testset "MOI Continuous Conic" begin - MOIT.lintest(BRIDGED, CONFIG) - - # SOC tests fail because of lower bound requirement of RHS var. - # MOIT.soctest(BRIDGED, CONFIG) - # MOIT.rsoctest(BRIDGED, CONFIG) - - # other cones not supported - # MOIT.geomeantest(BRIDGED, CONFIG) - # MOIT.exptest(BRIDGED, CONFIG) - # MOIT.sdptest(BRIDGED, CONFIG) - # MOIT.logdettest(BRIDGED, CONFIG) - # MOIT.rootdettest(BRIDGED, CONFIG) -end - -@testset "MOI Quadratic Constraint" begin - # needs objective bridge (MOI/#529) - # MOIT.qptest(BRIDGED, CONFIG) - - MOIT.qcptest(BRIDGED, CONFIG) - MOIT.socptest(BRIDGED, CONFIG3) -end - -@testset "MOI Integer Linear" begin - excluded = String["semiconttest", "semiinttest"] - MOIT.intlineartest(BRIDGED, CONFIG, excluded) - MOIT.indicator3_test(BRIDGED, CONFIG) -end - -@testset "MOI Integer Conic" begin - # SOC tests fail because of lower bound requirement of RHS var. - # MOIT.intconictest(BRIDGED, CONFIG) -end - -@testset "MOI NLP" begin - # None of tests provide expression graphs in the evaluator. - # MOIT.nlptest(BRIDGED, CONFIG) -end - -@testset "MOI Unit tests" begin - # TODO: most tests need get-variable-by-name etc. - # MOIT.unittest(BRIDGED, CONFIG) end diff --git a/test/MOI_wrapper_cached.jl b/test/MOI_wrapper_cached.jl index a0c148ea..195d8469 100644 --- a/test/MOI_wrapper_cached.jl +++ b/test/MOI_wrapper_cached.jl @@ -17,19 +17,25 @@ const CACHE = MOIU.UniversalFallback(ModelData{Float64}()) const CACHED = MOIU.CachingOptimizer(CACHE, SCIP.Optimizer(display_verblevel=0)) const BRIDGED2 = MOIB.full_bridge_optimizer(CACHED, Float64) -const CONFIG = MOIT.TestConfig(atol=1e-5, rtol=1e-5, duals=false, infeas_certificates=false) -const CONFIG3 = MOIT.TestConfig(atol=1e-3, rtol=1e-2, duals=false, infeas_certificates=false) - -@testset "MOI Unit tests" begin - excluded = [ - "feasibility_sense", # TODO: support feasibility sense - "solve_qp_edge_cases", # needs objective bridge - "number_threads", # can't set num. threads in single-threaded SCIP! - "delete_soc_variables", # SCIP requires non-negative "rhs variable" - ] - MOIT.unittest(BRIDGED2, CONFIG, excluded) -end +const CONFIG_CACHED = MOIT.Config( + atol=1e-5, rtol=1e-5, + exclude=Any[ + MOI.ConstraintDual, MOI.ConstraintName, MOI.VariableName, MOI.DualObjectiveValue, MOI.VariableBasisStatus, MOI.ConstraintBasisStatus, + ], +) @testset "MOI Modification tests" begin - MOIT.modificationtest(BRIDGED2, CONFIG) + exclude_list = copy(MOI_BASE_EXCLUDED) + append!( + exclude_list, + [ + "RawStatusString", + "SolveTimeSec", + "test_conic_", + "test_linear_integration", + "test_quadratic_duplicate_terms", + "test_quadratic_nonhomogeneous", + ] + ) + MOIT.runtests(BRIDGED2, CONFIG_CACHED, exclude = exclude_list) end diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index f538c50b..689fc2c6 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -3,51 +3,29 @@ const MOI = MathOptInterface const MOIT = MOI.Test const OPTIMIZER = SCIP.Optimizer(display_verblevel=0) -const CONFIG = MOIT.TestConfig(atol=1e-5, rtol=1e-5, duals=false, - infeas_certificates=false) - -@testset "MOI Continuous Linear" begin - # remember reason for excluded tests: - excluded = [ - "linear1", # needs MOI.delete (of variables in constraints) - "linear5", # needs MOI.delete (of variables in constraints) - "linear7", # needs MOI.VectorAffineFunction - "linear11", # broken in SCIP (#2556) - "linear13", # TODO: support MOI.FEASIBILITY_SENSE - "linear14", # needs MOI.delete (of variables in constraints) - "linear15", # needs MOI.VectorAffineFunction +const CONFIG_DIRECT = MOIT.Config( + atol=1e-5, rtol=1e-5, + exclude=Any[ + MOI.ConstraintDual, MOI.ConstraintName, MOI.VariableName, MOI.DualObjectiveValue, MOI.VariableBasisStatus, MOI.ConstraintBasisStatus, + ], +) + +@testset "MOI unit tests" begin + excluded = copy(MOI_BASE_EXCLUDED) + append!(excluded, + [ + "test_linear_integer_solve_twice", + "test_linear_integration", + "test_model_ordered_indices", ] - # MOIT.contlineartest(OPTIMIZER, CONFIG, excluded) - - # call individual tests - MOIT.linear2test(OPTIMIZER, CONFIG) - MOIT.linear3test(OPTIMIZER, CONFIG) - MOIT.linear4test(OPTIMIZER, CONFIG) - MOIT.linear6test(OPTIMIZER, CONFIG) - MOIT.linear8atest(OPTIMIZER, CONFIG) - MOIT.linear8btest(OPTIMIZER, CONFIG) - MOIT.linear8ctest(OPTIMIZER, CONFIG) - MOIT.linear9test(OPTIMIZER, CONFIG) - MOIT.linear10test(OPTIMIZER, CONFIG) - MOIT.linear10btest(OPTIMIZER, CONFIG) - MOIT.linear12test(OPTIMIZER, CONFIG) - MOIT.partial_start_test(OPTIMIZER, CONFIG) -end - -@testset "MOI Quadratic Constraint" begin - # remember reason for excluded tests: - excluded = [ - "qcp1", # needs VectorAffineFunction - ] - # MOIT.qcptest(OPTIMIZER, CONFIG, excluded) - - # call individual tests - MOIT.qcp2test(OPTIMIZER, CONFIG) - MOIT.qcp3test(OPTIMIZER, CONFIG) - MOIT.qcp4test(OPTIMIZER, CONFIG) + ) + MOIT.runtests( + OPTIMIZER, + CONFIG_DIRECT, + warn_unsupported=false, + exclude = excluded, + ) - MOIT.ncqcp1test(OPTIMIZER, CONFIG) - MOIT.ncqcp2test(OPTIMIZER, CONFIG) end function indicator4_test(model::MOI.ModelLike, config) @@ -114,32 +92,20 @@ function indicator4_test(model::MOI.ModelLike, config) ) MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - if config.solve - @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED - MOI.optimize!(model) + MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - @test MOI.get(model, MOI.ObjectiveValue()) ≈ 28.75 atol=atol rtol=rtol - @test MOI.get(model, MOI.VariablePrimal(), x1) ≈ 1.25 atol=atol rtol=rtol - @test MOI.get(model, MOI.VariablePrimal(), x2) ≈ 8.75 atol=atol rtol=rtol - @test MOI.get(model, MOI.VariablePrimal(), z1) ≈ 0.0 atol=atol rtol=rtol - @test MOI.get(model, MOI.VariablePrimal(), z2) ≈ 1.0 atol=atol rtol=rtol - end + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + @test MOI.get(model, MOI.ObjectiveValue()) ≈ 28.75 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), x1) ≈ 1.25 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), x2) ≈ 8.75 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), z1) ≈ 0.0 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), z2) ≈ 1.0 atol=atol rtol=rtol end @testset "MOI Integer Linear" begin - # MOIT.intlineartest(OPTIMIZER, CONFIG) - - # call individual tests - MOIT.knapsacktest(OPTIMIZER, CONFIG) - MOIT.int1test(OPTIMIZER, CONFIG) - MOIT.int2test(OPTIMIZER, CONFIG) - MOIT.int3test(OPTIMIZER, CONFIG) - MOIT.indicator1_test(OPTIMIZER, CONFIG) - MOIT.indicator2_test(OPTIMIZER, CONFIG) # replace with MOIT when MathOptInterface.jl#929 merged - indicator4_test(OPTIMIZER, CONFIG) - # MOIT.indicator3_test(OPTIMIZER, CONFIG) # no support for ACTIVATE_ON_ZERO + indicator4_test(OPTIMIZER, CONFIG_DIRECT) end diff --git a/test/runtests.jl b/test/runtests.jl index e8c29e1e..3dcf375d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,6 +28,55 @@ else @info "Separation and callbacks not tested for SCIP versions below 7" end +const MOI_BASE_EXCLUDED = [ + "Semicontinuous", + "ScalarAffineFunction_Semiinteger", + "ScalarAffineFunction_ZeroOne", + "ScalarQuadraticFunction_Semiinteger", + "ScalarQuadraticFunction_ZeroOne", + "VectorAffineFunction_GeometricMeanCone", + "Indicator_GreaterThan", + "Indicator_LessThan", + "VectorAffineFunction_NormOneCone", + "VectorQuadraticFunction_NormOneCone", + "VectorAffineFunction_RotatedSecondOrderCone", # SOC tests fail because of lower bound requirement of RHS var. + "VectorAffineFunction_SOS", + "VectorQuadraticFunction_SOS", + "VectorAffineFunction_SecondOrderCone", + "GeometricMeanCone", + "RotatedSecondOrderCone", + "SecondOrderCone", + "Indicator_ACTIVATE_ON_ZERO", + "test_constraint_ZeroOne_bounds", # accessing variable from string name + "test_constraint_get_ConstraintIndex", + "test_model_ListOfConstraintAttributesSet", + "BoundAlreadySet", # see TODO, + "ListOfConstraintIndices", # MathOptInterface.ListOfModelAttributesSet + "ListOfConstraintTypesPresent", + "ScalarAffineFunction_ConstraintName", # get(::SCIP.Optimizer, ::Type{MathOptInterface.ConstraintIndex}, ::String) + "ScalarFunctionConstantNotZero", + "UnsupportedAttribute", # test_model_copy_to_UnsupportedAttribute: MOI.copy_to(model, BadVariableAttributeModel()) + "UnsupportedConstraint", + "test_model_delete", # MOI.ListOfConstraintTypesPresent + "duplicate_VariableName", # get variable by name + "test_modification_coef_scalaraffine_", + "test_modification_coef_vectoraffine_", + "test_modification_const_vectoraffine_nonpos", + "test_modification_delete_variables_in_a_batch", + "test_modification_func_scalaraffine_", + "test_modification_func_vectoraffine_", + "test_modification_set_function_single_variable", + "test_modification_set_scalaraffine_", + "test_modification_set_singlevariable_", + "test_modification_transform_", + "test_nonlinear_", # None of tests provide expression graphs in the evaluator. + "FEASIBILITY_SENSE", # TODO + "ObjectiveFunction_ScalarAffineFunction", + "test_objective_set_via_modify", + "test_solve_ObjectiveBound_MAX_SENSE", + "test_solve_ObjectiveBound_MIN_SENSE", +] + @testset "MathOptInterface tests (bridged)" begin include("MOI_wrapper_bridged.jl") end From c64645f4388f101d2dff7ad42b6a1a1a45840df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 24 Sep 2021 18:39:02 +0200 Subject: [PATCH 07/16] remove bound tests for now --- test/MOI_additional.jl | 96 ------------------------------------------ 1 file changed, 96 deletions(-) diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index 05823751..ca5060f1 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -14,102 +14,6 @@ function chg_bounds(o::SCIP.Optimizer, vi::VI, set::S) where S return nothing end -@testset "Binary variables and explicit bounds" begin - optimizer = SCIP.Optimizer() - - # Binary variable without explicit bounds. - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test_throws KeyError var_bounds(optimizer, x) == MOI.Interval(0.0, 1.0) - - # Binary variable with [0, 1] bounds. - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0)) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 1.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 1.0) - - # Binary variable with [0, 1] bounds (order should not matter). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - b = MOI.add_constraint(optimizer, x, MOI.Interval(0.0, 1.0)) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 1.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 1.0) - - # Binary variable fixed to 0. - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(0.0)) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 0.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 0.0) - - # Binary variable fixed to 0 (different order). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(0.0)) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 0.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(0.0, 0.0) - - # Binary variable fixed to 1. - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(1.0)) - @test var_bounds(optimizer, x) == MOI.Interval(1.0, 1.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(1.0, 1.0) - - # Binary variable fixed to 1 (different order). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(1.0)) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test var_bounds(optimizer, x) == MOI.Interval(1.0, 1.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(1.0, 1.0) - - # Tightened bounds for binary variable - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.Interval(-1.0, 2.0)) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test var_bounds(optimizer, x) == MOI.Interval(-1.0, 2.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(-1.0, 2.0) - - # Tightened bounds for binary variable (different order). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - b = MOI.add_constraint(optimizer, x, MOI.Interval(-1.0, 2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(-1.0, 2.0) - MOI.delete(optimizer, t) - @test var_bounds(optimizer, x) == MOI.Interval(-1.0, 2.0) - - # No error: binary variable with conflicting bounds (infeasible). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.Interval(2.0, 3.0)) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) - - # No error: binary variable with conflicting bounds (infeasible, different order). - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - t = MOI.add_constraint(optimizer, x, MOI.ZeroOne()) - b = MOI.add_constraint(optimizer, x, MOI.Interval(2.0, 3.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) -end - @testset "Bound constraints for a general variable." begin optimizer = SCIP.Optimizer() inf = SCIP.SCIPinfinity(optimizer) From 4cdba4c36aac354611c193a3070ab207f7419ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 24 Sep 2021 19:03:28 +0200 Subject: [PATCH 08/16] remove bound checks --- test/MOI_additional.jl | 45 ------------------------------------------ 1 file changed, 45 deletions(-) diff --git a/test/MOI_additional.jl b/test/MOI_additional.jl index ca5060f1..129fe460 100644 --- a/test/MOI_additional.jl +++ b/test/MOI_additional.jl @@ -14,51 +14,6 @@ function chg_bounds(o::SCIP.Optimizer, vi::VI, set::S) where S return nothing end -@testset "Bound constraints for a general variable." begin - optimizer = SCIP.Optimizer() - inf = SCIP.SCIPinfinity(optimizer) - - # Should work: variable without explicit bounds - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - @test var_bounds(optimizer, x) == MOI.Interval(-inf, inf) - - # Should work: variable with range bounds, but only once! - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.Interval(2.0, 3.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) - @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.Interval(3.0, 4.0)) - - # Should work: variable with lower bound, but only once! - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.GreaterThan(2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, inf) - @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.GreaterThan(3.0)) - - # Should work: variable with lower bound, but only once! - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.LessThan(2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(-inf, 2.0) - @test_throws MOI.LowerBoundAlreadySet MOI.add_constraint(optimizer, x, MOI.LessThan(3.0)) - - # Should work: fixed variable, but only once! - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - b = MOI.add_constraint(optimizer, x, MOI.EqualTo(2.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 2.0) - @test_throws ErrorException MOI.add_constraint(optimizer, x, MOI.EqualTo(3.0)) - - # Mixed constraint types now allowed (when disjoint)! - MOI.empty!(optimizer) - x = MOI.add_variable(optimizer) - lb = MOI.add_constraint(optimizer, x, MOI.GreaterThan(2.0)) - ub = MOI.add_constraint(optimizer, x, MOI.LessThan(3.0)) - @test var_bounds(optimizer, x) == MOI.Interval(2.0, 3.0) -end - @testset "Second Order Cone Constraint" begin # Derived from MOI's problem SOC1 # max 0x + 1y + 1z From 9a2c400dad88d618c8a60b782cf45a08a64e3723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 24 Sep 2021 19:32:48 +0200 Subject: [PATCH 09/16] added correct exception --- src/MOI_wrapper/variable.jl | 4 ++++ test/MOI_wrapper_direct.jl | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index b8a214fc..a7e6877e 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -316,3 +316,7 @@ function MOI.set(o::Optimizer, ::MOI.VariablePrimalStart, vi::VI, value::Nothing end return end + +function MOI.set(::Optimizer, ::MOI.ConstraintFunction, ::CI{VI}, ::VI) + throw(MOI.SettingVariableIndexNotAllowed()) +end diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index 689fc2c6..03febfed 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -12,13 +12,11 @@ const CONFIG_DIRECT = MOIT.Config( @testset "MOI unit tests" begin excluded = copy(MOI_BASE_EXCLUDED) - append!(excluded, - [ - "test_linear_integer_solve_twice", - "test_linear_integration", - "test_model_ordered_indices", - ] - ) + append!(excluded, [ + "test_linear_integer_solve_twice", + "test_linear_integration", + "test_model_ordered_indices", + ]) MOIT.runtests( OPTIMIZER, CONFIG_DIRECT, From 137e445bb99f7bd8410727798722a42edf978468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 00:04:31 +0200 Subject: [PATCH 10/16] Update src/MOI_wrapper.jl Co-authored-by: Oscar Dowson --- src/MOI_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index cef757a7..e7c1629b 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -133,7 +133,7 @@ end MOI.get(::Optimizer, ::MOI.SolverName) = "SCIP" -MOIU.supports_default_copy_to(::Optimizer, copy_names::Bool) = !copy_names +MOI.supports_incremental_interface(::Optimizer) = true function _throw_if_invalid(o::Optimizer, ci::CI{F, S}) where {F, S} if !in(ConsRef(ci.value), o.constypes[F, S]) From fee20b81e4214ab9a65cc429fc468e8907ea5162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 00:04:40 +0200 Subject: [PATCH 11/16] Update src/MOI_wrapper.jl Co-authored-by: Oscar Dowson --- src/MOI_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index e7c1629b..63070ad7 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -218,7 +218,7 @@ function MOI.empty!(o::Optimizer) return nothing end -function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kws...) +function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) return MOIU.default_copy_to(dest, src; kws...) end From 6eba054b17b0de7ae23b93f9b45fa3175b834f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 00:04:52 +0200 Subject: [PATCH 12/16] Update src/MOI_wrapper.jl Co-authored-by: Oscar Dowson --- src/MOI_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 63070ad7..b6572932 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -219,7 +219,7 @@ function MOI.empty!(o::Optimizer) end function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) - return MOIU.default_copy_to(dest, src; kws...) + return MOIU.default_copy_to(dest, src) end MOI.get(o::Optimizer, ::MOI.Name) = SCIPgetProbName(o) From dfe442bc590532a35160235889cdeaa742831bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 06:13:47 +0200 Subject: [PATCH 13/16] remove white spaces --- src/MOI_wrapper/quadratic_constraints.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MOI_wrapper/quadratic_constraints.jl b/src/MOI_wrapper/quadratic_constraints.jl index f6a9a6a1..decab445 100644 --- a/src/MOI_wrapper/quadratic_constraints.jl +++ b/src/MOI_wrapper/quadratic_constraints.jl @@ -59,10 +59,10 @@ end function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where {S <: BOUNDS} _throw_if_invalid(o, ci) c = cons(o, ci) - + affterms = AFF_TERM[] quadterms = QUAD_TERM[] - + # variables that appear only linearly nlin = SCIPgetNLinearVarsQuadratic(o, c) linvars = unsafe_wrap(Vector{Ptr{SCIP_VAR}}, SCIPgetLinearVarsQuadratic(o, c), nlin) @@ -70,7 +70,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where { for i=1:nlin push!(affterms, AFF_TERM(lincoefs[i], VI(ref(o, linvars[i]).val))) end - + # variables that appear squared, and linearly nquadvarterms = SCIPgetNQuadVarTermsQuadratic(o, c) quadvarterms = unsafe_wrap(Vector{SCIP_QUADVARTERM}, SCIPgetQuadVarTermsQuadratic(o, c), nquadvarterms) @@ -88,7 +88,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where { # keep coefficients as they are! push!(quadterms, QUAD_TERM(term.coef, VI(ref(o, term.var1).val), VI(ref(o, term.var2).val))) end - + return SQF(quadterms, affterms, 0.0) end From 97afe2fde916cecf359db56184d82d33a72febf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 06:18:28 +0200 Subject: [PATCH 14/16] remove white spaces --- src/MOI_wrapper/quadratic_constraints.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper/quadratic_constraints.jl b/src/MOI_wrapper/quadratic_constraints.jl index decab445..b1a5e676 100644 --- a/src/MOI_wrapper/quadratic_constraints.jl +++ b/src/MOI_wrapper/quadratic_constraints.jl @@ -80,7 +80,7 @@ function MOI.get(o::Optimizer, ::MOI.ConstraintFunction, ci::CI{SQF, S}) where { # multiply quadratic coefficients by 2! push!(quadterms, QUAD_TERM(2.0 * term.sqrcoef, vi, vi)) end - + # bilinear terms (pair of different variables) nbilinterms = SCIPgetNBilinTermsQuadratic(o, c) bilinterms = unsafe_wrap(Vector{SCIP_BILINTERM}, SCIPgetBilinTermsQuadratic(o, c), nbilinterms) From 8e184f28ab5c617debe0f6f959357c876ea59c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 06:28:15 +0200 Subject: [PATCH 15/16] support list of variables ordered --- src/MOI_wrapper.jl | 2 -- src/MOI_wrapper/variable.jl | 2 +- test/MOI_wrapper_bridged.jl | 1 - test/MOI_wrapper_direct.jl | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index b6572932..b6f61fdb 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -273,8 +273,6 @@ function MOI.optimize!(o::Optimizer) return nothing end -MOI.supports_incremental_interface(::Optimizer) = true - include(joinpath("MOI_wrapper", "variable.jl")) include(joinpath("MOI_wrapper", "constraints.jl")) include(joinpath("MOI_wrapper", "linear_constraints.jl")) diff --git a/src/MOI_wrapper/variable.jl b/src/MOI_wrapper/variable.jl index a7e6877e..92ed4be1 100644 --- a/src/MOI_wrapper/variable.jl +++ b/src/MOI_wrapper/variable.jl @@ -10,7 +10,7 @@ end MOI.add_variables(o::Optimizer, n) = [MOI.add_variable(o) for i=1:n] MOI.get(o::Optimizer, ::MOI.NumberOfVariables) = length(o.inner.vars) -MOI.get(o::Optimizer, ::MOI.ListOfVariableIndices) = [VI(k.val) for k in keys(o.inner.vars)] +MOI.get(o::Optimizer, ::MOI.ListOfVariableIndices) = sort!([VI(k.val) for k in keys(o.inner.vars)], by=v->v.value) MOI.is_valid(o::Optimizer, vi::VI) = haskey(o.inner.vars, VarRef(vi.value)) function MOI.get(o::Optimizer, ::MOI.VariableName, vi::VI)::String diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index 701a8ba3..44bda8e6 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -13,7 +13,6 @@ const CONFIG_BRIDGED = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[ append!(excluded, [ "test_linear_Interval_inactive", "test_linear_integration", - "test_model_ordered_indices", # TODO should fix? ListOf in order of creation "test_quadratic_duplicate_terms", "test_quadratic_nonhomogeneous", ]) diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index 03febfed..b389ab17 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -15,7 +15,6 @@ const CONFIG_DIRECT = MOIT.Config( append!(excluded, [ "test_linear_integer_solve_twice", "test_linear_integration", - "test_model_ordered_indices", ]) MOIT.runtests( OPTIMIZER, From a94a111edb10b35836bf6b26004c36b76a99e0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 26 Sep 2021 06:51:33 +0200 Subject: [PATCH 16/16] list of constraint indices ordered --- src/MOI_wrapper.jl | 2 +- test/MOI_wrapper_bridged.jl | 7 +++---- test/MOI_wrapper_direct.jl | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index b6f61fdb..44ce32ae 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -241,7 +241,7 @@ function MOI.get(o::Optimizer, ::MOI.ListOfConstraintIndices{F, S}) where {F, S} for cref in o.constypes[F, S] push!(list_indices, CI{F,S}(cref.val)) end - return list_indices + return sort!(list_indices, by=v->v.value) end function set_start_values(o::Optimizer) diff --git a/test/MOI_wrapper_bridged.jl b/test/MOI_wrapper_bridged.jl index 44bda8e6..e441bfb8 100644 --- a/test/MOI_wrapper_bridged.jl +++ b/test/MOI_wrapper_bridged.jl @@ -11,10 +11,9 @@ const CONFIG_BRIDGED = MOIT.Config(atol=1e-5, rtol=1e-5, exclude=Any[ @testset "MOI unit tests" begin excluded = copy(MOI_BASE_EXCLUDED) append!(excluded, [ - "test_linear_Interval_inactive", - "test_linear_integration", - "test_quadratic_duplicate_terms", - "test_quadratic_nonhomogeneous", + "test_linear_integration", # Can not delete variable while model contains constraints + "test_quadratic_duplicate_terms", # Can not delete variable while model contains constraints + "test_quadratic_nonhomogeneous", # unsupported by bridge ]) MOIT.runtests( BRIDGED, diff --git a/test/MOI_wrapper_direct.jl b/test/MOI_wrapper_direct.jl index b389ab17..371cf620 100644 --- a/test/MOI_wrapper_direct.jl +++ b/test/MOI_wrapper_direct.jl @@ -13,8 +13,7 @@ const CONFIG_DIRECT = MOIT.Config( @testset "MOI unit tests" begin excluded = copy(MOI_BASE_EXCLUDED) append!(excluded, [ - "test_linear_integer_solve_twice", - "test_linear_integration", + "test_linear_integration", # Can not delete variable while model contains constraints ]) MOIT.runtests( OPTIMIZER,