Skip to content

Commit

Permalink
Update for KNITRO.jl v0.14.0
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored and amontoison committed Nov 29, 2023
1 parent 1603907 commit b044be8
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 33 deletions.
5 changes: 4 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ NLPModelsModifiers = "e01155f1-5c6f-4375-a9d8-616dd036575f"
SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843"

[compat]
KNITRO = "0.13"
ADNLPModels = "0.7"
KNITRO = "0.14"
LinearAlgebra = "<0.0.1, 1.6"
NLPModels = "0.18, 0.19, 0.20"
NLPModelsModifiers = "0.6"
SolverCore = "0.3"
Test = "<0.0.1, 1.6"
julia = "^1.6.0"

[extras]
Expand Down
5 changes: 2 additions & 3 deletions src/NLPModelsKnitro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function knitro end
Returns a `KnitroSolver` structure to solve the problem `nlp` with `knitro!`.
Knitro does not accept least-squares problems with constraints other than bounds.
Knitro does not accept least-squares problems with constraints other than bounds.
If an NLSModel has constraints other than bounds, we convert it to a FeasibilityFormNLS.
The first argument is `Val(false)` if the problem has been converted, and `Val(true)` otherwise.
Expand All @@ -44,8 +44,7 @@ mutable struct KnitroSolver <: AbstractOptimizationSolver
kc
end

const KNITRO_VERSION = KNITRO.KNITRO_VERSION
if KNITRO_VERSION == v"0.0.0"
if KNITRO.knitro_version() == v"0.0.0"
@error "KNITRO is not installed correctly"
else
include("api.jl")
Expand Down
30 changes: 22 additions & 8 deletions src/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,18 @@ function setparams!(solver::KnitroSolver; kwargs...)
end

# specify that we are able to provide the Hessian without including the objective
KNITRO.KN_set_param(kc, KNITRO.KN_PARAM_HESSIAN_NO_F, KNITRO.KN_HESSIAN_NO_F_ALLOW)
KNITRO.KN_set_int_param(kc, KNITRO.KN_PARAM_HESSIAN_NO_F, KNITRO.KN_HESSIAN_NO_F_ALLOW)

# pass options to KNITRO
for (k, v) in kwargs
KNITRO.KN_set_param(kc, string(k), v)
if v isa Integer
KNITRO.KN_set_int_param_by_name(kc, string(k), v)
elseif v isa Cdouble
KNITRO.KN_set_double_param_by_name(kc, string(k), v)
else
@assert v isa AbstractString
KNITRO.KN_set_char_param_by_name(kc, string(k), v)
end
end

