Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update support to MOI v1.0 #182

Merged
merged 5 commits into from
Mar 3, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Configuration file for JuliaFormatter.jl
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/

always_for_in = true
always_use_return = true
margin = 80
remove_extra_newlines = true
short_to_long_function_def = true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Manifest.toml
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name = "NLopt"
uuid = "76087f3c-5699-56af-9a33-bf431cd00edd"
version = "0.6.4"
version = "0.6.5"

[deps]
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
MathProgBase = "fdba3010-5040-5b88-9595-932c9decdf73"
NLopt_jll = "079eb43e-fd8e-5478-9966-2cf3e3edb778"

[compat]
MathOptInterface = "0.10.4"
MathOptInterface = "0.10.4, 1"
MathProgBase = "0.5, 0.6, 0.7, 0.8"
NLopt_jll = "2.7"
julia = "1.3"
914 changes: 605 additions & 309 deletions src/MOI_wrapper.jl

Large diffs are not rendered by default.

202 changes: 62 additions & 140 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
@@ -1,152 +1,74 @@
using Test
module TestMOIWrapper

using MathOptInterface
const MOI = MathOptInterface
const MOIT = MOI.DeprecatedTest
const MOIU = MOI.Utilities
const MOIB = MOI.Bridges

using NLopt
const solver = MOI.OptimizerWithAttributes(NLopt.Optimizer, "algorithm" => :LD_SLSQP)

optimizer = MOI.instantiate(solver)

const config = MOIT.Config(atol=1e-2, rtol=1e-2, duals=false,
optimal_status=MOI.LOCALLY_SOLVED)

@testset "SolverName" begin
@test MOI.get(optimizer, MOI.SolverName()) == "NLopt"
end

@testset "supports_default_copy_to" begin
@test MOI.supports_incremental_interface(optimizer)
end

function test_nlp(solver)
optimizer = MOI.instantiate(solver)
MOIT.nlptest(optimizer, config)
end
@testset "Non-Linear tests" begin
test_nlp(solver)
test_nlp(MOI.OptimizerWithAttributes(
NLopt.Optimizer,
"algorithm" => :AUGLAG,
"local_optimizer" => :LD_LBFGS,
))
# NLP tests have different number of variables so we
# cannot run through them all with the same `local_optimizer`.
# Let's just do hs071.
local_optimizer = Opt(:LD_LBFGS, 4)
MOIT.hs071_test(MOI.instantiate(MOI.OptimizerWithAttributes(
NLopt.Optimizer,
"algorithm" => :AUGLAG,
"local_optimizer" => local_optimizer,
)), config)
end

@testset "Testing getters" begin
MOIT.copytest(MOI.instantiate(solver, with_bridge_type=Float64), MOIU.Model{Float64}())
end

@testset "Bounds set twice" begin
MOIT.set_lower_bound_twice(optimizer, Float64)
MOIT.set_upper_bound_twice(optimizer, Float64)
end
using Test

MOI.empty!(optimizer)
bridged = MOIB.full_bridge_optimizer(MOIU.CachingOptimizer(MOIU.UniversalFallback(MOIU.Model{Float64}()), optimizer), Float64)
const MOI = MathOptInterface

@testset "Continuous Linear tests" begin
exclude = [
# Infeasibility and unboundedness not detected by NLopt
"linear8a", "linear8b", "linear8c", "linear12",
# Terminates with `:ROUNDOFF_LIMITED` due to the bad scaling of input problem
"linear9",
# FIXME invalid NLopt arguments: too many equality constraints
"linear15",
]
if Sys.WORD_SIZE == 32
# FIXME
# Expression: MOI.get(model, MOI.TerminationStatus()) == config.optimal_status
# Evaluated: MathOptInterface.OTHER_ERROR == MathOptInterface.LOCALLY_SOLVED
# Expression: MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT
# Evaluated: MathOptInterface.UNKNOWN_RESULT_STATUS == MathOptInterface.FEASIBLE_POINT
push!(exclude, "linear1")
function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
@testset "$(name)" begin
getfield(@__MODULE__, name)()
end
end
end
MOIT.contlineartest(bridged, config, exclude)
return
end

