diff --git a/.ci/ci.jl b/.ci/ci.jl index 64d98d42d..8007a2411 100644 --- a/.ci/ci.jl +++ b/.ci/ci.jl @@ -1,9 +1,13 @@ -rm("Manifest.toml";force=true) + +rm(joinpath(@__DIR__, "Project.toml");force=true) +rm(joinpath(@__DIR__, "Manifest.toml");force=true) using Pkg +Pkg.activate(@__DIR__) + if ARGS[1] == "full" - pkgs = ["MadNLPHSL","MadNLPPardiso","MadNLPMumps","MadNLPGPU","MadNLPGraph","MadNLPKrylov"] + pkgs = ["MadNLPHSL","MadNLPPardiso","MadNLPMumps","MadNLPGraph","MadNLPKrylov"] elseif ARGS[1] == "basic" pkgs = ["MadNLPMumps","MadNLPGraph","MadNLPKrylov"] else diff --git a/Project.toml b/Project.toml index 030d2ec54..5eb83cbdb 100644 --- a/Project.toml +++ b/Project.toml @@ -17,20 +17,18 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [compat] -AmplNLReader = "~0.11" MINLPTests = "~0.5" MadNLPTests = "~0.3" -MathOptInterface = "~0.9" +MathOptInterface = "0.10.5 - 0.10.8" NLPModels = "~0.17.2, 0.18" SolverCore = "~0.1,~0.2" julia = "1.3" [extras] -AmplNLReader = "77dd3d4c-cb1d-5e09-9340-85030ff7ba66" MINLPTests = "ee0a3090-8ee9-5cdb-b8cb-8eeba3165522" MadNLPTests = "b52a2a03-04ab-4a5f-9698-6a2deff93217" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "MadNLPTests", "AmplNLReader", "MINLPTests", "Random"] +test = ["Test", "MadNLPTests", "MINLPTests", "Random"] diff --git a/lib/MadNLPGraph/Project.toml b/lib/MadNLPGraph/Project.toml index e03dde159..7706e67af 100644 --- a/lib/MadNLPGraph/Project.toml +++ b/lib/MadNLPGraph/Project.toml @@ -12,7 +12,7 @@ Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b" [compat] MadNLP = "~0.3" -JuMP = "~0.21" +JuMP = "~0.22" Plasmo = "~0.4" LightGraphs = "~1.3" Metis = "1" diff --git a/lib/MadNLPGraph/src/MadNLPGraph.jl b/lib/MadNLPGraph/src/MadNLPGraph.jl index 85184c4f5..bdc7f60a0 100644 --- a/lib/MadNLPGraph/src/MadNLPGraph.jl +++ b/lib/MadNLPGraph/src/MadNLPGraph.jl @@ -16,7 +16,7 @@ import MadNLP: get_lcon, get_ucon, jac_structure!, hess_structure!, obj, grad!, cons!, jac_coord!, hess_coord! import Metis: partition import LightGraphs: Graph, Edge, add_edge!, edges, src, dst, neighbors, nv -import Plasmo: OptiGraph, OptiNode, OptiEdge, all_nodes, all_edges, all_variables, num_all_nodes, getlinkconstraints, getnode, num_variables, num_constraints +import Plasmo: OptiGraph, OptiNode, OptiEdge, all_nodes, all_edges, all_variables, num_all_nodes, link_constraints, getnode, num_variables, num_constraints import JuMP: _create_nlp_block_data, set_optimizer, GenericAffExpr include("plasmo_interface.jl") diff --git a/lib/MadNLPGraph/src/plasmo_interface.jl b/lib/MadNLPGraph/src/plasmo_interface.jl index eb42d5945..20e35b5b4 100644 --- a/lib/MadNLPGraph/src/plasmo_interface.jl +++ b/lib/MadNLPGraph/src/plasmo_interface.jl @@ -46,7 +46,7 @@ end function jacobian_structure(linkedge::OptiEdge,I,J,ninds,x_index_map,g_index_map) offset=1 - for linkcon in getlinkconstraints(linkedge) + for linkcon in link_constraints(linkedge) offset += jacobian_structure(linkcon,I,J,ninds,x_index_map,g_index_map,offset) end end @@ -107,7 +107,7 @@ function eval_function(aff::GenericAffExpr,x,ninds,x_index_map) end function eval_constraint(linkedge::OptiEdge,c,x,ninds,x_index_map) cnt = 1 - for linkcon in getlinkconstraints(linkedge) + for linkcon in link_constraints(linkedge) c[cnt] = eval_function(get_func(linkcon),x,ninds,x_index_map) cnt += 1 end @@ -134,7 +134,7 @@ end function eval_constraint_jacobian(linkedge::OptiEdge,jac,x) offset=0 - for linkcon in getlinkconstraints(linkedge) + for linkcon in link_constraints(linkedge) offset+=eval_constraint_jacobian(linkcon,jac,offset) end end @@ -400,5 +400,9 @@ function optimize!(graph::OptiGraph; option_dict = Dict{Symbol,Any}(), kwargs... view(result.multipliers_L,nlp.ninds[k]), view(result.multipliers_U,nlp.ninds[k]), ips.cnt.k, ips.nlp.counters,ips.cnt.total_time) + # TODO: quick hack to specify to JuMP that the + # model is not dirty (so we do not run in `OptimizeNotCalled` + # exception). + nlp.modelnodes[k].model.is_model_dirty = false end end diff --git a/lib/MadNLPTests/Project.toml b/lib/MadNLPTests/Project.toml index 0c0a3918e..c7d8d5d5e 100644 --- a/lib/MadNLPTests/Project.toml +++ b/lib/MadNLPTests/Project.toml @@ -12,7 +12,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -JuMP = "~0.21" +JuMP = "~0.22" MadNLP = "~0.3" NLPModels = "~0.17.2, 0.18" julia = "1.3" diff --git a/src/Interfaces/MOI_interface.jl b/src/Interfaces/MOI_interface.jl index 79b72ca27..8a4f46f3e 100644 --- a/src/Interfaces/MOI_interface.jl +++ b/src/Interfaces/MOI_interface.jl @@ -29,7 +29,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer nlp_data::MOI.NLPBlockData sense::MOI.OptimizationSense objective::Union{ - MOI.SingleVariable,MOI.ScalarAffineFunction{Float64},MOI.ScalarQuadraticFunction{Float64},Nothing} + MOI.VariableIndex,MOI.ScalarAffineFunction{Float64},MOI.ScalarQuadraticFunction{Float64},Nothing} linear_le_constraints::Vector{ConstraintInfo{MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}}} linear_ge_constraints::Vector{ConstraintInfo{MOI.ScalarAffineFunction{Float64},MOI.GreaterThan{Float64}}} @@ -70,15 +70,15 @@ empty_nlp_data() = MOI.NLPBlockData([], EmptyNLPEvaluator(), false) # for throw_if_valid MOI.is_valid(model::Optimizer, vi::MOI.VariableIndex) = vi.value in eachindex(model.variable_info) -function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) +function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}) vi = MOI.VariableIndex(ci.value) return MOI.is_valid(model, vi) && has_upper_bound(model, vi) end -function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}) +function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) vi = MOI.VariableIndex(ci.value) return MOI.is_valid(model, vi) && has_lower_bound(model, vi) end -function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}) +function MOI.is_valid(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) vi = MOI.VariableIndex(ci.value) return MOI.is_valid(model, vi) && is_fixed(model, vi) end @@ -86,13 +86,13 @@ end # supported obj/var/cons MOI.supports(::Optimizer, ::MOI.NLPBlock) = true -MOI.supports(::Optimizer,::MOI.ObjectiveFunction{MOI.SingleVariable}) = true +MOI.supports(::Optimizer,::MOI.ObjectiveFunction{MOI.VariableIndex}) = true MOI.supports(::Optimizer,::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}) = true MOI.supports(::Optimizer,::MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}) = true MOI.supports(::Optimizer, ::MOI.VariablePrimalStart,::Type{MOI.VariableIndex}) = true -MOI.supports_constraint(::Optimizer,::Type{MOI.SingleVariable},::Type{MOI.LessThan{Float64}})=true -MOI.supports_constraint(::Optimizer,::Type{MOI.SingleVariable},::Type{MOI.GreaterThan{Float64}})=true -MOI.supports_constraint(::Optimizer,::Type{MOI.SingleVariable},::Type{MOI.EqualTo{Float64}})=true +MOI.supports_constraint(::Optimizer,::Type{MOI.VariableIndex},::Type{MOI.LessThan{Float64}})=true +MOI.supports_constraint(::Optimizer,::Type{MOI.VariableIndex},::Type{MOI.GreaterThan{Float64}})=true +MOI.supports_constraint(::Optimizer,::Type{MOI.VariableIndex},::Type{MOI.EqualTo{Float64}})=true MOI.supports_constraint(::Optimizer,::Type{MOI.ScalarAffineFunction{Float64}},::Type{MOI.LessThan{Float64}})=true MOI.supports_constraint(::Optimizer,::Type{MOI.ScalarAffineFunction{Float64}},::Type{MOI.GreaterThan{Float64}})=true MOI.supports_constraint(::Optimizer,::Type{MOI.ScalarAffineFunction{Float64}},::Type{MOI.EqualTo{Float64}})=true @@ -105,14 +105,15 @@ MOI.supports_constraint(::Optimizer,::Type{MOI.ScalarAffineFunction{Float64}},:: MOI.supports_constraint(::Optimizer,::Type{MOI.ScalarQuadraticFunction{Float64}},::Type{MOI.Interval{Float64}})=false MOI.get(::Optimizer, ::MOI.SolverName) = "MadNLP" +MOI.get(::Optimizer, ::MOI.SolverVersion) = version() MOI.get(model::Optimizer,::MOI.ObjectiveFunctionType)=typeof(model.objective) MOI.get(model::Optimizer,::MOI.NumberOfVariables)=length(model.variable_info) MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}})=length(model.linear_le_constraints) MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}})=length(model.linear_eq_constraints) MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{Float64},MOI.GreaterThan{Float64}})=length(model.linear_ge_constraints) -MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.LessThan{Float64}})=count(e->e.has_upper_bound,model.variable_info) -MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.EqualTo{Float64}})=count(e->e.is_fixed,model.variable_info) -MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.GreaterThan{Float64}})=count(e->e.has_lower_bound,model.variable_info) +MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.LessThan{Float64}})=count(e->e.has_upper_bound,model.variable_info) +MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.EqualTo{Float64}})=count(e->e.is_fixed,model.variable_info) +MOI.get(model::Optimizer,::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.GreaterThan{Float64}})=count(e->e.has_lower_bound,model.variable_info) MOI.get(model::Optimizer,::MOI.ObjectiveFunction) = model.objective MOI.get(model::Optimizer,::MOI.ListOfVariableIndices) = [MOI.VariableIndex(i) for i in 1:length(model.variable_info)] MOI.get(model::Optimizer,::MOI.BarrierIterations) = model.ips.cnt.k @@ -140,42 +141,42 @@ end function MOI.get(model::Optimizer,::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}) return MOI.LessThan{Float64}(model.variable_info[c.value].upper_bound) end function MOI.get(model::Optimizer,::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) return MOI.EqualTo{Float64}(model.variable_info[c.value].lower_bound) end function MOI.get(model::Optimizer,::MOI.ConstraintSet, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) return MOI.GreaterThan{Float64}(model.variable_info[c.value].lower_bound) end function MOI.get(model::Optimizer,::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) - return MOI.SingleVariable(MOI.VariableIndex(c.value)) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}) + return MOI.VariableIndex(c.value) end function MOI.get(model::Optimizer,::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}) - return MOI.SingleVariable(MOI.VariableIndex(c.value)) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) + return MOI.VariableIndex(c.value) end function MOI.get( model::Optimizer,::MOI.ConstraintFunction, - c::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}) - return MOI.SingleVariable(MOI.VariableIndex(c.value)) + c::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) + return MOI.VariableIndex(c.value) end -function MOI.get(model::Optimizer, ::MOI.ListOfConstraints) +function MOI.get(model::Optimizer, ::MOI.ListOfConstraintTypesPresent) constraints = Set{Tuple{DataType, DataType}}() for info in model.variable_info - info.has_lower_bound && push!(constraints, (MOI.SingleVariable, MOI.LessThan{Float64})) - info.has_upper_bound && push!(constraints, (MOI.SingleVariable, MOI.GreaterThan{Float64})) - info.is_fixed && push!(constraints, (MOI.SingleVariable, MOI.EqualTo{Float64})) + info.has_lower_bound && push!(constraints, (MOI.VariableIndex, MOI.LessThan{Float64})) + info.has_upper_bound && push!(constraints, (MOI.VariableIndex, MOI.GreaterThan{Float64})) + info.is_fixed && push!(constraints, (MOI.VariableIndex, MOI.EqualTo{Float64})) end isempty(model.linear_le_constraints) || @@ -211,25 +212,25 @@ function MOI.get( ) return MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}.(eachindex(model.linear_ge_constraints)) end -function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, MOI.LessThan{Float64}}) +function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.VariableIndex, MOI.LessThan{Float64}}) dict = Dict(model.variable_info[i] => i for i in 1:length(model.variable_info)) filter!(info -> info.first.has_upper_bound, dict) - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}.(values(dict)) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}.(values(dict)) end -function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, MOI.EqualTo{Float64}}) +function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.VariableIndex, MOI.EqualTo{Float64}}) dict = Dict(model.variable_info[i] => i for i in 1:length(model.variable_info)) filter!(info -> info.first.is_fixed, dict) - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}.(values(dict)) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}.(values(dict)) end -function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, MOI.GreaterThan{Float64}}) +function MOI.get(model::Optimizer, ::MOI.ListOfConstraintIndices{MOI.VariableIndex, MOI.GreaterThan{Float64}}) dict = Dict(model.variable_info[i] => i for i in 1:length(model.variable_info)) filter!(info -> info.first.has_lower_bound, dict) - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}.(values(dict)) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}.(values(dict)) end function MOI.set(model::Optimizer, ::MOI.ConstraintSet, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}, set::MOI.LessThan{Float64}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].upper_bound = set.upper @@ -237,7 +238,7 @@ function MOI.set(model::Optimizer, ::MOI.ConstraintSet, end function MOI.set(model::Optimizer, ::MOI.ConstraintSet, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}, set::MOI.GreaterThan{Float64}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].lower_bound = set.lower @@ -245,7 +246,7 @@ function MOI.set(model::Optimizer, ::MOI.ConstraintSet, end function MOI.set(model::Optimizer, ::MOI.ConstraintSet, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}, set::MOI.EqualTo{Float64}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].lower_bound = set.value @@ -254,8 +255,8 @@ function MOI.set(model::Optimizer, ::MOI.ConstraintSet, end # default_copy_to -MOIU.supports_default_copy_to(model::Optimizer, copy_names::Bool) = !copy_names -MOI.copy_to(model::Optimizer, src::MOI.ModelLike; copy_names = false) = MOIU.default_copy_to(model, src, copy_names) +MOI.supports_incremental_interface(model::Optimizer) = true +MOI.copy_to(model::Optimizer, src::MOI.ModelLike) = MOIU.default_copy_to(model, src) # objective sense MOI.supports(::Optimizer,::MOI.ObjectiveSense) = true @@ -263,29 +264,29 @@ MOI.set(model::Optimizer, ::MOI.ObjectiveSense,sense::MOI.OptimizationSense) = ( MOI.get(model::Optimizer, ::MOI.ObjectiveSense) = model.sense # silence -const SILENT_KEY = :log_level +const SILENT_KEY = :print_level const SILENT_VAL = ERROR MOI.supports(::Optimizer,::MOI.Silent) = true MOI.set(model::Optimizer, ::MOI.Silent, value::Bool)= value ? - MOI.set(model,MOI.RawParameter(SILENT_KEY),SILENT_VAL) : delete!(model.option_dict,SILENT_KEY) + MOI.set(model,MOI.RawOptimizerAttribute(String(SILENT_KEY)),SILENT_VAL) : delete!(model.option_dict,SILENT_KEY) MOI.get(model::Optimizer, ::MOI.Silent) = get(model.option_dict,SILENT_KEY,String) == SILENT_VAL # time limit const TIME_LIMIT = :max_wall_time MOI.supports(::Optimizer,::MOI.TimeLimitSec) = true MOI.set(model::Optimizer,::MOI.TimeLimitSec,value)= value isa Real ? - MOI.set(model,MOI.RawParameter(TIME_LIMIT),Float64(value)) : error("Invalid time limit: $value") + MOI.set(model,MOI.RawOptimizerAttribute(String(TIME_LIMIT)),Float64(value)) : error("Invalid time limit: $value") MOI.set(model::Optimizer,::MOI.TimeLimitSec,::Nothing)=delete!(model.option_dict,TIME_LIMIT) MOI.get(model::Optimizer,::MOI.TimeLimitSec)=get(model.option_dict,TIME_LIMIT,Float64) # set/get options -MOI.supports(::Optimizer,::MOI.RawParameter) = true -MOI.set(model::Optimizer, p::MOI.RawParameter, value) = (model.option_dict[Symbol(p.name)] = value) -MOI.get(model::Optimizer, p::MOI.RawParameter) = haskey(model.option_dict, Symbol(p.name)) ? - (return model.option_dict[Symbol(p.name)]) : error("RawParameter with name $(p.name) is not set.") +MOI.supports(::Optimizer,::MOI.RawOptimizerAttribute) = true +MOI.set(model::Optimizer, p::MOI.RawOptimizerAttribute, value) = (model.option_dict[Symbol(p.name)] = value) +MOI.get(model::Optimizer, p::MOI.RawOptimizerAttribute) = haskey(model.option_dict, Symbol(p.name)) ? + (return model.option_dict[Symbol(p.name)]) : error("RawOptimizerAttribute with name $(p.name) is not set.") # solve time -MOI.get(model::Optimizer, ::MOI.SolveTime) = model.ips.cnt.total_time +MOI.get(model::Optimizer, ::MOI.SolveTimeSec) = model.ips.cnt.total_time function MOI.empty!(model::Optimizer) # empty!(model.option_dict) @@ -330,19 +331,18 @@ function check_inbounds(model::Optimizer, vi::MOI.VariableIndex) error("Invalid variable index $vi. ($num_variables variables in the model.)") end end -check_inbounds(model::Optimizer, var::MOI.SingleVariable) = check_inbounds(model, var.variable) function check_inbounds(model::Optimizer, aff::MOI.ScalarAffineFunction) for term in aff.terms - check_inbounds(model, term.variable_index) + check_inbounds(model, term.variable) end end function check_inbounds(model::Optimizer, quad::MOI.ScalarQuadraticFunction) for term in quad.affine_terms - check_inbounds(model, term.variable_index) + check_inbounds(model, term.variable) end for term in quad.quadratic_terms - check_inbounds(model, term.variable_index_1) - check_inbounds(model, term.variable_index_2) + check_inbounds(model, term.variable_1) + check_inbounds(model, term.variable_2) end end @@ -350,21 +350,21 @@ has_upper_bound(model::Optimizer, vi::MOI.VariableIndex) = model.variable_info[v has_lower_bound(model::Optimizer, vi::MOI.VariableIndex) = model.variable_info[vi.value].has_lower_bound is_fixed(model::Optimizer, vi::MOI.VariableIndex) = model.variable_info[vi.value].is_fixed -function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) +function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].upper_bound = Inf model.variable_info[ci.value].has_upper_bound = false return end -function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}) +function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].lower_bound = -Inf model.variable_info[ci.value].has_lower_bound = false return end -function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}) +function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) MOI.throw_if_not_valid(model, ci) model.variable_info[ci.value].lower_bound = -Inf model.variable_info[ci.value].upper_bound = Inf @@ -373,8 +373,7 @@ function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex{MOI.SingleVariable end -function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, lt::MOI.LessThan{Float64}) - vi = v.variable +function MOI.add_constraint(model::Optimizer, vi::MOI.VariableIndex, lt::MOI.LessThan{Float64}) check_inbounds(model, vi) if isnan(lt.upper) error("Invalid upper bound value $(lt.upper).") @@ -387,11 +386,10 @@ function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, lt::MOI.Les end model.variable_info[vi.value].upper_bound = lt.upper model.variable_info[vi.value].has_upper_bound = true - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}(vi.value) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}(vi.value) end -function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, gt::MOI.GreaterThan{Float64}) - vi = v.variable +function MOI.add_constraint(model::Optimizer, vi::MOI.VariableIndex, gt::MOI.GreaterThan{Float64}) check_inbounds(model, vi) if isnan(gt.lower) error("Invalid lower bound value $(gt.lower).") @@ -404,11 +402,10 @@ function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, gt::MOI.Gre end model.variable_info[vi.value].lower_bound = gt.lower model.variable_info[vi.value].has_lower_bound = true - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}(vi.value) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}(vi.value) end -function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, eq::MOI.EqualTo{Float64}) - vi = v.variable +function MOI.add_constraint(model::Optimizer, vi::MOI.VariableIndex, eq::MOI.EqualTo{Float64}) check_inbounds(model, vi) if isnan(eq.value) error("Invalid fixed value $(gt.lower).") @@ -425,7 +422,7 @@ function MOI.add_constraint(model::Optimizer, v::MOI.SingleVariable, eq::MOI.Equ model.variable_info[vi.value].lower_bound = eq.value model.variable_info[vi.value].upper_bound = eq.value model.variable_info[vi.value].is_fixed = true - return MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}(vi.value) + return MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}(vi.value) end macro define_add_constraint(function_type, set_type, prefix) @@ -454,12 +451,12 @@ function MOI.set(model::Optimizer, ::MOI.VariablePrimalStart, end function MOI.supports(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}, value::Union{Real, Nothing}) return true end function MOI.set(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}, value::Union{Real, Nothing}) vi = MOI.VariableIndex(ci.value) check_inbounds(model, vi) @@ -467,12 +464,12 @@ function MOI.set(model::Optimizer, ::MOI.ConstraintDualStart, return end function MOI.supports(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}, value::Union{Real, Nothing}) return true end function MOI.set(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.LessThan{Float64}}, value::Union{Real, Nothing}) vi = MOI.VariableIndex(ci.value) check_inbounds(model, vi) @@ -480,12 +477,12 @@ function MOI.set(model::Optimizer, ::MOI.ConstraintDualStart, return end function MOI.supports(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}, value::Union{Real, Nothing}) return true end function MOI.set(model::Optimizer, ::MOI.ConstraintDualStart, - ci::MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}, value::Union{Real, Nothing}) vi = MOI.VariableIndex(ci.value) check_inbounds(model, vi) @@ -500,7 +497,7 @@ MOI.set(model::Optimizer, ::MOI.NLPBlockDualStart, values) = (model.nlp_dual_sta MOI.set(model::Optimizer, ::MOI.NLPBlock, nlp_data::MOI.NLPBlockData) = (model.nlp_data = nlp_data) function MOI.set(model::Optimizer, ::MOI.ObjectiveFunction, - func::Union{MOI.SingleVariable, MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}) + func::Union{MOI.VariableIndex, MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}) check_inbounds(model, func) model.objective = func return @@ -520,7 +517,7 @@ function append_to_jacobian_sparsity!(I,J, cnt = 0 for term in aff.terms I[offset+cnt]= row - J[offset+cnt]= term.variable_index.value + J[offset+cnt]= term.variable.value cnt += 1 end return cnt @@ -531,12 +528,12 @@ function append_to_jacobian_sparsity!(I,J, cnt = 0 for term in quad.affine_terms I[offset+cnt]= row - J[offset+cnt]= term.variable_index.value + J[offset+cnt]= term.variable.value cnt += 1 end for term in quad.quadratic_terms - row_idx = term.variable_index_1 - col_idx = term.variable_index_2 + row_idx = term.variable_1 + col_idx = term.variable_2 if row_idx == col_idx I[offset+cnt]= row J[offset+cnt]= row_idx.value @@ -585,13 +582,13 @@ function jacobian_structure(model::Optimizer,I,J) return I,J end -append_to_hessian_sparsity!(I,J,::Union{MOI.SingleVariable,MOI.ScalarAffineFunction},offset) = 0 +append_to_hessian_sparsity!(I,J,::Union{MOI.VariableIndex,MOI.ScalarAffineFunction},offset) = 0 function append_to_hessian_sparsity!(I,J,quad::MOI.ScalarQuadraticFunction,offset) cnt = 0 for term in quad.quadratic_terms - I[offset+cnt]=term.variable_index_1.value - J[offset+cnt]=term.variable_index_2.value + I[offset+cnt]=term.variable_1.value + J[offset+cnt]=term.variable_2.value cnt+=1 end return cnt @@ -634,23 +631,23 @@ get_nnz_jac_linear(model::Optimizer) = (isempty(model.linear_ge_constraints) ? 0 : sum(length(info.func.terms) for info in model.linear_ge_constraints)) get_nnz_jac_quadratic(model::Optimizer) = (isempty(model.quadratic_eq_constraints) ? 0 : sum(length(info.func.affine_terms) for info in model.quadratic_eq_constraints)) + - (isempty(model.quadratic_eq_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_index_1 == term.variable_index_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_eq_constraints)) + + (isempty(model.quadratic_eq_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_1 == term.variable_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_eq_constraints)) + (isempty(model.quadratic_le_constraints) ? 0 : sum(length(info.func.affine_terms) for info in model.quadratic_le_constraints)) + - (isempty(model.quadratic_le_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_index_1 == term.variable_index_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_le_constraints)) + + (isempty(model.quadratic_le_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_1 == term.variable_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_le_constraints)) + (isempty(model.quadratic_ge_constraints) ? 0 : sum(length(info.func.affine_terms) for info in model.quadratic_ge_constraints)) + - (isempty(model.quadratic_ge_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_index_1 == term.variable_index_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_ge_constraints)) + (isempty(model.quadratic_ge_constraints) ? 0 : sum(isempty(info.func.quadratic_terms) ? 0 : sum(term.variable_1 == term.variable_2 ? 1 : 2 for term in info.func.quadratic_terms) for info in model.quadratic_ge_constraints)) get_nnz_jac_nonlinear(model::Optimizer) = (isempty(model.nlp_data.constraint_bounds) ? 0 : length(MOI.jacobian_structure(model.nlp_data.evaluator))) -function eval_function(var::MOI.SingleVariable, x) - return x[var.variable.value] +function eval_function(var::MOI.VariableIndex, x) + return x[var.value] end function eval_function(aff::MOI.ScalarAffineFunction, x) function_value = aff.constant for term in aff.terms - function_value += term.coefficient*x[term.variable_index.value] + function_value += term.coefficient*x[term.variable.value] end return function_value end @@ -659,12 +656,12 @@ function eval_function(quad::MOI.ScalarQuadraticFunction, x) function_value = quad.constant for term in quad.affine_terms - function_value += term.coefficient*x[term.variable_index.value] + function_value += term.coefficient*x[term.variable.value] end for term in quad.quadratic_terms - row_idx = term.variable_index_1 - col_idx = term.variable_index_2 + row_idx = term.variable_1 + col_idx = term.variable_2 coefficient = term.coefficient if row_idx == col_idx function_value += 0.5*coefficient*x[row_idx.value]*x[col_idx.value] @@ -688,26 +685,26 @@ function eval_objective(model::Optimizer, x) end end -function fill_gradient!(grad, x, var::MOI.SingleVariable) +function fill_gradient!(grad, x, var::MOI.VariableIndex) fill!(grad, 0.0) - grad[var.variable.value] = 1.0 + grad[var.value] = 1.0 end function fill_gradient!(grad, x, aff::MOI.ScalarAffineFunction{Float64}) fill!(grad, 0.0) for term in aff.terms - grad[term.variable_index.value] += term.coefficient + grad[term.variable.value] += term.coefficient end end function fill_gradient!(grad, x, quad::MOI.ScalarQuadraticFunction{Float64}) fill!(grad, 0.0) for term in quad.affine_terms - grad[term.variable_index.value] += term.coefficient + grad[term.variable.value] += term.coefficient end for term in quad.quadratic_terms - row_idx = term.variable_index_1 - col_idx = term.variable_index_2 + row_idx = term.variable_1 + col_idx = term.variable_2 coefficient = term.coefficient if row_idx == col_idx grad[row_idx.value] += coefficient*x[row_idx.value] @@ -767,8 +764,8 @@ function fill_constraint_jacobian!(values, start_offset, x, quad::MOI.ScalarQuad end num_quadratic_coefficients = 0 for term in quad.quadratic_terms - row_idx = term.variable_index_1 - col_idx = term.variable_index_2 + row_idx = term.variable_1 + col_idx = term.variable_2 coefficient = term.coefficient if row_idx == col_idx values[start_offset+num_affine_coefficients+num_quadratic_coefficients+1] = coefficient*x[col_idx.value] @@ -810,7 +807,7 @@ function eval_constraint_jacobian(model::Optimizer, values, x) end function fill_hessian_lagrangian!(values, start_offset, scale_factor, - ::Union{MOI.SingleVariable, + ::Union{MOI.VariableIndex, MOI.ScalarAffineFunction,Nothing}) return 0 end @@ -849,9 +846,9 @@ MOI.get(model::Optimizer, ::MOI.TerminationStatus) = model.result === nothing ? MOI.OPTIMIZE_NOT_CALLED : termination_status(model.result) MOI.get(model::Optimizer, ::MOI.RawStatusString) = string(model.result.status) MOI.get(model::Optimizer, ::MOI.ResultCount) = (model.result !== nothing) ? 1 : 0 -MOI.get(model::Optimizer, attr::MOI.PrimalStatus) = !(1 <= attr.N <= MOI.get(model, MOI.ResultCount())) ? +MOI.get(model::Optimizer, attr::MOI.PrimalStatus) = !(1 <= attr.result_index <= MOI.get(model, MOI.ResultCount())) ? MOI.NO_SOLUTION : primal_status(model.result) -MOI.get(model::Optimizer, attr::MOI.DualStatus) = !(1 <= attr.N <= MOI.get(model, MOI.ResultCount())) ? +MOI.get(model::Optimizer, attr::MOI.DualStatus) = !(1 <= attr.result_index <= MOI.get(model, MOI.ResultCount())) ? MOI.NO_SOLUTION : dual_status(model.result) const status_moi_dict = Dict( @@ -921,7 +918,19 @@ end @define_constraint_primal(MOI.ScalarQuadraticFunction{Float64},MOI.EqualTo{Float64}, quadratic_eq) function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal, - ci::MOI.ConstraintIndex{MOI.SingleVariable, + ci::MOI.ConstraintIndex{MOI.VariableIndex, + MOI.LessThan{Float64}}) + MOI.check_result_index_bounds(model, attr) + vi = MOI.VariableIndex(ci.value) + check_inbounds(model, vi) + if !has_upper_bound(model, vi) + error("Variable $vi has no upper bound -- ConstraintPrimal not defined.") + end + return model.result.solution[vi.value] +end + +function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) MOI.check_result_index_bounds(model, attr) vi = MOI.VariableIndex(ci.value) @@ -933,7 +942,7 @@ function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal, end function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal, - ci::MOI.ConstraintIndex{MOI.SingleVariable, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) MOI.check_result_index_bounds(model, attr) vi = MOI.VariableIndex(ci.value) @@ -966,7 +975,7 @@ end @define_constraint_dual(MOI.ScalarQuadraticFunction{Float64},MOI.EqualTo{Float64}, quadratic_eq) function MOI.get(model::Optimizer, attr::MOI.ConstraintDual, - ci::MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}) + ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}) MOI.check_result_index_bounds(model, attr) vi = MOI.VariableIndex(ci.value) check_inbounds(model, vi) @@ -975,7 +984,7 @@ function MOI.get(model::Optimizer, attr::MOI.ConstraintDual, end function MOI.get(model::Optimizer, attr::MOI.ConstraintDual, - ci::MOI.ConstraintIndex{MOI.SingleVariable, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.GreaterThan{Float64}}) MOI.check_result_index_bounds(model, attr) vi = MOI.VariableIndex(ci.value) @@ -985,7 +994,7 @@ function MOI.get(model::Optimizer, attr::MOI.ConstraintDual, end function MOI.get(model::Optimizer, attr::MOI.ConstraintDual, - ci::MOI.ConstraintIndex{MOI.SingleVariable, + ci::MOI.ConstraintIndex{MOI.VariableIndex, MOI.EqualTo{Float64}}) MOI.check_result_index_bounds(model, attr) vi = MOI.VariableIndex(ci.value) diff --git a/test/MOI_interface_test.jl b/test/MOI_interface_test.jl index 87bfca288..6da0c2611 100644 --- a/test/MOI_interface_test.jl +++ b/test/MOI_interface_test.jl @@ -1,130 +1,88 @@ -using MathOptInterface -const MOI = MathOptInterface -const MOIT = MOI.Test -const MOIU = MOI.Utilities -const MOIB = MOI.Bridges +module TestMOIWrapper -const config = MOIT.TestConfig(atol=1e-4, rtol=1e-4, - optimal_status=MOI.LOCALLY_SOLVED) -const config_no_duals = MOIT.TestConfig(atol=1e-4, rtol=1e-4, duals=false, - optimal_status=MOI.LOCALLY_SOLVED) +using MadNLP +using Test -@testset "MOI utils" begin - optimizer = MadNLP.Optimizer() - @testset "SolverName" begin - @test MOI.get(optimizer, MOI.SolverName()) == "MadNLP" - end - @testset "supports_default_copy_to" begin - @test MOIU.supports_default_copy_to(optimizer, false) - @test !MOIU.supports_default_copy_to(optimizer, true) - end - @testset "MOI.Silent" begin - @test MOI.supports(optimizer, MOI.Silent()) - @test MOI.get(optimizer, MOI.Silent()) == false - MOI.set(optimizer, MOI.Silent(), true) - @test MOI.get(optimizer, MOI.Silent()) == true - end - @testset "MOI.TimeLimitSec" begin - @test MOI.supports(optimizer, MOI.TimeLimitSec()) - my_time_limit = 10. - MOI.set(optimizer, MOI.TimeLimitSec(), my_time_limit) - @test MOI.get(optimizer, MOI.TimeLimitSec()) == my_time_limit - end - @testset "MOI.MaxIter" begin - MOI.set(optimizer,MOI.RawParameter("max_iter"),1) - @test MOI.get(optimizer,MOI.RawParameter("max_iter")) == 1 +const MOI = MadNLP.MathOptInterface + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$(name)", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end end + return end -@testset "Testing getters" begin - MOIT.copytest(MOI.instantiate(()->MadNLP.Optimizer(print_level=MadNLP.ERROR), - with_bridge_type=Float64), MOIU.Model{Float64}()) -end +function test_MOI_Test() + model = MOI.Bridges.full_bridge_optimizer( + MOI.Utilities.CachingOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), + MadNLP.Optimizer(), + ), + Float64, + ) + MOI.set(model, MOI.Silent(), true) + MOI.Test.runtests( + model, + MOI.Test.Config( + atol = 1e-4, + rtol = 1e-4, + optimal_status = MOI.LOCALLY_SOLVED, + exclude = Any[ + MOI.delete, + MOI.ConstraintDual, + MOI.ConstraintBasisStatus, + MOI.DualObjectiveValue, + MOI.ObjectiveBound, + ] + ); + exclude = String[ + "test_modification", + # - Need to implement TimeLimitSec + "test_attribute_TimeLimitSec", + # - Wrong return type + "test_model_UpperBoundAlreadySet", + # - Final objective value is not equal to 0.0 + "test_objective_FEASIBILITY_SENSE_clears_objective", -@testset "Bounds set twice" begin - optimizer = MadNLP.Optimizer(print_level=MadNLP.ERROR) - MOIT.set_lower_bound_twice(optimizer, Float64) - MOIT.set_upper_bound_twice(optimizer, Float64) -end + # TODO: Need to investigate why these tests are breaking + # get(model, MOI.ConstraintPrimal(), c) returns the + # opposite value: if 1.0 is expected, -1.0 is returned + "test_constraint_ScalarAffineFunction_EqualTo", + "test_quadratic_nonconvex_constraint_basic", + "test_linear_integration", -@testset "MOI Linear tests" begin - optimizer = MadNLP.Optimizer(print_level=MadNLP.ERROR) - exclude = ["linear1", # modify constraints not allowed - "linear5", # modify constraints not allowed - "linear6", # constraint set for l/q not allowed - "linear7", # VectorAffineFunction not supported. - "linear8a", # Behavior in infeasible case doesn't match test. - "linear8b", # Behavior in unbounded case doesn't match test. - "linear8c", # Behavior in unbounded case doesn't match test. - "linear10", # Interval not supported yet - "linear10b", # Interval not supported yet - "linear11", # Variable cannot be deleted - "linear12", # Behavior in infeasible case doesn't match test. - "linear14", # Variable cannot be deleted - "linear15", # VectorAffineFunction not supported. - ] - MOIT.contlineartest(optimizer, config_no_duals,exclude) -end + # TODO: there might be an issue with VectorAffineFunction/VectorOfVariables + "test_conic_NormOneCone_VectorOfVariables", + "test_conic_NormOneCone_VectorAffineFunction", + "test_conic_NormInfinityCone_VectorOfVariables", + "test_conic_NormInfinityCone_VectorAffineFunction", + "test_conic_linear_VectorAffineFunction", + "test_conic_linear_VectorOfVariables", -@testset "MOI NLP tests" begin - optimizer = MadNLP.Optimizer(print_level=MadNLP.ERROR) - exclude = [ - "feasibility_sense_with_objective_and_no_hessian", # we need Hessians - "feasibility_sense_with_no_objective_and_no_hessian", # we need Hessians - "hs071_no_hessian", # we need Hessians - "hs071_hessian_vector_product_test", # Hessian-vector product is needed - ] - MOIT.nlptest(optimizer,config,exclude) -end + # Tests excluded on purpose + # - Excluded as MadNLP returns LOCALLY_INFEASIBLE instead of INFEASIBLE + "INFEASIBLE", + "test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_", + # - Excluded because Hessian information is needed + "test_nonlinear_hs071_hessian_vector_product", + # - Excluded because Hessian information is needed + "test_nonlinear_hs071_no_hessian", + # - Excluded because Hessian information is needed + "test_nonlinear_invalid", -@testset "Unit" begin - bridged = MOIB.full_bridge_optimizer(MadNLP.Optimizer(print_level=MadNLP.ERROR),Float64) - exclude = ["delete_variable", # Deleting not supported. - "delete_variables", # Deleting not supported. - "getvariable", # Variable names not supported. - "solve_zero_one_with_bounds_1", # Variable names not supported. - "solve_zero_one_with_bounds_2", # Variable names not supported. - "solve_zero_one_with_bounds_3", # Variable names not supported. - "getconstraint", # Constraint names not suported. - "variablenames", # Variable names not supported. - "solve_with_upperbound", # loadfromstring! - "solve_with_lowerbound", # loadfromstring! - "solve_integer_edge_cases", # loadfromstring! - "solve_affine_lessthan", # loadfromstring! - "solve_affine_greaterthan", # loadfromstring! - "solve_affine_equalto", # loadfromstring! - "solve_affine_interval", # loadfromstring! - "get_objective_function", # Function getters not supported. - "solve_constant_obj", # loadfromstring! - "solve_blank_obj", # loadfromstring! - "solve_singlevariable_obj", # loadfromstring! - "solve_objbound_edge_cases", # ObjectiveBound not supported. - "solve_affine_deletion_edge_cases", # Deleting not supported. - "solve_unbounded_model", # `NORM_LIMIT` - "number_threads", # NumberOfThreads not supported - "delete_nonnegative_variables", # get ConstraintFunction n/a. - "update_dimension_nonnegative_variables", # get ConstraintFunction n/a. - "delete_soc_variables", # VectorOfVar. in SOC not supported - "solve_result_index", # DualObjectiveValue not supported - "time_limit_sec", #time limit given as Flaot64? - "solve_farkas_interval_lower", - "solve_farkas_lessthan", - "solve_farkas_interval_upper", - "solve_farkas_greaterthan", - "solve_farkas_variable_lessthan_max", - "solve_farkas_variable_lessthan", - "solve_farkas_equalto_lower", - "solve_farkas_equalto_upper", - "solve_qp_edge_cases" - ] - MOIT.unittest(bridged, config, exclude) + # - Excluded because this test is optional + "test_model_ScalarFunctionConstantNotZero", + # - Excluded because MadNLP returns INVALID_MODEL instead of LOCALLY_SOLVED + "test_linear_VectorAffineFunction_empty_row", + ] + ) + return end -@testset "MOI QP/QCQP tests" begin - optimizer = MadNLP.Optimizer(print_level=MadNLP.ERROR) - qp_optimizer = MOIU.CachingOptimizer(MOIU.Model{Float64}(), optimizer) - MOIT.qptest(qp_optimizer, config) - exclude = ["qcp1", # VectorAffineFunction not supported. - ] - MOIT.qcptest(qp_optimizer, config_no_duals, exclude) end + +TestMOIWrapper.runtests() diff --git a/test/runtests.jl b/test/runtests.jl index 5a93835a0..d8e9a5c04 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,6 @@ using Test, MadNLP, MadNLPTests, MINLPTests import MathOptInterface -import AmplNLReader: AmplModel +# import AmplNLReader: AmplModel import SparseArrays: sparse @testset "MadNLP test" begin