3
3
# Use of this source code is governed by an MIT-style license that can be found
4
4
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
5
5
6
+ using Test
7
+
6
8
import AmplNLWriter
9
+ import Bonmin_jll
10
+ import Couenne_jll
11
+ import Ipopt_jll
12
+ import MathOptInterface as MOI
7
13
import MINLPTests
8
- using Test
14
+ import SHOT_jll
15
+ import Uno_jll
9
16
10
17
const TERMINATION_TARGET = Dict (
11
- MINLPTests. FEASIBLE_PROBLEM => AmplNLWriter . MOI. LOCALLY_SOLVED,
12
- MINLPTests. INFEASIBLE_PROBLEM => AmplNLWriter . MOI. LOCALLY_INFEASIBLE,
18
+ MINLPTests. FEASIBLE_PROBLEM => MOI. LOCALLY_SOLVED,
19
+ MINLPTests. INFEASIBLE_PROBLEM => MOI. LOCALLY_INFEASIBLE,
13
20
)
14
21
15
22
const PRIMAL_TARGET = Dict (
16
- MINLPTests. FEASIBLE_PROBLEM => AmplNLWriter . MOI. FEASIBLE_POINT,
17
- MINLPTests. INFEASIBLE_PROBLEM => AmplNLWriter . MOI. NO_SOLUTION,
23
+ MINLPTests. FEASIBLE_PROBLEM => MOI. FEASIBLE_POINT,
24
+ MINLPTests. INFEASIBLE_PROBLEM => MOI. NO_SOLUTION,
18
25
)
19
26
20
27
# Common reasons for exclusion:
21
- # nlp/005_011 : Uses the function `\`
22
28
# nlp/006_010 : Uses a user-defined function
23
29
# nlp/007_010 : Ipopt returns an infeasible point, not NO_SOLUTION.
24
30
# nlp/008_010 : Couenne fails to converge
@@ -29,140 +35,188 @@ const PRIMAL_TARGET = Dict(
29
35
# nlp-cvx/206_010 : Couenne can't evaluate pow
30
36
# nlp-mi/001_010 : Couenne fails to converge
31
37
32
- const CONFIG = Dict {String,Any} ()
33
-
34
- import Bonmin_jll
35
- CONFIG[" Bonmin" ] = Dict (
36
- " amplexe" => Bonmin_jll. amplexe,
37
- " options" => String[" bonmin.nlp_log_level=0" ],
38
- " tol" => 1e-5 ,
39
- " dual_tol" => NaN ,
40
- " nlp_exclude" => [" 005_011" , " 006_010" ],
41
- " nlpcvx_exclude" => [" 109_010" ],
42
- # 004_010 and 004_011 are tolerance failures on Bonmin
43
- " nlpmi_exclude" => [" 004_010" , " 004_011" , " 005_011" , " 006_010" ],
44
- " infeasible_point" => AmplNLWriter. MOI. NO_SOLUTION,
38
+ const CONFIG = Dict {String,Any} (
39
+ " Bonmin" => Dict (
40
+ " mixed-integer" => true ,
41
+ " amplexe" => Bonmin_jll. amplexe,
42
+ " options" => String[" bonmin.nlp_log_level=0" ],
43
+ " dual_tol" => NaN ,
44
+ " nlpcvx_exclude" => [" 109_010" ],
45
+ # 004_010 and 004_011 are tolerance failures on Bonmin
46
+ " nlpmi_exclude" => [" 004_010" , " 004_011" ],
47
+ ),
48
+ " Couenne" => Dict (
49
+ " mixed-integer" => true ,
50
+ " amplexe" => Couenne_jll. amplexe,
51
+ " options" => String[],
52
+ " tol" => 1e-2 ,
53
+ " dual_tol" => NaN ,
54
+ " nlp_exclude" => [" 008_010" , " 008_011" , " 009_010" , " 009_011" ],
55
+ " nlpcvx_exclude" => [" 109_010" , " 206_010" ],
56
+ " nlpmi_exclude" => [" 001_010" ],
57
+ ),
58
+ " Ipopt" => Dict (
59
+ " mixed-integer" => false ,
60
+ " amplexe" => Ipopt_jll. amplexe,
61
+ " options" => String[" print_level=0" ],
62
+ " nlp_exclude" => [" 007_010" ],
63
+ " nlpcvx_exclude" => [" 109_010" ],
64
+ ),
65
+ # SHOT fails too many tests to recommend using it.
66
+ # e.g., https://github.com/coin-or/SHOT/issues/134
67
+ # Even problems such as `@variable(model, x); @objective(model, Min, (x-1)^2)`
68
+ # "SHOT" => Dict(
69
+ # "amplexe" => SHOT_jll.amplexe,
70
+ # "options" => String[
71
+ # "Output.Console.LogLevel=6",
72
+ # "Output.File.LogLevel=6",
73
+ # "Termination.ObjectiveGap.Absolute=1e-6",
74
+ # "Termination.ObjectiveGap.Relative=1e-6",
75
+ # ],
76
+ # "tol" => 1e-2,
77
+ # "dual_tol" => NaN,
78
+ # "infeasible_point" => AmplNLWriter.MOI.UNKNOWN_RESULT_STATUS,
79
+ # ),
80
+ " Uno" => Dict (
81
+ " mixed-integer" => false ,
82
+ " amplexe" => Uno_jll. amplexe,
83
+ " options" => [" logger=SILENT" ],
84
+ " nlp_exclude" => [
85
+ # See https://github.com/cvanaret/Uno/issues/39
86
+ " 005_010" ,
87
+ # See https://github.com/cvanaret/Uno/issues/38
88
+ " 007_010" ,
89
+ ],
90
+ ),
45
91
)
46
92
47
- import Couenne_jll
48
- CONFIG[" Couenne" ] = Dict (
49
- " amplexe" => Couenne_jll. amplexe,
50
- " options" => String[],
51
- " tol" => 1e-2 ,
52
- " dual_tol" => NaN ,
53
- " nlp_exclude" =>
54
- [" 005_011" , " 006_010" , " 008_010" , " 008_011" , " 009_010" , " 009_011" ],
55
- " nlpcvx_exclude" => [" 109_010" , " 206_010" ],
56
- " nlpmi_exclude" => [" 001_010" , " 005_011" , " 006_010" ],
57
- " infeasible_point" => AmplNLWriter. MOI. NO_SOLUTION,
58
- )
59
-
60
- import Ipopt_jll
61
- CONFIG[" Ipopt" ] = Dict (
62
- " amplexe" => Ipopt_jll. amplexe,
63
- " options" => String[" print_level=0" ],
64
- " tol" => 1e-5 ,
65
- " dual_tol" => 1e-5 ,
66
- " nlp_exclude" => [" 005_011" , " 006_010" , " 007_010" ],
67
- " nlpcvx_exclude" => [" 109_010" ],
68
- " nlpmi_exclude" => [" 005_011" , " 006_010" ],
69
- " infeasible_point" => AmplNLWriter. MOI. NO_SOLUTION,
70
- )
71
-
72
- # SHOT fails too many tests to recommend using it.
73
- # e.g., https://github.com/coin-or/SHOT/issues/134
74
- # Even problems such as `@variable(model, x); @objective(model, Min, (x-1)^2)`
75
- #
76
- # import SHOT_jll
77
- # CONFIG["SHOT"] = Dict(
78
- # "amplexe" => SHOT_jll.amplexe,
79
- # "options" => String[
80
- # "Output.Console.LogLevel=6",
81
- # "Output.File.LogLevel=6",
82
- # "Termination.ObjectiveGap.Absolute=1e-6",
83
- # "Termination.ObjectiveGap.Relative=1e-6",
84
- # ],
85
- # "tol" => 1e-2,
86
- # "dual_tol" => NaN,
87
- # "nlp_exclude" => [
88
- # "005_011", # `\` function
89
- # "006_010", # User-defined function
90
- # ],
91
- # "nlpcvx_exclude" => [
92
- # "501_011", # `\` function
93
- # ],
94
- # "nlpmi_exclude" => [
95
- # "005_011", # `\` function
96
- # "006_010", # User-defined function
97
- # ],
98
- # "infeasible_point" => AmplNLWriter.MOI.UNKNOWN_RESULT_STATUS,
99
- # )
100
-
101
- @testset " $(name) " for name in [" Ipopt" , " Bonmin" , " Couenne" ]
102
- config = CONFIG[name]
93
+ @testset " $k " for (k, config) in CONFIG
103
94
OPTIMIZER =
104
95
() -> AmplNLWriter. Optimizer (config[" amplexe" ], config[" options" ])
105
- PRIMAL_TARGET[MINLPTests. INFEASIBLE_PROBLEM] = config[" infeasible_point" ]
96
+ # PRIMAL_TARGET[MINLPTests.INFEASIBLE_PROBLEM] = config["infeasible_point"]
106
97
@testset " NLP" begin
98
+ exclude = vcat (get (config, " nlp_exclude" , String[]), [" 006_010" ])
107
99
MINLPTests. test_nlp (
108
- OPTIMIZER,
109
- exclude = config[ " nlp_exclude " ] ,
100
+ OPTIMIZER;
101
+ exclude = exclude ,
110
102
termination_target = TERMINATION_TARGET,
111
103
primal_target = PRIMAL_TARGET,
112
- objective_tol = config[ " tol" ] ,
113
- primal_tol = config[ " tol" ] ,
114
- dual_tol = config[ " dual_tol" ] ,
104
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
105
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
106
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
115
107
)
116
108
MINLPTests. test_nlp_expr (
117
- OPTIMIZER,
118
- exclude = config[ " nlp_exclude " ] ,
109
+ OPTIMIZER;
110
+ exclude = exclude ,
119
111
termination_target = TERMINATION_TARGET,
120
112
primal_target = PRIMAL_TARGET,
121
- objective_tol = config[ " tol" ] ,
122
- primal_tol = config[ " tol" ] ,
123
- dual_tol = config[ " dual_tol" ] ,
113
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
114
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
115
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
124
116
)
125
117
end
126
118
@testset " NLP-CVX" begin
119
+ exclude = get (config, " nlpcvx_exclude" , String[])
127
120
MINLPTests. test_nlp_cvx (
128
- OPTIMIZER,
129
- exclude = config[ " nlpcvx_exclude " ] ,
121
+ OPTIMIZER;
122
+ exclude = exclude ,
130
123
termination_target = TERMINATION_TARGET,
131
124
primal_target = PRIMAL_TARGET,
132
- objective_tol = config[ " tol" ] ,
133
- primal_tol = config[ " tol" ] ,
134
- dual_tol = config[ " dual_tol" ] ,
125
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
126
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
127
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
135
128
)
136
129
MINLPTests. test_nlp_cvx_expr (
137
- OPTIMIZER,
138
- exclude = config[ " nlpcvx_exclude " ] ,
130
+ OPTIMIZER;
131
+ exclude = exclude ,
139
132
termination_target = TERMINATION_TARGET,
140
133
primal_target = PRIMAL_TARGET,
141
- objective_tol = config[ " tol" ] ,
142
- primal_tol = config[ " tol" ] ,
143
- dual_tol = config[ " dual_tol" ] ,
134
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
135
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
136
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
144
137
)
145
138
end
146
- if name != " Ipopt"
139
+ if config[" mixed-integer" ]
140
+ exclude = vcat (get (config, " nlpmi_exclude" , String[]), [" 006_010" ])
147
141
@testset " NLP-MI" begin
148
142
MINLPTests. test_nlp_mi (
149
- OPTIMIZER,
150
- exclude = config[ " nlpmi_exclude " ] ,
143
+ OPTIMIZER;
144
+ exclude = exclude ,
151
145
termination_target = TERMINATION_TARGET,
152
146
primal_target = PRIMAL_TARGET,
153
- objective_tol = config[ " tol" ] ,
154
- primal_tol = config[ " tol" ] ,
155
- dual_tol = config[ " dual_tol" ] ,
147
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
148
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
149
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
156
150
)
157
151
MINLPTests. test_nlp_mi_expr (
158
- OPTIMIZER,
159
- exclude = config[ " nlpmi_exclude " ] ,
152
+ OPTIMIZER;
153
+ exclude = exclude ,
160
154
termination_target = TERMINATION_TARGET,
161
155
primal_target = PRIMAL_TARGET,
162
- objective_tol = config[ " tol" ] ,
163
- primal_tol = config[ " tol" ] ,
164
- dual_tol = config[ " dual_tol" ] ,
156
+ objective_tol = get ( config, " tol" , 1e-5 ) ,
157
+ primal_tol = get ( config, " tol" , 1e-5 ) ,
158
+ dual_tol = get ( config, " dual_tol" , 1e-5 ) ,
165
159
)
166
160
end
167
161
end
168
162
end
163
+
164
+ function test_uno_runtests ()
165
+ optimizer = MOI. instantiate (
166
+ () -> AmplNLWriter. Optimizer (Uno_jll. amplexe, [" logger=SILENT" ]);
167
+ with_cache_type = Float64,
168
+ with_bridge_type = Float64,
169
+ )
170
+ MOI. Test. runtests (
171
+ optimizer,
172
+ MOI. Test. Config (
173
+ atol = 1e-4 ,
174
+ rtol = 1e-4 ,
175
+ optimal_status = MOI. LOCALLY_SOLVED,
176
+ infeasible_status = MOI. LOCALLY_INFEASIBLE,
177
+ exclude = Any[
178
+ MOI. VariableBasisStatus,
179
+ MOI. ConstraintBasisStatus,
180
+ MOI. ObjectiveBound,
181
+ ],
182
+ );
183
+ exclude = [
184
+ # OTHER_LIMIT instead of LOCALLY_SOLVED
185
+ r" ^test_conic_linear_VectorOfVariables_2$" ,
186
+ r" ^test_nonlinear_expression_hs109$" ,
187
+ r" ^test_quadratic_constraint_GreaterThan$" ,
188
+ r" ^test_quadratic_constraint_LessThan$" ,
189
+ r" ^test_solve_VariableIndex_ConstraintDual_MAX_SENSE$" ,
190
+ r" ^test_solve_VariableIndex_ConstraintDual_MIN_SENSE$" ,
191
+ # OTHER_ERROR instead of LOCALLY_SOLVED
192
+ r" ^test_linear_integration$" ,
193
+ r" ^test_linear_transform$" ,
194
+ # OTHER_LIMIT instead of DUAL_INFEASIBLE
195
+ r" ^test_solve_TerminationStatus_DUAL_INFEASIBLE$" ,
196
+ # OTHER_LIMIT instead of LOCALLY_INFEASIBLE
197
+ r" ^test_conic_NormInfinityCone_INFEASIBLE$" ,
198
+ r" ^test_conic_NormOneCone_INFEASIBLE$" ,
199
+ r" ^test_conic_linear_INFEASIBLE$" ,
200
+ r" ^test_conic_linear_INFEASIBLE_2$" ,
201
+ r" ^test_linear_INFEASIBLE$" ,
202
+ r" ^test_linear_INFEASIBLE_2$" ,
203
+ r" ^test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_" ,
204
+ # Uno does not support integrality
205
+ " Indicator" ,
206
+ r" [Ii]nteger" ,
207
+ " Semicontinuous" ,
208
+ " Semiinteger" ,
209
+ " SOS1" ,
210
+ " SOS2" ,
211
+ " ZeroOne" ,
212
+ r" ^test_cpsat_" ,
213
+ # Existing MOI issues
214
+ r" ^test_attribute_SolverVersion$" ,
215
+ r" ^test_nonlinear_invalid$" ,
216
+ r" ^test_basic_VectorNonlinearFunction_" ,
217
+ ],
218
+ )
219
+ return
220
+ end
221
+
222
+ test_uno_runtests ()
0 commit comments