PuLP优化模型输出不合理:最优承诺费率为0问题求助
问题描述
我正在构建优化模型以确定最优承诺费率,核心逻辑如下:
- 10小时内每小时运行的不同类型实例数量已知且可变;
- 每种实例有按需费率(on-demand rate)和远低于前者的储蓄计划费率(SP费率),费率随实例类型变化但不随时间改变;
- 需设置统一适用于所有小时的承诺费率,要求每小时内「使用SP费率的实例数量×对应SP费率」之和≤承诺费率,同一类型实例无需全部使用SP费率;
- 成本规则:若某小时使用SP费率的实例总成本≤承诺费率,该小时成本为承诺费率;若超出则选最优组合最小化按需成本,未用SP费率的实例按按需费率计费。
我用PuLP构建了含示例数据的模型,但模型始终输出最优承诺费率为0——尽管实例A的SP费率(0.0001/实例/小时)远低于其按需费率(10000/实例/小时),这显然不合理。我猜测问题在于使用SP费率时未扣除对应实例的按需费率,但不确定如何正确实现该逻辑。模型输出的总成本如图所示:
附模型代码:
from pulp import * # Define input data instances = {'A': {'on_demand': 10000.0, 'savings_plan': 0.0001}, 'B': {'on_demand': 2.0, 'savings_plan': 1.5}, 'C': {'on_demand': 3.0, 'savings_plan': 2.0}} hourly_instances = { 1: {'A': 5, 'B': 2, 'C': 1}, 2: {'A': 6, 'B': 3, 'C': 1}, 3: {'A': 7, 'B': 4, 'C': 2}, 4: {'A': 8, 'B': 5, 'C': 2}, 5: {'A': 9, 'B': 6, 'C': 3}, 6: {'A': 10, 'B': 7, 'C': 3}, 7: {'A': 11, 'B': 8, 'C': 4}, 8: {'A': 12, 'B': 9, 'C': 4}, 9: {'A': 13, 'B': 10, 'C': 5}, 10: {'A': 14, 'B': 11, 'C': 5} } # Define the model model = LpProblem("Instance Optimization", LpMinimize) # Define decision variables commitment_rate = LpVariable("commitment_rate", lowBound=0) savings_plan_utilization = {} for hour in hourly_instances.keys(): for instance_type in instances.keys(): savings_plan_utilization[(hour, instance_type)] = LpVariable(f"savings_plan_utilization_{hour}_{instance_type}", cat='Binary') # Define objective function hourly_costs = [] for hour, instance_counts in hourly_instances.items(): hourly_cost = lpSum([instances[type]['savings_plan'] * count * savings_plan_utilization[(hour, type)] for type, count in instance_counts.items()]) hourly_cost += lpSum([instances[type]['on_demand'] * count for type, count in instance_counts.items() if instances[type]['savings_plan'] == 0]) hourly_costs.append(hourly_cost) model += lpSum(hourly_costs) + commitment_rate # Add utilization constraints for hour, instance_counts in hourly_instances.items(): for type in instances.keys(): model += savings_plan_utilization[(hour, type)] <= instance_counts[type] # Add commitment rate constraint model += lpSum([instances[type]['savings_plan'] * lpSum(savings_plan_utilization[(hour, type)] for hour in hourly_instances.keys()) for type in instances.keys()]) <= commitment_rate # Print the solver status print("Solver Status: ", LpStatus[model.status]) # Solve the model model.solve() # Print the values of the decision variables for v in model.variables(): print(v.name, "=", v.varValue) # Print the value of the objective function print("Objective =", value(model.objective)) # Output the results print(f"Optimal commitment rate: {commitment_rate.value()}") # Output the savings plan utilization for each hour for hour in hourly_instances.keys(): print(f"Hour {hour} Savings Plan Utilization: {lpSum(savings_plan_utilization[(hour, type)] for type in instances.keys()).value()}") # Calculate the hourly costs hourly_costs = [] for hour, instance_counts in hourly_instances.items(): hourly_cost = lpSum([instances[type]['on_demand'] * count for type, count in instance_counts.items()]) hourly_cost += lpSum([instances[type]['savings_plan'] * count * savings_plan_utilization[(hour, type)].value() for type, count in instance_counts.items()]) hourly_costs.append(hourly_cost.value()) # Calculate the optimized commitment rate commitment_rate = lpSum([instances[type]['savings_plan'] * lpSum(savings_plan_utilization[(hour, type)] for hour in hourly_instances.keys()) for type in instances.keys()]).value() # Output the optimized commitment rate print(f"Optimized Commitment Rate: {commitment_rate}") # Visualize the hourly costs and the optimized commitment rate import matplotlib.pyplot as plt plt.plot(range(1, len(hourly_costs)+1), hourly_costs, label='Hourly Cost') plt.axhline(y=commitment_rate, color='r', linestyle='-', label='Optimized Commitment Rate') plt.xlabel('Hour') plt.ylabel('$/hr') plt.legend() plt.show()
问题分析与修正
核心问题
- 目标函数逻辑错误:原模型中同时累加了SP费率成本和全部实例的按需费率成本,相当于使用SP的实例需要支付双份费用,导致使用SP反而成本更高,模型自然选择不启用SP。
- 承诺费率约束错误:原约束是所有小时的SP总成本之和≤承诺费率,但题目要求是每小时的SP总成本≤承诺费率,完全不符合业务规则。
- 成本规则未正确建模:原模型未实现「小时SP总成本≤承诺费率时,该小时成本为承诺费率」的规则,缺少对应的约束逻辑。
修正后的模型代码
from pulp import * import matplotlib.pyplot as plt # 输入数据 instances = {'A': {'on_demand': 10000.0, 'savings_plan': 0.0001}, 'B': {'on_demand': 2.0, 'savings_plan': 1.5}, 'C': {'on_demand': 3.0, 'savings_plan': 2.0}} hourly_instances = { 1: {'A': 5, 'B': 2, 'C': 1}, 2: {'A': 6, 'B': 3, 'C': 1}, 3: {'A': 7, 'B': 4, 'C': 2}, 4: {'A': 8, 'B': 5, 'C': 2}, 5: {'A': 9, 'B': 6, 'C': 3}, 6: {'A': 10, 'B': 7, 'C': 3}, 7: {'A': 11, 'B': 8, 'C': 4}, 8: {'A': 12, 'B': 9, 'C': 4}, 9: {'A': 13, 'B': 10, 'C': 5}, 10: {'A': 14, 'B': 11, 'C': 5} } # 创建模型 model = LpProblem("Instance Optimization", LpMinimize) # 决策变量 commitment_rate = LpVariable("commitment_rate", lowBound=0) # 每个小时每种实例使用SP的数量(改为连续变量,支持部分实例使用SP) sp_usage = {} for hour in hourly_instances.keys(): for instance_type in instances.keys(): sp_usage[(hour, instance_type)] = LpVariable(f"sp_usage_{hour}_{instance_type}", lowBound=0, upBound=hourly_instances[hour][instance_type]) # 每小时实际成本变量,用于建模max(承诺费率, 实际SP+按需成本)逻辑 hourly_cost = {} for hour in hourly_instances.keys(): hourly_cost[hour] = LpVariable(f"hourly_cost_{hour}", lowBound=0) # 约束1:每小时成本不得低于承诺费率 for hour in hourly_instances.keys(): model += hourly_cost[hour] >= commitment_rate # 约束2:每小时成本不得低于该小时的实际SP成本+未使用SP的实例按需成本 for hour in hourly_instances.keys(): hour_sp_total = lpSum([instances[type]['savings_plan'] * sp_usage[(hour, type)] for type in instances]) hour_remaining_on_demand = lpSum([instances[type]['on_demand'] * (hourly_instances[hour][type] - sp_usage[(hour, type)]) for type in instances]) model += hourly_cost[hour] >= hour_sp_total + hour_remaining_on_demand # 约束3:每小时的SP总成本不得超过承诺费率 for hour in hourly_instances.keys(): model += lpSum([instances[type]['savings_plan'] * sp_usage[(hour, type)] for type in instances]) <= commitment_rate # 目标函数:最小化所有小时的总成本之和 model += lpSum(hourly_cost.values()) # 求解模型 model.solve() # 输出结果 print("Solver Status: ", LpStatus[model.status]) print(f"Optimal commitment rate: {commitment_rate.value()}") for hour in hourly_instances.keys(): print(f"\nHour {hour} SP Usage:") for type in instances.keys(): print(f" {type}: {sp_usage[(hour, type)].value()}") print(f" Hourly Cost: {hourly_cost[hour].value()}") print("\nTotal Objective Cost: ", value(model.objective)) # 可视化结果 hourly_cost_values = [hourly_cost[h].value() for h in sorted(hourly_instances.keys())] plt.plot(range(1, len(hourly_cost_values)+1), hourly_cost_values, label='Hourly Cost') plt.axhline(y=commitment_rate.value(), color='r', linestyle='-', label='Optimal Commitment Rate') plt.xlabel('Hour') plt.ylabel('$/hr') plt.legend() plt.show()
关键修正点说明
- 决策变量调整:将SP使用量从二进制变量改为连续变量,支持同一类型实例部分使用SP费率,更贴合业务场景。
- 成本逻辑修正:通过
hourly_cost变量和双重约束,正确实现「每小时成本取承诺费率与实际运营成本的较大值」的规则,避免原模型重复计费的问题。 - 约束修正:将全局SP总成本约束改为每小时SP总成本≤承诺费率,完全符合题目要求。
- 目标函数优化:直接以所有小时的总成本之和为优化目标,确保模型会主动选择使用SP费率降低整体成本。
内容的提问来源于stack exchange,提问作者Runeaway3
相关产品推荐
相关产品推荐

