Skip to content

Commit 94edfcd

Browse files
committed
Update
1 parent 84d617f commit 94edfcd

File tree

2 files changed

+122
-69
lines changed

2 files changed

+122
-69
lines changed

src/MOI_wrapper.jl

Lines changed: 32 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,7 @@ function _add_complementarity_constraint!(
8484
index_vars_2::Vector{Cint},
8585
cc_types::Vector{Int},
8686
)
87-
if !(length(index_vars_1) == length(index_vars_2) == length(cc_types))
88-
error(
89-
"Arrays `index_vars_1`, `index_vars_2` and `cc_types` should" *
90-
" share the same length to specify a valid complementarity " *
91-
"constraint.",
92-
)
93-
end
87+
@assert length(index_vars_1) == length(index_vars_2) == length(cc_types)
9488
cache.n += 1
9589
append!(cache.index_comps_1, index_vars_1)
9690
append!(cache.index_comps_2, index_vars_2)
@@ -284,7 +278,7 @@ end
284278
# MOI.RawOptimizerAttribute
285279

286280
function MOI.supports(model::Optimizer, attr::MOI.RawOptimizerAttribute)
287-
if attr.name == "free"
281+
if attr.name in ("option_file", "tuner_file", "free")
288282
return true
289283
end
290284
p = Ref{Cint}(0)
@@ -304,10 +298,13 @@ end
304298
function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value)
305299
if attr.name == "option_file"
306300
@_checked KN_load_param_file(model.inner, value)
301+
return
307302
elseif attr.name == "tuner_file"
308303
@_checked KN_load_tuner_file(model.inner, value)
304+
return
309305
elseif attr.name == "free"
310306
@_checked KN_free(model.inner)
307+
return
311308
end
312309
pId = Ref{Cint}(0)
313310
ret = KN_get_param_id(model.inner, attr.name, pId)
@@ -495,9 +492,6 @@ function MOI.add_constraint(
495492
)
496493
_throw_if_solved(model, x, set)
497494
MOI.throw_if_not_valid(model, x)
498-
if isnan(set.upper)
499-
error("Invalid upper bound value $(set.upper).")
500-
end
501495
if _has_upper_bound(model, x)
502496
error("Upper bound on variable $x already exists.")
503497
end
@@ -534,9 +528,6 @@ function MOI.add_constraint(
534528
)
535529
_throw_if_solved(model, x, set)
536530
MOI.throw_if_not_valid(model, x)
537-
if isnan(set.lower)
538-
error("Invalid lower bound value $(set.lower).")
539-
end
540531
if _has_lower_bound(model, x)
541532
error("Lower bound on variable $x already exists.")
542533
end
@@ -573,9 +564,6 @@ function MOI.add_constraint(
573564
)
574565
_throw_if_solved(model, x, set)
575566
MOI.throw_if_not_valid(model, x)
576-
if isnan(set.lower) || isnan(set.upper)
577-
error("Invalid lower bound value $(set.lower).")
578-
end
579567
if _has_lower_bound(model, x) || _has_upper_bound(model, x)
580568
error("Bounds on variable $x already exists.")
581569
end
@@ -615,9 +603,6 @@ function MOI.add_constraint(
615603
)
616604
_throw_if_solved(model, x, set)
617605
MOI.throw_if_not_valid(model, x)
618-
if isnan(set.value)
619-
error("Invalid fixed value $(set.value).")
620-
end
621606
if _has_lower_bound(model, x)
622607
error("Variable $x has a lower bound. Cannot be fixed.")
623608
end
@@ -642,11 +627,8 @@ end
642627
function MOI.supports(
643628
::Optimizer,
644629
::MOI.ConstraintDualStart,
645-
::MOI.ConstraintIndex{
646-
MOI.VariableIndex,
647-
<:Union{MOI.EqualTo{Float64},MOI.GreaterThan{Float64},MOI.LessThan{Float64}},
648-
},
649-
)
630+
::Type{MOI.ConstraintIndex{MOI.VariableIndex,S}},
631+
) where {S<:Union{MOI.EqualTo{Float64},MOI.GreaterThan{Float64},MOI.LessThan{Float64}}}
650632
return true
651633
end
652634

@@ -659,8 +641,9 @@ function MOI.set(
659641
},
660642
value::Union{Real,Nothing},
661643
)
662-
start = something(value, 0.0)
663-
@_checked KN_set_var_dual_init_values(model.inner, ci.value, Cdouble(start))
644+
start = convert(Cdouble, something(value, 0.0))
645+
indexVars = [_c_column(MOI.VariableIndex(ci.value))]
646+
@_checked KN_set_var_dual_init_values(model.inner, 1, indexVars, [start])
664647
return
665648
end
666649

