Skip to content

Commit

Permalink
port MadNLP to JuMP 0.22
Browse files Browse the repository at this point in the history
  • Loading branch information
frapac committed Nov 10, 2021
1 parent 74d4c00 commit 979ba03
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 134 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
AmplNLReader = "~0.9,~0.10"
MINLPTests = "~0.5"
MadNLPTests = "~0.3"
MathOptInterface = "~0.10"
MathOptInterface = "~0.10.5"
NLPModels = "~0.14,~0.15,~0.16,~0.17"
SolverCore = "~0.1,~0.2"
julia = "1.3"
Expand All @@ -33,4 +33,4 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test","MadNLPTests","AmplNLReader","MINLPTests", "Random"]
test = ["Test", "MadNLPTests", "AmplNLReader", "MINLPTests", "Random"]
2 changes: 1 addition & 1 deletion lib/MadNLPTests/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
JuMP = "~0.21"
JuMP = "~0.22"
MadNLP = "~0.3"
julia = "1.3"
15 changes: 8 additions & 7 deletions src/Interfaces/MOI_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ 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)
Expand Down Expand Up @@ -841,14 +842,14 @@ end



MOI.get(model::Optimizer, ::MOI.TerminationStatus) = model.nlp === nothing ?
MOI.OPTIMIZE_NOT_CALLED : termination_status(model.nlp)
MOI.get(model::Optimizer, ::MOI.RawStatusString) = string(model.nlp.status)
MOI.get(model::Optimizer, ::MOI.ResultCount) = (model.nlp !== nothing) ? 1 : 0
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.result_index <= MOI.get(model, MOI.ResultCount())) ?
MOI.NO_SOLUTION : primal_status(model.ips)
MOI.NO_SOLUTION : primal_status(model.result)
MOI.get(model::Optimizer, attr::MOI.DualStatus) = !(1 <= attr.result_index <= MOI.get(model, MOI.ResultCount())) ?
MOI.NO_SOLUTION : dual_status(model.ips)
MOI.NO_SOLUTION : dual_status(model.result)

const status_moi_dict = Dict(
SOLVE_SUCCEEDED => MOI.LOCALLY_SOLVED,
Expand Down Expand Up @@ -925,7 +926,7 @@ function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal,
if !has_upper_bound(model, vi)
error("Variable $vi has no upper bound -- ConstraintPrimal not defined.")
end
return model.nlp.x[vi.value]
return model.result.solution[vi.value]
end

function MOI.get(model::Optimizer, attr::MOI.ConstraintPrimal,
Expand Down
196 changes: 77 additions & 119 deletions test/MOI_interface_test.jl
Original file line number Diff line number Diff line change
@@ -1,131 +1,89 @@
using MathOptInterface
const MOI = MathOptInterface
const MOIT = MOI.DeprecatedTest
const MOIU = MOI.Utilities
const MOIB = MOI.Bridges
module TestMOIWrapper

const config = MOIT.Config(atol=1e-4, rtol=1e-4,
optimal_status=MOI.LOCALLY_SOLVED)
const config_no_duals = MOIT.Config(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 MOI.supports_incremental_interface(optimizer)
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.RawOptimizerAttribute("max_iter"),1)
@test MOI.get(optimizer,MOI.RawOptimizerAttribute("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

# Currently broken on MOI 0.10
# See: https://github.com/jump-dev/MathOptInterface.jl/pull/1591
# @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[
# - 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_VectorAffineFunction_2",
"test_conic_linear_VectorOfVariables",
"test_conic_linear_VectorOfVariables_2",

@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()
11 changes: 6 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Test, MadNLP, MadNLPTests, MINLPTests
using Test, MadNLP, MadNLPTests #, MINLPTests
import MathOptInterface
import AmplNLReader: AmplModel
# import AmplNLReader: AmplModel
import SparseArrays: sparse

@testset "MadNLP test" begin
Expand All @@ -22,7 +22,8 @@ import SparseArrays: sparse
include("madnlp_dense.jl")
end

@testset "MINLP test" begin
include("minlp_test.jl")
end
# this is temporarily commented out: MINLPTests does not support JuMP 0.22 yet
# @testset "MINLP test" begin
# include("minlp_test.jl")
# end
end # @testset

0 comments on commit 979ba03

Please sign in to comment.