如何借助Casadi的Bonmin求解器获取解的迭代过程
问题描述
使用Casadi调用Bonmin求解MINLP问题时,无法通过opti.callback()获取迭代过程,但切换为IPOPT求解器时该代码可以正常运行并输出迭代信息。以下是可复现的代码:
import casadi as ca opti = ca.Opti() x1 = opti.variable() x2 = opti.variable() opti.set_initial(x1, 1) opti.set_initial(x2, 10) obj = x1**2 + x2**2 opti.minimize(obj) opti.subject_to( x1*x2 >= 1 ) p_opts = {} s_opts = {'print_level': 4} opti.solver('ipopt', p_opts, s_opts) opti.callback(lambda i: print(i, opti.debug.value(x1))) sol = opti.solve()
将求解器改为'bonmin'后,回调函数不再输出任何内容,请问如何通过Bonmin获取解的迭代过程?
解决方案
Bonmin是基于分支定界框架的MINLP求解器,底层会调用IPOPT这类NLP求解器处理子问题,但Casadi的opti.callback()仅对直接调用的NLP求解器(如IPOPT)生效,无法直接捕获Bonmin的分支定界迭代或子问题求解过程。要获取Bonmin的迭代信息,可以通过以下两种方式:
1. 开启Bonmin的详细日志输出
通过设置Bonmin的求解器选项,让其输出分支定界过程、子问题求解的详细日志,替代回调函数的功能:
import casadi as ca opti = ca.Opti() x1 = opti.variable() x2 = opti.variable() opti.set_initial(x1, 1) opti.set_initial(x2, 10) obj = x1**2 + x2**2 opti.minimize(obj) opti.subject_to( x1*x2 >= 1 ) # 设置Bonmin的选项,开启详细日志 p_opts = {} s_opts = { 'print_level': 6, # 更高的打印级别,输出分支定界细节 'bonmin.print_level': 6, 'ipopt.print_level': 4 # 同时输出子问题IPOPT的迭代信息 } opti.solver('bonmin', p_opts, s_opts) sol = opti.solve()
调整print_level的值(通常1-6,数值越高输出越详细),可以得到分支定界的迭代次数、当前上下界、子问题的求解状态等信息。
2. 自定义Bonmin的回调函数(进阶)
如果需要程序化地捕获迭代数据,可以通过Casadi的Function创建Bonmin的回调函数,并通过求解器选项注册:
import casadi as ca # 定义回调函数,参数需符合Bonmin的要求 def bonmin_callback(iter_num, obj_val, primal_vars, dual_vars, stats): print(f"Bonmin迭代 {iter_num}: 目标值={obj_val}, x1={primal_vars[0]}") return True # 返回True表示继续求解 # 将Python函数包装为Casadi Function callback_fun = ca.Function('bonmin_callback', [ca.MX.sym('iter'), ca.MX.sym('obj'), ca.MX.sym('x', 2), ca.MX.sym('lam'), ca.MX.sym('stats')], [ca.MX(True)], ['iter', 'obj', 'x', 'lam', 'stats'], ['continue']) opti = ca.Opti() x1 = opti.variable() x2 = opti.variable() opti.set_initial(x1, 1) opti.set_initial(x2, 10) obj = x1**2 + x2**2 opti.minimize(obj) opti.subject_to( x1*x2 >= 1 ) p_opts = { 'bonmin.callback': callback_fun # 注册回调函数 } s_opts = {'print_level': 4} opti.solver('bonmin', p_opts, s_opts) sol = opti.solve()
注意:Bonmin的回调函数参数格式需要严格匹配,这种方式可以更灵活地处理迭代过程中的数据。
内容的提问来源于stack exchange,提问作者tempname
相关产品推荐
相关产品推荐

