Skip to content

Commit

Permalink
formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
mohamed82008 committed Nov 15, 2023
1 parent afb8ecc commit 0cd5651
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 49 deletions.
132 changes: 100 additions & 32 deletions src/NonconvexNOMAD.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,30 @@ speculative_search::Bool=true, speculative_search_max::Int=1, nm_search::Bool=tr
nm_search_stop_on_success::Bool=false, max_time::Union{Nothing,Int}=nothing,
linear_converter::String=SVD
=#
function NOMADOptions(; linear_equality_constraints = false, min_mesh_size = 0.0, initial_mesh_size = Float64[], granularity = 0.0, display_stats = ["OBJ", "CONS_H", "BBE", "TIME"], extra_display_stats = String[], linear_constraints_atol=1e-6, kwargs...)
function NOMADOptions(;
linear_equality_constraints = false,
min_mesh_size = 0.0,
initial_mesh_size = Float64[],
granularity = 0.0,
display_stats = ["OBJ", "CONS_H", "BBE", "TIME"],
extra_display_stats = String[],
linear_constraints_atol = 1e-6,
kwargs...,
)
display_stats = unique(vcat(display_stats, extra_display_stats))
return NOMADOptions(merge((; linear_equality_constraints, min_mesh_size, initial_mesh_size, granularity, display_stats, linear_constraints_atol), NamedTuple(kwargs)))
return NOMADOptions(
merge(
(;
linear_equality_constraints,
min_mesh_size,
initial_mesh_size,
granularity,
display_stats,
linear_constraints_atol,
),
NamedTuple(kwargs),
),
)
end

@params mutable struct NOMADWorkspace <: Workspace
Expand All @@ -37,27 +58,44 @@ end
alg::NOMADAlg
end
function NOMADWorkspace(
model::VecModel, optimizer::NOMADAlg,
model::VecModel,
optimizer::NOMADAlg,
x0::AbstractVector = getinit(model);
options = NOMADOptions(), kwargs...,
options = NOMADOptions(),
kwargs...,
)
return NOMADWorkspace(model, copy(x0), options, optimizer)
end
@params struct NOMADResult <: AbstractResult
minimizer
minimum
result
alg
options
minimizer::Any
minimum::Any
result::Any
alg::Any
options::Any
end

function NonconvexCore._optimize_precheck(model::NonconvexCore.AbstractModel, ::NOMADAlg, x0; options)
length(model.eq_constraints.fs) == 0 || options.nt.linear_equality_constraints || throw(ArgumentError("NOMAD does not support nonlinear equality constraints, only bound constraints, inequality constraints and linear equality constraints. You can set the `linear_equality_constraints` option to `true` if the equality constraint functions are indeed linear/affine."))
length(model.sd_constraints.fs) == 0 || throw(ArgumentError("NOMAD does not support semidefinite constraints, only bound constraints, inequality constraints and linear equality constraints."))
function NonconvexCore._optimize_precheck(
model::NonconvexCore.AbstractModel,
::NOMADAlg,
x0;
options,
)
length(model.eq_constraints.fs) == 0 ||
options.nt.linear_equality_constraints ||
throw(
ArgumentError(
"NOMAD does not support nonlinear equality constraints, only bound constraints, inequality constraints and linear equality constraints. You can set the `linear_equality_constraints` option to `true` if the equality constraint functions are indeed linear/affine.",
),
)
length(model.sd_constraints.fs) == 0 || throw(
ArgumentError(
"NOMAD does not support semidefinite constraints, only bound constraints, inequality constraints and linear equality constraints.",
),
)
return
end

@generated function drop_ks(nt::NamedTuple{names}, ::Val{ks}) where {names, ks}
@generated function drop_ks(nt::NamedTuple{names}, ::Val{ks}) where {names,ks}
ns = Tuple(setdiff(names, ks))
return :(NamedTuple{$ns}(nt))
end
Expand All @@ -76,10 +114,18 @@ function optimize!(workspace::NOMADWorkspace)
end

if A !== nothing && norm(A * x0 - b) > options.nt.linear_constraints_atol
throw(ArgumentError("The initial solution doesn't satisfy the linear equality constraints."))
throw(
ArgumentError(
"The initial solution doesn't satisfy the linear equality constraints.",
),
)
end
if length(model.ineq_constraints.fs) > 0 && any(>(0), model.ineq_constraints(x0))
throw(ArgumentError("The initial solution doesn't satisfy the inequality constraints."))
throw(
ArgumentError(
"The initial solution doesn't satisfy the inequality constraints.",
),
)
end

