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

如何用Pulp实现含阶梯维护成本的整数线性规划条件约束?

问题背景

某工厂生产x、y两种产品,售价分别为10.5美元和8.5美元,需满足阶梯维护成本规则:当x产量超过20单位时,扣除10美元维护成本;超过50单位时,扣除20美元维护成本(替代10美元成本)。

已实现的CPLEX代码

用户已通过CPLEX完成单条件约束建模,代码如下:

import cplex
import docplex.mp
from docplex.mp.model import Model

maintenance_cost = 10
maintenance_trigger = 20

# Create model
model = Model(name='LP_example', log_output=True)

# Decisions variables
x = model.integer_var(name='x')
y = model.integer_var(name='y')
z = model.binary_var(name='z')

# Objective function
model.maximize(10.5 * x + 8.5 * y - z * maintenance_cost)

# Constraints
model.add_constraint(3 * x + 2 * y  <= 420)

# if then constraint
model.add_constraint(model.if_then(x >= maintenance_trigger, z == 1))


model.print_information() 
sol_model = model.solve()
model.print_solution()
Pulp建模遇到的问题

用户在使用Pulp建模时,无法正确设置二进制变量z及条件约束,尝试添加BigM约束后结果正确,但不理解其原理,同时需扩展实现阶梯维护成本约束,当前Pulp代码如下:

import pulp as p 
Lp_prob = p.LpProblem('Problem', p.LpMaximize)  

x = p.LpVariable("x", lowBound = 0, cat='Integer')   # Create a variable x >= 0 
y = p.LpVariable("y", lowBound = 0, cat='Integer')   # Create a variable y >= 0 
z = p.LpVariable("z", lowBound=0, cat='Binary')

Lp_prob +=  10.5 * x + 8.5 * y - maintenance_cost * z

Lp_prob += 3 * x + 2 * y  <= 420
 
# if then constraint
# The problematic part (Conditional constraint):
Lp_prob += z  == 1 # ???

status = Lp_prob.solve()   
print(p.value(x)," x produced objects")
print(p.value(y) , "y produced objects"  )
print(p.value(z) , "The value of the binary variable, used or not 1 or 0"  )
print(p.value(Lp_prob.objective) ,"our Profit" )

# 添加的BigM约束
M1 = 1e6
Lp_prob += z >= (x - 20)/M1
需求
  • 解释BigM约束的工作原理;
  • 用Pulp正确建模"x产量超20单位扣10美元维护成本"的约束;
  • 扩展实现"x产量超50单位扣20美元维护成本"的阶梯约束。

解答

1. BigM约束的工作原理

BigM是线性规划中转化逻辑条件的常用技巧,核心是用一个足够大的常数M来控制约束的生效状态。以实现「如果x≥20,则z=1」为例,需要把逻辑条件拆成两个双向的线性约束:

  • 约束1:x ≤ 20 + M*(1-z)
    当z=0时,约束变为x ≤20,直接限制x不能超过20;当z=1时,x ≤20+M,由于M远大于x的最大可能值(比如根据生产约束3x+2y≤420,x最大为140),这个约束相当于无效,不会限制x的取值。
  • 约束2:x ≥20 - M*(1-z)
    当z=1时,约束变为x≥20;当z=0时,x≥20-M,由于M足够大,对x≥0的变量来说没有限制作用。

这两个约束结合,就能准确实现「x≥20时z必须为1,z=0时x必须≤20」的逻辑。你之前写的z ≥ (x-20)/M只是部分约束,无法覆盖完整逻辑。

2. Pulp实现单条件维护成本约束

以下是完整的单条件建模代码,包含正确的BigM约束:

import pulp as p

# 参数定义
MAINTENANCE_COST_20 = 10
TRIGGER_20 = 20
M = 150  # 取大于x最大可能值的常数,这里150足够

# 创建模型
Lp_prob = p.LpProblem('Single_Maintenance_Cost', p.LpMaximize)  

# 决策变量
x = p.LpVariable("x", lowBound=0, cat='Integer')
y = p.LpVariable("y", lowBound=0, cat='Integer')
z = p.LpVariable("z", cat='Binary')  # z=1表示触发10美元维护成本

# 目标函数:利润=销售收入-维护成本
Lp_prob += 10.5 * x + 8.5 * y - MAINTENANCE_COST_20 * z

# 生产能力约束
Lp_prob += 3 * x + 2 * y <= 420

# BigM约束实现逻辑:x≥20则z=1,z=0则x≤20
Lp_prob += x <= TRIGGER_20 + M * (1 - z)
Lp_prob += x >= TRIGGER_20 - M * (1 - z)

# 求解并输出结果
status = Lp_prob.solve()
print(f"x产量: {p.value(x)}")
print(f"y产量: {p.value(y)}")
print(f"是否触发10美元维护成本: {p.value(z)}")
print(f"总利润: {p.value(Lp_prob.objective)}")

3. 扩展实现阶梯维护成本约束

阶梯规则为:x≤20时无成本;20<x≤50时扣10美元;x>50时扣20美元。需要引入两个二进制变量区分不同阶梯,同时约束变量间的互斥关系,完整代码如下:

import pulp as p

# 参数定义
COST_10 = 10
COST_20 = 20
TRIGGER_20 = 20
TRIGGER_50 = 50
M = 150

# 创建模型
Lp_prob = p.LpProblem('Step_Maintenance_Cost', p.LpMaximize)  

# 决策变量
x = p.LpVariable("x", lowBound=0, cat='Integer')
y = p.LpVariable("y", lowBound=0, cat='Integer')
z1 = p.LpVariable("z1", cat='Binary')  # 触发10美元成本(20<x≤50)
z2 = p.LpVariable("z2", cat='Binary')  # 触发20美元成本(x>50)

# 目标函数:利润=销售收入-对应维护成本
Lp_prob += 10.5 * x + 8.5 * y - COST_10 * z1 - COST_20 * z2

# 生产能力约束
Lp_prob += 3 * x + 2 * y <= 420

# 阶梯约束逻辑
# 1. x≤20时,z1和z2都为0
Lp_prob += x <= TRIGGER_20 + M * (z1 + z2)
# 2. 20<x≤50时,z1=1、z2=0
Lp_prob += x >= TRIGGER_20 + 1 - M * (1 - z1)  # 整数变量下x>20等价于x≥21
Lp_prob += x <= TRIGGER_50 + M * (1 - z1)
Lp_prob += z2 <= 1 - z1  # z1=1时z2必须为0
# 3. x>50时,z2=1、z1=0
Lp_prob += x >= TRIGGER_50 + 1 - M * (1 - z2)
Lp_prob += z1 <= 1 - z2  # z2=1时z1必须为0

# 求解并输出结果
status = Lp_prob.solve()
print(f"x产量: {p.value(x)}")
print(f"y产量: {p.value(y)}")
print(f"是否触发10美元成本: {p.value(z1)}")
print(f"是否触发20美元成本: {p.value(z2)}")
print(f"总利润: {p.value(Lp_prob.objective)}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 21:13:09