Gekko求解复杂MINLP任务调度模型性能优化问询
问题背景
- 求解一个MINLP模型,用于给不同日程的人员分配任务,需根据可用时间限制每人每个日程的最大任务数。
- 模型索引:i=人员,z=日程,j=任务,a=任务执行顺序。
- 目标函数包含四类成本:
- 任务耗时超计划成本
- 任务耗时不足计划成本
- 后续任务延迟成本
- 人员空闲时间成本
- 决策变量:
- TC:各任务的执行时长(同一任务对所有人员时长一致)
- C:任务是否按指定顺序执行的0-1变量(部分日程可执行多任务)
- 问题:小规模数据集求解需10分钟,但较大数据集超出140分钟时限,需支持更大规模数据;已尝试简化模型、调整Gekko参数,不确定是模型定义(数学/概念层面)问题,还是有其他性能优化方法。
当前尝试代码
tc_var = {} for index in index_f_a: tc_var[index] = m.Var(value=25, name='tc_var_{}'.format(index), lb=15, ub=45, integer=False) s_var = {} for index in index_f_h: s_var[index] = m.Var() for i, z in index_f_h: m.Equation(tmd[(i, z)]*0.8 + s_var[(i, z)] == np.sum([index_a_v[(i, z)][-1][1]*tc_var[(i, j)] for j in list(set([x[0] for x in index_a_v[(i, z)]]))]) ) m.Equation(s_var[(i, z)] >= 0) def k1(i, z, j, a): a_dif = tce[(i, z, j, a)] - tc_var[(i, j)].VALUE return a_dif if a_dif > 0 else 0 def k2(i, z, j, a): a_dif = tc_var[(i, j)].VALUE - tce[(i, z, j, a)] return a_dif if a_dif > 0 else 0 def k3(i, z, j, a): a_dif = np.sum([tce[(i, z, j, a2)] for a2 in index_f_h_a_v1[i, z, j]]) - (a-1)*tc_var[(i, j)].VALUE return a_dif if a_dif > 0 else 0 def k4(i, z): a_dif = tmd[(i, z)] - np.sum([index_a_v[(i, z)][-1][1]*tc_var[(i, j)].VALUE for j in list(set([x[0] for x in index_a_v[(i, z)]]))]) return a_dif if a_dif > 0 else 0 m.Minimize(m.sum([k1(i, z, j, a)*KCA + k2(i, z, j, a)*KCI + k3(i, z, j, a)*KME for i, z, j, a in index_f_h_a_v]) + m.sum([k4(i, z) for i, z in index_f_h]) * KI ) m.options.MAX_TIME=600 m.options.MAX_ITER=5000 m.options.REDUCE=3 m.solver_options = ['minlp_gap_tol 1.0e-2', 'minlp_branch_method 1', 'minlp_max_iter_with_int_sol 500']
最终修正方案
代码核心问题是错误使用决策变量的.VALUE属性:在Gekko中,.VALUE仅代表变量的初始值或求解后的结果,求解过程中不能用它构建模型逻辑表达式,否则会导致求解器无法正确解析模型,既影响结果正确性,也会大幅降低求解性能。
需用Gekko内置的m.max2()函数替代Python原生条件判断,将非线性逻辑转化为求解器可处理的数学表达式,修正后的成本函数示例如下:
def k1(i, z, j, a): return m.max2(tce[(i, z, j, a)] - tc_var[(i, j)], 0) def k2(i, z, j, a): return m.max2(tc_var[(i, j)] - tce[(i, z, j, a)], 0) def k3(i, z, j, a): sum_tce = np.sum([tce[(i, z, j, a2)] for a2 in index_f_h_a_v1[i, z, j]]) return m.max2(sum_tce - (a-1)*tc_var[(i, j)], 0) def k4(i, z): sum_tc = np.sum([index_a_v[(i, z)][-1][1]*tc_var[(i, j)] for j in list(set([x[0] for x in index_a_v[(i, z)]]))]) return m.max2(tmd[(i, z)] - sum_tc, 0)
额外优化手段(针对大规模数据集):
- 精简变量与约束:排查冗余变量或可合并的约束,对重复求和逻辑预计算中间变量。
- 调优求解器参数:
- 适当调大
minlp_gap_tol(如1e-2至1e-1),在可接受精度范围内减少求解时间。 - 尝试不同
minlp_branch_method(0=深度优先,1=广度优先),匹配问题特性选择分支策略。
- 适当调大
- 优化初始值:给决策变量设置更贴近最优解的初始值,帮助求解器快速收敛。
- 线性化处理:将可转化的非线性逻辑改为线性约束,降低求解计算负担。
内容的提问来源于stack exchange,提问作者Rita s
相关产品推荐
相关产品推荐