nb_outputs = 1
Expand All @@ -103,7 +149,11 @@ function optimize!(workspace::NOMADWorkspace)
nb_outputs += N
fill("PB", N)
else
throw(ArgumentError("""Unsupported flag `"type"` value, please choose from `:explicit` and `:progressive`."""))
throw(
ArgumentError(
"""Unsupported flag `"type"` value, please choose from `:explicit` and `:progressive`.""",
),
)
end
end
else
Expand All @@ -118,19 +168,20 @@ function optimize!(workspace::NOMADWorkspace)
obj(x0)
model.ineq_constraints(x0)

eval_bb = x -> begin
try
if length(model.ineq_constraints.fs) > 0
out = [finite_or_inf(obj(x)); finite_or_inf.(model.ineq_constraints(x))]
else
out = [finite_or_inf(obj(x))]
eval_bb =
x -> begin
try
if length(model.ineq_constraints.fs) > 0
out = [finite_or_inf(obj(x)) finite_or_inf.(model.ineq_constraints(x))]
else
out = [finite_or_inf(obj(x))]
end
return (true, true, out)
catch
out = fill(Inf, nb_outputs)
return (false, true, out)
end
return (true, true, out)
catch
out = fill(Inf, nb_outputs)
return (false, true, out)
end
end

nb_inputs = length(x0)
input_types = map(enumerate(model.integer)) do (i, int)
Expand Down Expand Up @@ -165,12 +216,29 @@ function optimize!(workspace::NOMADWorkspace)
upper_bound = getmax(model)

nomad_problem = NOMAD.NomadProblem(
nb_inputs, nb_outputs, output_types, eval_bb;
input_types, lower_bound, upper_bound, A, b,
min_mesh_size, initial_mesh_size, granularity,
nb_inputs,
nb_outputs,
output_types,
eval_bb;
input_types,
lower_bound,
upper_bound,
A,
b,
min_mesh_size,
initial_mesh_size,
granularity,
)

nomad_options = drop_ks(options.nt, Val((:linear_equality_constraints, :min_mesh_size, :initial_mesh_size, :granularity)))
nomad_options = drop_ks(
options.nt,
Val((
:linear_equality_constraints,
:min_mesh_size,
:initial_mesh_size,
:granularity,
)),
)

for k in keys(nomad_options)
setproperty!(nomad_problem.options, k, nomad_options[k])
Expand All @@ -185,7 +253,7 @@ function optimize!(workspace::NOMADWorkspace)
end
end

function Workspace(model::VecModel, optimizer::NOMADAlg, args...; kwargs...,)
function Workspace(model::VecModel, optimizer::NOMADAlg, args...; kwargs...)
return NOMADWorkspace(model, optimizer, args...; kwargs...)
end

Expand Down
42 changes: 25 additions & 17 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using NonconvexNOMAD, LinearAlgebra, Test

f(x::AbstractVector) = sqrt(x[2])
g(x::AbstractVector, a, b) = (a*x[1] + b)^3 - x[2]
g(x::AbstractVector, a, b) = (a * x[1] + b)^3 - x[2]
x0 = [0.5, 2.3]

@testset "Alg type - $alg_type" for alg_type in [:explicit, :progressive, :custom]
Expand All @@ -14,8 +14,8 @@ x0 = [0.5, 2.3]

alg = NOMADAlg(alg_type)
r1 = NonconvexNOMAD.optimize(m, alg, x0, options = options)
@test abs(r1.minimum - sqrt(8/27)) < 1e-4
@test norm(r1.minimizer - [1/3, 8/27]) < 1e-4
@test abs(r1.minimum - sqrt(8 / 27)) < 1e-4
@test norm(r1.minimizer - [1 / 3, 8 / 27]) < 1e-4

setinteger!(m, 1, true)
r2 = NonconvexNOMAD.optimize(m, alg, [0.0, x0[2]], options = options)
Expand All @@ -38,8 +38,8 @@ x0 = [0.5, 2.3]

