CPlex Python中cumul函数Step_at的容量不跨区间累加问题求助
解决CPlex Python调度问题中Sprint容量跨期累加的问题
方法一:用step_at函数在每个Sprint结束时重置容量
你之前仅用step_at初始化容量,未在Sprint结束时清零。可以给每个Sprint的时间区间设置两个step_at操作:一个在Sprint开始时设置目标容量,另一个在Sprint结束时将容量归0。
假设每个Sprint的时间区间为[start_t, end_t)(比如第一个Sprint从0到14天,第二个从14到28天),代码示例如下:
# 定义Sprint的时间区间和对应容量 sprint_intervals = [(0, 14), (14, 28)] sprint_capacities = [20, 50] # 创建容量资源变量 capacity = model.continuous_var(name="capacity") # 为每个Sprint设置容量的分段变化 for (start, end), cap in zip(sprint_intervals, sprint_capacities): # 开始时设置容量,结束时清零 model.add(capacity == model.step_at(start, cap) + model.step_at(end, -cap))
这样每个Sprint结束时,容量会被减去当前值回到0,下一个Sprint开始时再重新设置新容量,彻底避免剩余容量跨期累加的问题。
方法二:为每个Sprint单独定义容量变量
如果不想依赖时间分段的step函数,更直观的方式是给每个Sprint创建独立的容量约束,直接关联对应Sprint内选中任务的总点数。
- 先定义二进制变量标记任务是否被某Sprint选中:
# tasks为任务列表(每个任务含points属性),sprints为Sprint列表 selected = model.binary_var_matrix(tasks, sprints, name="selected")
- 添加任务不可重复的约束:每个任务只能被一个Sprint选中(或不选)
for task in tasks: model.add(model.sum(selected[task, s] for s in sprints) <= 1)
- 为每个Sprint添加独立的容量约束:选中任务的总点数必须等于该Sprint的容量
for s in sprints: model.add(model.sum(selected[task, s] * task.points for task in tasks) == s.capacity)
这种方法完全隔离了不同Sprint的容量逻辑,新手更容易理解和维护,也不会出现跨期累加的问题。
方法三:调整workUsage的时间范围约束
如果坚持用资源累计的方式,需要确保任务的资源消耗仅被计入对应Sprint的容量,同时为每个Sprint独立分配资源:
# task_start为任务的启动时间变量 for task in tasks: # 约束任务只能在某一个Sprint的时间区间内启动 model.add(model.sum(model.logical_and(task_start >= s.start, task_start < s.end) for s in sprints) == 1) # 为每个Sprint创建独立的容量资源 sprint_capacity = {s: model.continuous_var(name=f"capacity_{s.name}") for s in sprints} for s in sprints: # 设置当前Sprint的初始容量 model.add(sprint_capacity[s] == model.step_at(s.start, s.capacity)) # 约束该Sprint内的任务总消耗等于容量 model.add(model.sum(selected[task, s] * task.points for task in tasks) == s.capacity)
总结
新手优先推荐方法二,逻辑清晰且不易出错;如果需要快速修正现有代码,方法一的双step_at设置是最直接的解决方案。
内容的提问来源于stack exchange,提问作者Gops
相关产品推荐
相关产品推荐

