From c03887cd0f184ddfa6e0caf268ef494a04ee9d97 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 19 Aug 2024 14:14:14 +1200 Subject: [PATCH] Use Clang.jl to automate C wrapper --- Project.toml | 13 +- gen/Project.toml | 6 + gen/gen.jl | 33 +++ gen/generate.toml | 7 + src/NLopt.jl | 518 ++++++++++++++++++++-------------------------- src/libnlopt.jl | 418 +++++++++++++++++++++++++++++++++++++ 6 files changed, 698 insertions(+), 297 deletions(-) create mode 100644 gen/Project.toml create mode 100644 gen/gen.jl create mode 100644 gen/generate.toml create mode 100644 src/libnlopt.jl diff --git a/Project.toml b/Project.toml index 8f5beb0..3c8d815 100644 --- a/Project.toml +++ b/Project.toml @@ -3,23 +3,24 @@ uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" version = "1.0.2" [deps] +CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" NLopt_jll = "079eb43e-fd8e-5478-9966-2cf3e3edb778" +[weakdeps] +MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" + +[extensions] +NLoptMathOptInterfaceExt = ["MathOptInterface"] + [compat] MathOptInterface = "1" NLopt_jll = "2.7" julia = "1.6" -[extensions] -NLoptMathOptInterfaceExt = ["MathOptInterface"] - [extras] MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["MathOptInterface", "Test"] - -[weakdeps] -MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" diff --git a/gen/Project.toml b/gen/Project.toml new file mode 100644 index 0000000..4a956a7 --- /dev/null +++ b/gen/Project.toml @@ -0,0 +1,6 @@ +[deps] +Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31" +NLopt_jll = "079eb43e-fd8e-5478-9966-2cf3e3edb778" + +[compat] +Clang = "0.17" diff --git a/gen/gen.jl b/gen/gen.jl new file mode 100644 index 0000000..332fd0a --- /dev/null +++ b/gen/gen.jl @@ -0,0 +1,33 @@ +# Copyright (c) 2019 Mathieu Besançon, Oscar Dowson, and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +using Clang.Generators +import NLopt_jll + +c_api = joinpath(NLopt_jll.artifact_dir, "include", "nlopt.h") + +build!( + create_context( + [c_api], + get_default_args(), + load_options(joinpath(@__DIR__, "generate.toml")), + ), +) + +header = """ +# Copyright (c) 2013: Steven G. Johnson and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +#! format: off + +""" + +filename = joinpath(@__DIR__, "..", "src", "libnlopt.jl") +contents = read(filename, String) +contents = header * contents +contents = replace(contents, "const nlopt_opt = Ptr{nlopt_opt_s}" => "const nlopt_opt = Ptr{Cvoid}") +write(filename, contents) diff --git a/gen/generate.toml b/gen/generate.toml new file mode 100644 index 0000000..041be5c --- /dev/null +++ b/gen/generate.toml @@ -0,0 +1,7 @@ +[general] +library_name = "libnlopt" +output_file_path = "src/libnlopt.jl" +# print_enum_as_integer = true +# print_using_CEnum = false +opaque_as_mutable_struct = false +opaque_func_arg_as_PtrCvoid = true diff --git a/src/NLopt.jl b/src/NLopt.jl index bf67372..f8c6f9a 100644 --- a/src/NLopt.jl +++ b/src/NLopt.jl @@ -50,6 +50,9 @@ export Opt, using NLopt_jll +using CEnum +include("libnlopt.jl") + ############################################################################ # Mirrors of NLopt's C enum constants: @@ -100,6 +103,8 @@ using NLopt_jll GN_AGS = 43 end +Base.convert(::Type{nlopt_algorithm}, a::Algorithm) = nlopt_algorithm(Int(a)) + const sym2alg = Dict(Symbol(i) => i for i in instances(Algorithm)) function Algorithm(name::Symbol) @@ -125,6 +130,9 @@ end MAXTIME_REACHED = 6 end +Base.convert(::Type{nlopt_result}, r::Result) = nlopt_result(Int(r)) +Base.convert(::Type{Result}, r::nlopt_result) = Result(Int(r)) + # so that result < 0 checks continue to work Base.isless(x::Integer, r::Result) = isless(x, Cint(r)) Base.isless(r::Result, x::Integer) = isless(Cint(r), x) @@ -135,22 +143,24 @@ Base.:(==)(r::Result, s::Symbol) = s == r ############################################################################ # wrapper around nlopt_opt type -const _Opt = Ptr{Cvoid} # nlopt_opt - # pass both f and o to the callback so that we can handle exceptions mutable struct Callback_Data f::Function o::Any # should be Opt, but see Julia issue #269 end +function Base.unsafe_convert(::Type{Ptr{Cvoid}}, c::Callback_Data) + return pointer_from_objref(c) +end + mutable struct Opt - opt::_Opt + opt::Ptr{Cvoid} # need to store callback data for objective and constraints in # Opt so that they aren't garbage-collected. cb[1] is the objective. cb::Vector{Callback_Data} - function Opt(p::_Opt) + function Opt(p::Ptr{Cvoid}) opt = new(p, Array{Callback_Data}(undef, 1)) finalizer(destroy, opt) return opt @@ -160,13 +170,7 @@ mutable struct Opt if n < 0 throw(ArgumentError("invalid dimension $n < 0")) end - p = ccall( - (:nlopt_create, libnlopt), - _Opt, - (Algorithm, Cuint), - algorithm, - n, - ) + p = nlopt_create(algorithm, n) if p == C_NULL error("Error in nlopt_create") end @@ -178,17 +182,13 @@ mutable struct Opt end end -Base.unsafe_convert(::Type{_Opt}, o::Opt) = getfield(o, :opt) # for passing to ccall +Base.unsafe_convert(::Type{Ptr{Cvoid}}, o::Opt) = getfield(o, :opt) -destroy(o::Opt) = ccall((:nlopt_destroy, libnlopt), Cvoid, (_Opt,), o) +destroy(o::Opt) = nlopt_destroy(o) -function Base.ndims(o::Opt) - return Int(ccall((:nlopt_get_dimension, libnlopt), Cuint, (_Opt,), o)) -end +Base.ndims(o::Opt)::Int = nlopt_get_dimension(o) -function algorithm(o::Opt) - return ccall((:nlopt_get_algorithm, libnlopt), Algorithm, (_Opt,), o) -end +algorithm(o::Opt)::Algorithm = nlopt_get_algorithm(o) Base.show(io::IO, o::Opt) = print(io, "Opt($(algorithm(o)), $(ndims(o)))") @@ -203,7 +203,7 @@ function munge_callback(p::Ptr{Cvoid}, f_::Ptr{Cvoid}) end function Base.copy(o::Opt) - p = ccall((:nlopt_copy, libnlopt), _Opt, (_Opt,), o) + p = nlopt_copy(o) if p == C_NULL error("Error in nlopt_copy") end @@ -235,16 +235,11 @@ function Base.copy(o::Opt) catch end end - munge_callback_ptr = - @cfunction(munge_callback, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid})) - ccall( - (:nlopt_munge_data, libnlopt), - Cvoid, - (_Opt, Ptr{Cvoid}, Any), + c_fn = @cfunction(munge_callback, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid})) + nlopt_munge_data( n, - munge_callback_ptr, - p::Ptr{Cvoid} -> - p == C_NULL ? C_NULL : pointer_from_objref(ncb[cbi[p]]), + c_fn, + p -> p == C_NULL ? C_NULL : pointer_from_objref(ncb[cbi[p]]), ) return n end @@ -258,7 +253,7 @@ struct ForcedStop <: Exception end nlopt_exception = nothing function errmsg(o::Opt) - msg = ccall((:nlopt_get_errmsg, libnlopt), Ptr{UInt8}, (_Opt,), o) + msg = nlopt_get_errmsg(o) return msg == C_NULL ? nothing : unsafe_string(msg) end @@ -268,6 +263,9 @@ function _errmsg(o::Opt) end # check result and throw an exception if necessary +chk(o::Opt, result::nlopt_result) = chk(o, convert(Result, result)) +chk(o::Opt, result::Integer) = chk(o, Result(result)) + function chk(o::Opt, result::Result) if result >= 0 return @@ -292,109 +290,108 @@ end ############################################################################ # getting and setting scalar and vector parameters -# make a quoted symbol expression out of the arguments -qsym(args...) = Expr(:quote, Symbol(string(args...))) +stopval(o::Opt) = nlopt_get_stopval(o) +stopval!(o::Opt, val::Real) = chk(o, nlopt_set_stopval(o, val)) -# scalar parameters p of type T -macro GETSET(T, p) - Tg = T == :Cdouble ? :Real : (T == :Cint || T == :Cuint ? :Integer : :Any) - ps = Symbol(string(p, "!")) - quote - function $(esc(p))(o::Opt) - return ccall(($(qsym("nlopt_get_", p)), libnlopt), $T, (_Opt,), o) - end +ftol_rel(o::Opt) = nlopt_get_ftol_rel(o) +ftol_rel!(o::Opt, val::Real) = chk(o, nlopt_set_ftol_rel(o, val)) - function $(esc(ps))(o::Opt, val::$Tg) - ret = ccall( - ($(qsym("nlopt_set_", p)), libnlopt), - Result, - (_Opt, $T), - o, - val, - ) - return chk(o, ret) - end +ftol_abs(o::Opt) = nlopt_get_ftol_abs(o) +ftol_abs!(o::Opt, val::Real) = chk(o, nlopt_set_ftol_abs(o, val)) + +xtol_rel(o::Opt) = nlopt_get_xtol_rel(o) +xtol_rel!(o::Opt, val::Real) = chk(o, nlopt_set_xtol_rel(o, val)) + +maxeval(o::Opt) = nlopt_get_maxeval(o) +maxeval!(o::Opt, val::Integer) = chk(o, nlopt_set_maxeval(o, val)) + +maxtime(o::Opt) = nlopt_get_maxtime(o) +maxtime!(o::Opt, val::Real) = chk(o, nlopt_set_maxtime(o, val)) + +force_stop(o::Opt) = nlopt_get_force_stop(o) +force_stop!(o::Opt, val::Integer) = chk(o, nlopt_set_force_stop(o, val)) +force_stop!(o::Opt) = force_stop!(o, 1) + +population(o::Opt) = nlopt_get_population(o) +population!(o::Opt, val::Integer) = chk(o, nlopt_set_population(o, val)) + +vector_storage(o::Opt) = nlopt_get_vector_storage(o) +vector_storage!(o::Opt, val::Integer) = chk(o, nlopt_set_vector_storage(o, val)) + +############################################################################ +# Optimizer parameters + +function lower_bounds( + o::Opt, + v::Vector{Cdouble} = Array{Cdouble}(undef, ndims(o)), +) + if length(v) != ndims(o) + throw(BoundsError()) end + chk(o, nlopt_get_lower_bounds(o, v)) + return v end -# Vector{Cdouble} parameters p -macro GETSET_VEC(p) - ps = Symbol(string(p, "!")) - quote - function $(esc(p))(o::Opt, v::Vector{Cdouble}) - if length(v) != ndims(o) - throw(BoundsError()) - end - ret = ccall( - ($(qsym("nlopt_get_", p)), libnlopt), - Result, - (_Opt, Ptr{Cdouble}), - o, - v, - ) - chk(o, ret) - return v - end +function lower_bounds!(o::Opt, v::Vector{Cdouble}) + if length(v) != ndims(o) + throw(BoundsError()) + end + return chk(o, nlopt_set_lower_bounds(o, v)) +end - $(esc(p))(o::Opt) = $(esc(p))(o, Array{Cdouble}(undef, ndims(o))) +function lower_bounds!(o::Opt, v::AbstractVector{<:Real}) + return lower_bounds!(o, Array{Cdouble}(v)) +end - function $(esc(ps))(o::Opt, v::Vector{Cdouble}) - if length(v) != ndims(o) - throw(BoundsError()) - end - ret = ccall( - ($(qsym("nlopt_set_", p)), libnlopt), - Result, - (_Opt, Ptr{Cdouble}), - o, - v, - ) - return chk(o, ret) - end +lower_bounds!(o::Opt, val::Real) = chk(o, nlopt_set_lower_bounds1(o, val)) - function $(esc(ps))(o::Opt, v::AbstractVector{<:Real}) - return $(esc(ps))(o, Array{Cdouble}(v)) - end +function upper_bounds( + o::Opt, + v::Vector{Cdouble} = Array{Cdouble}(undef, ndims(o)), +) + if length(v) != ndims(o) + throw(BoundsError()) + end + chk(o, nlopt_get_upper_bounds(o, v)) + return v +end - function $(esc(ps))(o::Opt, val::Real) - ret = ccall( - ($(qsym("nlopt_set_", p, "1")), libnlopt), - Result, - (_Opt, Cdouble), - o, - val, - ) - return chk(o, ret) - end +function upper_bounds!(o::Opt, v::Vector{Cdouble}) + if length(v) != ndims(o) + throw(BoundsError()) end + return chk(o, nlopt_set_upper_bounds(o, v)) end -############################################################################ -# Optimizer parameters +function upper_bounds!(o::Opt, v::AbstractVector{<:Real}) + return upper_bounds!(o, Array{Cdouble}(v)) +end -@GETSET_VEC lower_bounds -@GETSET_VEC upper_bounds -@GETSET Cdouble stopval -@GETSET Cdouble ftol_rel -@GETSET Cdouble ftol_abs -@GETSET Cdouble xtol_rel -@GETSET_VEC xtol_abs -@GETSET Cint maxeval -@GETSET Cdouble maxtime -@GETSET Cint force_stop -@GETSET Cuint population -@GETSET Cuint vector_storage +upper_bounds!(o::Opt, val::Real) = chk(o, nlopt_set_upper_bounds1(o, val)) -force_stop!(o::Opt) = force_stop!(o, 1) +function xtol_abs(o::Opt, v::Vector{Cdouble} = Array{Cdouble}(undef, ndims(o))) + if length(v) != ndims(o) + throw(BoundsError()) + end + chk(o, nlopt_get_xtol_abs(o, v)) + return v +end + +function xtol_abs!(o::Opt, v::Vector{Cdouble}) + if length(v) != ndims(o) + throw(BoundsError()) + end + return chk(o, nlopt_set_xtol_abs(o, v)) +end + +function xtol_abs!(o::Opt, v::AbstractVector{<:Real}) + return xtol_abs!(o, Array{Cdouble}(v)) +end + +xtol_abs!(o::Opt, val::Real) = chk(o, nlopt_set_xtol_abs1(o, val)) function local_optimizer!(o::Opt, lo::Opt) - ret = ccall( - (:nlopt_set_local_optimizer, libnlopt), - Result, - (_Opt, _Opt), - o, - lo, - ) + ret = nlopt_set_local_optimizer(o, lo) return chk(o, ret) end @@ -405,13 +402,7 @@ function default_initial_step!(o::Opt, x::Vector{Cdouble}) if length(x) != ndims(o) throw(BoundsError()) end - ret = ccall( - (:nlopt_set_default_initial_step, libnlopt), - Result, - (_Opt, Ptr{Cdouble}), - o, - x, - ) + ret = nlopt_set_default_initial_step(o, x) return chk(o, ret) end @@ -423,13 +414,7 @@ function initial_step!(o::Opt, dx::Vector{Cdouble}) if length(dx) != ndims(o) throw(BoundsError()) end - ret = ccall( - (:nlopt_set_initial_step, libnlopt), - Result, - (_Opt, Ptr{Cdouble}), - o, - dx, - ) + ret = nlopt_set_initial_step(o, dx) return chk(o, ret) end @@ -438,13 +423,7 @@ function initial_step!(o::Opt, dx::AbstractVector{<:Real}) end function initial_step!(o::Opt, dx::Real) - ret = ccall( - (:nlopt_set_initial_step1, libnlopt), - Result, - (_Opt, Cdouble), - o, - dx, - ) + ret = nlopt_set_initial_step1(o, dx) return chk(o, ret) end @@ -452,14 +431,7 @@ function initial_step(o::Opt, x::Vector{Cdouble}, dx::Vector{Cdouble}) if length(x) != ndims(o) || length(dx) != ndims(o) throw(BoundsError()) end - ret = ccall( - (:nlopt_get_initial_step, libnlopt), - Result, - (_Opt, Ptr{Cdouble}, Ptr{Cdouble}), - o, - x, - dx, - ) + ret::Result = nlopt_get_initial_step(o, x, dx) chk(o, ret) return dx end @@ -471,7 +443,7 @@ end ############################################################################ function algorithm_name(a::Algorithm) - s = ccall((:nlopt_algorithm_name, libnlopt), Ptr{UInt8}, (Algorithm,), a) + s = nlopt_algorithm_name(a) if s == C_NULL throw(ArgumentError("invalid algorithm $a")) end @@ -487,20 +459,13 @@ function Base.show(io::IO, ::MIME"text/plain", a::Algorithm) return print(io, ": ", algorithm_name(a)) end -numevals(o::Opt) = ccall((:nlopt_get_numevals, libnlopt), Cint, (_Opt,), o) +numevals(o::Opt) = nlopt_get_numevals(o) ############################################################################ function version() major, minor, patch = Ref{Cint}(), Ref{Cint}(), Ref{Cint}() - ccall( - (:nlopt_version, libnlopt), - Cvoid, - (Ref{Cint}, Ref{Cint}, Ref{Cint}), - major, - minor, - patch, - ) + nlopt_version(major, minor, patch) return VersionNumber(major[], minor[], patch[]) end @@ -508,9 +473,9 @@ const NLOPT_VERSION = version() ############################################################################ -srand(seed::Integer) = ccall((:nlopt_srand, libnlopt), Cvoid, (Culong,), seed) +srand(seed::Integer) = nlopt_srand(seed) -srand_time() = ccall((:nlopt_srand_time, libnlopt), Cvoid, ()) +srand_time() = nlopt_srand_time() ############################################################################ # Objective function: @@ -541,68 +506,63 @@ function nlopt_callback_wrapper( end end -for m in (:min, :max) - mf = Symbol(string(m, "_objective!")) - @eval function $mf(o::Opt, f::Function) - getfield(o, :cb)[1] = Callback_Data(f, o) - nlopt_callback_wrapper_ptr = @cfunction( - nlopt_callback_wrapper, - Cdouble, - (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) - ) - ret = ccall( - ($(qsym("nlopt_set_", m, "_objective")), libnlopt), - Result, - (_Opt, Ptr{Cvoid}, Any), - o, - nlopt_callback_wrapper_ptr, - getfield(o, :cb)[1], - ) - return chk(o, ret) - end +function min_objective!(o::Opt, f::Function) + cb = Callback_Data(f, o) + getfield(o, :cb)[1] = cb + c_fn = @cfunction( + nlopt_callback_wrapper, + Cdouble, + (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) + ) + ret = nlopt_set_min_objective(o, c_fn, cb) + return chk(o, ret) +end + +function max_objective!(o::Opt, f::Function) + cb = Callback_Data(f, o) + getfield(o, :cb)[1] = cb + c_fn = @cfunction( + nlopt_callback_wrapper, + Cdouble, + (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) + ) + ret = nlopt_set_max_objective(o, c_fn, cb) + return chk(o, ret) end ############################################################################ # Nonlinear constraints: -for c in (:inequality, :equality) - cf = Symbol(string(c, "_constraint!")) - @eval function $cf(o::Opt, f::Function, tol::Real = 0.0) - push!(getfield(o, :cb), Callback_Data(f, o)) - nlopt_callback_wrapper_ptr = @cfunction( - nlopt_callback_wrapper, - Cdouble, - (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) - ) - ret = ccall( - ($(qsym("nlopt_add_", c, "_constraint")), libnlopt), - Result, - (_Opt, Ptr{Cvoid}, Any, Cdouble), - o, - nlopt_callback_wrapper_ptr, - getfield(o, :cb)[end], - tol, - ) - return chk(o, ret) - end +function inequality_constraint!(o::Opt, f::Function, tol::Real = 0.0) + cb = Callback_Data(f, o) + push!(getfield(o, :cb), cb) + c_fn = @cfunction( + nlopt_callback_wrapper, + Cdouble, + (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) + ) + ret::Result = nlopt_add_inequality_constraint(o, c_fn, cb, tol) + return chk(o, ret) +end + +function equality_constraint!(o::Opt, f::Function, tol::Real = 0.0) + cb = Callback_Data(f, o) + push!(getfield(o, :cb), cb) + c_fn = @cfunction( + nlopt_callback_wrapper, + Cdouble, + (Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}) + ) + ret::Result = nlopt_add_equality_constraint(o, c_fn, cb, tol) + return chk(o, ret) end function remove_constraints!(o::Opt) resize!(getfield(o, :cb), 1) - ret = ccall( - (:nlopt_remove_inequality_constraints, libnlopt), - Result, - (_Opt,), - o, - ) + ret = nlopt_remove_inequality_constraints(o) chk(o, ret) # TODO(odow): why is this called twice? - ret = ccall( - (:nlopt_remove_equality_constraints, libnlopt), - Result, - (_Opt,), - o, - ) + ret = nlopt_remove_equality_constraints(o) return chk(o, ret) end @@ -638,40 +598,54 @@ function nlopt_vcallback_wrapper( return nothing end -for c in (:inequality, :equality) - cf = Symbol(string(c, "_constraint!")) - @eval begin - function $cf(o::Opt, f::Function, tol::Vector{Cdouble}) - push!(getfield(o, :cb), Callback_Data(f, o)) - nlopt_vcallback_wrapper_ptr = @cfunction( - nlopt_vcallback_wrapper, - Cvoid, - ( - Cuint, - Ptr{Cdouble}, - Cuint, - Ptr{Cdouble}, - Ptr{Cdouble}, - Ptr{Cvoid}, - ) - ) - ret = ccall( - ($(qsym("nlopt_add_", c, "_mconstraint")), libnlopt), - Result, - (_Opt, Cuint, Ptr{Cvoid}, Any, Ptr{Cdouble}), - o, - length(tol), - nlopt_vcallback_wrapper_ptr, - getfield(o, :cb)[end], - tol, - ) - return chk(o, ret) - end - $cf(o::Opt, f::Function, tol::AbstractVector{<:Real}) = - $cf(o, f, Array{Float64}(tol)) - $cf(o::Opt, m::Integer, f::Function, tol::Real = 0.0) = - $cf(o, f, fill(Cdouble(tol), m)) - end +function inequality_constraint!(o::Opt, f::Function, tol::Vector{Cdouble}) + cb = Callback_Data(f, o) + push!(getfield(o, :cb), cb) + c_fn = @cfunction( + nlopt_vcallback_wrapper, + Cvoid, + (Cuint, Ptr{Cdouble}, Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}), + ) + ret::Result = + nlopt_add_inequality_mconstraint(o, length(tol), c_fn, cb, tol) + return chk(o, ret) +end + +function inequality_constraint!( + o::Opt, + f::Function, + tol::AbstractVector{<:Real}, +) + return inequality_constraint!(o, f, Array{Float64}(tol)) +end + +function inequality_constraint!( + o::Opt, + m::Integer, + f::Function, + tol::Real = 0.0, +) + return inequality_constraint!(o, f, fill(Cdouble(tol), m)) +end + +function equality_constraint!(o::Opt, f::Function, tol::Vector{Cdouble}) + cb = Callback_Data(f, o) + push!(getfield(o, :cb), cb) + c_fn = @cfunction( + nlopt_vcallback_wrapper, + Cvoid, + (Cuint, Ptr{Cdouble}, Cuint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cvoid}), + ) + ret::Result = nlopt_add_equality_mconstraint(o, length(tol), c_fn, cb, tol) + return chk(o, ret) +end + +function equality_constraint!(o::Opt, f::Function, tol::AbstractVector{<:Real}) + return equality_constraint!(o, f, Array{Float64}(tol)) +end + +function equality_constraint!(o::Opt, m::Integer, f::Function, tol::Real = 0.0) + return equality_constraint!(o, f, fill(Cdouble(tol), m)) end ############################################################################ @@ -688,48 +662,23 @@ struct OptParams <: AbstractDict{String,Float64} o::Opt end -function Base.length(p::OptParams) - return Int(ccall(("nlopt_num_params", libnlopt), Cuint, (_Opt,), p.o)) -end +Base.length(p::OptParams)::Int = nlopt_num_params(p.o) -function Base.haskey(p::OptParams, s::AbstractString) - return Bool( - ccall(("nlopt_has_param", libnlopt), Cint, (_Opt, Cstring), p.o, s), - ) -end +Base.haskey(p::OptParams, s::AbstractString)::Bool = nlopt_has_param(p.o, s) function Base.get(p::OptParams, s::AbstractString, defaultval::Float64) - return ccall( - ("nlopt_get_param", libnlopt), - Cdouble, - (_Opt, Cstring, Cdouble), - p.o, - s, - defaultval, - ) + return nlopt_get_param(p.o, s, defaultval) end function Base.get(p::OptParams, s::AbstractString, defaultval) - return haskey(p, s) ? - ccall( - ("nlopt_get_param", libnlopt), - Cdouble, - (_Opt, Cstring, Cdouble), - p.o, - s, - NaN, - ) : defaultval + if !haskey(p, s) + return defaultval + end + return nlopt_get_param(p.o, s, NaN) end function Base.setindex!(p::OptParams, v::Real, s::AbstractString) - ret = ccall( - ("nlopt_set_param", libnlopt), - Result, - (_Opt, Cstring, Cdouble), - p.o, - s, - v, - ) + ret = nlopt_set_param(p.o, s, v) return chk(p.o, ret) end @@ -741,13 +690,7 @@ function Base.iterate(p::OptParams, state = 0) if state ≥ length(p) return nothing end - name_ptr = ccall( - ("nlopt_nth_param", libnlopt), - Ptr{UInt8}, - (_Opt, Cuint), - p.o, - state, - ) + name_ptr = nlopt_nth_param(p.o, state) @assert name_ptr != C_NULL name = unsafe_string(name_ptr) return (name => p[name], state + 1) @@ -882,14 +825,7 @@ function optimize!(o::Opt, x::Vector{Cdouble}) throw(BoundsError()) end opt_f = Array{Cdouble}(undef, 1) - ret = ccall( - (:nlopt_optimize, libnlopt), - Result, - (_Opt, Ptr{Cdouble}, Ptr{Cdouble}), - o, - x, - opt_f, - ) + ret::Result = nlopt_optimize(o, x, opt_f) # We do not need to check the value of `ret`, except if it is a FORCED_STOP # with a Julia-related exception from a callback if ret == FORCED_STOP diff --git a/src/libnlopt.jl b/src/libnlopt.jl new file mode 100644 index 0000000..5a52da7 --- /dev/null +++ b/src/libnlopt.jl @@ -0,0 +1,418 @@ +# Copyright (c) 2013: Steven G. Johnson and contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +#! format: off + +using CEnum + +# typedef double ( * nlopt_func ) ( unsigned n , const double * x , double * gradient , /* NULL if not needed */ void * func_data ) +const nlopt_func = Ptr{Cvoid} + +# typedef void ( * nlopt_mfunc ) ( unsigned m , double * result , unsigned n , const double * x , double * gradient , /* NULL if not needed */ void * func_data ) +const nlopt_mfunc = Ptr{Cvoid} + +# typedef void ( * nlopt_precond ) ( unsigned n , const double * x , const double * v , double * vpre , void * data ) +const nlopt_precond = Ptr{Cvoid} + +@cenum nlopt_algorithm::UInt32 begin + NLOPT_GN_DIRECT = 0 + NLOPT_GN_DIRECT_L = 1 + NLOPT_GN_DIRECT_L_RAND = 2 + NLOPT_GN_DIRECT_NOSCAL = 3 + NLOPT_GN_DIRECT_L_NOSCAL = 4 + NLOPT_GN_DIRECT_L_RAND_NOSCAL = 5 + NLOPT_GN_ORIG_DIRECT = 6 + NLOPT_GN_ORIG_DIRECT_L = 7 + NLOPT_GD_STOGO = 8 + NLOPT_GD_STOGO_RAND = 9 + NLOPT_LD_LBFGS_NOCEDAL = 10 + NLOPT_LD_LBFGS = 11 + NLOPT_LN_PRAXIS = 12 + NLOPT_LD_VAR1 = 13 + NLOPT_LD_VAR2 = 14 + NLOPT_LD_TNEWTON = 15 + NLOPT_LD_TNEWTON_RESTART = 16 + NLOPT_LD_TNEWTON_PRECOND = 17 + NLOPT_LD_TNEWTON_PRECOND_RESTART = 18 + NLOPT_GN_CRS2_LM = 19 + NLOPT_GN_MLSL = 20 + NLOPT_GD_MLSL = 21 + NLOPT_GN_MLSL_LDS = 22 + NLOPT_GD_MLSL_LDS = 23 + NLOPT_LD_MMA = 24 + NLOPT_LN_COBYLA = 25 + NLOPT_LN_NEWUOA = 26 + NLOPT_LN_NEWUOA_BOUND = 27 + NLOPT_LN_NELDERMEAD = 28 + NLOPT_LN_SBPLX = 29 + NLOPT_LN_AUGLAG = 30 + NLOPT_LD_AUGLAG = 31 + NLOPT_LN_AUGLAG_EQ = 32 + NLOPT_LD_AUGLAG_EQ = 33 + NLOPT_LN_BOBYQA = 34 + NLOPT_GN_ISRES = 35 + NLOPT_AUGLAG = 36 + NLOPT_AUGLAG_EQ = 37 + NLOPT_G_MLSL = 38 + NLOPT_G_MLSL_LDS = 39 + NLOPT_LD_SLSQP = 40 + NLOPT_LD_CCSAQ = 41 + NLOPT_GN_ESCH = 42 + NLOPT_GN_AGS = 43 + NLOPT_NUM_ALGORITHMS = 44 +end + +function nlopt_algorithm_name(a) + ccall((:nlopt_algorithm_name, libnlopt), Ptr{Cchar}, (nlopt_algorithm,), a) +end + +function nlopt_algorithm_to_string(algorithm) + ccall((:nlopt_algorithm_to_string, libnlopt), Ptr{Cchar}, (nlopt_algorithm,), algorithm) +end + +function nlopt_algorithm_from_string(name) + ccall((:nlopt_algorithm_from_string, libnlopt), nlopt_algorithm, (Ptr{Cchar},), name) +end + +@cenum nlopt_result::Int32 begin + NLOPT_FAILURE = -1 + NLOPT_INVALID_ARGS = -2 + NLOPT_OUT_OF_MEMORY = -3 + NLOPT_ROUNDOFF_LIMITED = -4 + NLOPT_FORCED_STOP = -5 + NLOPT_NUM_FAILURES = -6 + NLOPT_SUCCESS = 1 + NLOPT_STOPVAL_REACHED = 2 + NLOPT_FTOL_REACHED = 3 + NLOPT_XTOL_REACHED = 4 + NLOPT_MAXEVAL_REACHED = 5 + NLOPT_MAXTIME_REACHED = 6 + NLOPT_NUM_RESULTS = 7 +end + +function nlopt_result_to_string(algorithm) + ccall((:nlopt_result_to_string, libnlopt), Ptr{Cchar}, (nlopt_result,), algorithm) +end + +function nlopt_result_from_string(name) + ccall((:nlopt_result_from_string, libnlopt), nlopt_result, (Ptr{Cchar},), name) +end + +function nlopt_srand(seed) + ccall((:nlopt_srand, libnlopt), Cvoid, (Culong,), seed) +end + +function nlopt_srand_time() + ccall((:nlopt_srand_time, libnlopt), Cvoid, ()) +end + +function nlopt_version(major, minor, bugfix) + ccall((:nlopt_version, libnlopt), Cvoid, (Ptr{Cint}, Ptr{Cint}, Ptr{Cint}), major, minor, bugfix) +end + +mutable struct nlopt_opt_s end + +const nlopt_opt = Ptr{Cvoid} + +function nlopt_create(algorithm, n) + ccall((:nlopt_create, libnlopt), nlopt_opt, (nlopt_algorithm, Cuint), algorithm, n) +end + +function nlopt_destroy(opt) + ccall((:nlopt_destroy, libnlopt), Cvoid, (nlopt_opt,), opt) +end + +function nlopt_copy(opt) + ccall((:nlopt_copy, libnlopt), nlopt_opt, (nlopt_opt,), opt) +end + +function nlopt_optimize(opt, x, opt_f) + ccall((:nlopt_optimize, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}, Ptr{Cdouble}), opt, x, opt_f) +end + +function nlopt_set_min_objective(opt, f, f_data) + ccall((:nlopt_set_min_objective, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, Ptr{Cvoid}), opt, f, f_data) +end + +function nlopt_set_max_objective(opt, f, f_data) + ccall((:nlopt_set_max_objective, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, Ptr{Cvoid}), opt, f, f_data) +end + +function nlopt_set_precond_min_objective(opt, f, pre, f_data) + ccall((:nlopt_set_precond_min_objective, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, nlopt_precond, Ptr{Cvoid}), opt, f, pre, f_data) +end + +function nlopt_set_precond_max_objective(opt, f, pre, f_data) + ccall((:nlopt_set_precond_max_objective, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, nlopt_precond, Ptr{Cvoid}), opt, f, pre, f_data) +end + +function nlopt_get_algorithm(opt) + ccall((:nlopt_get_algorithm, libnlopt), nlopt_algorithm, (nlopt_opt,), opt) +end + +function nlopt_get_dimension(opt) + ccall((:nlopt_get_dimension, libnlopt), Cuint, (nlopt_opt,), opt) +end + +function nlopt_get_errmsg(opt) + ccall((:nlopt_get_errmsg, libnlopt), Ptr{Cchar}, (nlopt_opt,), opt) +end + +function nlopt_set_param(opt, name, val) + ccall((:nlopt_set_param, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cchar}, Cdouble), opt, name, val) +end + +function nlopt_get_param(opt, name, defaultval) + ccall((:nlopt_get_param, libnlopt), Cdouble, (nlopt_opt, Ptr{Cchar}, Cdouble), opt, name, defaultval) +end + +function nlopt_has_param(opt, name) + ccall((:nlopt_has_param, libnlopt), Cint, (nlopt_opt, Ptr{Cchar}), opt, name) +end + +function nlopt_num_params(opt) + ccall((:nlopt_num_params, libnlopt), Cuint, (nlopt_opt,), opt) +end + +function nlopt_nth_param(opt, n) + ccall((:nlopt_nth_param, libnlopt), Ptr{Cchar}, (nlopt_opt, Cuint), opt, n) +end + +function nlopt_set_lower_bounds(opt, lb) + ccall((:nlopt_set_lower_bounds, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, lb) +end + +function nlopt_set_lower_bounds1(opt, lb) + ccall((:nlopt_set_lower_bounds1, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, lb) +end + +function nlopt_set_lower_bound(opt, i, lb) + ccall((:nlopt_set_lower_bound, libnlopt), nlopt_result, (nlopt_opt, Cint, Cdouble), opt, i, lb) +end + +function nlopt_get_lower_bounds(opt, lb) + ccall((:nlopt_get_lower_bounds, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, lb) +end + +function nlopt_set_upper_bounds(opt, ub) + ccall((:nlopt_set_upper_bounds, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, ub) +end + +function nlopt_set_upper_bounds1(opt, ub) + ccall((:nlopt_set_upper_bounds1, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, ub) +end + +function nlopt_set_upper_bound(opt, i, ub) + ccall((:nlopt_set_upper_bound, libnlopt), nlopt_result, (nlopt_opt, Cint, Cdouble), opt, i, ub) +end + +function nlopt_get_upper_bounds(opt, ub) + ccall((:nlopt_get_upper_bounds, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, ub) +end + +function nlopt_remove_inequality_constraints(opt) + ccall((:nlopt_remove_inequality_constraints, libnlopt), nlopt_result, (nlopt_opt,), opt) +end + +function nlopt_add_inequality_constraint(opt, fc, fc_data, tol) + ccall((:nlopt_add_inequality_constraint, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, Ptr{Cvoid}, Cdouble), opt, fc, fc_data, tol) +end + +function nlopt_add_precond_inequality_constraint(opt, fc, pre, fc_data, tol) + ccall((:nlopt_add_precond_inequality_constraint, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, nlopt_precond, Ptr{Cvoid}, Cdouble), opt, fc, pre, fc_data, tol) +end + +function nlopt_add_inequality_mconstraint(opt, m, fc, fc_data, tol) + ccall((:nlopt_add_inequality_mconstraint, libnlopt), nlopt_result, (nlopt_opt, Cuint, nlopt_mfunc, Ptr{Cvoid}, Ptr{Cdouble}), opt, m, fc, fc_data, tol) +end + +function nlopt_remove_equality_constraints(opt) + ccall((:nlopt_remove_equality_constraints, libnlopt), nlopt_result, (nlopt_opt,), opt) +end + +function nlopt_add_equality_constraint(opt, h, h_data, tol) + ccall((:nlopt_add_equality_constraint, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, Ptr{Cvoid}, Cdouble), opt, h, h_data, tol) +end + +function nlopt_add_precond_equality_constraint(opt, h, pre, h_data, tol) + ccall((:nlopt_add_precond_equality_constraint, libnlopt), nlopt_result, (nlopt_opt, nlopt_func, nlopt_precond, Ptr{Cvoid}, Cdouble), opt, h, pre, h_data, tol) +end + +function nlopt_add_equality_mconstraint(opt, m, h, h_data, tol) + ccall((:nlopt_add_equality_mconstraint, libnlopt), nlopt_result, (nlopt_opt, Cuint, nlopt_mfunc, Ptr{Cvoid}, Ptr{Cdouble}), opt, m, h, h_data, tol) +end + +function nlopt_set_stopval(opt, stopval) + ccall((:nlopt_set_stopval, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, stopval) +end + +function nlopt_get_stopval(opt) + ccall((:nlopt_get_stopval, libnlopt), Cdouble, (nlopt_opt,), opt) +end + +function nlopt_set_ftol_rel(opt, tol) + ccall((:nlopt_set_ftol_rel, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, tol) +end + +function nlopt_get_ftol_rel(opt) + ccall((:nlopt_get_ftol_rel, libnlopt), Cdouble, (nlopt_opt,), opt) +end + +function nlopt_set_ftol_abs(opt, tol) + ccall((:nlopt_set_ftol_abs, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, tol) +end + +function nlopt_get_ftol_abs(opt) + ccall((:nlopt_get_ftol_abs, libnlopt), Cdouble, (nlopt_opt,), opt) +end + +function nlopt_set_xtol_rel(opt, tol) + ccall((:nlopt_set_xtol_rel, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, tol) +end + +function nlopt_get_xtol_rel(opt) + ccall((:nlopt_get_xtol_rel, libnlopt), Cdouble, (nlopt_opt,), opt) +end + +function nlopt_set_xtol_abs1(opt, tol) + ccall((:nlopt_set_xtol_abs1, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, tol) +end + +function nlopt_set_xtol_abs(opt, tol) + ccall((:nlopt_set_xtol_abs, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, tol) +end + +function nlopt_get_xtol_abs(opt, tol) + ccall((:nlopt_get_xtol_abs, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, tol) +end + +function nlopt_set_x_weights1(opt, w) + ccall((:nlopt_set_x_weights1, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, w) +end + +function nlopt_set_x_weights(opt, w) + ccall((:nlopt_set_x_weights, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, w) +end + +function nlopt_get_x_weights(opt, w) + ccall((:nlopt_get_x_weights, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, w) +end + +function nlopt_set_maxeval(opt, maxeval) + ccall((:nlopt_set_maxeval, libnlopt), nlopt_result, (nlopt_opt, Cint), opt, maxeval) +end + +function nlopt_get_maxeval(opt) + ccall((:nlopt_get_maxeval, libnlopt), Cint, (nlopt_opt,), opt) +end + +function nlopt_get_numevals(opt) + ccall((:nlopt_get_numevals, libnlopt), Cint, (nlopt_opt,), opt) +end + +function nlopt_set_maxtime(opt, maxtime) + ccall((:nlopt_set_maxtime, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, maxtime) +end + +function nlopt_get_maxtime(opt) + ccall((:nlopt_get_maxtime, libnlopt), Cdouble, (nlopt_opt,), opt) +end + +function nlopt_force_stop(opt) + ccall((:nlopt_force_stop, libnlopt), nlopt_result, (nlopt_opt,), opt) +end + +function nlopt_set_force_stop(opt, val) + ccall((:nlopt_set_force_stop, libnlopt), nlopt_result, (nlopt_opt, Cint), opt, val) +end + +function nlopt_get_force_stop(opt) + ccall((:nlopt_get_force_stop, libnlopt), Cint, (nlopt_opt,), opt) +end + +function nlopt_set_local_optimizer(opt, local_opt) + ccall((:nlopt_set_local_optimizer, libnlopt), nlopt_result, (nlopt_opt, nlopt_opt), opt, local_opt) +end + +function nlopt_set_population(opt, pop) + ccall((:nlopt_set_population, libnlopt), nlopt_result, (nlopt_opt, Cuint), opt, pop) +end + +function nlopt_get_population(opt) + ccall((:nlopt_get_population, libnlopt), Cuint, (nlopt_opt,), opt) +end + +function nlopt_set_vector_storage(opt, dim) + ccall((:nlopt_set_vector_storage, libnlopt), nlopt_result, (nlopt_opt, Cuint), opt, dim) +end + +function nlopt_get_vector_storage(opt) + ccall((:nlopt_get_vector_storage, libnlopt), Cuint, (nlopt_opt,), opt) +end + +function nlopt_set_default_initial_step(opt, x) + ccall((:nlopt_set_default_initial_step, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, x) +end + +function nlopt_set_initial_step(opt, dx) + ccall((:nlopt_set_initial_step, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}), opt, dx) +end + +function nlopt_set_initial_step1(opt, dx) + ccall((:nlopt_set_initial_step1, libnlopt), nlopt_result, (nlopt_opt, Cdouble), opt, dx) +end + +function nlopt_get_initial_step(opt, x, dx) + ccall((:nlopt_get_initial_step, libnlopt), nlopt_result, (nlopt_opt, Ptr{Cdouble}, Ptr{Cdouble}), opt, x, dx) +end + +# typedef void * ( * nlopt_munge ) ( void * p ) +const nlopt_munge = Ptr{Cvoid} + +function nlopt_set_munge(opt, munge_on_destroy, munge_on_copy) + ccall((:nlopt_set_munge, libnlopt), Cvoid, (nlopt_opt, nlopt_munge, nlopt_munge), opt, munge_on_destroy, munge_on_copy) +end + +# typedef void * ( * nlopt_munge2 ) ( void * p , void * data ) +const nlopt_munge2 = Ptr{Cvoid} + +function nlopt_munge_data(opt, munge, data) + ccall((:nlopt_munge_data, libnlopt), Cvoid, (nlopt_opt, nlopt_munge2, Ptr{Cvoid}), opt, munge, data) +end + +# typedef double ( * nlopt_func_old ) ( int n , const double * x , double * gradient , /* NULL if not needed */ void * func_data ) +const nlopt_func_old = Ptr{Cvoid} + +function nlopt_minimize(algorithm, n, f, f_data, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, maxeval, maxtime) + ccall((:nlopt_minimize, libnlopt), nlopt_result, (nlopt_algorithm, Cint, nlopt_func_old, Ptr{Cvoid}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Cdouble, Cdouble, Cdouble, Ptr{Cdouble}, Cint, Cdouble), algorithm, n, f, f_data, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, maxeval, maxtime) +end + +function nlopt_minimize_constrained(algorithm, n, f, f_data, m, fc, fc_data, fc_datum_size, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, maxeval, maxtime) + ccall((:nlopt_minimize_constrained, libnlopt), nlopt_result, (nlopt_algorithm, Cint, nlopt_func_old, Ptr{Cvoid}, Cint, nlopt_func_old, Ptr{Cvoid}, Cptrdiff_t, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Cdouble, Cdouble, Cdouble, Ptr{Cdouble}, Cint, Cdouble), algorithm, n, f, f_data, m, fc, fc_data, fc_datum_size, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, maxeval, maxtime) +end + +function nlopt_minimize_econstrained(algorithm, n, f, f_data, m, fc, fc_data, fc_datum_size, p, h, h_data, h_datum_size, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, htol_rel, htol_abs, maxeval, maxtime) + ccall((:nlopt_minimize_econstrained, libnlopt), nlopt_result, (nlopt_algorithm, Cint, nlopt_func_old, Ptr{Cvoid}, Cint, nlopt_func_old, Ptr{Cvoid}, Cptrdiff_t, Cint, nlopt_func_old, Ptr{Cvoid}, Cptrdiff_t, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Cdouble, Cdouble, Cdouble, Ptr{Cdouble}, Cdouble, Cdouble, Cint, Cdouble), algorithm, n, f, f_data, m, fc, fc_data, fc_datum_size, p, h, h_data, h_datum_size, lb, ub, x, minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtol_abs, htol_rel, htol_abs, maxeval, maxtime) +end + +function nlopt_get_local_search_algorithm(deriv, nonderiv, maxeval) + ccall((:nlopt_get_local_search_algorithm, libnlopt), Cvoid, (Ptr{nlopt_algorithm}, Ptr{nlopt_algorithm}, Ptr{Cint}), deriv, nonderiv, maxeval) +end + +function nlopt_set_local_search_algorithm(deriv, nonderiv, maxeval) + ccall((:nlopt_set_local_search_algorithm, libnlopt), Cvoid, (nlopt_algorithm, nlopt_algorithm, Cint), deriv, nonderiv, maxeval) +end + +function nlopt_get_stochastic_population() + ccall((:nlopt_get_stochastic_population, libnlopt), Cint, ()) +end + +function nlopt_set_stochastic_population(pop) + ccall((:nlopt_set_stochastic_population, libnlopt), Cvoid, (Cint,), pop) +end + +const NLOPT_MINF_MAX_REACHED = NLOPT_STOPVAL_REACHED + +# Skipping MacroDefinition: NLOPT_DEPRECATED __attribute__ ( ( deprecated ) )