Pyomo调用MindtPy求解时报NoneType无__round__方法错误如何解决
Pyomo调用MindtPy求解MINLP时报TypeError: type NoneType doesn't define round method 问题分析
问题复现
用户使用Pyomo实现带二元变量的动态优化问题,代码如下:
import pyomo import pyomo.opt import pyomo.environ as pe import numpy as np a = np.array([1,1,1,15]) b = np.array([1,2,3,4]) c = 10 P_res = 5 model = pe.ConcreteModel(name = "base optimizer") model.M = pe.RangeSet(1,2) model.T = pe.RangeSet(1,P_res) model.state = pe.RangeSet(1,4) st_lb = np.array((-1.22,) * P_res) st_ub = np.array((1.22,) * P_res) th_lb = np.array((0,) * P_res) th_ub = np.array((1.0,) * P_res) def th_b(model, i): return (th_lb[i-1], th_ub[i-1]) model.th = pe.Var(model.T, domain=pe.Reals, bounds = th_b) model.x = pe.Var(model.T, model.state, domain = pe.Reals) model.z_predicate = pe.Var(model.T, model.M, domain=pe.Binary) def obj_rule(model): return model.th[P_res]**2 model.OBJ = pe.Objective(rule=obj_rule, sense = pe.minimize) def init_state(model,s): return model.x[1,s] == a[s-1] def dynamic_1(model,t): if t == P_res: return pe.Constraint.Skip return model.x[t+1,1] == model.x[t,1] + model.x[t,4] * pe.cos(model.x[t,3]) def dynamic_2(model,t): if t == P_res: return pe.Constraint.Skip return model.x[t+1,2] == model.x[t,2] + model.x[t,4] * pe.sin(model.x[t,3]) def dynamic_3(model,t): if t == P_res: return pe.Constraint.Skip return model.x[t+1,4] == model.x[t,4] + model.th[t] model.InitConstraint = pe.Constraint(model.state, rule = init_state) model.DynConstraint1 = pe.Constraint(model.T, rule=dynamic_1) model.DynConstraint2 = pe.Constraint(model.T, rule=dynamic_2) model.DynConstraint3 = pe.Constraint(model.T, rule=dynamic_3) def binary_constraint(model,t): return model.z_predicate[t,1] <= 1 model.BiConstraint = pe.Constraint(model.T,rule=binary_constraint) solver = pyomo.opt.SolverFactory('mindtpy') results = solver.solve(model, mip_solver='gurobi', nlp_solver='ipopt', tee=True)
运行后报错栈如下:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-7-d441aab4faca> in <module> 56 57 solver = pyomo.opt.SolverFactory('mindtpy') ---> 58 results = solver.solve(model, mip_solver='gurobi', nlp_solver='ipopt', tee=True) 59 60 # solver = pyomo.opt.SolverFactory('ipopt') c:\users\hongk\appdata\local\programs\python\python36\lib\site-packages\pyomo\contrib\mindtpy\MindtPy.py in solve(self, model, **kwds) 169 # Algorithm main loop 170 with time_code(solve_data.timing, 'main loop'): --> 171 MindtPy_iteration_loop(solve_data, config) 172 if solve_data.best_solution_found is not None: 173 # Update values in original model c:\users\hongk\appdata\local\programs\python\python36\lib\site-packages\pyomo\contrib\mindtpy\iterate.py in MindtPy_iteration_loop(solve_data, config) 99 fixed_nlp, fixed_nlp_result, solve_data, config) 100 --> 101 if algorithm_should_terminate(solve_data, config, check_cycling=True): 102 last_iter_cuts = False 103 break c:\users\hongk\appdata\local\programs\python\python36\lib\site-packages\pyomo\contrib\mindtpy\iterate.py in algorithm_should_terminate(solve_data, config, check_cycling) 307 if check_cycling: 308 if config.cycling_check or config.use_tabu_list: --> 309 solve_data.curr_int_sol = get_integer_solution(solve_data.mip) 310 if config.cycling_check and solve_data.mip_iter >= 1: 311 if solve_data.curr_int_sol in set(solve_data.integer_list): c:\users\hongk\appdata\local\programs\python\python36\lib\site-packages\pyomo\contrib\mindtpy\util.py in get_integer_solution(model, string_zero) 550 temp.append(int(round(var.value))) 551 else: --> 552 temp.append(int(round(var.value))) 553 return tuple(temp) 554 TypeError: type NoneType doesn't define __round__ method
用户测试发现:注释掉model.BiConstraint并将求解器替换为Ipopt后,程序可正常运行,推测报错与该约束有关。
报错诱因
1. 存在完全冗余的二元变量
你定义的model.z_predicate是维度为T×M(M=1、2)的二元变量,存在两个问题:
- 你仅对
z_predicate[t,1]添加了<=1的约束,而二元变量的默认上界就是1,该约束完全无效 z_predicate[t,2]从未出现在任何约束、目标函数中,属于对优化结果无任何影响的自由变量- 整个
z_predicate变量族都没有参与目标函数计算,不会对优化结果产生任何影响
2. MindtPy的整数解提取逻辑触发报错
MindtPy求解MINLP问题时,会先调用Gurobi求解MIP子问题。对于这类对目标、约束无影响的冗余二元变量,Gurobi不会为其分配具体值(无论取0还是1都不影响结果,求解器会直接跳过赋值),导致变量的value属性为None。当MindtPy执行整数解提取逻辑时,尝试对None调用round()方法,直接触发类型错误。
3. 替换为Ipopt后可运行的原因
Ipopt是纯NLP求解器,会自动将所有Binary域变量松弛为[0,1]区间的连续变量求解。即使变量冗余,Ipopt也会基于初始值(默认取0或初始猜测值)返回一个求解结果,不会出现value为None的情况,因此不会触发报错。
解决方案
如果你的问题确实需要用到z_predicate变量,请补充对应的约束逻辑,确保所有二元变量都参与到约束或目标计算中;如果不需要该变量,直接删除z_predicate的定义和对应的BiConstraint即可。
内容的提问来源于stack exchange,提问作者JohnSmith
相关产品推荐
相关产品推荐

