Julia中如何在IPOPT回调函数内获取表达式的当前迭代值?
在JuMP+IPOPT回调中获取表达式当前迭代值
我正在Julia中用JuMP和IPOPT实现特殊优化算法,需要在IPOPT每次迭代时检查条件:当norm(currentValue, Inf) > η*max_val时终止求解。
我定义了一个包含多个JuMP表达式的向量:
a = [x[1] + y^2, x[2] + 2y, x[3]^2]
已经通过回调获取了迭代的变量值,但不知道怎么在回调里计算这个表达式向量的当前值。我知道求解完成后可以用value.(a)获取结果,但回调里尝试currentValues = a(x)的方式行不通,回调代码如下:
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存储当前变量值 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) # 此处无法正常运行 return norm(currentValue,Inf) < η*max_val # 终止条件判断 end MOI.set(model, Ipopt.CallbackFunction(), my_callback) @test MOI.get(model, MOI.TerminationStatus()) == MOI.INTERRUPTED
请问怎么在IPOPT回调函数里计算表达式的当前迭代值?
解决方案
JuMP表达式是绑定到模型的抽象对象,无法直接通过a(x)的方式求值,以下是三种可行的实现方式:
方法一:使用JuMP.eval_expression(推荐)
JuMP提供了eval_expression函数,可传入表达式和变量值字典直接计算结果:
- 提前建立变量到回调
x数组索引的映射:
# 根据模型中变量的实际顺序调整索引 var_indices = Dict( x[1] => 1, x[2] => 2, x[3] => 3, y => 4 )
- 在回调内部构造变量值字典,逐个计算表达式值:
# 替换回调中currentValues = a(x)的部分 var_values = Dict(var => x[idx] for (var, idx) in var_indices) currentValues = [JuMP.eval_expression(expr, var_values) for expr in a]
方法二:手动转换为数值计算函数
将表达式逻辑直接写成Julia原生函数,用回调获取的x数组直接计算:
# 提前定义计算函数,需匹配x数组的变量顺序 function compute_a(x_vals) x1, x2, x3, y_val = x_vals[1], x_vals[2], x_vals[3], x_vals[4] return [x1 + y_val^2, x2 + 2*y_val, x3^2] end # 在回调中调用 currentValues = compute_a(x)
方法三:通过辅助变量间接获取
将表达式转为模型的辅助约束,通过获取辅助变量的当前值来得到表达式结果:
- 提前为每个表达式创建辅助变量和约束:
aux_vars = @variable(model, [1:length(a)]) for i in 1:length(a) @constraint(model, aux_vars[i] == a[i]) end
- 在回调中像获取
x一样获取辅助变量的当前值(需注意辅助变量在模型变量列表中的索引)。
注意事项
- 确保回调中
x数组的顺序与all_variables(model)返回的变量顺序一致,可通过all_variables(model)查看变量排序。 - IPOPT回调返回
true会继续迭代,返回false会终止求解,你的终止条件逻辑是正确的。
内容的提问来源于stack exchange,提问作者Annaquest
相关产品推荐
相关产品推荐

