基于Pyomo子集条件求和生成约束的实现问题
能源分配Pyomo模型核心约束实现方案
问题背景
作为Pyomo和线性优化新手,正在处理固定时间范围内的能源分配问题,目标是最大化能源利用率,无需满足所有请求。
已定义的模型元素
集合
model.t = pyomo.Set(initialize = (supply_unix_ts.index)) # 时间集合 model.r = pyomo.Set(initialize = request_ids) # 能源消耗请求集合
参数
- 各时段可用能源:
model.available_supply = pyomo.Param(model.t, initialize = supply_unix_ts.to_dict(), domain=pyomo.NonNegativeReals)
- 请求相关参数:
model.request_earliest_start_time = pyomo.Param(model.r, initialize = request_earliest_start_times_dict, domain=pyomo.NonNegativeReals) # 请求最早开始时间 model.request_latest_end_time = pyomo.Param(model.r, initialize = request_latest_end_time_dict, domain=pyomo.NonNegativeReals) # 请求最晚结束时间 model.request_max_power_dict = pyomo.Param(model.r, initialize = request_max_power_dict, domain=pyomo.NonNegativeReals) # 请求最大供电功率 model.request_energy_needed_dict = pyomo.Param(model.r, initialize = request_energy_needed_dict, domain=pyomo.NonNegativeReals) # 请求所需总能量
- 采样周期(功率转能量用):
model.sampling_period_dict = pyomo.Param(model.t, initialize = sampling_period_dict, domain=pyomo.NonNegativeReals)
决策变量
model.booked_supply = pyomo.Var(model.t, domain = pyomo.NonNegativeReals) # 各时段已预订的总能源 model.request_status = pyomo.Var(model.t, model.r, domain = pyomo.Binary) # 指示请求r在时段t是否被分配能源 model.request_satisfied = pyomo.Var(model.r, domain = pyomo.Binary) # 指示请求r是否被完全满足
目标函数
def obj_rule(model): return sum(model.booked_supply[t] for t in model.t) model.obj = pyomo.Objective(rule = obj_rule, sense = pyomo.maximize)
已实现约束
- 各时段预订能源不超过可用能源:
model.booked_supply[t] <= model.available_supply[t](针对每个t∈model.t) - 预订能源等于该时段所有分配请求的总和:
model.booked_supply[t] = sum(model.request_status[t,r] * model.request_max_power_dict[r] * model.sampling_period_dict[t] for r in model.r)(针对每个t∈model.t)
待实现核心约束
当请求r被完全满足(model.request_satisfied[r] = 1)时,其在时间区间[model.request_earliest_start_time[r], model.request_latest_end_time[r]]内分配的总能量等于model.request_energy_needed_dict[r];若未被满足(model.request_satisfied[r] = 0)则无要求。
错误尝试分析
- 为每个请求创建时间子集:请求数量达数千个,动态创建大量集合会引发性能问题,不可行。
- 错误约束规则:
- 第一个约束错误地将
t作为索引参数,内部又遍历所有t导致索引冲突,且使用了未定义的model.request_confirmed_power变量。 - 第二个约束存在逻辑错误(条件写错最晚结束时间参数),且遍历所有请求和时间,不符合Pyomo约束规则的定义逻辑。
- 第一个约束错误地将
可行方案及代码示例
核心思路
采用大M法将二元变量的逻辑转化为线性约束:
- 当
model.request_satisfied[r] = 1时,总分配能量必须等于需求能量; - 当
model.request_satisfied[r] = 0时,总分配能量可在合理范围内自由取值(结合目标函数会尽可能分配)。
代码实现
# 定义大M参数:针对每个请求计算其最大可能分配能量,避免数值稳定性问题 def M_rule(model, r): max_possible_energy = model.request_max_power_dict[r] * sum(model.sampling_period_dict[t] for t in model.t) return max_possible_energy model.M = pyomo.Param(model.r, rule=M_rule, domain=pyomo.NonNegativeReals) # 核心约束:绑定请求满足状态与能量分配量 def satisfied_energy_constraint(model, r): # 计算请求r在允许时间区间内的总分配能量 allocated_energy = sum( model.request_status[t, r] * model.request_max_power_dict[r] * model.sampling_period_dict[t] for t in model.t if model.request_earliest_start_time[r] <= t <= model.request_latest_end_time[r] ) # 约束1:请求被满足时,分配能量不低于需求;未满足时自动满足下限 constraint1 = allocated_energy >= model.request_energy_needed_dict[r] * model.request_satisfied[r] # 约束2:请求被满足时,分配能量不超过需求;未满足时限制在最大可能值内 constraint2 = allocated_energy <= model.request_energy_needed_dict[r] * model.request_satisfied[r] + model.M[r] * (1 - model.request_satisfied[r]) return constraint1 and constraint2 model.satisfied_energy = pyomo.Constraint(model.r, rule=satisfied_energy_constraint)
补充说明
- 若需灵活分配功率而非仅用最大功率,可将
model.request_status改为连续变量model.request_power_fraction = pyomo.Var(model.t, model.r, domain=pyomo.UnitInterval),表示时段内使用最大功率的比例,此时分配能量为model.request_power_fraction[t,r] * model.request_max_power_dict[r] * model.sampling_period_dict[t]。 - 大M值需合理选择:过小会导致约束失效,过大影响求解器稳定性,建议针对每个请求单独计算。
内容的提问来源于stack exchange,提问作者user23390596
相关产品推荐
相关产品推荐