@testset "Continuous Quadratic tests" begin
MOIT.qptest(bridged, config)
function test_runtests()
model = MOI.instantiate(NLopt.Optimizer; with_bridge_type = Float64)
MOI.set(model, MOI.RawOptimizerAttribute("algorithm"), :LD_SLSQP)
MOI.Test.runtests(
model,
MOI.Test.Config(
optimal_status = MOI.LOCALLY_SOLVED,
atol = 1e-2,
rtol = 1e-2,
exclude = Any[
MOI.ConstraintBasisStatus,
MOI.ConstraintDual,
MOI.ConstraintName,
MOI.DualObjectiveValue,
MOI.ObjectiveBound,
MOI.NLPBlockDual,
MOI.SolverVersion,
MOI.VariableBasisStatus,
MOI.VariableName,
]
),
exclude = String[
# TODO(odow): investigate failures. A lot of these are probably just
# suboptimal solutions.
"test_conic_NormInfinityCone_3",
"test_conic_NormInfinityCone_INFEASIBLE",
"test_conic_NormOneCone",
"test_conic_NormOneCone_INFEASIBLE",
"test_conic_linear_INFEASIBLE",
"test_conic_linear_INFEASIBLE_2",
"test_constraint_qcp_duplicate_diagonal", # Fails on 32-bit
"test_infeasible_",
"test_linear_DUAL_INFEASIBLE",
"test_linear_INFEASIBLE",
"test_linear_add_constraints",
"test_linear_VectorAffineFunction_empty_row",
"test_model_ScalarAffineFunction_ConstraintName",
"test_model_duplicate_ScalarAffineFunction_ConstraintName",
"test_nonlinear_invalid",
"test_objective_ObjectiveFunction_VariableIndex",
"test_quadratic_SecondOrderCone_basic",
"test_quadratic_constraint_integration",
"test_quadratic_nonconvex_constraint_basic",
"test_quadratic_nonconvex_constraint_integration",
"test_unbounded_",
"test_solve_TerminationStatus_DUAL_INFEASIBLE",
"test_solve_result_index",
]
)
return
end

MOIB.add_bridge(bridged, MOIB.Constraint.SOCtoNonConvexQuadBridge{Float64})

@testset "Continuous Conic tests" begin
MOIT.lintest(bridged, config, [
# Infeasibility and unboundedness not detected by NLopt
"lin3", "lin4"
])
MOIT.soctest(bridged, config, [
# Infeasibility and unboundedness not detected by NLopt
"soc3"
])
MOIT.rsoctest(bridged, config, [
# Infeasibility and unboundedness not detected by NLopt
"rotatedsoc2",
# FIXME invalid NLopt arguments: bounds 4 fail 1 <= 0 <= 1
"rotatedsoc3",
])
MOIT.geomeantest(bridged, config, [
# FIXME Status is ok but solution is not, e.g.
# Expression: ≈(MOI.get(model, MOI.ObjectiveValue()), 1.0, atol = atol, rtol = rtol)
# Evaluated: 0.006271435980170771 ≈ 1.0 (atol=0.01, rtol=0.01)
"geomean2v", "geomean2f",
# FIXME Status is ok but solution is not, e.g.
# Expression: ≈(MOI.get(model, MOI.ObjectiveValue()), 1, atol = atol, rtol = rtol)
# Evaluated: 0.0881801049773095 ≈ 1 (atol=0.01, rtol=0.01)
"geomean1v", "geomean1f",
])
MOIT.norminftest(bridged, config, [
# Infeasibility and unboundedness not detected by NLopt
"norminf2",
])
MOIT.normonetest(bridged, config, [
# Infeasibility and unboundedness not detected by NLopt
"normone2",
])
end

@testset "Unit" begin
exclude = [
# Integer variables not supported
"solve_zero_one_with_bounds_1",
"solve_zero_one_with_bounds_2",
"solve_zero_one_with_bounds_3",
"solve_integer_edge_cases",
# ObjectiveBound not supported.
"solve_objbound_edge_cases",
# NumberOfThreads not supported
"number_threads",
# Infeasibility and unboundedness not detected by NLopt
"solve_unbounded_model",
"solve_farkas_interval_lower",
"solve_farkas_lessthan",
"solve_farkas_equalto_lower",
"solve_farkas_equalto_upper",
"solve_farkas_variable_lessthan",
"solve_farkas_variable_lessthan_max",
"solve_farkas_greaterthan",
"solve_farkas_interval_upper",
"solve_farkas_lessthan",
]
if Sys.WORD_SIZE == 32
# FIXME
# Expression: MOI.get(model, MOI.TerminationStatus()) == config.optimal_status
# Evaluated: MathOptInterface.OTHER_ERROR == MathOptInterface.LOCALLY_SOLVED
# Expression: MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT
# Evaluated: MathOptInterface.UNKNOWN_RESULT_STATUS == MathOptInterface.FEASIBLE_POINT
push!(exclude, "solve_qcp_edge_cases")
end
MOIT.unittest(bridged, config, exclude)
end
TestMOIWrapper.runtests()