Документация Engee

Использование ограничений в виде равенств и неравенств

Страница в процессе перевода.

Многие пакеты оптимизации, доступные с MathOptInterface и решателем IPNewton из Optim, могут работать с нелинейными ограничениями. Optimization.jl предоставляет простой интерфейс для определения ограничения в виде функции Julia с последующим указанием границ для результата в OptimizationFunction. Таким образом указывается, задано ли ограничение в виде равенства или неравенства.

Давайте определим функцию Розенброка в качестве целевой функции и примем приведенные ниже неравенства как ограничения.

using Optimization, OptimizationMOI, OptimizationOptimJL, Ipopt
using ForwardDiff, ModelingToolkit

rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
x0 = zeros(2)
_p = [1.0, 1.0]
2-element Vector{Float64}:
 1.0
 1.0

Далее определим сумму квадратов и произведение переменных оптимизации в качестве функций ограничений.

cons(res, x, p) = (res .= [x[1]^2 + x[2]^2, x[1] * x[2]])
cons (generic function with 1 method)

Для решения задачи мы используем решатель IPNewton из Optim.

optprob = OptimizationFunction(rosenbrock, Optimization.AutoForwardDiff(), cons = cons)
prob = OptimizationProblem(optprob, x0, _p, lcons = [-Inf, -1.0], ucons = [0.8, 2.0])
sol = solve(prob, IPNewton())
retcode: Success
u: 2-element Vector{Float64}:
 0.7519644536194577
 0.484303066780286

Давайте проверим, выполняются ли ограничения и меньше ли значение целевой функции начальных значений.

res = zeros(2)
cons(res, sol.u, _p)
res
2-element Vector{Float64}:
 0.7999999999999997
 0.36417869099766553
prob.f(sol.u, _p)
0.06810654459826093

Можно также использовать библиотеку Ipopt с пакетом OptimizationMOI.

sol = solve(prob, Ipopt.Optimizer())
retcode: Success
u: 2-element Vector{Float64}:
 0.7519644519971305
 0.4843030638909282
res = zeros(2)
cons(res, sol.u, _p)
res
2-element Vector{Float64}:
 0.7999999947614852
 0.3641786880392731
prob.f(sol.u, _p)
0.06810654547600103

Мы также можем использовать ModelingToolkit в качестве бэкенда автоматического дифференцирования и сгенерировать символьные производные и граф выражений для целевой функции и ограничений.

Давайте изменим границы так, чтобы функция использовалась в качестве ограничения в виде равенства. Теперь ограничение выглядит так:

optprob = OptimizationFunction(rosenbrock, Optimization.AutoSymbolics(), cons = cons)
prob = OptimizationProblem(optprob, x0, _p, lcons = [1.0, 0.5], ucons = [1.0, 0.5])
OptimizationProblem. In-place: true
u0: 2-element Vector{Float64}:
 0.0
 0.0

Ниже для решения этой задачи используется пакет AmplNLWriter.jl с библиотекой Ipopt.

using AmplNLWriter, Ipopt_jll
sol = solve(prob, AmplNLWriter.Optimizer(Ipopt_jll.amplexe))
retcode: Default
u: 2-element Vector{Float64}:
 NaN
 NaN

По результатам вычислений получаются ограничения 1,0 и 0,5 соответственно, как и ожидалось.

res = zeros(2)
cons(res, sol.u, _p)
println(res)
[NaN, NaN]