alg = NOMADAlg(alg_type)
r1 = NonconvexNOMAD.optimize(m, alg, x0, options = options)
@test abs(r1.minimum - sqrt(8/27)) < 1e-4
@test norm(r1.minimizer - [1/3, 8/27]) < 1e-4
@test abs(r1.minimum - sqrt(8 / 27)) < 1e-4
@test norm(r1.minimizer - [1 / 3, 8 / 27]) < 1e-4

setinteger!(m, 1, true)
r2 = NonconvexNOMAD.optimize(m, alg, [0.0, x0[2]], options = options)
Expand All @@ -58,50 +58,58 @@ x0 = [0.5, 2.3]
m = Model(f)
addvar!(m, [0.0, 0.0], [10.0, 10.0])
add_ineq_constraint!(m, x -> g(x, 2, 0), flags = [:explicit])
add_eq_constraint!(m, x -> sum(x) - 1/3 - 8/27)
add_eq_constraint!(m, x -> sum(x) - 1 / 3 - 8 / 27)

alg = NOMADAlg(alg_type)
_x0 = x0 / sum(x0) * (1 / 3 + 8 / 27)
r = NonconvexNOMAD.optimize(m, alg, _x0, options = options)
@test abs(r.minimum - sqrt(8/27)) < 1e-6
@test norm(r.minimizer - [1/3, 8/27]) < 1e-6
@test abs(r.minimum - sqrt(8 / 27)) < 1e-6
@test norm(r.minimizer - [1 / 3, 8 / 27]) < 1e-6
end

@testset "Equality constraints 2" begin
options = NOMADOptions(linear_equality_constraints = true)
m = Model(f)
addvar!(m, [1e-4, 1e-4], [10.0, 10.0])
add_ineq_constraint!(m, x -> g(x, 2, 0), flags = [:progressive])
add_eq_constraint!(m, x -> sum(x) - 1/3 - 8/27)
add_eq_constraint!(m, x -> sum(x) - 1 / 3 - 8 / 27)

alg = NOMADAlg(alg_type)
_x0 = x0 / sum(x0) * (1 / 3 + 8 / 27)
r = NonconvexNOMAD.optimize(m, alg, _x0, options = options)
@test abs(r.minimum - sqrt(8/27)) < 1e-6
@test norm(r.minimizer - [1/3, 8/27]) < 1e-6
@test abs(r.minimum - sqrt(8 / 27)) < 1e-6
@test norm(r.minimizer - [1 / 3, 8 / 27]) < 1e-6
end

@testset "Block constraints 1" begin
options = NOMADOptions()
m = Model(f)
addvar!(m, [1e-4, 1e-4], [10.0, 10.0])
add_ineq_constraint!(m, FunctionWrapper(x -> [g(x, 2, 0), g(x, -1, 1)], 2), flags = [:explicit])
add_ineq_constraint!(
m,
FunctionWrapper(x -> [g(x, 2, 0), g(x, -1, 1)], 2),
flags = [:explicit],
)

alg = NOMADAlg(alg_type)
r = NonconvexNOMAD.optimize(m, alg, x0, options = options)
@test abs(r.minimum - sqrt(8/27)) < 1e-6
@test norm(r.minimizer - [1/3, 8/27]) < 1e-6
@test abs(r.minimum - sqrt(8 / 27)) < 1e-6
@test norm(r.minimizer - [1 / 3, 8 / 27]) < 1e-6
end

@testset "Block constraints 2" begin
options = NOMADOptions()
m = Model(f)
addvar!(m, [1e-4, 1e-4], [10.0, 10.0])
add_ineq_constraint!(m, FunctionWrapper(x -> [g(x, 2, 0), g(x, -1, 1)], 2), flags = [:progressive])
add_ineq_constraint!(
m,
FunctionWrapper(x -> [g(x, 2, 0), g(x, -1, 1)], 2),
flags = [:progressive],
)

alg = NOMADAlg(alg_type)
r = NonconvexNOMAD.optimize(m, alg, x0, options = options)
@test abs(r.minimum - sqrt(8/27)) < 1e-6
@test norm(r.minimizer - [1/3, 8/27]) < 1e-6
@test abs(r.minimum - sqrt(8 / 27)) < 1e-6
@test norm(r.minimizer - [1 / 3, 8 / 27]) < 1e-6
end
end

0 comments on commit 0cd5651

Please sign in to comment.