You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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函数,可传入表达式和变量值字典直接计算结果:

  1. 提前建立变量到回调x数组索引的映射:
# 根据模型中变量的实际顺序调整索引
var_indices = Dict(
    x[1] => 1,
    x[2] => 2,
    x[3] => 3,
    y => 4
)
  1. 在回调内部构造变量值字典,逐个计算表达式值:
# 替换回调中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)

方法三:通过辅助变量间接获取

将表达式转为模型的辅助约束,通过获取辅助变量的当前值来得到表达式结果:

  1. 提前为每个表达式创建辅助变量和约束:
aux_vars = @variable(model, [1:length(a)])
for i in 1:length(a)
    @constraint(model, aux_vars[i] == a[i])
end
  1. 在回调中像获取x一样获取辅助变量的当前值(需注意辅助变量在模型变量列表中的索引)。

注意事项

  • 确保回调中x数组的顺序与all_variables(model)返回的变量顺序一致,可通过all_variables(model)查看变量排序。
  • IPOPT回调返回true会继续迭代,返回false会终止求解,你的终止条件逻辑是正确的。

内容的提问来源于stack exchange,提问作者Annaquest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 04:43:15