Skip to content

Commit

Permalink
Merge branch 'libprima:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
emmt authored Jan 29, 2024
2 parents 7ca1e4b + 6c30115 commit bfffb13
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
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

0 comments on commit bfffb13

Please sign in to comment.