线性规划——Pyhton库PULP的使用
PuLP是一个用于线性规划(LP)、整数线性规划(ILP)和混合整数线性规划(MILP)问题的Python库。PuLP的全称是"Python for Mathematical Programming",它提供了一个简单而强大的工具,使得用户能够定义优化问题、构建数学模型并使用不同的求解器进行求解。PuLP的主要特点之一是其易用性。它允许用户通过简单的方式定义优化问题,而无需深入了解数学规划的细节。PuLP的语法设计旨在使用户能够直观地表达问题的约束和目标函数。这种简洁而清晰的语法使得PuLP成为解决线性规划问题的理想选择,特别是对于那些对数学规划领域不太熟悉的用户。在PuLP中,用户可以轻松地定义变量、约束和目标函数。通过简单的API调用,用户可以指定变量的上下界、约束条件的系数以及目标函数的系数。PuLP还提供了对问题特性的检查和显示,以帮助用户验证模型的正确性。PuLP的使用不仅限于线性规划问题,还可以处理整数线性规划和混合整数线性规划。
| 图1 | 图2 |
|---|---|
![]() |
![]() |
一、PuLP库的使用
PuLP Main Topics教程
PuLP是一个开源的第三方工具包,可以求解线性规划、整数规划、混合整数规划问题。下面先介绍一下Pulp一些基础的库函数,再以一些例题为例进行重复讲解。
PuLP库的安装和导入:
pip install pulp
import pulp
import numpy as np
PuLP创建求解问题:
prob = pulp.LpProblem("LPProbDemo", sense=pulp.LpMaximize)
#pulp.LpProblem 是定义问题的构造函数。
#LPProbDemo是用户定义的问题名(用于输出信息)。
#sense用来指定求最小值/最大值问题,可选参数值:LpMinimize、LpMaximize
PuLP定义变量
x1 = pulp.LpVariable('x1',lowBound=0, upBound=None, cat=pulp.LpInteger)
x2 = pulp.LpVariable('x2', lowBound=0, upBound=None, cat=pulp.LpBinary)
x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous')
#x1,x2是用户定义的变量名
#lowBound、upBound用来设定决策变量的下界、上界;可以不定义下界/上界,默认的下界/上界是负无穷/正无穷。
#cat用来设定变量类型,可选参数值:pulp.LpContnuous为连续变量;pulp.LpBinary为0-1变量;pulp.LpInteger为整数离散变量。
PuLP定义目标函数:
prob += 3*x1 + 5*x2
prob += 2*x0-5*x1+4*x2
PuLP定义约束条件:
prob += 2*x1 + x2 <= 100
prob += x1 + x2 <= 80
prob += x1 <= 40
prob += x2 <= 60
PuLP求解和状态函数:
prob.solve()
pulp.LpStatus[prob.status] #合理Status: Optimal
pulp.value(prob.objective) #目标函数值
二、PuLP库的使用示例
2.1示例1
import pulp
MyProbLP = pulp.LpProblem("LPProbDemo1", sense=pulp.LpMaximize)
x1 = pulp.LpVariable('x1', lowBound=0, upBound=7, cat='Continuous')
x2 = pulp.LpVariable('x2', lowBound=0, upBound=7, cat='Continuous')
x3 = pulp.LpVariable('x3', lowBound=0, upBound=7, cat='Continuous')
MyProbLP += 2*x1 + 3*x2 - 5*x3 # 设置目标函数
MyProbLP += (2*x1 - 5*x2 + x3 >= 10) # 不等式约束
MyProbLP += (x1 + 3*x2 + x3 <= 12) # 不等式约束
MyProbLP += (x1 + x2 + x3 == 7) # 等式约束
MyProbLP.solve()
# 输出求解状态
print("Status:", pulp.LpStatus[MyProbLP.status])
# 输出每个变量的最优值
for v in MyProbLP.variables():
print(v.name, "=", v.varValue)
# 输出最优解的目标函数值
print("F(x) = ", pulp.value(MyProbLP.objective))
# 输出结果如下
Status: Optimal
x1 = 6.4285714
x2 = 0.57142857
x3 = 0.0
F(x) = 14.57142851
2.2示例2
import pulp
import numpy as np
# 定义问题
ProbLP3 = pulp.LpProblem("ProbLP3", sense=pulp.LpMaximize)
# 定义变量
x1 = pulp.LpVariable('x1', lowBound=0, upBound=8, cat='Continuous')
x2 = pulp.LpVariable('x2', lowBound=0, upBound=7.5, cat='Continuous')
# 定义目标函数
ProbLP3 += 11 * x1 + 9 * x2
# 添加约束
ProbLP3 += 6 * x1 + 5 * x2 <= 60
ProbLP3 += 10 * x1 + 20 * x2 <= 150
# 求解问题
ProbLP3.solve()
# 输出结果
print("Problem Name:", ProbLP3.name)
print("Status:", pulp.LpStatus[ProbLP3.status])
# 输出每个变量的最优值
for variable in ProbLP3.variables():
print(f"{variable.name} = {variable.varValue}")
# 输出最优解的目标函数值
print("F3(x) =", pulp.value(ProbLP3.objective))
三、案例——猫粮问题
问题描述:Uncle Ben's希望以尽可能低的成本生产他们的猫粮产品,同时确保它们符合罐头上显示的营养分析要求。猫粮的配料有chicken, beef, mutton,rice, wheat,gel,它们的成本分别是$0.013, $0.008,$0.010,$0.002, $0.005, $0.001。为了满足营养标准,每100g成品必须至少有8gProtein,6gfat,但是不超过2g的fibre以及0.4g的salt。下面是营养成分表。
| Stuff | Protein | Fat | Fibre | Salt |
|---|---|---|---|---|
| Chicken | 0.100 | 0.080 | 0.001 | 0.002 |
| Beef | 0.200 | 0.100 | 0.005 | 0.005 |
| Mutton | 0.150 | 0.110 | 0.003 | 0.007 |
| Rice | 0.000 | 0.010 | 0.100 | 0.002 |
| Wheat bran | 0.040 | 0.010 | 0.150 | 0.008 |
| Gel | 0.000 | 0.000 | 0.000 | 0.000 |
3.1 建模表示
为使得更改其他测试的任何问题数据变得更容易,我们将以代数方式定义问题的方式开始:
确定决策变量
决策变量是我们在罐中包含的不同成分的百分比。由于罐子重100g,这些百分比也代表每种成分包含的克数。请注意,这些百分比必须介于0和100之间。
制定目标函数
对于Whiskas猫食品问题,目标是最小化每罐猫食品成分的总成本,即
确定约束条件
Whiskas猫食品问题的约束条件是:
- 百分比总和必须占整个罐子(= 100%)。
- 满足规定的营养分析要求。
“整罐”的约束是:
为了满足营养分析要求,我们需要每100g至少8g蛋白质,6g脂肪,但不超过2g纤维和0.4g盐。为了制定这些约束条件,我们利用以前的每种成分贡献表。这使我们能够制定有关来自成分的蛋白质,脂肪,纤维和盐总贡献的以下约束条件:
3.2 python实现
import numpy as np
from pulp import *
#Creates a list of the Ingredients
Ingredients = ['CHICKEN', 'BEEF', 'MUTTON', 'RICE', 'WHEAT', 'GEL']
# A dictionary of the costs of each of the Ingredients is created
costs = {'CHICKEN': 0.013,
'BEEF': 0.008,
'MUTTON': 0.010,
'RICE': 0.002,
'WHEAT': 0.005,
'GEL': 0.001}
# A dictionary of the protein percent in each of the Ingredients is created
proteinPercent = {'CHICKEN': 0.100,
'BEEF': 0.200,
'MUTTON': 0.150,
'RICE': 0.000,
'WHEAT': 0.040,
'GEL': 0.000}
# A dictionary of the fat percent in each of the Ingredients is created
fatPercent = {'CHICKEN': 0.080,
'BEEF': 0.100,
'MUTTON': 0.110,
'RICE': 0.010,
'WHEAT': 0.010,
'GEL': 0.000}
# A dictionary of the fibre percent in each of the Ingredients is created
fibrePercent = {'CHICKEN': 0.001,
'BEEF': 0.005,
'MUTTON': 0.003,
'RICE': 0.100,
'WHEAT': 0.150,
'GEL': 0.000}
# A dictionary of the salt percent in each of the Ingredients is created
saltPercent = {'CHICKEN': 0.002,
'BEEF': 0.005,
'MUTTON': 0.007,
'RICE': 0.002,
'WHEAT': 0.008,
'GEL': 0.000}
# 创建问题实例,求最小极值
prob = LpProblem("The Whiskas Problem", LpMinimize)
# 构建Lp变量字典,键名是Ingredients,值(变量名)以Ingr开头,如Ingr_CHICKEN,下界是0
ingredient_vars = LpVariable.dicts("Ingr", Ingredients, 0)
# 添加目标方程
prob += lpSum([costs[i] * ingredient_vars[i] for i in Ingredients])
# 添加约束条件
prob += lpSum([ingredient_vars[i] for i in Ingredients]) == 100
prob += lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 8.0
prob += lpSum([fatPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 6.0
prob += lpSum([fibrePercent[i] * ingredient_vars[i] for i in Ingredients]) <= 2.0
prob += lpSum([saltPercent[i] * ingredient_vars[i] for i in Ingredients]) <= 0.4
# 求解
prob.solve()
# 查看解的状态
print("Status:", LpStatus[prob.status])
# 查看解
for v in prob.variables():
print(v.name, "=", v.varValue)
3.3 计算结果
Status: Optimal
Ingr_BEEF = 60.0
Ingr_CHICKEN = 0.0
Ingr_GEL = 40.0
Ingr_MUTTON = 0.0
Ingr_RICE = 0.0
Ingr_WHEAT = 0.0
四、案例——固定成本问题
4.1 建模表示
高压容器公司制造小、中、大三种尺寸的金属容器,所用资源为金属板、劳动力和机器设备。制造一个容器所需的各种资源数量如下表(单位:金属板 = 吨,劳动力 = 人/月,机器设备 = 台/月)。不考虑除下面固定费用外的其他固定费用;每种容器单位利润分别为:小容器 4 万元/个,中容器 5 万元/个,大容器 6 万元/个。可使用的资源总量为:金属板 500 吨,劳动力 300 人/月,机器 100 台/月。此外只要生产某种容器(即产量 > 0),需支付一次固定成本:小号 100 万元,中号 150 万元,大号 200 万元。试制定一个生产计划,使公司 总利润最大化。
| 资源 \ 容器 | 小号容器 | 中号容器 | 大号容器 |
|---|---|---|---|
| 金属板(吨/个) | 2 | 4 | 8 |
| 劳动力(人/月/个) | 2 | 3 | 4 |
| 机器设备(台/月/个) | 1 | 2 | 3 |
数学模型(混合整数规划)
设变量:
- \(x_{1}\) = 小号容器产量(个,整数且 \(\geq 0\))
- \(x_{2}\) = 中号容器产量(个,整数且 \(\geq 0\))
- \(x_{3}\) = 大号容器产量(个,整数且 \(\geq 0\))
引入二进制变量表示是否开产某种型号(若产量>0 则为1,否则为0):
- \(y_{1} \in \{0,1\}\):若 \(x_{1} > 0\) 则 \(y_{1} = 1\)
- \(y_{2} \in \{0,1\}\):若 \(x_{2} > 0\) 则 \(y_{2} = 1\)
- \(y_{3} \in \{0,1\}\):若 \(x_{3} > 0\) 则 \(y_{3} = 1\)
目标函数(以万元为单位):
资源约束:
连接约束(大\(M\)法,将产量与对应的开产指示相连):
其中 \(M_{i}\) 为可行的上界(可取来自资源的上界,例如 \(M_{1} = 100\), \(M_{2} = 50\), \(M_{3} = 33\)等)。
非负及整型:
4.2 Python实现
# 若已安装 pulp,可运行下面 MILP 示例
# pip install pulp
import pulp
# 定义模型
model = pulp.LpProblem("容器生产计划", pulp.LpMaximize)
# 变量
x1 = pulp.LpVariable('x1', lowBound=0, cat='Integer') # 小号产量
x2 = pulp.LpVariable('x2', lowBound=0, cat='Integer') # 中号产量
x3 = pulp.LpVariable('x3', lowBound=0, cat='Integer') # 大号产量
y1 = pulp.LpVariable('y1', cat='Binary') # 小号是否生产
y2 = pulp.LpVariable('y2', cat='Binary') # 中号是否生产
y3 = pulp.LpVariable('y3', cat='Binary') # 大号是否生产
# 大M 上界(可取资源导出上限)
M1 = min(500//2, 300//2, 100//1) # =100
M2 = min(500//4, 300//3, 100//2) # =50
M3 = min(500//8, 300//4, 100//3) # =33
# 目标函数(最大化利润)
model += 4*x1 + 5*x2 + 6*x3 - 100*y1 - 150*y2 - 200*y3
# 资源约束
model += 2*x1 + 4*x2 + 8*x3 <= 500 # 金属
model += 2*x1 + 3*x2 + 4*x3 <= 300 # 劳动力
model += x1 + 2*x2 + 3*x3 <= 100 # 机器
# 连接约束
model += x1 <= M1 * y1
model += x2 <= M2 * y2
model += x3 <= M3 * y3
# 求解
model.solve(pulp.PULP_CBC_CMD(msg=1))
print("Status:", pulp.LpStatus[model.status])
print("x1 =", pulp.value(x1))
print("x2 =", pulp.value(x2))
print("x3 =", pulp.value(x3))
print("y1 =", pulp.value(y1))
print("y2 =", pulp.value(y2))
print("y3 =", pulp.value(y3))
print("最大利润 =", pulp.value(model.objective), "万元")
4.3 计算结果
x2 = 0.0
x3 = 0.0
y1 = 1.0
y2 = 0.0
y3 = 0.0
最大利润 = 300.0 万元



浙公网安备 33010602011771号