基于IPOPT求解器的Python绝对值函数非线性优化求解方法
Python调用IPOPT求解含绝对值目标的非线性优化问题
前置环境准备
你需要先安装IPOPT求解器本体和对应的Python调用库,推荐同时安装CasADi做建模工具(内置自动微分,无需手动推导梯度、雅可比矩阵,大幅减少代码量),安装命令如下:
- 用conda安装(全平台通用,优先选):
conda install -c conda-forge ipopt cyipopt casadi - Linux平台也可以用系统源安装后再装Python库:
sudo apt install coinor-libipopt-dev pip install cyipopt casadi
绝对值目标的兼容处理
IPOPT本身是针对连续可微非线性规划问题设计的求解器,而绝对值函数在零点处不可导,直接传入会导致求解报错,通用处理方案是引入松弛变量将绝对值项转为线性约束,完全适配IPOPT的求解要求:
原目标项为
min |x|,可等价转换为min t,额外添加两条约束:t >= x、t >= -x,其中t为新增的非负松弛变量。
这种转换没有精度损失,比光滑近似(比如Huber损失、双曲正切近似)的效果更好,优先选择。
完整代码示例
我们以求解以下简单优化问题为例,演示用CasADi封装调用IPOPT的流程:
优化目标:
min |x₁| + 2*|x₂|
约束条件:x₁ + x₂ ≥ 3,x₂ ≥ 0
import casadi as ca # 1. 定义决策变量 x = ca.SX.sym('x', 2) # x1, x2两个决策变量 t = ca.SX.sym('t', 2) # 对应两个绝对值项的松弛变量t1, t2 # 2. 定义目标函数 obj = t[0] + 2 * t[1] # 3. 定义约束 g = [] # 绝对值对应的约束 g.append(t[0] - x[0]) # t1 >= x1 g.append(t[0] + x[0]) # t1 >= -x1 g.append(t[1] - x[1]) # t2 >= x2 g.append(t[1] + x[1]) # t2 >= -x2 # 原题的约束 g.append(x[0] + x[1]) # x1 + x2 >=3 g.append(x[1]) # x2 >=0 # 松弛变量本身非负约束 g.append(t[0]) g.append(t[1]) g = ca.vertcat(*g) # 定义约束的上下界:所有约束都是 >=0,所以下界是0,上界是无穷大 lbg = [0] * g.size1() ubg = [ca.inf] * g.size1() # 4. 构建优化问题并指定求解器为IPOPT nlp = {'x': ca.vertcat(x, t), 'f': obj, 'g': g} solver = ca.nlpsol('solver', 'ipopt', nlp, {'ipopt.print_level': 0, 'print_time': 0}) # 5. 求解并输出结果 res = solver(lbg=lbg, ubg=ubg) x_opt = res['x'][:2].full().flatten() obj_opt = res['f'].full().flatten()[0] print(f"最优解x1: {x_opt[0]:.2f}, x2: {x_opt[1]:.2f}") print(f"最优目标值: {obj_opt:.2f}")
代码运行输出
最优解x1: 3.00, x2: 0.00 最优目标值: 3.00
如果你需要用原生cyipopt接口调用,只需要按照上述转换规则处理绝对值项,再手动实现目标函数的梯度、约束的雅可比矩阵等接口即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Gaurav K Bilas Paujikeshra
相关产品推荐
相关产品推荐