@@ -756,16 +739,15 @@ end
756739
function MOI.supports(
757740
::Optimizer,
758741
::MOI.ConstraintDualStart,
759-
::MOI.ConstraintIndex{
760-
MOI.ScalarAffineFunction{Float64},
761-
<:Union{
762-
MOI.EqualTo{Float64},
763-
MOI.GreaterThan{Float64},
764-
MOI.LessThan{Float64},
765-
MOI.Interval{Float64},
766-
},
742+
::Type{MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},S}},
743+
) where {
744+
S<:Union{
745+
MOI.EqualTo{Float64},
746+
MOI.GreaterThan{Float64},
747+
MOI.LessThan{Float64},
748+
MOI.Interval{Float64},
767749
},
768-
)
750+
}
769751
return true
770752
end
771753

@@ -783,8 +765,9 @@ function MOI.set(
783765
},
784766
value::Union{Real,Nothing},
785767
)
786-
start = something(value, 0.0)
787-
@_checked KN_set_con_dual_init_values(model.inner, ci.value, Cdouble(start))
768+
start = convert(Cdouble, something(value, 0.0))
769+
indexCons = KNINT[ci.value]
770+
@_checked KN_set_con_dual_init_values(model.inner, 1, indexCons, [start])
788771
return
789772
end
790773

@@ -838,16 +821,15 @@ end
838821
function MOI.supports(
839822
::Optimizer,
840823
::MOI.ConstraintDualStart,
841-
::MOI.ConstraintIndex{
842-
MOI.ScalarQuadraticFunction{Float64},
843-
<:Union{
844-
MOI.EqualTo{Float64},
845-
MOI.GreaterThan{Float64},
846-
MOI.LessThan{Float64},
847-
MOI.Interval{Float64},
848-
},
824+
::Type{MOI.ConstraintIndex{MOI.ScalarQuadraticFunction{Float64},S}},
825+
) where {
826+
S<:Union{
827+
MOI.EqualTo{Float64},
828+
MOI.GreaterThan{Float64},
829+
MOI.LessThan{Float64},
830+
MOI.Interval{Float64},
849831
},
850-
)
832+
}
851833
return true
852834
end
853835

@@ -865,8 +847,9 @@ function MOI.set(
865847
},
866848
value::Union{Real,Nothing},
867849
)
868-
start = something(value, 0.0)
869-
@_checked KN_set_con_dual_init_values(model.inner, ci.value, Cdouble(start))
850+
start = convert(Cdouble, something(value, 0.0))
851+
indexCons = KNINT[ci.value]
852+
@_checked KN_set_con_dual_init_values(model.inner, 1, indexCons, [start])
870853
return
871854
end
872855

@@ -1349,26 +1332,6 @@ function MOI.get(model::Optimizer, ::MOI.RawStatusString)
13491332
return string(statusP[])
13501333
end
13511334

