如何在Pyomo中添加分段线性约束解决任务分配工时优化问题
问题原因
Python内置min函数会在建模阶段立即对输入表达式做布尔比较,但Pyomo的变量表达式在求解前没有实际常量值,无法转换为布尔值,因此触发报错。你需要将分段工时规则转换为混合整数规划可识别的线性约束形式。
解决方案
由于日任务数的取值范围非常有限(最多2个,否则超过日最长8工时限制),直接使用Pyomo内置的Piecewise分段线性组件实现工时映射逻辑是最简单的方案。
修改后完整可运行代码
# 修复后的任务分配代码 from pyomo.environ import * m = ConcreteModel() m.TASKS = ('task1', 'task2', 'task3', 'task4') m.DAYS = (1, 2, 3, 4) # 变量定义 m.ALLOCATION = Var(m.TASKS, m.DAYS, domain=Binary) # 单日最多2个任务就达到工时上限,直接限定取值范围减少求解复杂度 m.N_TASKS_PER_DAY = Var(m.DAYS, domain=Integers, bounds=(0, 2)) m.TOTAL_HOURS = Var(m.DAYS, domain=Integers, bounds=(0, 8)) # 优化目标:最小化总工时 m.OBJ = Objective(expr=sum(m.TOTAL_HOURS[day] for day in m.DAYS), sense=minimize) m.c = ConstraintList() # 约束1:每个任务仅分配一次 for task in m.TASKS: m.c.add(sum(m.ALLOCATION[task, day] for day in m.DAYS) == 1) # 约束2:每日实际分配任务数计算 for day in m.DAYS: m.c.add(sum(m.ALLOCATION[task, day] for task in m.TASKS) == m.N_TASKS_PER_DAY[day]) # 约束3:分段工时映射(替代原直接调用min的错误写法) # 断点对应每日任务数,f_rule对应任务数匹配的工时 breakpoints = [0, 1, 2] hour_values = [0, 6, 8] m.pw_constraint = Piecewise(m.DAYS, m.TOTAL_HOURS, m.N_TASKS_PER_DAY, pw_pts=breakpoints, f_rule=hour_values, pw_constr_type='EQ') # 约束4:每日工时不超过上限(可省略,分段规则已隐含该限制) for day in m.DAYS: m.c.add(m.TOTAL_HOURS[day] <= 8) # 求解并输出结果 solver = SolverFactory('glpk') res = solver.solve(m) res.write() print("总工时:", value(m.OBJ)) for day in m.DAYS: task_num = value(m.N_TASKS_PER_DAY[day]) if task_num > 0: print(f"第{day}天分配{task_num}个任务,工时{value(m.TOTAL_HOURS[day])}")
运行结果说明
求解后总工时为16小时,符合预期:4个任务分2天执行,每天分配2个任务,单日工时8小时。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

