You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python PuLP线性规划优化机组调度:状态切换约束问题

机组调度优化问题解决方案

问题概述

使用Python PuLP工具优化12小时机组调度,目标是在电价最高时段运行机组以最大化利润。当前存在以下问题:

  • 无法正确实现启停次数限制约束
  • 疑问:该问题是否适合用线性规划解决?
  • 后续需求:添加油箱燃料约束(持续加注,不能排空或溢出)

原代码中定义的核心变量:

hours = range(12) # 调度时长
generator_on = LpVariable.dicts("Generator_On", hours, cat="Binary")  # 二进制变量,1表示运行,0表示停机

原错误的启停约束代码:

# 尝试通过比较变量值统计切换次数,但无法生效
prob += lpSum([1 if generator_on[i].value() != generator_on[i-1].value() else 0 for i in range(1, len(hours))]) <= max_state_changes, "Max_switch_time"

解决方案

1. 修复启停次数约束

原代码错误原因:在建模阶段调用.value()方法是无效的,该方法仅在求解后返回变量的具体数值,建模时必须用线性表达式描述约束。

正确的做法是引入二进制变量switch[i]表示第i小时是否发生状态切换(0=无切换,1=有切换),然后通过线性约束关联switch[i]与generator_on变量:

  • 当generator_on[i]与generator_on[i-1]状态不同时,switch[i]必须为1
  • 当状态相同时,switch[i]可以为0

具体实现代码:

# 定义切换变量:switch[i]表示第i小时相对于i-1小时是否发生状态切换
switch = LpVariable.dicts("Switch", range(1, len(hours)), cat="Binary")

# 添加切换约束
for i in range(1, len(hours)):
    # 状态不同时,switch[i]至少为1
    prob += switch[i] >= generator_on[i] - generator_on[i-1]
    prob += switch[i] >= generator_on[i-1] - generator_on[i]

# 限制总切换次数
prob += lpSum(switch.values()) <= max_state_changes, "Max_switch_time"

2. 线性规划适用性分析

该问题包含二进制决策变量(机组开/关),属于**整数线性规划(ILP)**范畴,而非普通线性规划(LP)。PuLP完全支持整数规划求解,因此该工具适合解决此问题。后续添加的油箱约束若为线性关系(如燃料加注/消耗的线性计算),也可直接整合到ILP模型中。

3. 油箱约束实现思路

假设已知以下参数:

  • fuel_in:每小时油箱加注的燃料量
  • fuel_out:机组运行时每小时消耗的燃料量
  • min_fuel:油箱最低允许油量(不能排空)
  • max_fuel:油箱最大容量(不能溢出)
  • initial_fuel:初始油箱油量

需要定义连续变量fuel_level[i]表示第i小时结束时的油箱油量,然后添加以下线性约束:

# 定义油箱油量变量
fuel_level = LpVariable.dicts("Fuel_Level", hours, lowBound=min_fuel, upBound=max_fuel)

# 初始油量约束(第0小时结束)
prob += fuel_level[0] == initial_fuel + fuel_in - generator_on[0] * fuel_out, "Initial_Fuel"

# 后续时段油量变化约束
for i in range(1, len(hours)):
    prob += fuel_level[i] == fuel_level[i-1] + fuel_in - generator_on[i] * fuel_out, f"Fuel_Balance_Hour_{i}"

完整修正代码

from pulp import LpProblem, LpVariable, lpSum, LpMaximize

# 初始化问题
prob = LpProblem("GeneratorScheduling", LpMaximize)

# 基础参数
hours = range(12)
electricity_prices = [10, 8, 12, 7, 15, 9, 11, 14, 10, 8, 13, 10]
max_state_changes = 2
max_total_on_time = 6  # 总运行时长上限(原代码中变量名修正为更清晰的名称)

# 决策变量
generator_on = LpVariable.dicts("Generator_On", hours, cat="Binary")
switch = LpVariable.dicts("Switch", range(1, len(hours)), cat="Binary")

# 目标函数:最大化总利润
prob += lpSum(electricity_prices[i] * generator_on[i] for i in hours), "Total_Profit"

# 约束1:总运行时长上限
prob += lpSum(generator_on.values()) <= max_total_on_time, "Max_Total_On_Time"

# 约束2:启停次数限制
for i in range(1, len(hours)):
    prob += switch[i] >= generator_on[i] - generator_on[i-1]
    prob += switch[i] >= generator_on[i-1] - generator_on[i]
prob += lpSum(switch.values()) <= max_state_changes, "Max_switch_time"

# 可选:添加油箱约束(示例参数)
fuel_in = 5
fuel_out = 10
min_fuel = 10
max_fuel = 50
initial_fuel = 20
fuel_level = LpVariable.dicts("Fuel_Level", hours, lowBound=min_fuel, upBound=max_fuel)

prob += fuel_level[0] == initial_fuel + fuel_in - generator_on[0] * fuel_out, "Initial_Fuel"
for i in range(1, len(hours)):
    prob += fuel_level[i] == fuel_level[i-1] + fuel_in - generator_on[i] * fuel_out, f"Fuel_Balance_Hour_{i}"

# 求解问题
prob.solve()

# 输出结果
print("Optimal Schedule:")
for i in hours:
    print(f"Hour {i + 1}: {'On' if generator_on[i].value() == 1 else 'Off'}")
print("Total Profit:", round(prob.objective.value(), 2))

# 若添加了油箱约束,输出油量
print("\nFuel Levels:")
for i in hours:
    print(f"Hour {i + 1}: {round(fuel_level[i].value(), 2)}")

内容的提问来源于stack exchange,提问作者IvarsB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:21:14