Quick start
using NonconvexBayesian, NonconvexIpopt
f(x) = sqrt(x[2])
g(x, a, b) = (a*x[1] + b)^3 - x[2]
model = Model()
set_objective!(model, f, flags = [:expensive])
addvar!(model, [1e-4, 1e-4], [10.0, 10.0])
add_ineq_constraint!(model, x -> g(x, 2, 0), flags = [:expensive])
add_ineq_constraint!(model, x -> g(x, -1, 1))
alg = BayesOptAlg(IpoptAlg())
options = BayesOptOptions(
sub_options = IpoptOptions(),
maxiter = 50, ftol = 1e-4, ctol = 1e-5,
)
r = optimize(model, alg, [1.234, 2.345], options = options)The flags = [:expensive] hint marks the functions that should be replaced by surrogates; the remaining functions are kept and modeled natively by the sub-optimizer (see Constraints for how expensive equality and inequality constraints are transformed). Each iteration of the BO loop
- solves the surrogate model (the acquisition) with the sub-optimizer,
- evaluates the true expensive functions at the proposed point, and
- updates the surrogates and the incumbent.
The initial surrogates are seeded by evaluating the true functions at Sobol points (see BayesOptOptions's init_strategy).
Manual surrogates
Surrogates can also be constructed and passed in explicitly:
s1 = surrogate(f, x0) # zero-order surrogate
s2 = first_order_surrogate(g, x0) # gradient-enhanced surrogate
model = Model()
set_objective!(model, x -> get_lo(s1(x)), flags = [:expensive])
add_ineq_constraint!(model, x -> get_lo.(s2(x)), flags = [:expensive])
r = optimize(model, BayesOptAlg(IpoptAlg()), x0,
options = BayesOptOptions(sub_options = IpoptOptions()),
surrogates = [s1, s2])In interval mode s(x) returns an interval with lo = μ(x) - η σ(x) and hi = μ(x) + η σ(x) (LCB); get_lo extracts the lower bound. Equality constraints must be transformed to a 2-block inequality constraint manually as [lo; -hi].