diff --git a/Project.toml b/Project.toml index 231a519d..227035a8 100644 --- a/Project.toml +++ b/Project.toml @@ -10,7 +10,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" [compat] CEnum = "0.3, 0.4" -MathOptInterface = "~0.9.19" +MathOptInterface = "~0.10" julia = "1" [extras] diff --git a/src/MOI_wrapper/MOI_callbacks.jl b/src/MOI_wrapper/MOI_callbacks.jl index f9d2cab5..4dfd71fb 100644 --- a/src/MOI_wrapper/MOI_callbacks.jl +++ b/src/MOI_wrapper/MOI_callbacks.jl @@ -173,7 +173,7 @@ end # ============================================================================== function MOI.set(model::Optimizer, ::MOI.LazyConstraintCallback, cb::Function) - MOI.set(model, MOI.RawParameter("LazyConstraints"), 1) + MOI.set(model, MOI.RawOptimizerAttribute("LazyConstraints"), 1) model.lazy_callback = cb return end diff --git a/src/MOI_wrapper/MOI_indicator_constraint.jl b/src/MOI_wrapper/MOI_indicator_constraint.jl index 4a1a2592..c2518511 100644 --- a/src/MOI_wrapper/MOI_indicator_constraint.jl +++ b/src/MOI_wrapper/MOI_indicator_constraint.jl @@ -1,9 +1,6 @@ function _info( model::Optimizer, - c::MOI.ConstraintIndex{ - MOI.VectorAffineFunction{Float64}, - <:MOI.IndicatorSet, - }, + c::MOI.ConstraintIndex{MOI.VectorAffineFunction{Float64},<:MOI.Indicator}, ) if haskey(model.indicator_constraint_info, c.value) return model.indicator_constraint_info[c.value] @@ -14,7 +11,7 @@ end function MOI.supports_constraint( ::Optimizer, ::Type{MOI.VectorAffineFunction{Float64}}, - ::Type{<:MOI.IndicatorSet{A,S}}, + ::Type{<:MOI.Indicator{A,S}}, ) where {A,S<:_SUPPORTED_SCALAR_SETS} return true end @@ -22,7 +19,7 @@ end function MOI.is_valid( model::Optimizer, c::MOI.ConstraintIndex{MOI.VectorAffineFunction{Float64},S}, -) where {S<:MOI.IndicatorSet} +) where {S<:MOI.Indicator} info = get(model.indicator_constraint_info, c.value, nothing) if info === nothing return false @@ -33,7 +30,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.IndicatorSet}, + c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.Indicator}, ) MOI.throw_if_not_valid(model, c) return _info(model, c).set @@ -42,7 +39,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.IndicatorSet}, + c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.Indicator}, ) MOI.throw_if_not_valid(model, c) _update_if_necessary(model) @@ -89,7 +86,7 @@ end function MOI.add_constraint( model::Optimizer, func::MOI.VectorAffineFunction{Float64}, - s::MOI.IndicatorSet{A,S}, + s::MOI.Indicator{A,S}, ) where {A,S<:_SUPPORTED_SCALAR_SETS} if !iszero(func.constants[1]) error( @@ -112,10 +109,10 @@ function MOI.add_constraint( "be 1.0. Got $(term.coefficient).", ) end - binvar = Cint(column(model, term.variable_index) - 1) + binvar = Cint(column(model, term.variable) - 1) else @assert row == 2 - vars[i] = Cint(column(model, term.variable_index) - 1) + vars[i] = Cint(column(model, term.variable) - 1) vals[i] = term.coefficient i += 1 end @@ -146,7 +143,7 @@ end function MOI.get( model::Optimizer, ::MOI.ListOfConstraintIndices{<:MOI.VectorAffineFunction,S}, -) where {S<:MOI.IndicatorSet} +) where {S<:MOI.Indicator} indices = MOI.ConstraintIndex{MOI.VectorAffineFunction{Float64},S}[ MOI.ConstraintIndex{MOI.VectorAffineFunction{Float64},S}(key) for (key, info) in model.indicator_constraint_info if isa(info.set, S) @@ -157,14 +154,14 @@ end function MOI.get( model::Optimizer, ::MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64},S}, -) where {S<:MOI.IndicatorSet} +) where {S<:MOI.Indicator} return count(x -> isa(x.set, S), values(model.indicator_constraint_info)) end function MOI.get( model::Optimizer, ::MOI.ConstraintName, - c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.IndicatorSet}, + c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.Indicator}, ) MOI.throw_if_not_valid(model, c) return _info(model, c).name @@ -175,7 +172,7 @@ function MOI.set( ::MOI.ConstraintName, c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,S}, name::String, -) where {S<:MOI.IndicatorSet} +) where {S<:MOI.Indicator} MOI.throw_if_not_valid(model, c) _update_if_necessary(model) info = _info(model, c) @@ -190,7 +187,7 @@ end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.IndicatorSet}, + c::MOI.ConstraintIndex{<:MOI.VectorAffineFunction,<:MOI.Indicator}, ) MOI.throw_if_not_valid(model, c) row = _info(model, c).row diff --git a/src/MOI_wrapper/MOI_multi_objective.jl b/src/MOI_wrapper/MOI_multi_objective.jl index 3ce90b7f..949bbb38 100644 --- a/src/MOI_wrapper/MOI_multi_objective.jl +++ b/src/MOI_wrapper/MOI_multi_objective.jl @@ -26,7 +26,7 @@ function MOI.set( num_vars = length(model.variable_info) obj = zeros(Float64, num_vars) for term in f.terms - column = _info(model, term.variable_index).column + column = _info(model, term.variable).column obj[column] += term.coefficient end indices, coefficients = _indices_and_coefficients(model, f) diff --git a/src/MOI_wrapper/MOI_wrapper.jl b/src/MOI_wrapper/MOI_wrapper.jl index 318b0e45..6c37c339 100644 --- a/src/MOI_wrapper/MOI_wrapper.jl +++ b/src/MOI_wrapper/MOI_wrapper.jl @@ -48,7 +48,7 @@ mutable struct _VariableInfo # Storage for constraint names associated with variables because Gurobi # can only store names for variables and proper constraints. # We can perform an optimization and only store three strings for the - # constraint names because, at most, there can be three SingleVariable + # constraint names because, at most, there can be three VariableIndex # constraints, e.g., LessThan, GreaterThan, and Integer. lessthan_name::String greaterthan_interval_or_equalto_name::String @@ -149,7 +149,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer # A mapping from the MOI.VariableIndex to the Gurobi column. _VariableInfo # also stores some additional fields like what bounds have been added, the - # variable type, and the names of SingleVariable-in-Set constraints. + # variable type, and the names of VariableIndex-in-Set constraints. variable_info::CleverDicts.CleverDict{ MOI.VariableIndex, _VariableInfo, @@ -249,7 +249,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer times. However, you can disable it (at the cost of not being able to interrupt a solve) by passing `enable_interrupts = false`. - Set optimizer attributes using `MOI.RawParameter` or + Set optimizer attributes using `MOI.RawOptimizerAttribute` or `JuMP.set_optimizer_atttribute`. ## Example @@ -272,7 +272,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer if length(kwargs) > 0 @warn("""Passing optimizer attributes as keyword arguments to Gurobi.Optimizer is deprecated. Use - MOI.set(model, MOI.RawParameter("key"), value) + MOI.set(model, MOI.RawOptimizerAttribute("key"), value) or JuMP.set_optimizer_attribute(model, "key", value) instead. @@ -394,7 +394,7 @@ function MOI.empty!(model::Optimizer) _check_ret(model, ret) # Reset the parameters in this new environment for (name, value) in model.params - MOI.set(model, MOI.RawParameter(name), value) + MOI.set(model, MOI.RawOptimizerAttribute(name), value) end if model.silent MOI.set(model, MOI.Silent(), true) @@ -496,7 +496,7 @@ function MOI.supports( ::MOI.ObjectiveFunction{F}, ) where { F<:Union{ - MOI.SingleVariable, + MOI.VariableIndex, MOI.ScalarAffineFunction{Float64}, MOI.ScalarQuadraticFunction{Float64}, }, @@ -506,7 +506,7 @@ end function MOI.supports_constraint( ::Optimizer, - ::Type{MOI.SingleVariable}, + ::Type{MOI.VariableIndex}, ::Type{F}, ) where { F<:Union{ @@ -577,17 +577,17 @@ MOI.supports(::Optimizer, ::MOI.Silent) = true MOI.supports(::Optimizer, ::MOI.NumberOfThreads) = true MOI.supports(::Optimizer, ::MOI.TimeLimitSec) = true MOI.supports(::Optimizer, ::MOI.ObjectiveSense) = true -MOI.supports(::Optimizer, ::MOI.RawParameter) = true +MOI.supports(::Optimizer, ::MOI.RawOptimizerAttribute) = true MOI.supports(::Optimizer, ::MOI.ConstraintPrimalStart) = false MOI.supports(::Optimizer, ::MOI.ConstraintDualStart) = false -function MOI.set(model::Optimizer, raw::MOI.RawParameter, value) +function MOI.set(model::Optimizer, raw::MOI.RawOptimizerAttribute, value) env = GRBgetenv(model) param = raw.name model.params[param] = value param_type = GRBgetparamtype(env, param) ret = if param_type == -1 - throw(MOI.UnsupportedAttribute(MOI.RawParameter(param))) + throw(MOI.UnsupportedAttribute(MOI.RawOptimizerAttribute(param))) elseif param_type == 1 GRBsetintparam(env, param, value) elseif param_type == 2 @@ -599,12 +599,12 @@ function MOI.set(model::Optimizer, raw::MOI.RawParameter, value) return _check_ret(env, ret) end -function MOI.get(model::Optimizer, raw::MOI.RawParameter) +function MOI.get(model::Optimizer, raw::MOI.RawOptimizerAttribute) env = GRBgetenv(model) param = raw.name param_type = GRBgetparamtype(env, param) if param_type == -1 - throw(MOI.UnsupportedAttribute(MOI.RawParameter(param))) + throw(MOI.UnsupportedAttribute(MOI.RawOptimizerAttribute(param))) elseif param_type == 1 a = Ref{Cint}() ret = GRBgetintparam(env, param, a) @@ -625,22 +625,37 @@ function MOI.get(model::Optimizer, raw::MOI.RawParameter) end function MOI.set(model::Optimizer, ::MOI.TimeLimitSec, limit::Real) - MOI.set(model, MOI.RawParameter("TimeLimit"), limit) + MOI.set(model, MOI.RawOptimizerAttribute("TimeLimit"), limit) return end function MOI.get(model::Optimizer, ::MOI.TimeLimitSec) - return MOI.get(model, MOI.RawParameter("TimeLimit")) + return MOI.get(model, MOI.RawOptimizerAttribute("TimeLimit")) end -MOI.Utilities.supports_default_copy_to(::Optimizer, ::Bool) = true +MOI.supports_incremental_interface(::Optimizer) = true -function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kwargs...) - return MOI.Utilities.automatic_copy_to(dest, src; kwargs...) +function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) + return MOI.Utilities.default_copy_to(dest, src) end function MOI.get(model::Optimizer, ::MOI.ListOfVariableAttributesSet) - return MOI.AbstractVariableAttribute[MOI.VariableName()] + ret = MOI.AbstractVariableAttribute[] + found_name, found_start = false, false + for info in values(model.variable_info) + if !found_name && !isempty(info.name) + push!(ret, MOI.VariableName()) + found_name = true + end + if !found_start && info.start !== nothing + push!(ret, MOI.VariablePrimalStart()) + found_start = true + end + if found_start && found_name + return ret + end + end + return ret end function MOI.get(model::Optimizer, ::MOI.ListOfModelAttributesSet) @@ -667,7 +682,7 @@ function _indices_and_coefficients( ) i = 1 for term in f.terms - indices[i] = Cint(column(model, term.variable_index) - 1) + indices[i] = Cint(column(model, term.variable) - 1) coefficients[i] = term.coefficient i += 1 end @@ -700,8 +715,8 @@ function _indices_and_coefficients( f::MOI.ScalarQuadraticFunction, ) for (i, term) in enumerate(f.quadratic_terms) - I[i] = Cint(column(model, term.variable_index_1) - 1) - J[i] = Cint(column(model, term.variable_index_2) - 1) + I[i] = Cint(column(model, term.variable_1) - 1) + J[i] = Cint(column(model, term.variable_2) - 1) V[i] = term.coefficient # Gurobi returns a list of terms. MOI requires 0.5 x' Q x. So, to get # from @@ -718,7 +733,7 @@ function _indices_and_coefficients( end end for (i, term) in enumerate(f.affine_terms) - indices[i] = Cint(column(model, term.variable_index) - 1) + indices[i] = Cint(column(model, term.variable) - 1) coefficients[i] = term.coefficient end return @@ -837,7 +852,7 @@ function MOI.add_constrained_variable( set::S, )::Tuple{ MOI.VariableIndex, - MOI.ConstraintIndex{MOI.SingleVariable,S}, + MOI.ConstraintIndex{MOI.VariableIndex,S}, } where {S<:_SCALAR_SETS} vi = CleverDicts.add_item( model.variable_info, @@ -874,7 +889,7 @@ function MOI.add_constrained_variable( ret = GRBaddvar(model, 0, C_NULL, C_NULL, 0.0, lb, ub, GRB_CONTINUOUS, "") _check_ret(model, ret) _require_update(model) - ci = MOI.ConstraintIndex{MOI.SingleVariable,typeof(set)}(vi.value) + ci = MOI.ConstraintIndex{MOI.VariableIndex,typeof(set)}(vi.value) return vi, ci end @@ -895,7 +910,7 @@ function MOI.delete(model::Optimizer, indices::Vector{<:MOI.VariableIndex}) end append!(model.columns_deleted_since_last_update, del_cols .+ 1) model.name_to_variable = nothing - # We throw away name_to_constraint_index so we will rebuild SingleVariable + # We throw away name_to_constraint_index so we will rebuild VariableIndex # constraint names without v. model.name_to_constraint_index = nothing _require_update(model) @@ -913,7 +928,7 @@ function MOI.delete(model::Optimizer, v::MOI.VariableIndex) _check_ret(model, ret) delete!(model.variable_info, v) model.name_to_variable = nothing - # We throw away name_to_constraint_index so we will rebuild SingleVariable + # We throw away name_to_constraint_index so we will rebuild VariableIndex # constraint names without v. model.name_to_constraint_index = nothing _require_update(model) @@ -1028,7 +1043,7 @@ function MOI.set( model::Optimizer, ::MOI.ObjectiveFunction{F}, f::F, -) where {F<:MOI.SingleVariable} +) where {F<:MOI.VariableIndex} MOI.set( model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), @@ -1038,12 +1053,12 @@ function MOI.set( return end -function MOI.get(model::Optimizer, ::MOI.ObjectiveFunction{MOI.SingleVariable}) +function MOI.get(model::Optimizer, ::MOI.ObjectiveFunction{MOI.VariableIndex}) obj = MOI.get( model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), ) - return convert(MOI.SingleVariable, obj) + return convert(MOI.VariableIndex, obj) end function MOI.set( @@ -1059,7 +1074,7 @@ function MOI.set( num_vars = length(model.variable_info) obj = zeros(Float64, num_vars) for term in f.terms - obj[column(model, term.variable_index)] += term.coefficient + obj[column(model, term.variable)] += term.coefficient end # NOTE: variables added may be referred before a `_update_if_necessary` # what is the problem we try to prevent below? @@ -1169,7 +1184,7 @@ function MOI.get( ), ) end - return MOI.ScalarQuadraticFunction(terms, q_terms, constant[]) + return MOI.ScalarQuadraticFunction(q_terms, terms, constant[]) end function MOI.modify( @@ -1184,12 +1199,12 @@ function MOI.modify( end ## -## SingleVariable-in-Set constraints. +## VariableIndex-in-Set constraints. ## function _info( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,<:Any}, + c::MOI.ConstraintIndex{MOI.VariableIndex,<:Any}, ) var_index = MOI.VariableIndex(c.value) if haskey(model.variable_info, var_index) @@ -1199,7 +1214,7 @@ function _info( end """ - column(model::Optimizer, c::MOI.ConstraintIndex{MOI.SingleVariable, <:Any}) + column(model::Optimizer, c::MOI.ConstraintIndex{MOI.VariableIndex, <:Any}) Return the 1-indexed column associated with `c`. @@ -1207,14 +1222,14 @@ The C API requires 0-indexed columns. """ function column( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,<:Any}, + c::MOI.ConstraintIndex{MOI.VariableIndex,<:Any}, ) return _info(model, c).column end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}, ) if haskey(model.variable_info, MOI.VariableIndex(c.value)) info = _info(model, c) @@ -1225,7 +1240,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}, ) if haskey(model.variable_info, MOI.VariableIndex(c.value)) info = _info(model, c) @@ -1237,7 +1252,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Interval{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{Float64}}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).bound == _INTERVAL @@ -1245,7 +1260,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).bound == _EQUAL_TO @@ -1253,7 +1268,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.ZeroOne}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).type == GRB_BINARY @@ -1261,7 +1276,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Integer}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).type == GRB_INTEGER @@ -1269,7 +1284,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semicontinuous{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semicontinuous{Float64}}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).type == GRB_SEMICONT @@ -1277,7 +1292,7 @@ end function MOI.is_valid( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semiinteger{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semiinteger{Float64}}, ) return haskey(model.variable_info, MOI.VariableIndex(c.value)) && _info(model, c).type == GRB_SEMIINT @@ -1286,19 +1301,19 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{MOI.SingleVariable,<:Any}, + c::MOI.ConstraintIndex{MOI.VariableIndex,<:Any}, ) MOI.throw_if_not_valid(model, c) - return MOI.SingleVariable(MOI.VariableIndex(c.value)) + return MOI.VariableIndex(c.value) end function MOI.set( model::Optimizer, ::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{MOI.SingleVariable,<:Any}, - ::MOI.SingleVariable, + c::MOI.ConstraintIndex{MOI.VariableIndex,<:Any}, + ::MOI.VariableIndex, ) - return throw(MOI.SettingSingleVariableFunctionNotAllowed()) + return throw(MOI.SettingVariableIndexNotAllowed()) end _bounds(s::MOI.GreaterThan{Float64}) = (s.lower, nothing) @@ -1356,34 +1371,34 @@ end function MOI.add_constraint( model::Optimizer, - f::MOI.SingleVariable, + f::MOI.VariableIndex, s::S, ) where {S<:_SCALAR_SETS} - info = _info(model, f.variable) + info = _info(model, f) if S <: MOI.LessThan{Float64} - _throw_if_existing_upper(info.bound, info.type, S, f.variable) + _throw_if_existing_upper(info.bound, info.type, S, f) info.bound = info.bound == _GREATER_THAN ? _LESS_AND_GREATER_THAN : _LESS_THAN info.upper_bound_if_bounded = s.upper elseif S <: MOI.GreaterThan{Float64} - _throw_if_existing_lower(info.bound, info.type, S, f.variable) + _throw_if_existing_lower(info.bound, info.type, S, f) info.bound = info.bound == _LESS_THAN ? _LESS_AND_GREATER_THAN : _GREATER_THAN info.lower_bound_if_bounded = s.lower elseif S <: MOI.EqualTo{Float64} - _throw_if_existing_lower(info.bound, info.type, S, f.variable) - _throw_if_existing_upper(info.bound, info.type, S, f.variable) + _throw_if_existing_lower(info.bound, info.type, S, f) + _throw_if_existing_upper(info.bound, info.type, S, f) info.bound = _EQUAL_TO info.upper_bound_if_bounded = info.lower_bound_if_bounded = s.value else @assert S <: MOI.Interval{Float64} - _throw_if_existing_lower(info.bound, info.type, S, f.variable) - _throw_if_existing_upper(info.bound, info.type, S, f.variable) + _throw_if_existing_lower(info.bound, info.type, S, f) + _throw_if_existing_upper(info.bound, info.type, S, f) info.bound = _INTERVAL info.upper_bound_if_bounded = s.upper info.lower_bound_if_bounded = s.lower end - index = MOI.ConstraintIndex{MOI.SingleVariable,typeof(s)}(f.variable.value) + index = MOI.ConstraintIndex{MOI.VariableIndex,typeof(s)}(f.value) # This sets the bounds in the inner model and set the cache in _VariableInfo # again (we could just set them there, but then _VariableInfo is in a # invalid state that trigger some asserts, i.e., has bound but no cache). @@ -1393,47 +1408,46 @@ end function MOI.add_constraints( model::Optimizer, - f::Vector{MOI.SingleVariable}, + f::Vector{MOI.VariableIndex}, s::Vector{S}, ) where {S<:_SCALAR_SETS} for (fi, si) in zip(f, s) - info = _info(model, fi.variable) + info = _info(model, fi) if S <: MOI.LessThan{Float64} - _throw_if_existing_upper(info.bound, info.type, S, fi.variable) + _throw_if_existing_upper(info.bound, info.type, S, fi) info.bound = info.bound == _GREATER_THAN ? _LESS_AND_GREATER_THAN : _LESS_THAN info.upper_bound_if_bounded = si.upper elseif S <: MOI.GreaterThan{Float64} - _throw_if_existing_lower(info.bound, info.type, S, fi.variable) + _throw_if_existing_lower(info.bound, info.type, S, fi) info.bound = info.bound == _LESS_THAN ? _LESS_AND_GREATER_THAN : _GREATER_THAN info.lower_bound_if_bounded = si.lower elseif S <: MOI.EqualTo{Float64} - _throw_if_existing_lower(info.bound, info.type, S, fi.variable) - _throw_if_existing_upper(info.bound, info.type, S, fi.variable) + _throw_if_existing_lower(info.bound, info.type, S, fi) + _throw_if_existing_upper(info.bound, info.type, S, fi) info.bound = _EQUAL_TO info.upper_bound_if_bounded = info.lower_bound_if_bounded = si.value else @assert S <: MOI.Interval{Float64} - _throw_if_existing_lower(info.bound, info.type, S, fi.variable) - _throw_if_existing_upper(info.bound, info.type, S, fi.variable) + _throw_if_existing_lower(info.bound, info.type, S, fi) + _throw_if_existing_upper(info.bound, info.type, S, fi) info.bound = _INTERVAL info.upper_bound_if_bounded = si.upper info.lower_bound_if_bounded = si.lower end end - indices = [ - MOI.ConstraintIndex{MOI.SingleVariable,eltype(s)}(fi.variable.value) for fi in f - ] + indices = + [MOI.ConstraintIndex{MOI.VariableIndex,eltype(s)}(fi.value) for fi in f] _set_bounds(model, indices, s) return indices end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1498,7 +1512,7 @@ end _get_variable_lower_bound(model, info) Get the current variable lower bound, ignoring a potential bound of `0.0` set -by a second order cone constraint, if an adequate `SingleVariable` constraint +by a second order cone constraint, if an adequate `VariableIndex` constraint is set (i.e., `info.bound` is not `_NONE` or `_LESS_THAN`) then use a cached value; otherwise update the model if necessary and query the LB from it. @@ -1525,7 +1539,7 @@ end """ _get_variable_upper_bound(model, info) -Get the current variable upper bound, if an adequate `SingleVariable` +Get the current variable upper bound, if an adequate `VariableIndex` constraint is set (i.e., `info.bound` is not `_NONE` or `_GREATER_THAN`) then use a cached value; otherwise update the model if necessary and query the UB from it. @@ -1547,7 +1561,7 @@ end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1565,7 +1579,7 @@ end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Interval{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1582,7 +1596,7 @@ end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1600,7 +1614,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1611,7 +1625,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1622,7 +1636,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1634,7 +1648,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Interval{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1648,7 +1662,7 @@ end function _set_bounds( model::Optimizer, - indices::Vector{MOI.ConstraintIndex{MOI.SingleVariable,S}}, + indices::Vector{MOI.ConstraintIndex{MOI.VariableIndex,S}}, sets::Vector{S}, ) where {S} lower_columns, lower_values = Cint[], Float64[] @@ -1695,7 +1709,7 @@ end function MOI.set( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,S}, + c::MOI.ConstraintIndex{MOI.VariableIndex,S}, s::S, ) where {S<:_SCALAR_SETS} MOI.throw_if_not_valid(model, c) @@ -1718,21 +1732,21 @@ end function MOI.add_constraint( model::Optimizer, - f::MOI.SingleVariable, + f::MOI.VariableIndex, ::MOI.ZeroOne, ) - info = _info(model, f.variable) + info = _info(model, f) ret = GRBsetcharattrelement(model, "VType", Cint(info.column - 1), Char('B')) _check_ret(model, ret) _require_update(model) info.type = GRB_BINARY - return MOI.ConstraintIndex{MOI.SingleVariable,MOI.ZeroOne}(f.variable.value) + return MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne}(f.value) end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.ZeroOne}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1749,7 +1763,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.ZeroOne}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne}, ) MOI.throw_if_not_valid(model, c) return MOI.ZeroOne() @@ -1757,21 +1771,21 @@ end function MOI.add_constraint( model::Optimizer, - f::MOI.SingleVariable, + f::MOI.VariableIndex, ::MOI.Integer, ) - info = _info(model, f.variable) + info = _info(model, f) ret = GRBsetcharattrelement(model, "VType", Cint(info.column - 1), Char('I')) _check_ret(model, ret) _require_update(model) info.type = GRB_INTEGER - return MOI.ConstraintIndex{MOI.SingleVariable,MOI.Integer}(f.variable.value) + return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer}(f.value) end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Integer}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1788,7 +1802,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Integer}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer}, ) MOI.throw_if_not_valid(model, c) return MOI.Integer() @@ -1796,12 +1810,12 @@ end function MOI.add_constraint( model::Optimizer, - f::MOI.SingleVariable, + f::MOI.VariableIndex, s::MOI.Semicontinuous{Float64}, ) - info = _info(model, f.variable) - _throw_if_existing_lower(info.bound, info.type, typeof(s), f.variable) - _throw_if_existing_upper(info.bound, info.type, typeof(s), f.variable) + info = _info(model, f) + _throw_if_existing_lower(info.bound, info.type, typeof(s), f) + _throw_if_existing_upper(info.bound, info.type, typeof(s), f) ret = GRBsetcharattrelement(model, "VType", Cint(info.column - 1), Char('S')) _check_ret(model, ret) @@ -1810,14 +1824,14 @@ function MOI.add_constraint( _check_ret(model, ret) _require_update(model) info.type = GRB_SEMICONT - return MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semicontinuous{Float64}}( - f.variable.value, + return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semicontinuous{Float64}}( + f.value, ) end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semicontinuous{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semicontinuous{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1837,7 +1851,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semicontinuous{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semicontinuous{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1850,12 +1864,12 @@ end function MOI.add_constraint( model::Optimizer, - f::MOI.SingleVariable, + f::MOI.VariableIndex, s::MOI.Semiinteger{Float64}, ) - info = _info(model, f.variable) - _throw_if_existing_lower(info.bound, info.type, typeof(s), f.variable) - _throw_if_existing_upper(info.bound, info.type, typeof(s), f.variable) + info = _info(model, f) + _throw_if_existing_lower(info.bound, info.type, typeof(s), f) + _throw_if_existing_upper(info.bound, info.type, typeof(s), f) ret = GRBsetcharattrelement(model, "VType", Cint(info.column - 1), Char('N')) _check_ret(model, ret) @@ -1864,14 +1878,14 @@ function MOI.add_constraint( _check_ret(model, ret) _require_update(model) info.type = GRB_SEMIINT - return MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semiinteger{Float64}}( - f.variable.value, + return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semiinteger{Float64}}( + f.value, ) end function MOI.delete( model::Optimizer, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semiinteger{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semiinteger{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1891,7 +1905,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Semiinteger{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Semiinteger{Float64}}, ) MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1905,7 +1919,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintName, - c::MOI.ConstraintIndex{MOI.SingleVariable,S}, + c::MOI.ConstraintIndex{MOI.VariableIndex,S}, ) where {S} MOI.throw_if_not_valid(model, c) info = _info(model, c) @@ -1927,7 +1941,7 @@ end function MOI.set( model::Optimizer, ::MOI.ConstraintName, - c::MOI.ConstraintIndex{MOI.SingleVariable,S}, + c::MOI.ConstraintIndex{MOI.VariableIndex,S}, name::String, ) where {S} MOI.throw_if_not_valid(model, c) @@ -2287,7 +2301,7 @@ function _rebuild_name_to_constraint_index_variables(model::Optimizer) model.name_to_constraint_index[constraint_name] = nothing else model.name_to_constraint_index[constraint_name] = - MOI.ConstraintIndex{MOI.SingleVariable,S}(key.value) + MOI.ConstraintIndex{MOI.VariableIndex,S}(key.value) end end end @@ -2443,7 +2457,7 @@ function MOI.get( model.variable_info[CleverDicts.LinearIndex(J[i] + 1)].index, ) end - return MOI.ScalarQuadraticFunction(affine_terms, quadratic_terms, 0.0) + return MOI.ScalarQuadraticFunction(quadratic_terms, affine_terms, 0.0) end function MOI.get( @@ -2783,7 +2797,7 @@ function MOI.get(model::Optimizer, attr::MOI.PrimalStatus) _throw_if_optimize_in_progress(model, attr) term = MOI.get(model, MOI.TerminationStatus()) if term == MOI.DUAL_INFEASIBLE || term == MOI.INFEASIBLE_OR_UNBOUNDED - if attr.N != 1 + if attr.result_index != 1 return MOI.NO_SOLUTION elseif _has_primal_ray(model) return MOI.INFEASIBILITY_CERTIFICATE @@ -2796,7 +2810,8 @@ function MOI.get(model::Optimizer, attr::MOI.PrimalStatus) valueP = Ref{Cint}() ret = GRBgetintattr(model, "SolCount", valueP) _check_ret(model, ret) - return 1 <= attr.N <= valueP[] ? MOI.FEASIBLE_POINT : MOI.NO_SOLUTION + return 1 <= attr.result_index <= valueP[] ? MOI.FEASIBLE_POINT : + MOI.NO_SOLUTION end function _has_dual_ray(model::Optimizer) @@ -2812,11 +2827,12 @@ _is_qcp(model::Optimizer) = _get_intattr(model, "IsQCP") != 0 function MOI.get(model::Optimizer, attr::MOI.DualStatus) _throw_if_optimize_in_progress(model, attr) - if attr.N != 1 + if attr.result_index != 1 return MOI.NO_SOLUTION elseif _is_mip(model) return MOI.NO_SOLUTION - elseif _is_qcp(model) && MOI.get(model, MOI.RawParameter("QCPDual")) != 1 + elseif _is_qcp(model) && + MOI.get(model, MOI.RawOptimizerAttribute("QCPDual")) != 1 return MOI.NO_SOLUTION end term = MOI.get(model, MOI.TerminationStatus()) @@ -2851,8 +2867,12 @@ function MOI.get( _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) key = model.has_unbounded_ray ? "UnbdRay" : "X" - if attr.N > 1 - MOI.set(model, MOI.RawParameter("SolutionNumber"), attr.N - 1) + if attr.result_index > 1 + MOI.set( + model, + MOI.RawOptimizerAttribute("SolutionNumber"), + attr.result_index - 1, + ) key = "Xn" end col = Cint(column(model, x) - 1) @@ -2865,7 +2885,7 @@ end function MOI.get( model::Optimizer, attr::MOI.ConstraintPrimal, - c::MOI.ConstraintIndex{MOI.SingleVariable,<:Any}, + c::MOI.ConstraintIndex{MOI.VariableIndex,<:Any}, ) _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) @@ -2942,7 +2962,7 @@ end function MOI.get( model::Optimizer, attr::MOI.ConstraintDual, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}, ) _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) @@ -2976,7 +2996,7 @@ end function MOI.get( model::Optimizer, attr::MOI.ConstraintDual, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}, ) _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) @@ -3010,7 +3030,7 @@ end function MOI.get( model::Optimizer, attr::MOI.ConstraintDual, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}}, ) _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) @@ -3027,7 +3047,7 @@ end function MOI.get( model::Optimizer, attr::MOI.ConstraintDual, - c::MOI.ConstraintIndex{MOI.SingleVariable,MOI.Interval{Float64}}, + c::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{Float64}}, ) _throw_if_optimize_in_progress(model, attr) MOI.check_result_index_bounds(model, attr) @@ -3087,7 +3107,7 @@ function MOI.get(model::Optimizer, attr::MOI.ObjectiveValue) if attr.result_index > 1 MOI.set( model, - MOI.RawParameter("SolutionNumber"), + MOI.RawOptimizerAttribute("SolutionNumber"), attr.result_index - 1, ) end @@ -3106,7 +3126,7 @@ function MOI.get(model::Optimizer, attr::MOI.ObjectiveBound) return valueP[] end -function MOI.get(model::Optimizer, attr::MOI.SolveTime) +function MOI.get(model::Optimizer, attr::MOI.SolveTimeSec) _throw_if_optimize_in_progress(model, attr) valueP = Ref{Cdouble}() ret = GRBgetdblattr(model, "RunTime", valueP) @@ -3173,23 +3193,23 @@ end function MOI.set(model::Optimizer, ::MOI.Silent, flag::Bool) model.silent = flag output_flag = flag ? 0 : 1 - MOI.set(model, MOI.RawParameter("OutputFlag"), output_flag) + MOI.set(model, MOI.RawOptimizerAttribute("OutputFlag"), output_flag) return end function MOI.get(model::Optimizer, ::MOI.NumberOfThreads) - x = MOI.get(model, MOI.RawParameter("Threads")) + x = MOI.get(model, MOI.RawOptimizerAttribute("Threads")) # Instead of default `0`, return `nothing` return x == 0 ? nothing : x end function MOI.set(model::Optimizer, ::MOI.NumberOfThreads, x::Int) - MOI.set(model, MOI.RawParameter("Threads"), x) + MOI.set(model, MOI.RawOptimizerAttribute("Threads"), x) return end function MOI.set(model::Optimizer, ::MOI.NumberOfThreads, ::Nothing) - MOI.set(model, MOI.RawParameter("Threads"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Threads"), 0) return end @@ -3267,12 +3287,12 @@ _type_enums(::Any) = (nothing,) function MOI.get( model::Optimizer, - ::MOI.ListOfConstraintIndices{MOI.SingleVariable,S}, + ::MOI.ListOfConstraintIndices{MOI.VariableIndex,S}, ) where {S} - indices = MOI.ConstraintIndex{MOI.SingleVariable,S}[] + indices = MOI.ConstraintIndex{MOI.VariableIndex,S}[] for (key, info) in model.variable_info if info.bound in _bound_enums(S) || info.type in _type_enums(S) - push!(indices, MOI.ConstraintIndex{MOI.SingleVariable,S}(key.value)) + push!(indices, MOI.ConstraintIndex{MOI.VariableIndex,S}(key.value)) end end return sort!(indices, by = x -> x.value) @@ -3337,34 +3357,31 @@ function MOI.get( return sort!(indices, by = x -> x.value) end -function MOI.get(model::Optimizer, ::MOI.ListOfConstraints) - constraints = Set{Tuple{DataType,DataType}}() +function MOI.get(model::Optimizer, ::MOI.ListOfConstraintTypesPresent) + constraints = Set{Tuple{Type,Type}}() for info in values(model.variable_info) if info.bound == _NONE elseif info.bound == _LESS_THAN - push!(constraints, (MOI.SingleVariable, MOI.LessThan{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.LessThan{Float64})) elseif info.bound == _GREATER_THAN - push!(constraints, (MOI.SingleVariable, MOI.GreaterThan{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.GreaterThan{Float64})) elseif info.bound == _LESS_AND_GREATER_THAN - push!(constraints, (MOI.SingleVariable, MOI.LessThan{Float64})) - push!(constraints, (MOI.SingleVariable, MOI.GreaterThan{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.LessThan{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.GreaterThan{Float64})) elseif info.bound == _EQUAL_TO - push!(constraints, (MOI.SingleVariable, MOI.EqualTo{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.EqualTo{Float64})) elseif info.bound == _INTERVAL - push!(constraints, (MOI.SingleVariable, MOI.Interval{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.Interval{Float64})) end if info.type == GRB_CONTINUOUS elseif info.type == GRB_BINARY - push!(constraints, (MOI.SingleVariable, MOI.ZeroOne)) + push!(constraints, (MOI.VariableIndex, MOI.ZeroOne)) elseif info.type == GRB_INTEGER - push!(constraints, (MOI.SingleVariable, MOI.Integer)) + push!(constraints, (MOI.VariableIndex, MOI.Integer)) elseif info.type == GRB_SEMICONT - push!( - constraints, - (MOI.SingleVariable, MOI.Semicontinuous{Float64}), - ) + push!(constraints, (MOI.VariableIndex, MOI.Semicontinuous{Float64})) elseif info.type == GRB_SEMIINT - push!(constraints, (MOI.SingleVariable, MOI.Semiinteger{Float64})) + push!(constraints, (MOI.VariableIndex, MOI.Semiinteger{Float64})) end end for info in values(model.affine_constraint_info) @@ -3393,7 +3410,7 @@ function MOI.get(model::Optimizer, ::MOI.ObjectiveFunctionType) if model.is_feasibility return nothing elseif model.objective_type == _SINGLE_VARIABLE - return MOI.SingleVariable + return MOI.VariableIndex elseif model.objective_type == _SCALAR_AFFINE return MOI.ScalarAffineFunction{Float64} else @@ -3458,7 +3475,7 @@ function _replace_with_matching_sparsity!( row::Int, ) rows = fill(Cint(row - 1), length(replacement.terms)) - cols = Cint[column(model, t.variable_index) - 1 for t in replacement.terms] + cols = Cint[column(model, t.variable) - 1 for t in replacement.terms] coefs = MOI.coefficient.(replacement.terms) ret = GRBchgcoeffs(model, length(cols), rows, cols, coefs) _check_ret(model, ret) @@ -3491,13 +3508,13 @@ function _replace_with_different_sparsity!( ) # First, zero out the old constraint function terms. rows = fill(Cint(row - 1), length(previous.terms)) - cols = Cint[column(model, t.variable_index) - 1 for t in previous.terms] + cols = Cint[column(model, t.variable) - 1 for t in previous.terms] coefs = fill(0.0, length(previous.terms)) ret = GRBchgcoeffs(model, length(cols), rows, cols, coefs) _check_ret(model, ret) # Next, set the new constraint function terms. rows = fill(Cint(row - 1), length(replacement.terms)) - cols = Cint[column(model, t.variable_index) - 1 for t in replacement.terms] + cols = Cint[column(model, t.variable) - 1 for t in replacement.terms] coefs = MOI.coefficient.(replacement.terms) ret = GRBchgcoeffs(model, length(cols), rows, cols, coefs) _check_ret(model, ret) @@ -3583,41 +3600,23 @@ end function MOI.get( model::Optimizer, - ::MOI.ConstraintBasisStatus, - c::MOI.ConstraintIndex{MOI.SingleVariable,S}, -) where {S<:_SCALAR_SETS} + ::MOI.VariableBasisStatus, + x::MOI.VariableIndex, +) _update_if_necessary(model) valueP = Ref{Cint}() - ret = GRBgetintattrelement( - model, - "VBasis", - Cint(column(model, c) - 1), - valueP, - ) + col = Cint(column(model, x) - 1) + ret = GRBgetintattrelement(model, "VBasis", col, valueP) _check_ret(model, ret) if valueP[] == 0 return MOI.BASIC elseif valueP[] == -1 - if S <: MOI.LessThan - return MOI.BASIC - elseif !(S <: MOI.Interval) - return MOI.NONBASIC - else - return MOI.NONBASIC_AT_LOWER - end + return MOI.NONBASIC_AT_LOWER elseif valueP[] == -2 - MOI.NONBASIC_AT_UPPER - if S <: MOI.GreaterThan - return MOI.BASIC - elseif !(S <: MOI.Interval) - return MOI.NONBASIC - else - return MOI.NONBASIC_AT_UPPER - end - elseif valueP[] == -3 - return MOI.SUPER_BASIC + return MOI.NONBASIC_AT_UPPER else - error("VBasis value of $(valueP[]) isn't defined.") + @assert valueP[] == -3 + return MOI.SUPER_BASIC end end @@ -3627,7 +3626,6 @@ function MOI.set( c::MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},S}, bs::MOI.BasisStatusCode, ) where {S<:_SCALAR_SETS} - # _update_if_necessary(model) row = _info(model, c).row valueP::Cint = ( if bs == MOI.BASIC @@ -3646,39 +3644,22 @@ end function MOI.set( model::Optimizer, - ::MOI.ConstraintBasisStatus, - c::MOI.ConstraintIndex{MOI.SingleVariable,S}, + ::MOI.VariableBasisStatus, + x::MOI.VariableIndex, bs::MOI.BasisStatusCode, -) where {S<:_SCALAR_SETS} - # _update_if_necessary(model) - valueP::Cint = ( - if bs == MOI.BASIC - Cint(0) - elseif bs == MOI.NONBASIC_AT_LOWER - Cint(-1) - elseif bs == MOI.NONBASIC_AT_UPPER - Cint(-2) - elseif bs == MOI.SUPER_BASIC - Cint(-3) - else - @assert bs == MOI.NONBASIC - if S <: MOI.LessThan - Cint(-2) - elseif S <: MOI.GreaterThan - Cint(-1) - else - error( - "Do not know how to set variable basis status $bs with constraint set $set.", - ) - end - end - ) - ret = GRBsetintattrelement( - model, - "VBasis", - Cint(column(model, c) - 1), - valueP, - ) +) + valueP = if bs == MOI.BASIC + Cint(0) + elseif bs == MOI.NONBASIC_AT_LOWER + Cint(-1) + elseif bs == MOI.NONBASIC_AT_UPPER + Cint(-2) + else + @assert bs == MOI.SUPER_BASIC + Cint(-3) + end + col = Cint(column(model, x) - 1) + ret = GRBsetintattrelement(model, "VBasis", col, valueP) _check_ret(model, ret) _require_update(model) return @@ -3737,7 +3718,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintConflictStatus, - index::MOI.ConstraintIndex{MOI.SingleVariable,<:MOI.LessThan}, + index::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.LessThan}, ) _ensure_conflict_computed(model) if _is_feasible(model) @@ -3753,7 +3734,7 @@ end function MOI.get( model::Optimizer, ::MOI.ConstraintConflictStatus, - index::MOI.ConstraintIndex{MOI.SingleVariable,<:MOI.GreaterThan}, + index::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.GreaterThan}, ) _ensure_conflict_computed(model) if _is_feasible(model) @@ -3770,7 +3751,7 @@ function MOI.get( model::Optimizer, ::MOI.ConstraintConflictStatus, index::MOI.ConstraintIndex{ - MOI.SingleVariable, + MOI.VariableIndex, <:Union{MOI.EqualTo,MOI.Interval}, }, ) @@ -3844,7 +3825,7 @@ function MOI.get( model::Optimizer, ::MOI.ConstraintConflictStatus, index::MOI.ConstraintIndex{ - MOI.SingleVariable, + MOI.VariableIndex, <:Union{MOI.Integer,MOI.ZeroOne}, }, ) @@ -3853,10 +3834,10 @@ function MOI.get( return MOI.NOT_IN_CONFLICT end - # Gurobi doesn't give that information (only linear constraints and bounds, + # Gurobi doesn't give that information (only linear constraints and bounds, # i.e. about the linear relaxation), even though it will report a conflict. # Even for binary variables (MOI.ZeroOne), no variable attribute is set by - # the IIS computation, including the bounds. + # the IIS computation, including the bounds. # -> https://www.gurobi.com/documentation/9.1/refman/iislb.html # Report that lack of information to the user. if MOI.is_valid(model, index) @@ -4047,8 +4028,8 @@ function MOI.set( model::Optimizer, attr::ConstraintAttribute, ci::MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}}, - value::T, -) where {T} + value, +) _set_attribute(model, attr, Cint(_info(model, ci).row - 1), value) _require_update(model) return diff --git a/test/MOI/MOI_callbacks.jl b/test/MOI/MOI_callbacks.jl index 90898a5f..31812d14 100644 --- a/test/MOI/MOI_callbacks.jl +++ b/test/MOI/MOI_callbacks.jl @@ -1,6 +1,19 @@ module TestCallbacks -using Gurobi, Test, Random +using Gurobi +using Random +using Test + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$(name)", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end + return +end const MOI = Gurobi.MOI @@ -8,10 +21,10 @@ const GRB_ENV = isdefined(Main, :GRB_ENV) ? Main.GRB_ENV : Gurobi.Env() function callback_simple_model() model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.RawParameter("OutputFlag"), 0) - MOI.set(model, MOI.RawParameter("Cuts"), 0) - MOI.set(model, MOI.RawParameter("Presolve"), 0) - MOI.set(model, MOI.RawParameter("Heuristics"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("OutputFlag"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Cuts"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Presolve"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Heuristics"), 0) MOI.Utilities.loadfromstring!( model, """ @@ -30,14 +43,14 @@ end function callback_knapsack_model() model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.RawParameter("OutputFlag"), 0) - MOI.set(model, MOI.RawParameter("Cuts"), 0) - MOI.set(model, MOI.RawParameter("Presolve"), 0) - MOI.set(model, MOI.RawParameter("PreCrush"), 0) - MOI.set(model, MOI.RawParameter("Heuristics"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("OutputFlag"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Cuts"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Presolve"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("PreCrush"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Heuristics"), 0) N = 30 x = MOI.add_variables(model, N) - MOI.add_constraints(model, MOI.SingleVariable.(x), MOI.ZeroOne()) + MOI.add_constraints(model, x, MOI.ZeroOne()) MOI.set.(model, MOI.VariablePrimalStart(), x, 0.0) Random.seed!(1) item_weights, item_values = rand(N), rand(N) @@ -392,7 +405,7 @@ function test_CallbackFunction_callback_LazyConstraint() end end end - MOI.set(model, MOI.RawParameter("LazyConstraints"), 1) + MOI.set(model, MOI.RawOptimizerAttribute("LazyConstraints"), 1) MOI.set(model, Gurobi.CallbackFunction(), callback_function) MOI.optimize!(model) @test MOI.get(model, MOI.VariablePrimal(), x) == 1 @@ -538,4 +551,4 @@ end end # module TestCallbacks -runtests(TestCallbacks) +TestCallbacks.runtests() diff --git a/test/MOI/MOI_multiobjective.jl b/test/MOI/MOI_multiobjective.jl index 75a8e870..869eb81f 100644 --- a/test/MOI/MOI_multiobjective.jl +++ b/test/MOI/MOI_multiobjective.jl @@ -3,6 +3,17 @@ module TestMultiobjective using Gurobi using Test +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$(name)", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end + return +end + const MOI = Gurobi.MOI const GRB_ENV = isdefined(Main, :GRB_ENV) ? Main.GRB_ENV : Gurobi.Env() @@ -85,4 +96,4 @@ end end -runtests(TestMultiobjective) +TestMultiobjective.runtests() diff --git a/test/MOI/MOI_wrapper.jl b/test/MOI/MOI_wrapper.jl index b51d67fa..b9932398 100644 --- a/test/MOI/MOI_wrapper.jl +++ b/test/MOI/MOI_wrapper.jl @@ -5,230 +5,92 @@ using Random using Test const MOI = Gurobi.MOI -const MOIT = MOI.Test -const GRB_ENV = isdefined(Main, :GRB_ENV) ? Main.GRB_ENV : Gurobi.Env() +function runtests() + for name in names(@__MODULE__; all = true) + if !startswith("$(name)", "test_") + continue + end + @testset "$(name)" begin + if startswith("$(name)", "test_MULTI_ENV") + try + getfield(@__MODULE__, name)() + catch ex + if ex == ErrorException( + "Gurobi Error 10009: Failed to obtain a valid license", + ) + @warn( + "Skipping a test because there was an issue " * + "creating multiple licenses. This is probably " * + "because you have a limited license." + ) + else + rethrow(ex) + end + end + else + getfield(@__MODULE__, name)() + end + end + end + return +end -const OPTIMIZER = MOI.Bridges.full_bridge_optimizer( - begin - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - # We set `DualReductions = 0` so that we never return - # `INFEASIBLE_OR_UNBOUNDED`. - MOI.set(model, MOI.RawParameter("DualReductions"), 0) - MOI.set(model, MOI.RawParameter("QCPDual"), 1) - MOI.set(model, MOI.RawParameter("InfUnbdInfo"), 1) - MOI.set(model, MOI.RawParameter("NonConvex"), 2) - model - end, - Float64, -) -const CONFIG = MOIT.TestConfig() +const GRB_ENV = isdefined(Main, :GRB_ENV) ? Main.GRB_ENV : Gurobi.Env() -function test_basic_constraint_tests() - MOIT.basic_constraint_tests( - OPTIMIZER, - CONFIG; - exclude = [ - (MOI.VectorOfVariables, MOI.SecondOrderCone), - (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone), - (MOI.VectorOfVariables, MOI.GeometricMeanCone), - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone), - (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone), - (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.SecondOrderCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.RotatedSecondOrderCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.GeometricMeanCone), +function test_runtests() + model = + MOI.Bridges.full_bridge_optimizer(Gurobi.Optimizer(GRB_ENV), Float64) + MOI.set(model, MOI.Silent(), true) + # We set `DualReductions = 0` so that we never return + # `INFEASIBLE_OR_UNBOUNDED`. + MOI.set(model, MOI.RawOptimizerAttribute("DualReductions"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("QCPDual"), 1) + MOI.set(model, MOI.RawOptimizerAttribute("InfUnbdInfo"), 1) + MOI.set(model, MOI.RawOptimizerAttribute("NonConvex"), 2) + MOI.Test.runtests( + model, + MOI.Test.Config(atol = 1e-3, rtol = 1e-3), + exclude = String[ + # TODO(odow): investigate errors + "test_objective_set_via_modify", + "test_model_ListOfConstraintAttributesSet", + "test_solve_conflict_feasible", + # TODO(odow): fixed in MOI 0.10.1 + "test_solve_SOS2_add_and_delete", + "test_objective_get_ObjectiveFunction_ScalarAffineFunction", + # SecondOrderCone does not return dual solutions. Tested below. + "_SecondOrderCone_", + "test_constraint_PrimalStart_DualStart_SecondOrderCone", + "_RotatedSecondOrderCone_", + "_GeometricMeanCone_", ], ) - # TODO(odow): bugs deleting SOC variables. See also the - # `delete_soc_variables` test. - return MOIT.basic_constraint_tests( - OPTIMIZER, - CONFIG; - include = [ - (MOI.VectorOfVariables, MOI.SecondOrderCone), - (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone), - (MOI.VectorOfVariables, MOI.GeometricMeanCone), - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone), - (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone), - (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.SecondOrderCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.RotatedSecondOrderCone), - (MOI.VectorQuadraticFunction{Float64}, MOI.GeometricMeanCone), + MOI.Test.runtests( + model, + MOI.Test.Config( + # Some of these conic ones have very low accuracy. + atol = 2e-3, + rtol = 1e-3, + exclude = Any[MOI.ConstraintDual, MOI.DualObjectiveValue], + ), + include = String[ + "_SecondOrderCone_", + "test_constraint_PrimalStart_DualStart_SecondOrderCone", + "_RotatedSecondOrderCone_", + "_GeometricMeanCone_", ], - delete = false, - ) -end - -function test_unittest() - return MOIT.unittest( - OPTIMIZER, - MOIT.TestConfig(atol = 1e-6), - [ - # TODO(odow): bug! We can't delete a vector of variables if one is in - # a second order cone. - "delete_soc_variables", + exclude = String[ + # TODO(odow): fixed in MOI 0.10.1 + "test_conic_SecondOrderCone_negative_initial_bound", + "test_conic_SecondOrderCone_negative_post_bound", + "test_conic_SecondOrderCone_negative_post_bound_ii", + "test_conic_SecondOrderCone_no_initial_bound", + "test_conic_SecondOrderCone_nonnegative_initial_bound", + "test_conic_SecondOrderCone_nonnegative_post_bound", ], ) -end - -function test_modificationtest() - return MOIT.modificationtest(OPTIMIZER, CONFIG) -end - -function test_contlineartest() - return MOIT.contlineartest(OPTIMIZER, MOIT.TestConfig(basis = true)) -end - -function test_contquadratictest() - return MOIT.contquadratictest( - OPTIMIZER, - MOIT.TestConfig(atol = 1e-3, rtol = 1e-3), - ) -end - -function test_conictest() - MOIT.lintest(OPTIMIZER, CONFIG) - MOIT.soctest( - OPTIMIZER, - MOIT.TestConfig(duals = false, atol = 1e-3), - ["soc3"], - ) - MOIT.soc3test( - OPTIMIZER, - MOIT.TestConfig( - duals = false, - infeas_certificates = false, - atol = 1e-3, - ), - ) - MOIT.rsoctest(OPTIMIZER, MOIT.TestConfig(duals = false, atol = 5e-3)) - return MOIT.geomeantest( - OPTIMIZER, - MOIT.TestConfig(duals = false, atol = 1e-3), - ) -end - -function test_intlinear() - return MOIT.intlineartest(OPTIMIZER, CONFIG) -end - -function test_solvername() - @test MOI.get(OPTIMIZER, MOI.SolverName()) == "Gurobi" -end - -function test_default_objective_test() - return MOIT.default_objective_test(OPTIMIZER) -end - -function test_default_status_test() - return MOIT.default_status_test(OPTIMIZER) -end - -function test_nametest() - return MOIT.nametest(OPTIMIZER) -end - -function test_validtest() - return MOIT.validtest(OPTIMIZER) -end - -function test_emptytest() - return MOIT.emptytest(OPTIMIZER) -end - -function test_orderedindicestest() - return MOIT.orderedindicestest(OPTIMIZER) -end - -function test_copytest() - return MOIT.copytest( - OPTIMIZER, - MOI.Bridges.full_bridge_optimizer(Gurobi.Optimizer(GRB_ENV), Float64), - ) -end - -function test_scalar_function_constant_not_zero() - return MOIT.scalar_function_constant_not_zero(OPTIMIZER) -end - -function test_start_values_test() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - @test MOI.supports(model, MOI.VariablePrimalStart(), MOI.VariableIndex) - @test MOI.get(model, MOI.VariablePrimalStart(), x[1]) === nothing - @test MOI.get(model, MOI.VariablePrimalStart(), x[2]) === nothing - Gurobi._update_if_necessary(model) - p = Ref{Cdouble}() - Gurobi.GRBgetdblattrelement(model.inner, "Start", Cint(0), p) - @test p[] == Gurobi.GRB_UNDEFINED - MOI.set(model, MOI.VariablePrimalStart(), x[1], 1.0) - MOI.set(model, MOI.VariablePrimalStart(), x[2], nothing) - @test MOI.get(model, MOI.VariablePrimalStart(), x[1]) == 1.0 - @test MOI.get(model, MOI.VariablePrimalStart(), x[2]) === nothing - Gurobi._update_if_necessary(model) - Gurobi.GRBgetdblattrelement(model.inner, "Start", Cint(1), p) - @test p[] == Gurobi.GRB_UNDEFINED - MOI.optimize!(model) - @test MOI.get(model, MOI.ObjectiveValue()) == 0.0 - # We don't support ConstraintDualStart or ConstraintPrimalStart yet. - # @test_broken MOIT.start_values_test(Gurobi.Optimizer(GRB_ENV), OPTIMIZER) -end - -function test_supports_constrainttest() - # supports_constrainttest needs VectorOfVariables-in-Zeros, - # MOIT.supports_constrainttest(Gurobi.Optimizer(GRB_ENV), Float64, Float32) - # but supports_constrainttest is broken via bridges: - MOI.empty!(OPTIMIZER) - MOI.add_variable(OPTIMIZER) - @test MOI.supports_constraint( - OPTIMIZER, - MOI.SingleVariable, - MOI.EqualTo{Float64}, - ) - @test MOI.supports_constraint( - OPTIMIZER, - MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, - ) - # This test is broken for some reason: - @test_broken !MOI.supports_constraint( - OPTIMIZER, - MOI.ScalarAffineFunction{Int}, - MOI.EqualTo{Float64}, - ) - @test !MOI.supports_constraint( - OPTIMIZER, - MOI.ScalarAffineFunction{Int}, - MOI.EqualTo{Int}, - ) - @test !MOI.supports_constraint( - OPTIMIZER, - MOI.SingleVariable, - MOI.EqualTo{Int}, - ) - @test MOI.supports_constraint(OPTIMIZER, MOI.VectorOfVariables, MOI.Zeros) - @test !MOI.supports_constraint( - OPTIMIZER, - MOI.VectorOfVariables, - MOI.EqualTo{Float64}, - ) - @test !MOI.supports_constraint(OPTIMIZER, MOI.SingleVariable, MOI.Zeros) - @test !MOI.supports_constraint( - OPTIMIZER, - MOI.VectorOfVariables, - MOIT.UnknownVectorSet, - ) -end - -function test_set_lower_bound_twice() - return MOIT.set_lower_bound_twice(OPTIMIZER, Float64) -end - -function test_set_upper_bound_twice() - return MOIT.set_upper_bound_twice(OPTIMIZER, Float64) + return end function test_User_limit_handling_issue_140() @@ -242,13 +104,13 @@ function test_User_limit_handling_issue_140() # flaky or system-dependent time limits. m = Gurobi.Optimizer(GRB_ENV) MOI.set(m, MOI.Silent(), true) - MOI.set(m, MOI.RawParameter("SolutionLimit"), 1) - MOI.set(m, MOI.RawParameter("Heuristics"), 0) - MOI.set(m, MOI.RawParameter("Presolve"), 0) + MOI.set(m, MOI.RawOptimizerAttribute("SolutionLimit"), 1) + MOI.set(m, MOI.RawOptimizerAttribute("Heuristics"), 0) + MOI.set(m, MOI.RawOptimizerAttribute("Presolve"), 0) N = 100 x = MOI.add_variables(m, N) for xi in x - MOI.add_constraint(m, MOI.SingleVariable(xi), MOI.ZeroOne()) + MOI.add_constraint(m, xi, MOI.ZeroOne()) MOI.set(m, MOI.VariablePrimalStart(), xi, 0.0) end # Given a collection of items with individual weights and values, @@ -274,6 +136,7 @@ function test_User_limit_handling_issue_140() @test MOI.get(m, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT # But we have no dual status: @test MOI.get(m, MOI.DualStatus()) == MOI.NO_SOLUTION + return end function test_Constant_objective_issue_111() @@ -303,6 +166,7 @@ function test_Constant_objective_issue_111() ).constant == 3.0 Gurobi.GRBgetdblattr(m.inner, "ObjCon", p) @test p[] == 3.0 + return end function test_user_provided_env() @@ -313,6 +177,7 @@ function test_user_provided_env() # Check that finalizer doesn't touch GRB_ENV when manually provided. finalize(model_1) @test GRB_ENV.ptr_env != C_NULL + return end function test_MULTI_ENV() @@ -328,6 +193,7 @@ function test_MULTI_ENV_automatic_env() # Check that env is finalized with model when not supplied manually. finalize(model_1) @test model_1.env.ptr_env == C_NULL + return end function test_user_provided_env_empty() @@ -337,6 +203,7 @@ function test_user_provided_env_empty() MOI.empty!(model) @test model.env === GRB_ENV @test GRB_ENV.ptr_env != C_NULL + return end function test_MULTI_ENV_automatic_env_empty() @@ -345,6 +212,7 @@ function test_MULTI_ENV_automatic_env_empty() MOI.empty!(model) @test model.env === env @test env.ptr_env != C_NULL + return end function test_MULTI_ENV_manual_finalize() @@ -354,275 +222,13 @@ function test_MULTI_ENV_manual_finalize() @test env.finalize_called finalize(model) @test env.ptr_env == C_NULL -end - -function test_Conflict_refiner_bound_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - c1 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(2.0)) - c2 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.LessThan(1.0)) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == MOI.IN_CONFLICT -end - -function test_Conflict_refiner_bound_affine() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - c1 = MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0], [x]), 0.0), - MOI.GreaterThan(2.0), - ) - c2 = MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0], [x]), 0.0), - MOI.LessThan(1.0), - ) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == MOI.IN_CONFLICT -end - -function test_Conflict_refiner_invalid_interval() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - c1 = - MOI.add_constraint(model, MOI.SingleVariable(x), MOI.Interval(1.0, 0.0)) - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT -end - -function test_Conflict_refiner_affine_affine() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - y = MOI.add_variable(model) - b1 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) - b2 = MOI.add_constraint(model, MOI.SingleVariable(y), MOI.GreaterThan(0.0)) - cf1 = - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 1.0], [x, y]), 0.0) - c1 = MOI.add_constraint(model, cf1, MOI.LessThan(-1.0)) - cf2 = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, -1.0], [x, y]), - 0.0, - ) - c2 = MOI.add_constraint(model, cf2, MOI.GreaterThan(1.0)) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), b2) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == - MOI.NOT_IN_CONFLICT -end - -function test_Conflict_refiner_equalto() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - y = MOI.add_variable(model) - b1 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) - b2 = MOI.add_constraint(model, MOI.SingleVariable(y), MOI.GreaterThan(0.0)) - cf1 = - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 1.0], [x, y]), 0.0) - c1 = MOI.add_constraint(model, cf1, MOI.EqualTo(-1.0)) - cf2 = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, -1.0], [x, y]), - 0.0, - ) - c2 = MOI.add_constraint(model, cf2, MOI.GreaterThan(1.0)) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), b2) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == - MOI.NOT_IN_CONFLICT -end - -function test_Conflict_refiner_outside_conflict() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - y = MOI.add_variable(model) - z = MOI.add_variable(model) - b1 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) - b2 = MOI.add_constraint(model, MOI.SingleVariable(y), MOI.GreaterThan(0.0)) - b3 = MOI.add_constraint(model, MOI.SingleVariable(z), MOI.GreaterThan(0.0)) - cf1 = - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 1.0], [x, y]), 0.0) - c1 = MOI.add_constraint(model, cf1, MOI.LessThan(-1.0)) - cf2 = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, -1.0, 1.0], [x, y, z]), - 0.0, - ) - c2 = MOI.add_constraint(model, cf2, MOI.GreaterThan(1.0)) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # Once it's called, no problem. - MOI.compute_conflict!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND - @test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), b2) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), b3) == - MOI.NOT_IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == - MOI.NOT_IN_CONFLICT -end - -function test_Conflict_refiner_no_conflict() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - c1 = MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0], [x]), 0.0), - MOI.GreaterThan(1.0), - ) - c2 = MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0], [x]), 0.0), - MOI.LessThan(2.0), - ) - - # Getting the results before the conflict refiner has been called must return an error. - @test MOI.get(model, Gurobi.ConflictStatus()) == -1 - @test MOI.get(model, MOI.ConflictStatus()) == - MOI.COMPUTE_CONFLICT_NOT_CALLED - @test_throws ErrorException MOI.get( - model, - MOI.ConstraintConflictStatus(), - c1, - ) - - # TODO(odow): bypass Gurobi's IIS checker when underlying model is - # feasible. - # @test_throws Gurobi.GurobiError MOI.compute_conflict!(model) - # @test MOI.get(model, Gurobi.ConflictStatus()) == Gurobi.IIS_NOT_INFEASIBLE - # @test MOI.get(model, MOI.ConflictStatus()) == MOI.NO_CONFLICT_EXISTS - # @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.NOT_IN_CONFLICT - # @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == MOI.NOT_IN_CONFLICT -end - -function test_Conflict_refiner_integer_constraint() - # Root problem: missing method to get the status for an integrality - # constraint. - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x, c1 = MOI.add_constrained_variable(model, MOI.ZeroOne()) - c2 = MOI.add_constraint( - model, - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0], [x]), 0.0), - MOI.GreaterThan(2.0), - ) - - MOI.optimize!(model) - MOI.compute_conflict!(model) - @test MOI.get(model, Gurobi.ConflictStatus()) == 0 - @test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == - MOI.MAYBE_IN_CONFLICT - @test MOI.get(model, MOI.ConstraintConflictStatus(), c2) == MOI.IN_CONFLICT -end - -function test_RawParameter() - model = Gurobi.Optimizer(GRB_ENV) - @test MOI.get(model, MOI.RawParameter("OutputFlag")) == 1 - MOI.set(model, MOI.RawParameter("OutputFlag"), 0) - @test MOI.get(model, MOI.RawParameter("OutputFlag")) == 0 + return end function test_QCPDual_1() model = Gurobi.Optimizer(GRB_ENV) MOI.set(model, MOI.Silent(), true) - MOI.set(model, MOI.RawParameter("QCPDual"), 1) + MOI.set(model, MOI.RawOptimizerAttribute("QCPDual"), 1) MOI.Utilities.loadfromstring!( model, """ @@ -631,9 +237,9 @@ minobjective: 1.0 * x + 1.0 * y + 1.0 * z c1: x + y == 2.0 c2: x + y + z >= 0.0 c3: 1.0 * x * x + -1.0 * y * y + -1.0 * z * z >= 0.0 -c4: x >= 0.0 -c5: y >= 0.0 -c6: z >= 0.0 +x >= 0.0 +y >= 0.0 +z >= 0.0 """, ) MOI.optimize!(model) @@ -646,6 +252,7 @@ c6: z >= 0.0 @test MOI.get(model, MOI.ConstraintDual(), c1) ≈ 1.0 atol = 1e-6 @test MOI.get(model, MOI.ConstraintDual(), c2) ≈ 0.0 atol = 1e-6 @test MOI.get(model, MOI.ConstraintDual(), c3) ≈ 0.0 atol = 1e-6 + return end function test_QCPDual_default() @@ -659,9 +266,9 @@ minobjective: 1.0 * x + 1.0 * y + 1.0 * z c1: x + y == 2.0 c2: x + y + z >= 0.0 c3: 1.0 * x * x + -1.0 * y * y + -1.0 * z * z >= 0.0 -c4: x >= 0.0 -c5: y >= 0.0 -c6: z >= 0.0 +x >= 0.0 +y >= 0.0 +z >= 0.0 """, ) MOI.optimize!(model) @@ -674,155 +281,7 @@ c6: z >= 0.0 @test_throws ErrorException MOI.get(model, MOI.ConstraintDual(), c1) @test_throws ErrorException MOI.get(model, MOI.ConstraintDual(), c2) @test_throws ErrorException MOI.get(model, MOI.ConstraintDual(), c3) -end - -function test_Add_and_delete_constraints() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variables(model, 2) - cs = MOI.add_constraints( - model, - [ - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x[i])], 0.0) for i in 1:2 - ], - MOI.EqualTo.([0.0, 0.0]), - ) - @test MOI.get( - model, - MOI.NumberOfConstraints{ - MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, - }(), - ) == 2 - MOI.delete(model, cs) - @test iszero( - MOI.get( - model, - MOI.NumberOfConstraints{ - MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, - }(), - ), - ) -end - -function test_Add_and_delete_sos_constraints() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - # SOS2 to model piecewise linear function - xp1 = [1.0, 2.0, 3.0] - yp1 = [3.0, 2.0, 3.0] - λ = MOI.add_variables(model, length(xp1)) - for v in λ - MOI.add_constraint(model, MOI.SingleVariable(v), MOI.LessThan(1.0)) - MOI.add_constraint(model, MOI.SingleVariable(v), MOI.GreaterThan(0.0)) - end - xp2 = [1.0, 2.0, 3.0, 4.0] - yp2 = [3.0, 3.0, 2.0, 4.0] - η = MOI.add_variables(model, length(xp2)) - for v in η - MOI.add_constraint(model, MOI.SingleVariable(v), MOI.LessThan(1.0)) - MOI.add_constraint(model, MOI.SingleVariable(v), MOI.GreaterThan(0.0)) - end - x = MOI.add_variables(model, 2) - y = MOI.add_variables(model, 2) - SOS2_cons = MOI.add_constraints( - model, - MOI.VectorOfVariables.([λ, η]), - MOI.SOS2{Float64}.([ones(length(λ)), ones(length(η))]), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - map(v -> MOI.ScalarAffineTerm(1.0, v), λ), - 0.0, - ), - MOI.EqualTo(1.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - map(v -> MOI.ScalarAffineTerm(1.0, v), η), - 0.0, - ), - MOI.EqualTo(1.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - [ - MOI.ScalarAffineTerm(-1.0, x[1]), - map(i -> MOI.ScalarAffineTerm(xp1[i], λ[i]), 1:length(xp1))..., - ], - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - [ - MOI.ScalarAffineTerm(-1.0, y[1]), - map(i -> MOI.ScalarAffineTerm(yp1[i], λ[i]), 1:length(xp1))..., - ], - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - [ - MOI.ScalarAffineTerm(-1.0, x[2]), - map(i -> MOI.ScalarAffineTerm(xp2[i], η[i]), 1:length(xp2))..., - ], - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.add_constraint( - model, - MOI.ScalarAffineFunction( - [ - MOI.ScalarAffineTerm(-1.0, y[2]), - map(i -> MOI.ScalarAffineTerm(yp2[i], η[i]), 1:length(xp2))..., - ], - 0.0, - ), - MOI.EqualTo(0.0), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), - MOI.ScalarAffineFunction( - [MOI.ScalarAffineTerm(1.0, y[1]), MOI.ScalarAffineTerm(1.0, y[2])], - 0.0, - ), - ) - @test MOI.get( - model, - MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.SOS2{Float64}}(), - ) == 2 - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), x[1]) ≈ 2.0 atol = 1e-6 - @test MOI.get(model, MOI.VariablePrimal(), x[2]) ≈ 3.0 atol = 1e-6 - MOI.delete(model, SOS2_cons) - @test MOI.get( - model, - MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.SOS2{Float64}}(), - ) == 0 - SOS2_cons = MOI.add_constraints( - model, - MOI.VectorOfVariables.([λ, η]), - MOI.SOS2{Float64}.([ones(length(λ)), ones(length(η))]), - ) - @test MOI.get( - model, - MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.SOS2{Float64}}(), - ) == 2 - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), x[1]) ≈ 2.0 atol = 1e-6 - @test MOI.get(model, MOI.VariablePrimal(), x[2]) ≈ 3.0 atol = 1e-6 + return end function test_Buffered_deletion_test() @@ -860,55 +319,7 @@ function test_Buffered_deletion_test() @test vars_obj[2] == MOI.get(model, obj_attr, vars[2]) @test MOI.is_valid(model, fourth_var) @test fourth_var_obj == MOI.get(model, obj_attr, fourth_var) -end - -function test_extra_name_Variables() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variables(model, 3) - MOI.set(model, MOI.VariableName(), x[1], "x1") - @test MOI.get(model, MOI.VariableIndex, "x1") == x[1] - MOI.set(model, MOI.VariableName(), x[1], "x2") - @test MOI.get(model, MOI.VariableIndex, "x1") === nothing - @test MOI.get(model, MOI.VariableIndex, "x2") == x[1] - MOI.set(model, MOI.VariableName(), x[2], "x1") - @test MOI.get(model, MOI.VariableIndex, "x1") == x[2] - MOI.set(model, MOI.VariableName(), x[3], "xα") - @test MOI.get(model, MOI.VariableIndex, "xα") == x[3] - MOI.set(model, MOI.VariableName(), x[1], "x1") - @test_throws ErrorException MOI.get(model, MOI.VariableIndex, "x1") -end - -function test_extra_name_Variable_bounds() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variable(model) - c1 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(0.0)) - c2 = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.LessThan(1.0)) - MOI.set(model, MOI.ConstraintName(), c1, "c1") - @test MOI.get(model, MOI.ConstraintIndex, "c1") == c1 - MOI.set(model, MOI.ConstraintName(), c1, "c2") - @test MOI.get(model, MOI.ConstraintIndex, "c1") === nothing - @test MOI.get(model, MOI.ConstraintIndex, "c2") == c1 - MOI.set(model, MOI.ConstraintName(), c2, "c1") - @test MOI.get(model, MOI.ConstraintIndex, "c1") == c2 - MOI.set(model, MOI.ConstraintName(), c1, "c1") - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "c1") -end - -function test_extra_name_Affine_constraints() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variable(model) - f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0) - c1 = MOI.add_constraint(model, f, MOI.GreaterThan(0.0)) - c2 = MOI.add_constraint(model, f, MOI.LessThan(1.0)) - MOI.set(model, MOI.ConstraintName(), c1, "c1") - @test MOI.get(model, MOI.ConstraintIndex, "c1") == c1 - MOI.set(model, MOI.ConstraintName(), c1, "c2") - @test MOI.get(model, MOI.ConstraintIndex, "c1") === nothing - @test MOI.get(model, MOI.ConstraintIndex, "c2") == c1 - MOI.set(model, MOI.ConstraintName(), c2, "c1") - @test MOI.get(model, MOI.ConstraintIndex, "c1") == c2 - MOI.set(model, MOI.ConstraintName(), c1, "c1") - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "c1") + return end function test_ConstraintAttribute() @@ -918,13 +329,12 @@ function test_ConstraintAttribute() """ variables: x minobjective: x -c1: x >= 0.0 -c2: 2x >= 1.0 -c3: x in Integer() +x >= 0.0 +c: 2x >= 1.0 +x in Integer() """, ) - c2 = MOI.get(model, MOI.ConstraintIndex, "c2") - c3 = MOI.get(model, MOI.ConstraintIndex, "c3") + c2 = MOI.get(model, MOI.ConstraintIndex, "c") # Linear constraints are supported - one test for each different type. # Integer attribute MOI.set(model, Gurobi.ConstraintAttribute("Lazy"), c2, 2) @@ -938,12 +348,6 @@ c3: x in Integer() # String attribute MOI.set(model, Gurobi.ConstraintAttribute("ConstrName"), c2, "c4") @test MOI.get(model, Gurobi.ConstraintAttribute("ConstrName"), c2) == "c4" - # Things that should fail follow. - # Non-linear constraints are not supported. - @test_throws( - MOI.SetAttributeNotAllowed(Gurobi.ConstraintAttribute("Lazy")), - MOI.set(model, Gurobi.ConstraintAttribute("Lazy"), c3, 1) - ) # Getting/setting a non-existing attribute. attr = Gurobi.ConstraintAttribute("Non-existing") err = ErrorException("Gurobi Error 10004: Unknown attribute 'Non-existing'") @@ -956,6 +360,7 @@ c3: x in Integer() ), MOI.set(model, Gurobi.ConstraintAttribute("Lazy"), c2, 1.5) ) + return end function test_VariableAttribute() @@ -997,6 +402,7 @@ c3: x in Integer() ), MOI.set(model, Gurobi.VariableAttribute("BranchPriority"), x, 1.5) ) + return end function test_ModelAttribute() @@ -1034,371 +440,7 @@ c3: x in Integer() ), MOI.set(model, Gurobi.ModelAttribute("NumStart"), 4.0) ) -end - -function test_soc_no_initial_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.DUAL_INFEASIBLE -end - -function test_soc_nonnegative_initial_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(1.0)) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 1.0 -end - -function test_soc_negative_initial_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(-1.0)) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - MOI.optimize!(model) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == -1.0 -end - -function test_soc_nonnegative_post_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - c_lb = - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(6.0)) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 6.0 - MOI.delete(model, c_lb) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 -end - -function test_soc_negative_post_bound() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(-6.0)) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == -6.0 -end - -function test_soc_negative_post_bound_ii() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.(3.0:4.0), - ) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - c_lb = - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(-6.0)) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_lb) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.DUAL_INFEASIBLE -end - -function test_soc_negative_post_bound_iii() - # This test was added because add_constraint and add_constraints had - # different implementations and add_constraints failed where - # add_constraint succeeded. - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - c_soc = MOI.add_constraint( - model, - MOI.VectorOfVariables([t; x]), - MOI.SecondOrderCone(3), - ) - c_lbs = MOI.add_constraints( - model, - MOI.SingleVariable.([t; x]), - MOI.GreaterThan.([-6.0, 3.0, 4.0]), - ) - c_lb = first(c_lbs) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_lb) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 5.0 - MOI.delete(model, c_soc) - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.DUAL_INFEASIBLE -end - -function test_2_soc() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - t = MOI.add_variable(model) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(t), MOI.GreaterThan(-1.0)) - MOI.add_constraints( - model, - MOI.SingleVariable.(x), - MOI.GreaterThan.([4.0, 3.0]), - ) - c_soc_1 = MOI.add_constraint( - model, - MOI.VectorOfVariables([t, x[1]]), - MOI.SecondOrderCone(2), - ) - c_soc_2 = MOI.add_constraint( - model, - MOI.VectorOfVariables([t, x[2]]), - MOI.SecondOrderCone(2), - ) - MOI.optimize!(model) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(t), - ) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - @test MOI.get(model, MOI.VariablePrimal(), t) == 4.0 - MOI.delete(model, c_soc_1) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == 3.0 - MOI.delete(model, c_soc_2) - MOI.optimize!(model) - @test MOI.get(model, MOI.VariablePrimal(), t) == -1.0 -end - -function test_Duplicate_names_Variables() - model = Gurobi.Optimizer(GRB_ENV) - (x, y, z) = MOI.add_variables(model, 3) - MOI.set(model, MOI.VariableName(), x, "x") - MOI.set(model, MOI.VariableName(), y, "x") - MOI.set(model, MOI.VariableName(), z, "z") - @test MOI.get(model, MOI.VariableIndex, "z") == z - @test_throws ErrorException MOI.get(model, MOI.VariableIndex, "x") - MOI.set(model, MOI.VariableName(), y, "y") - @test MOI.get(model, MOI.VariableIndex, "x") == x - @test MOI.get(model, MOI.VariableIndex, "y") == y - MOI.set(model, MOI.VariableName(), z, "x") - @test_throws ErrorException MOI.get(model, MOI.VariableIndex, "x") - MOI.delete(model, x) - @test MOI.get(model, MOI.VariableIndex, "x") == z -end - -function test_Duplicate_names_SingleVariable() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variables(model, 3) - c = MOI.add_constraints(model, MOI.SingleVariable.(x), MOI.GreaterThan(0.0)) - MOI.set(model, MOI.ConstraintName(), c[1], "x") - MOI.set(model, MOI.ConstraintName(), c[2], "x") - MOI.set(model, MOI.ConstraintName(), c[3], "z") - @test MOI.get(model, MOI.ConstraintIndex, "z") == c[3] - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "x") - MOI.set(model, MOI.ConstraintName(), c[2], "y") - @test MOI.get(model, MOI.ConstraintIndex, "x") == c[1] - @test MOI.get(model, MOI.ConstraintIndex, "y") == c[2] - MOI.set(model, MOI.ConstraintName(), c[3], "x") - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "x") - MOI.delete(model, c[1]) - @test MOI.get(model, MOI.ConstraintIndex, "x") == c[3] - MOI.set(model, MOI.ConstraintName(), c[2], "x") - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "x") - MOI.delete(model, x[3]) - @test MOI.get(model, MOI.ConstraintIndex, "x") == c[2] -end - -function test_Duplicate_names_ScalarAffineFunction() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variables(model, 3) - fs = [ - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, xi)], 0.0) for - xi in x - ] - c = MOI.add_constraints(model, fs, MOI.GreaterThan(0.0)) - MOI.set(model, MOI.ConstraintName(), c[1], "x") - MOI.set(model, MOI.ConstraintName(), c[2], "x") - MOI.set(model, MOI.ConstraintName(), c[3], "z") - @test MOI.get(model, MOI.ConstraintIndex, "z") == c[3] - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "x") - MOI.set(model, MOI.ConstraintName(), c[2], "y") - @test MOI.get(model, MOI.ConstraintIndex, "x") == c[1] - @test MOI.get(model, MOI.ConstraintIndex, "y") == c[2] - MOI.set(model, MOI.ConstraintName(), c[3], "x") - @test_throws ErrorException MOI.get(model, MOI.ConstraintIndex, "x") - MOI.delete(model, c[1]) - @test MOI.get(model, MOI.ConstraintIndex, "x") == c[3] -end - -function test_Duals_with_equal_bounds_250() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - xl = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0)) - xu = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.LessThan(1.0)) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(x), - ) - MOI.optimize!(model) - @test MOI.get(model, MOI.ConstraintDual(), xl) == 1.0 - @test MOI.get(model, MOI.ConstraintDual(), xu) == 0.0 -end - -function test_Objective_functions() - model = Gurobi.Optimizer(GRB_ENV) - x = MOI.add_variable(model) - @test MOI.get(model, MOI.ObjectiveSense()) == MOI.FEASIBILITY_SENSE - @test MOI.get(model, MOI.ListOfModelAttributesSet()) == - Any[MOI.ObjectiveSense()] - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(x), - ) - @test MOI.get(model, MOI.ListOfModelAttributesSet()) == - Any[MOI.ObjectiveSense(), MOI.ObjectiveFunction{MOI.SingleVariable}()] - MOI.set(model, MOI.ObjectiveSense(), MOI.FEASIBILITY_SENSE) - @test MOI.get(model, MOI.ListOfModelAttributesSet()) == - Any[MOI.ObjectiveSense()] -end - -function test_FEASIBILITY_SENSE_zeros_objective() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variable(model) - MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0)) - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(x), - ) - MOI.optimize!(model) - @test MOI.get(model, MOI.ObjectiveValue()) == 1.0 - MOI.set(model, MOI.ObjectiveSense(), MOI.FEASIBILITY_SENSE) - MOI.optimize!(model) - @test MOI.get(model, MOI.ObjectiveValue()) == 0.0 + return end function test_Attributes() @@ -1417,12 +459,11 @@ function test_GRBterminate() MOI.set( model, Gurobi.CallbackFunction(), - (cb_data, cb_where) -> begin - GRBterminate(model) - end, + (cb_data, cb_where) -> GRBterminate(model), ) MOI.optimize!(model) @test MOI.get(model, MOI.TerminationStatus()) == MOI.INTERRUPTED + return end """ @@ -1443,14 +484,10 @@ function test_InterruptException() model = Gurobi.Optimizer(GRB_ENV) MOI.set(model, MOI.Silent(), true) x = MOI.add_variable(model) - MOI.add_constraint(model, MOI.SingleVariable(x), MOI.Integer()) + MOI.add_constraint(model, x, MOI.Integer()) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - MOI.set( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(x), - ) - MOI.set(model, MOI.RawParameter("LazyConstraints"), 1) + MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x) + MOI.set(model, MOI.RawOptimizerAttribute("LazyConstraints"), 1) interrupt_thrown = false i = 0.0 MOI.set( @@ -1478,108 +515,7 @@ function test_InterruptException() ) MOI.optimize!(model) @test MOI.get(model, MOI.TerminationStatus()) == MOI.INTERRUPTED -end - -function test_indicator_name() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x[1])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [0.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.GreaterThan(1.0)) - c = MOI.add_constraint(model, f, s) - MOI.set(model, MOI.ConstraintName(), c, "my_indicator") - @test MOI.get(model, MOI.ConstraintName(), c) == "my_indicator" -end - -function test_indicator_on_one() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x[1])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [0.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.GreaterThan(1.0)) - c = MOI.add_constraint(model, f, s) - @test MOI.get(model, MOI.ConstraintSet(), c) == s - @test isapprox(MOI.get(model, MOI.ConstraintFunction(), c), f) -end - -function test_indicator_on_zero() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x[1])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [0.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}(MOI.GreaterThan(1.0)) - c = MOI.add_constraint(model, f, s) - @test MOI.get(model, MOI.ConstraintSet(), c) == s - @test isapprox(MOI.get(model, MOI.ConstraintFunction(), c), f) -end - -function test_indicator_nonconstant_x() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-1.0, x[1])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [0.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.GreaterThan(1.0)) - @test_throws ErrorException MOI.add_constraint(model, f, s) -end - -function test_indicator_too_many_indicators() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-1.0, x[1])), - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [0.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.GreaterThan(1.0)) - @test_throws ErrorException MOI.add_constraint(model, f, s) -end - -function test_indicator_nonconstant() - model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.Silent(), true) - x = MOI.add_variables(model, 2) - MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.ZeroOne()) - f = MOI.VectorAffineFunction( - [ - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x[1])), - MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(2.0, x[2])), - ], - [1.0, 0.0], - ) - s = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.GreaterThan(1.0)) - @test_throws ErrorException MOI.add_constraint(model, f, s) + return end function _build_basis_model() @@ -1599,23 +535,15 @@ function _build_basis_model() ) c = MOI.add_constraint(model, cf, MOI.LessThan(one(T))) - vc1 = MOI.add_constraint( - model, - MOI.SingleVariable(x), - MOI.GreaterThan(zero(T)), - ) - vc2 = MOI.add_constraint( - model, - MOI.SingleVariable(y), - MOI.GreaterThan(zero(T)), - ) + vc1 = MOI.add_constraint(model, x, MOI.GreaterThan(zero(T))) + vc2 = MOI.add_constraint(model, y, MOI.GreaterThan(zero(T))) objf = MOI.ScalarAffineFunction{T}( MOI.ScalarAffineTerm{T}.([-one(T), zero(T)], [x, y]), zero(T), ) MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), objf) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) - return model, vc1, vc2, c + return model, x, y, c end function test_set_basis() @@ -1629,22 +557,22 @@ function test_set_basis() # and just verify that, after setting the basis, we can get the same basis # statuses back. let - model, vc1, vc2, c = _build_basis_model() - MOI.set(model, MOI.ConstraintBasisStatus(), vc1, MOI.BASIC) - MOI.set(model, MOI.ConstraintBasisStatus(), vc2, MOI.NONBASIC) + model, x, y, c = _build_basis_model() + MOI.set(model, MOI.VariableBasisStatus(), x, MOI.BASIC) + MOI.set(model, MOI.VariableBasisStatus(), y, MOI.NONBASIC_AT_LOWER) MOI.set(model, MOI.ConstraintBasisStatus(), c, MOI.NONBASIC) MOI.optimize!(model) @test MOI.get(model, MOI.SimplexIterations()) == 0 end - let - model, vc1, vc2, c = _build_basis_model() - MOI.set(model, MOI.ConstraintBasisStatus(), vc1, MOI.NONBASIC) - MOI.set(model, MOI.ConstraintBasisStatus(), vc2, MOI.NONBASIC) + model, x, y, c = _build_basis_model() + MOI.set(model, MOI.VariableBasisStatus(), x, MOI.NONBASIC_AT_LOWER) + MOI.set(model, MOI.VariableBasisStatus(), y, MOI.NONBASIC_AT_LOWER) MOI.set(model, MOI.ConstraintBasisStatus(), c, MOI.BASIC) MOI.optimize!(model) @test MOI.get(model, MOI.SimplexIterations()) == 1 end + return end function test_add_constrained_variables() @@ -1653,10 +581,11 @@ function test_add_constrained_variables() set = MOI.Interval{Float64}(-1.2, 3.4) vi, ci = MOI.add_constrained_variable(model, set) @test MOI.get(model, MOI.NumberOfVariables()) == 1 - @test MOI.get(model, MOI.ListOfConstraints()) == - [(MOI.SingleVariable, MOI.Interval{Float64})] - @test MOI.get(model, MOI.ConstraintFunction(), ci) == MOI.SingleVariable(vi) + @test MOI.get(model, MOI.ListOfConstraintTypesPresent()) == + [(MOI.VariableIndex, MOI.Interval{Float64})] + @test MOI.get(model, MOI.ConstraintFunction(), ci) == vi @test MOI.get(model, MOI.ConstraintSet(), ci) == set + return end function _is_binary(x; atol = 1e-6) @@ -1665,14 +594,14 @@ end function test_multiple_solutions() model = Gurobi.Optimizer(GRB_ENV) - MOI.set(model, MOI.RawParameter("OutputFlag"), 0) - MOI.set(model, MOI.RawParameter("Cuts"), 0) - MOI.set(model, MOI.RawParameter("Presolve"), 0) - MOI.set(model, MOI.RawParameter("PreCrush"), 0) - MOI.set(model, MOI.RawParameter("Heuristics"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("OutputFlag"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Cuts"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Presolve"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("PreCrush"), 0) + MOI.set(model, MOI.RawOptimizerAttribute("Heuristics"), 0) N = 30 x = MOI.add_variables(model, N) - MOI.add_constraints(model, MOI.SingleVariable.(x), MOI.ZeroOne()) + MOI.add_constraints(model, x, MOI.ZeroOne()) MOI.set.(model, MOI.VariablePrimalStart(), x, 0.0) Random.seed!(1) item_weights, item_values = rand(N), rand(N) @@ -1713,8 +642,9 @@ function test_multiple_solutions() @test MOI.get(model, MOI.PrimalStatus(n)) == MOI.FEASIBLE_POINT @test MOI.get(model, MOI.DualStatus(n)) == MOI.NO_SOLUTION end + return end end -runtests(TestMOIWrapper) +TestMOIWrapper.runtests() diff --git a/test/runtests.jl b/test/runtests.jl index 10787af2..ccfc2ca2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,39 +5,8 @@ using Test # re-use an existing environment in the module, or name the test function # `test_MULTI_ENV_xxx` to trap the specific Gurobi error indicating that an # environment could not be created. - const GRB_ENV = Gurobi.Env() -function runtests(mod) - for name in names(mod; all = true) - sname = "$(name)" - if !startswith(sname, "test_") - continue - end - @testset "$(name)" begin - if startswith(sname, "test_MULTI_ENV") - try - getfield(mod, name)() - catch ex - if ex == ErrorException( - "Gurobi Error 10009: Failed to obtain a valid license", - ) - @warn( - "Skipping a test because there was an issue " * - "creating multiple licenses. This is probably " * - "because you have a limited license." - ) - else - rethrow(ex) - end - end - else - getfield(mod, name)() - end - end - end -end - @testset "MathOptInterface Tests" begin for file in readdir("MOI") include(joinpath("MOI", file))