I am currently working on implementing an algorithm for solving a special type of optimization problem by using JuMP and IPOPT in Julia. This problem requires that I check some kind of statement for each iteration in IPOPT. If the statement comes true, norm(currentValue,Inf) > η*max_val
I want IPOPT to terminate.
I have a vector containing many different expressions, for example like;
a = [x[1] + y^2, x[2] + 2y, x[3]^2]
I am using the callback function to get the different values of the variables at each iteration. However, for each iteration, I want to check the values inside a
. I know that at the end (when optimize! has finished) I can check the values of the expressions by using value.(a)
. Is it possible to do something similar inside the callback function? Something like this;
function my_callback(
alg_mod::Cint,
iter_count::Cint,
obj_value::Float64,
inf_pr::Float64,
inf_du::Float64,
mu::Float64,
d_norm::Float64,
regularization_size::Float64,
alpha_du::Float64,
alpha_pr::Float64,
ls_trials::Cint)
x, z_L, z_U = zeros(n), zeros(n), zeros(n). # x contains the values
g, lambda = zeros(m), zeros(m)
scaled = true
prob = unsafe_backend(model).inner
Ipopt.GetIpoptCurrentIterate(prob, scaled, n, x, z_L, z_U, m, g, lambda)
x_L_violation, x_U_violation = zeros(n), zeros(n)
compl_x_L, compl_x_U, grad_lag_x = zeros(n), zeros(n), zeros(n)
nlp_constraint_violation, compl_g = zeros(m), zeros(m)
Ipopt.GetIpoptCurrentViolations(
prob,
scaled,
n,
x_L_violation,
x_U_violation,
compl_x_L,
compl_x_U,
grad_lag_x,
m,
nlp_constraint_violation,
compl_g,
)
currentValues = a(x) # this is what I want to do but is not working...
return norm(currentValue,Inf) < η*max_val. # the statement
end
MOI.set(model, Ipopt.CallbackFunction(), my_callback)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INTERRUPTED
So, my question is how to get the current value of an expression after each iteration in IPOPT using a callback function?
You can query the value of variables in a callback using callback_value
. See the README for details: https://github.com/jump-dev/Ipopt.jl#solver-specific-callback.
Then, you can evaluate JuMP expressions using value(f, expr)
, where f(x)
returns the value of the variable x
. For example:
julia> using JuMP, Ipopt, LinearAlgebra
julia> model = Model(Ipopt.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Ipopt
julia> @variable(model, x[1:3] >= 1)
3-element Vector{VariableRef}:
x[1]
x[2]
x[3]
julia> @variable(model, y)
y
julia> a = [x[1] + y^2, x[2] + 2y, x[3]^2]
3-element Vector{QuadExpr}:
y² + x[1]
x[2] + 2 y
x[3]²
julia> function my_callback(args...)
function f(xi)
return callback_value(model, xi)
end
a_value = value.(f, a)
return LinearAlgebra.norm(a_value, Inf) < 0.1
end
my_callback (generic function with 1 method)
julia> MOI.set(model, Ipopt.CallbackFunction(), my_callback)
julia> optimize!(model)
This is Ipopt version 3.14.4, running with linear solver MUMPS 5.4.1.
Number of nonzeros in equality constraint Jacobian...: 0
Number of nonzeros in inequality constraint Jacobian.: 0
Number of nonzeros in Lagrangian Hessian.............: 0
Total number of variables............................: 4
variables with only lower bounds: 3
variables with lower and upper bounds: 0
variables with only upper bounds: 0
Total number of equality constraints.................: 0
Total number of inequality constraints...............: 0
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 0
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 0.0000000e+00 0.00e+00 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
Number of Iterations....: 0
(scaled) (unscaled)
Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00
Dual infeasibility......: 1.0000000000000000e+00 1.0000000000000000e+00
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 9.9999999999998979e-03 9.9999999999998979e-03
Overall NLP error.......: 1.0000000000000000e+00 1.0000000000000000e+00
Number of objective function evaluations = 1
Number of objective gradient evaluations = 1
Number of equality constraint evaluations = 0
Number of inequality constraint evaluations = 0
Number of equality constraint Jacobian evaluations = 0
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations = 0
Total seconds in IPOPT = 0.116
EXIT: Stopping optimization at current point as requested by user.
julia> @test MOI.get(model, MOI.TerminationStatus()) == MOI.INTERRUPTED
Test Passed
p.s., consider posting these sorts of questions on the Discourse forum: https://discourse.julialang.org/c/domain/opt/13.