return solver
Expand Down Expand Up @@ -153,12 +160,19 @@ function SolverCore.solve!(
nStatus, obj_val, x, lambda_ = KNITRO.KN_get_solution(kc)
n = length(x)
m = length(lambda_) - n
primal_feas = KNITRO.KN_get_abs_feas_error(kc)
dual_feas = KNITRO.KN_get_abs_opt_error(kc)
iter = KNITRO.KN_get_number_iters(kc)
if KNITRO_VERSION v"12.0"
Δt = KNITRO.KN_get_solve_time_cpu(kc)
real_time = KNITRO.KN_get_solve_time_real(kc)
pCdouble = Ref{Cdouble}()
KNITRO.KN_get_abs_feas_error(kc, pCdouble)
primal_feas = pCdouble[]
KNITRO.KN_get_abs_opt_error(kc, pCdouble)
dual_feas = pCdouble[]
pCint = Ref{Cint}()
KNITRO.KN_get_number_iters(kc, pCint)
iter = pCint[]
if KNITRO.knitro_version() v"12.0"
KNITRO.KN_get_solve_time_cpu(kc, pCdouble)
Δt = pCdouble[]
KNITRO.KN_get_solve_time_real(kc, pCdouble)
real_time = pCdouble[]
else
Δt = real_time = t[2]
end
Expand Down
17 changes: 12 additions & 5 deletions src/nlp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function KnitroSolver(
end

# add variables and bound constraints
KNITRO.KN_add_vars(kc, n)
KNITRO.KN_add_vars(kc, n, C_NULL)

lvarinf = isinf.(nlp.meta.lvar)
if !all(lvarinf)
Expand All @@ -38,7 +38,7 @@ function KnitroSolver(
end

# add constraints
KNITRO.KN_add_cons(kc, m)
KNITRO.KN_add_cons(kc, m, C_NULL)
lcon = nlp.meta.lcon
lconinf = isinf.(lcon)
if any(lconinf)
Expand All @@ -58,7 +58,7 @@ function KnitroSolver(
jlrows, jlcols = jac_lin_structure(nlp)
for klin = 1:(nlp.meta.lin_nnzj)
row = nlp.meta.lin[jlrows[klin]]
KNITRO.KN_add_con_linear_struct(kc, Int32(row - 1), Int32(jlcols[klin] - 1), jlvals[klin])
KNITRO.KN_add_con_linear_struct_one(kc, 1, row - 1, Cint[jlcols[klin] - 1], Cdouble[jlvals[klin]])
end
end

Expand Down Expand Up @@ -157,11 +157,18 @@ function KnitroSolver(
)

# specify that we are able to provide the Hessian without including the objective
KNITRO.KN_set_param(kc, KNITRO.KN_PARAM_HESSIAN_NO_F, KNITRO.KN_HESSIAN_NO_F_ALLOW)
KNITRO.KN_set_int_param(kc, KNITRO.KN_PARAM_HESSIAN_NO_F, KNITRO.KN_HESSIAN_NO_F_ALLOW)

# pass options to KNITRO
for (k, v) in kwargs
KNITRO.KN_set_param(kc, string(k), v)
if v isa Integer
KNITRO.KN_set_int_param_by_name(kc, string(k), v)
elseif v isa Cdouble
KNITRO.KN_set_double_param_by_name(kc, string(k), v)
else
@assert v isa AbstractString
KNITRO.KN_set_char_param_by_name(kc, string(k), v)
end
end

# set user-defined callback called after each iteration
Expand Down
13 changes: 10 additions & 3 deletions src/nls.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function KnitroSolver(
end

# add variables and bound constraints
KNITRO.KN_add_vars(kc, n)
KNITRO.KN_add_vars(kc, n, C_NULL)

lvarinf = isinf.(nls.meta.lvar)
if !all(lvarinf)
Expand Down Expand Up @@ -52,7 +52,7 @@ function KnitroSolver(
end

# add number of residual functions
KNITRO.KN_add_rsds(kc, ne)
KNITRO.KN_add_rsds(kc, ne, C_NULL)

jrows, jcols = jac_structure_residual(nls)

Expand Down Expand Up @@ -89,7 +89,14 @@ function KnitroSolver(

# pass options to KNITRO
for (k, v) in kwargs
KNITRO.KN_set_param(kc, string(k), v)
if v isa Integer
KNITRO.KN_set_int_param_by_name(kc, string(k), v)
elseif v isa Cdouble
KNITRO.KN_set_double_param_by_name(kc, string(k), v)
else
@assert v isa AbstractString
KNITRO.KN_set_char_param_by_name(kc, string(k), v)
end
end

# set user-defined callback called after each iteration
Expand Down
48 changes: 35 additions & 13 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@ function test_qp_with_solver_and_evals()
@test stats.iter == 1
@test stats.status == :first_order

gx = KNITRO.KN_get_objgrad_values(solver.kc)[2]
gx = zeros(2)
KNITRO.KN_get_objgrad_values_all(solver.kc, gx)
@test isapprox(gx, [-4.8; -4.8], rtol = 1e-6)
cx = KNITRO.KN_get_con_values(solver.kc)
cx = zeros(1)
KNITRO.KN_get_con_values_all(solver.kc, cx)
@test isapprox(norm(cx), 0, atol = 1e-6)
Jx = KNITRO.KN_get_jacobian_values(solver.kc)
@test Jx[1] == [0; 0]
@test Jx[2] == [0; 1]
@test Jx[3] == [1; 1]
nnz = Ref{Clonglong}()
KN_get_jacobian_nnz(solver.kc, nnz)
@test nnz[] == 2
vars, cons, coef = zeros(Cint, 2), zeros(Cint, 2), zeros(2)
KNITRO.KN_get_jacobian_values(solver.kc, vars, cons, coef)
@test vars == Cint[0, 0]
@test cons == Cint[0, 1]
@test coef == Cdouble[1, 1]
finalize(solver)
end

Expand Down Expand Up @@ -66,7 +72,9 @@ end

function test_with_callback()
function callback(kc, x, lambda_, userParams)
if KNITRO.KN_get_number_iters(kc) > 1
pCint = Ref{Cint}()
KNITRO.KN_get_number_iters(kc, pCint)
if pCint[] > 1
return KNITRO.KN_RC_USER_TERMINATION
end
return 0
Expand Down Expand Up @@ -177,10 +185,17 @@ function test_linear_constraints()
@test isapprox(stats.solution, [-1; 1], rtol = 1e-6)
@test isapprox(stats.objective, 0.0, atol = 1e-6)
@test stats.status == :first_order
cx = KNITRO.KN_get_con_values(solver.kc)
cx = zeros(2)
KNITRO.KN_get_con_values_all(solver.kc, cx)
@test isapprox(cx, [1, 1], rtol = 1e-6)
Jx = KNITRO.KN_get_jacobian_values(solver.kc)
@test Jx == (Int32[0, 0, 1, 1], Int32[0, 1, 0, 1], [1.0, 2.0, 3.0, 4.0])
nnz = Ref{Clonglong}()
KN_get_jacobian_nnz(solver.kc, nnz)
@test nnz[] == 4
vars, cons, coef = zeros(Cint, 4), zeros(Cint, 4), zeros(4)
KNITRO.KN_get_jacobian_values(solver.kc, vars, cons, coef)
@test vars == Int32[0, 0, 1, 1]
@test cons == Int32[0, 1, 0, 1]
@test coef == [1.0, 2.0, 3.0, 4.0]
finalize(solver)
end

Expand All @@ -200,10 +215,17 @@ function test_mixed_linear_constraints()
@test isapprox(stats.solution, [-1; 1], rtol = 1e-6)
@test isapprox(stats.objective, 0.0, atol = 1e-6)
@test stats.status == :first_order
cx = KNITRO.KN_get_con_values(solver.kc)
cx = zeros(2)
KNITRO.KN_get_con_values_all(solver.kc, cx)
@test isapprox(cx, [1, 1], rtol = 1e-6)
Jx = KNITRO.KN_get_jacobian_values(solver.kc)
@test Jx == (Int32[0, 0, 1, 1], Int32[0, 1, 0, 1], [3.0, 4.0, 1.0, 2.0])
nnz = Ref{Clonglong}()
KN_get_jacobian_nnz(solver.kc, nnz)
@test nnz[] == 4
vars, cons, coef = zeros(Cint, 4), zeros(Cint, 4), zeros(4)
KNITRO.KN_get_jacobian_values(solver.kc, vars, cons, coef)
@test vars == Int32[0, 0, 1, 1]
@test cons == Int32[0, 1, 0, 1]
@test coef == [3.0, 4.0, 1.0, 2.0]
finalize(solver)
end

Expand Down

0 comments on commit b044be8

Please sign in to comment.