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

Interface to CUTEst #20

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
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
10 changes: 10 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PRIMA_jll = "eead6e0c-2d5b-5641-a95c-b722de96d551"
TypeUtils = "c3b1956e-8857-4d84-9b79-890df85b1e67"

[weakdeps]
CUTEst = "1b53aba6-35b6-5f92-a507-53c67d53f819"
NLPModels = "a4795742-8479-5a88-8948-cc11e1c8c1a6"

[extensions]
PRIMACUTEstExt = "CUTEst"
PRIMANLPModelsExt = "NLPModels"

[compat]
CUTEst = "0.13"
NLPModels = "0.20"
PRIMA_jll = "0.7.1"
TypeUtils = "0.3"
julia = "1.6"
Expand Down
24 changes: 24 additions & 0 deletions ext/PRIMACUTEstExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module PRIMACUTEstExt

if isdefined(Base, :get_extension)
using NLPModels
using CUTEst
using PRIMA
else
using ..NLPModels
using ..CUTEst
using ..PRIMA
end

for func in (:uobyqa, :newuoa, :bobyqa, :lincoa, :cobyla, :prima)
@eval function PRIMA.$(Symbol(func,"_CUTEst"))(name::AbstractString; kwds...)
nlp = CUTEstModel(name)
try
return $func(nlp; kwds...)
finally
finalize(nlp)
end
end
end

end # module
82 changes: 82 additions & 0 deletions ext/PRIMANLPModelsExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module PRIMANLPModelsExt

if isdefined(Base, :get_extension)
using NLPModels
using PRIMA
else
using ..NLPModels
using ..PRIMA
end

# This structure is to wrap a non-linear problem model into a callable object.
struct ObjectiveFunction{F<:AbstractNLPModel} <: Function
nlp::F
end
(f::ObjectiveFunction)(x::AbstractVector) = obj(f.nlp, x)

function check_variables(nlp::AbstractNLPModel, x0::AbstractVector)
length(x0) == get_nvar(nlp) || error(
"initial variables must have $(get_nvar(nlp)) elements")
return x0
end

const Variables = AbstractVector{<:Real}

for func in (:uobyqa, :newuoa)
@eval function PRIMA.$func(nlp::AbstractNLPModel, x0::Variables = get_x0(nlp); kwds...)
has_bounds(nlp) && error("`$($func)` cannot solve problems with bound constraints")
has_equalities(nlp) && error("`$($func)` cannot solve problems with equality constraints")
has_inequalities(nlp) && error("`$($func)` cannot solve problems with inequality constraints")
return uobyqa(ObjectiveFunction(nlp), check_variables(nlp, x0); kwds...)
end
end

function PRIMA.bobyqa(nlp::AbstractNLPModel, x0::Variables = get_x0(nlp); kwds...)
has_equalities(nlp) && error("`bobyqa` cannot solve problems with equality constraints")
has_inequalities(nlp) && error("`bobyqa` cannot solve problems with inequality constraints")
return bobyqa(ObjectiveFunction(nlp), check_variables(nlp, x0); kwds...,
xl = get_lvar(nlp), xu = get_uvar(nlp))
end

function PRIMA.lincoa(nlp::AbstractNLPModel, x0::Variables = get_x0(nlp); kwds...)
nlin = get_nlin(nlp) # number of linear constraints
nnln = get_nnln(nlp) # number of non-linear constraints
nlin == 0 || error("linear constraints not yet implemented for NLPModels in `lincoa`")
nnln == 0 || error("`lincoa` cannot solve problems with non-linear constraints")
return lincoa(ObjectiveFunction(nlp), check_variables(nlp, x0); kwds...,
xl = get_lvar(nlp), xu = get_uvar(nlp),
linear_eq = nothing, linear_ineq = nothing)
end

function PRIMA.cobyla(nlp::AbstractNLPModel, x0::Variables = get_x0(nlp); kwds...)
nlin = get_nlin(nlp) # number of linear constraints
nnln = get_nnln(nlp) # number of non-linear constraints
nlin == 0 || error("linear constraints not yet implemented for NLPModels in `cobyla`")
nnln == 0 || error("non-linear constraints not yet implemented for NLPModels in `cobyla`")
return cobyla(ObjectiveFunction(nlp), check_variables(nlp, x0); kwds...,
xl = get_lvar(nlp), xu = get_uvar(nlp),
linear_eq = nothing, linear_ineq = nothing,
nonlinear_eq = nothing, nonlinear_ineq = nothing)
end

function PRIMA.prima(nlp::AbstractNLPModel, x0::Variables = get_x0(nlp); kwds...)
nlin = get_nlin(nlp) # number of linear constraints
nnln = get_nnln(nlp) # number of non-linear constraints
if nnln > 0
# Only COBYLA can deal with non-linear constraints.
error("solving problem with non-linear constraints by COBYLA not yet implemented")
return cobyla(nlp, x0; kwds...)
elseif nlin > 0
# LINCOA can deal with bounds and linear constraints.
error("solving problem with linear constraints by LINCOA not yet implemented")
return lincoa(nlp, x0; kwds...)
elseif has_bounds(nlp)
# BOBYQA can deal with bounds.
return bobyqa(nlp, x0; kwds...)
else
# Use NEWUOA for unconstrained problems.
return newuoa(nlp, x0; kwds...)
end
end

end # module
17 changes: 17 additions & 0 deletions src/PRIMA.jl
Original file line number Diff line number Diff line change
Expand Up @@ -985,4 +985,21 @@ function _get_scaling(scl::AbstractVector{<:Real}, n::Int)
return convert(Vector{Cdouble}, scl)
end

for func in (:uobyqa, :newuoa, :bobyqa, :lincoa, :cobyla, :prima)
@eval $(Symbol(func,"_CUTEst"))(args...; kwds...) =
error("invalid arguments or `CUTEst` package not yet loaded")
end

@static if !isdefined(Base, :get_extension)
using Requires
function __init__()
if !isdefined(Base, :get_extension)
@require CUTEst = "1b53aba6-35b6-5f92-a507-53c67d53f819" include(
"../ext/PRIMACUTEstExt.jl")
@require NLPModels = "a4795742-8479-5a88-8948-cc11e1c8c1a6" include(
"../ext/PRIMANLPModelsExt.jl")
end
end
end

end # module
Loading