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

PuLP优化模型输出不合理:最优承诺费率为0问题求助

问题描述

我正在构建优化模型以确定最优承诺费率,核心逻辑如下:

  • 10小时内每小时运行的不同类型实例数量已知且可变;
  • 每种实例有按需费率(on-demand rate)和远低于前者的储蓄计划费率(SP费率),费率随实例类型变化但不随时间改变;
  • 需设置统一适用于所有小时的承诺费率,要求每小时内「使用SP费率的实例数量×对应SP费率」之和≤承诺费率,同一类型实例无需全部使用SP费率;
  • 成本规则:若某小时使用SP费率的实例总成本≤承诺费率,该小时成本为承诺费率;若超出则选最优组合最小化按需成本,未用SP费率的实例按按需费率计费。

我用PuLP构建了含示例数据的模型,但模型始终输出最优承诺费率为0——尽管实例A的SP费率(0.0001/实例/小时)远低于其按需费率(10000/实例/小时),这显然不合理。我猜测问题在于使用SP费率时未扣除对应实例的按需费率,但不确定如何正确实现该逻辑。模型输出的总成本如图所示:
Solution

附模型代码:

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()
问题分析与修正

核心问题

  1. 目标函数逻辑错误:原模型中同时累加了SP费率成本和全部实例的按需费率成本,相当于使用SP的实例需要支付双份费用,导致使用SP反而成本更高,模型自然选择不启用SP。
  2. 承诺费率约束错误:原约束是所有小时的SP总成本之和≤承诺费率,但题目要求是每小时的SP总成本≤承诺费率,完全不符合业务规则。
  3. 成本规则未正确建模:原模型未实现「小时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()

关键修正点说明

  1. 决策变量调整:将SP使用量从二进制变量改为连续变量,支持同一类型实例部分使用SP费率,更贴合业务场景。
  2. 成本逻辑修正:通过hourly_cost变量和双重约束,正确实现「每小时成本取承诺费率与实际运营成本的较大值」的规则,避免原模型重复计费的问题。
  3. 约束修正:将全局SP总成本约束改为每小时SP总成本≤承诺费率,完全符合题目要求。
  4. 目标函数优化:直接以所有小时的总成本之和为优化目标,确保模型会主动选择使用SP费率降低整体成本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:15:13