1352-
function _interpret_return_code(code)
1353-
if code == KN_RC_OPTIMAL_OR_SATISFACTORY
1354-
return MOI.LOCALLY_SOLVED, MOI.FEASIBLE_POINT, MOI.FEASIBLE_POINT
1355-
elseif code == KN_RC_NEAR_OPT
1356-
return MOI.ALMOST_OPTIMAL, MOI.FEASIBLE_POINT, MOI.FEASIBLE_POINT
1357-
elseif -199 <= code <= -101
1358-
return MOI.SLOW_PROGRESS, MOI.FEASIBLE_POINT, MOI.FEASIBLE_POINT
1359-
elseif -299 <= code <= -200
1360-
return MOI.LOCALLY_INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.UNKNOWN_RESULT_STATUS
1361-
elseif code == KN_RC_UNBOUNDED
1362-
elseif code == KN_RC_UNBOUNDED_OR_INFEAS
1363-
elseif code == KN_RC_ITER_LIMIT_FEAS
1364-
return MOI.ITERATION_LIMIT, MOI.FEASIBLE_POINT, MOI.UNKNOWN_RESULT_STATUS
1365-
elseif code == KN_RC_TIME_LIMIT_FEAS
1366-
return MOI.TIME_LIMIT, MOI.FEASIBLE_POINT, MOI.UNKNOWN_RESULT_STATUS
1367-
elseif -499 <= code <= -400
1368-
end
1369-
return MOI.OTHER_ERROR, MOI.UNKNOWN_RESULT_STATUS, MOI.UNKNOWN_RESULT_STATUS
1370-
end
1371-
13721335
# Refer to KNITRO manual for solver status:
13731336
# https://www.artelys.com/tools/knitro_doc/3_referenceManual/returnCodes.html#returncodes
13741337
const _KN_TO_MOI_RETURN_STATUS = Dict{Int,MOI.TerminationStatusCode}(

test/MOI_wrapper.jl

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,96 @@ function test_RelativeGap()
258258
return
259259
end
260260

261+
function test_NumberOfVariales()
262+
model = KNITRO.Optimizer()
263+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
264+
x = MOI.add_variable(model)
265+
@test MOI.get(model, MOI.NumberOfVariables()) == 1
266+
y = MOI.add_variables(model, 2)
267+
@test MOI.get(model, MOI.NumberOfVariables()) == 3
268+
return
269+
end
270+
271+
function test_RawOptimizerParameter_free()
272+
model = KNITRO.Optimizer()
273+
@test MOI.supports(model, MOI.RawOptimizerAttribute("free"))
274+
@test model.inner.env.ptr_env != C_NULL
275+
MOI.set(model, MOI.RawOptimizerAttribute("free"), true)
276+
@test model.inner.env.ptr_env == C_NULL
277+
return
278+
end
279+
280+
function test_RawOptimizerParameter_option_file()
281+
model = KNITRO.Optimizer()
282+
@test MOI.supports(model, MOI.RawOptimizerAttribute("option_file"))
283+
dir = mktempdir()
284+
filename = joinpath(dir, "option_file")
285+
write(filename, "outlev 1")
286+
MOI.set(model, MOI.RawOptimizerAttribute("option_file"), filename)
287+
valueP = Ref{Cint}()
288+
KN_get_int_param(model.inner, KN_PARAM_OUTLEV, valueP)
289+
@test valueP[] == 1
290+
return
291+
end
292+
293+
function test_RawOptimizerParameter_tuner_file()
294+
model = KNITRO.Optimizer()
295+
@test MOI.supports(model, MOI.RawOptimizerAttribute("tuner_file"))
296+
dir = mktempdir()
297+
filename = joinpath(dir, "tuner_file")
298+
write(filename, "algorithm")
299+
MOI.set(model, MOI.RawOptimizerAttribute("tuner_file"), filename)
300+
valueP = Ref{Cint}()
301+
KN_get_int_param(model.inner, KN_PARAM_OUTLEV, valueP)
302+
@test valueP[] == 1
303+
return
304+
end
305+
306+
function test_VariableName()
307+
model = KNITRO.Optimizer()
308+
x = MOI.add_variable(model)
309+
@test MOI.supports(model, MOI.VariableName(), MOI.VariableIndex)
310+
@test MOI.get(model, MOI.VariableName(), x) == ""
311+
MOI.set(model, MOI.VariableName(), x, "x")
312+
@test MOI.get(model, MOI.VariableName(), x) == "x"
313+
return
314+
end
315+
316+
function test_ConstraintDualStart()
317+
model = KNITRO.Optimizer()
318+
x = MOI.add_variable(model)
319+
for f in (x, 1.0 * x, 1.0 * x * x)
320+
c = MOI.add_constraint(model, f, MOI.LessThan(1.0))
321+
@test MOI.supports(model, MOI.ConstraintDualStart(), typeof(c))
322+
# Just test that this doesn't error.
323+
MOI.set(model, MOI.ConstraintDualStart(), c, nothing)
324+
MOI.set(model, MOI.ConstraintDualStart(), c, 1.0)
325+
end
326+
return
327+
end
328+
329+
function test_error_kwargs()
330+
@test_throws(
331+
ErrorException(
332+
"Unsupported keyword arguments passed to `Optimizer`. Set attributes instead",
333+
),
334+
KNITRO.Optimizer(; outlev = 1),
335+
)
336+
return
337+
end
338+
339+
function test_lm_context()
340+
lm = KNITRO.LMcontext()
341+
@test isempty(lm.linked_models)
342+
model = KNITRO.Optimizer(; license_manager = lm)
343+
@test length(lm.linked_models) == 1
344+
@test model.inner in lm.linked_models
345+
MOI.empty!(model)
346+
@test length(lm.linked_models) == 2
347+
@test model.inner in lm.linked_models
348+
return
349+
end
350+
261351
end
262352

263353
TestMOIWrapper.runtests()

0 commit comments

Comments
 (0)