Skip to content

Commit

Permalink
Add Uno_jll to MINLPTests (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Oct 28, 2024
1 parent bb82f27 commit e32115c
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 109 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ Supported packages include:
| [Bonmin](https://github.com/coin-or/Bonmin) | `Bonmin_jll.jl` | `Bomin_jll.amplexe` |
| [Couenne](https://github.com/coin-or/Couenne) | `Couenne_jll.jl` | `Couenne_jll.amplexe` |
| [Ipopt](https://github.com/coin-or/Ipopt) | `Ipopt_jll.jl` | `Ipopt_jll.amplexe` |
| [SHOT](https://github.com/coin-or/SHOT) | `SHOT_jll.jl` | `SHOT_jll.amplexe` |
| [KNITRO](https://github.comjump-dev/KNITRO.jl)| `KNITRO.jl` | `KNITRO.amplexe` |
| [SHOT](https://github.com/coin-or/SHOT) | `SHOT_jll.jl` | `SHOT_jll.amplexe` |
| [Uno](https://github.com/cvanaret/Uno) | `Uno_jll.jl` | `Uno_jll.amplexe` |

## MathOptInterface API

Expand Down
6 changes: 5 additions & 1 deletion test/MINLPTests/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ Couenne_jll = "f09e9e23-9010-5c9e-b679-9f1d8f79b85c"
Ipopt_jll = "9cc047cb-c261-5740-88fc-0cf96f7bdcc7"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
MINLPTests = "ee0a3090-8ee9-5cdb-b8cb-8eeba3165522"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
SHOT_jll = "c1ab834c-c4a5-50f5-9156-8f0fe7758b0e"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Uno_jll = "396d5378-14f1-5ab1-981d-48acd51740ed"

[compat]
Bonmin_jll = "100.800.801"
Couenne_jll = "0.500.801"
Ipopt_jll = "=300.1400.400, =300.1400.1400"
Ipopt_jll = "=300.1400.1600"
JuMP = "1"
MathOptInterface = "1.33"
MINLPTests = "0.6"
SHOT_jll = "100.100.0"
Uno_jll = "1.1.0"
julia = "1.6"
268 changes: 161 additions & 107 deletions test/MINLPTests/run_minlptests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

using Test

import AmplNLWriter
import Bonmin_jll
import Couenne_jll
import Ipopt_jll
import MathOptInterface as MOI
import MINLPTests
using Test
import SHOT_jll
import Uno_jll

const TERMINATION_TARGET = Dict(
MINLPTests.FEASIBLE_PROBLEM => AmplNLWriter.MOI.LOCALLY_SOLVED,
MINLPTests.INFEASIBLE_PROBLEM => AmplNLWriter.MOI.LOCALLY_INFEASIBLE,
MINLPTests.FEASIBLE_PROBLEM => MOI.LOCALLY_SOLVED,
MINLPTests.INFEASIBLE_PROBLEM => MOI.LOCALLY_INFEASIBLE,
)

const PRIMAL_TARGET = Dict(
MINLPTests.FEASIBLE_PROBLEM => AmplNLWriter.MOI.FEASIBLE_POINT,
MINLPTests.INFEASIBLE_PROBLEM => AmplNLWriter.MOI.NO_SOLUTION,
MINLPTests.FEASIBLE_PROBLEM => MOI.FEASIBLE_POINT,
MINLPTests.INFEASIBLE_PROBLEM => MOI.NO_SOLUTION,
)

# Common reasons for exclusion:
# nlp/005_011 : Uses the function `\`
# nlp/006_010 : Uses a user-defined function
# nlp/007_010 : Ipopt returns an infeasible point, not NO_SOLUTION.
# nlp/008_010 : Couenne fails to converge
Expand All @@ -29,140 +35,188 @@ const PRIMAL_TARGET = Dict(
# nlp-cvx/206_010 : Couenne can't evaluate pow
# nlp-mi/001_010 : Couenne fails to converge

const CONFIG = Dict{String,Any}()

import Bonmin_jll
CONFIG["Bonmin"] = Dict(
"amplexe" => Bonmin_jll.amplexe,
"options" => String["bonmin.nlp_log_level=0"],
"tol" => 1e-5,
"dual_tol" => NaN,
"nlp_exclude" => ["005_011", "006_010"],
"nlpcvx_exclude" => ["109_010"],
# 004_010 and 004_011 are tolerance failures on Bonmin
"nlpmi_exclude" => ["004_010", "004_011", "005_011", "006_010"],
"infeasible_point" => AmplNLWriter.MOI.NO_SOLUTION,
const CONFIG = Dict{String,Any}(
"Bonmin" => Dict(
"mixed-integer" => true,
"amplexe" => Bonmin_jll.amplexe,
"options" => String["bonmin.nlp_log_level=0"],
"dual_tol" => NaN,
"nlpcvx_exclude" => ["109_010"],
# 004_010 and 004_011 are tolerance failures on Bonmin
"nlpmi_exclude" => ["004_010", "004_011"],
),
"Couenne" => Dict(
"mixed-integer" => true,
"amplexe" => Couenne_jll.amplexe,
"options" => String[],
"tol" => 1e-2,
"dual_tol" => NaN,
"nlp_exclude" => ["008_010", "008_011", "009_010", "009_011"],
"nlpcvx_exclude" => ["109_010", "206_010"],
"nlpmi_exclude" => ["001_010"],
),
"Ipopt" => Dict(
"mixed-integer" => false,
"amplexe" => Ipopt_jll.amplexe,
"options" => String["print_level=0"],
"nlp_exclude" => ["007_010"],
"nlpcvx_exclude" => ["109_010"],
),
# SHOT fails too many tests to recommend using it.
# e.g., https://github.com/coin-or/SHOT/issues/134
# Even problems such as `@variable(model, x); @objective(model, Min, (x-1)^2)`
# "SHOT" => Dict(
# "amplexe" => SHOT_jll.amplexe,
# "options" => String[
# "Output.Console.LogLevel=6",
# "Output.File.LogLevel=6",
# "Termination.ObjectiveGap.Absolute=1e-6",
# "Termination.ObjectiveGap.Relative=1e-6",
# ],
# "tol" => 1e-2,
# "dual_tol" => NaN,
# "infeasible_point" => AmplNLWriter.MOI.UNKNOWN_RESULT_STATUS,
# ),
"Uno" => Dict(
"mixed-integer" => false,
"amplexe" => Uno_jll.amplexe,
"options" => ["logger=SILENT"],
"nlp_exclude" => [
# See https://github.com/cvanaret/Uno/issues/39
"005_010",
# See https://github.com/cvanaret/Uno/issues/38
"007_010",
],
),
)

import Couenne_jll
CONFIG["Couenne"] = Dict(
"amplexe" => Couenne_jll.amplexe,
"options" => String[],
"tol" => 1e-2,
"dual_tol" => NaN,
"nlp_exclude" =>
["005_011", "006_010", "008_010", "008_011", "009_010", "009_011"],
"nlpcvx_exclude" => ["109_010", "206_010"],
"nlpmi_exclude" => ["001_010", "005_011", "006_010"],
"infeasible_point" => AmplNLWriter.MOI.NO_SOLUTION,
)

import Ipopt_jll
CONFIG["Ipopt"] = Dict(
"amplexe" => Ipopt_jll.amplexe,
"options" => String["print_level=0"],
"tol" => 1e-5,
"dual_tol" => 1e-5,
"nlp_exclude" => ["005_011", "006_010", "007_010"],
"nlpcvx_exclude" => ["109_010"],
"nlpmi_exclude" => ["005_011", "006_010"],
"infeasible_point" => AmplNLWriter.MOI.NO_SOLUTION,
)

# SHOT fails too many tests to recommend using it.
# e.g., https://github.com/coin-or/SHOT/issues/134
# Even problems such as `@variable(model, x); @objective(model, Min, (x-1)^2)`
#
# import SHOT_jll
# CONFIG["SHOT"] = Dict(
# "amplexe" => SHOT_jll.amplexe,
# "options" => String[
# "Output.Console.LogLevel=6",
# "Output.File.LogLevel=6",
# "Termination.ObjectiveGap.Absolute=1e-6",
# "Termination.ObjectiveGap.Relative=1e-6",
# ],
# "tol" => 1e-2,
# "dual_tol" => NaN,
# "nlp_exclude" => [
# "005_011", # `\` function
# "006_010", # User-defined function
# ],
# "nlpcvx_exclude" => [
# "501_011", # `\` function
# ],
# "nlpmi_exclude" => [
# "005_011", # `\` function
# "006_010", # User-defined function
# ],
# "infeasible_point" => AmplNLWriter.MOI.UNKNOWN_RESULT_STATUS,
# )

@testset "$(name)" for name in ["Ipopt", "Bonmin", "Couenne"]
config = CONFIG[name]
@testset "$k" for (k, config) in CONFIG
OPTIMIZER =
() -> AmplNLWriter.Optimizer(config["amplexe"], config["options"])
PRIMAL_TARGET[MINLPTests.INFEASIBLE_PROBLEM] = config["infeasible_point"]
# PRIMAL_TARGET[MINLPTests.INFEASIBLE_PROBLEM] = config["infeasible_point"]
@testset "NLP" begin
exclude = vcat(get(config, "nlp_exclude", String[]), ["006_010"])
MINLPTests.test_nlp(
OPTIMIZER,
exclude = config["nlp_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
MINLPTests.test_nlp_expr(
OPTIMIZER,
exclude = config["nlp_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
end
@testset "NLP-CVX" begin
exclude = get(config, "nlpcvx_exclude", String[])
MINLPTests.test_nlp_cvx(
OPTIMIZER,
exclude = config["nlpcvx_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
MINLPTests.test_nlp_cvx_expr(
OPTIMIZER,
exclude = config["nlpcvx_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
end
if name != "Ipopt"
if config["mixed-integer"]
exclude = vcat(get(config, "nlpmi_exclude", String[]), ["006_010"])
@testset "NLP-MI" begin
MINLPTests.test_nlp_mi(
OPTIMIZER,
exclude = config["nlpmi_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
MINLPTests.test_nlp_mi_expr(
OPTIMIZER,
exclude = config["nlpmi_exclude"],
OPTIMIZER;
exclude = exclude,
termination_target = TERMINATION_TARGET,
primal_target = PRIMAL_TARGET,
objective_tol = config["tol"],
primal_tol = config["tol"],
dual_tol = config["dual_tol"],
objective_tol = get(config, "tol", 1e-5),
primal_tol = get(config, "tol", 1e-5),
dual_tol = get(config, "dual_tol", 1e-5),
)
end
end
end

function test_uno_runtests()
optimizer = MOI.instantiate(
() -> AmplNLWriter.Optimizer(Uno_jll.amplexe, ["logger=SILENT"]);
with_cache_type = Float64,
with_bridge_type = Float64,
)
MOI.Test.runtests(
optimizer,
MOI.Test.Config(
atol = 1e-4,
rtol = 1e-4,
optimal_status = MOI.LOCALLY_SOLVED,
infeasible_status = MOI.LOCALLY_INFEASIBLE,
exclude = Any[
MOI.VariableBasisStatus,
MOI.ConstraintBasisStatus,
MOI.ObjectiveBound,
],
);
exclude = [
# OTHER_LIMIT instead of LOCALLY_SOLVED
r"^test_conic_linear_VectorOfVariables_2$",
r"^test_nonlinear_expression_hs109$",
r"^test_quadratic_constraint_GreaterThan$",
r"^test_quadratic_constraint_LessThan$",
r"^test_solve_VariableIndex_ConstraintDual_MAX_SENSE$",
r"^test_solve_VariableIndex_ConstraintDual_MIN_SENSE$",
# OTHER_ERROR instead of LOCALLY_SOLVED
r"^test_linear_integration$",
r"^test_linear_transform$",
# OTHER_LIMIT instead of DUAL_INFEASIBLE
r"^test_solve_TerminationStatus_DUAL_INFEASIBLE$",
# OTHER_LIMIT instead of LOCALLY_INFEASIBLE
r"^test_conic_NormInfinityCone_INFEASIBLE$",
r"^test_conic_NormOneCone_INFEASIBLE$",
r"^test_conic_linear_INFEASIBLE$",
r"^test_conic_linear_INFEASIBLE_2$",
r"^test_linear_INFEASIBLE$",
r"^test_linear_INFEASIBLE_2$",
r"^test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_",
# Uno does not support integrality
"Indicator",
r"[Ii]nteger",
"Semicontinuous",
"Semiinteger",
"SOS1",
"SOS2",
"ZeroOne",
r"^test_cpsat_",
# Existing MOI issues
r"^test_attribute_SolverVersion$",
r"^test_nonlinear_invalid$",
r"^test_basic_VectorNonlinearFunction_",
],
)
return
end

test_uno_runtests()

0 comments on commit e32115c

Please sign in to comment.