线性规划——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之间。

x1=(Chicken)x2=(Beef)x3=(Mutton)x4=(Rice)x5=(Wheatbran)x6=(Gel)

制定目标函数
对于Whiskas猫食品问题,目标是最小化每罐猫食品成分的总成本,即

min0.013x1+0.008x2+0.010x3+0.002x4+0.005x5+0.001x6

确定约束条件
Whiskas猫食品问题的约束条件是:
- 百分比总和必须占整个罐子(= 100%)。
- 满足规定的营养分析要求。
“整罐”的约束是:

x1+x2+x3+x4+x5+x6=100

为了满足营养分析要求,我们需要每100g至少8g蛋白质,6g脂肪,但不超过2g纤维和0.4g盐。为了制定这些约束条件,我们利用以前的每种成分贡献表。这使我们能够制定有关来自成分的蛋白质,脂肪,纤维和盐总贡献的以下约束条件:

0.100x1+0.200x2+0.150x3+0.000x4+0.040x5+0.0x68.00.080x1+0.100x2+0.110x3+0.010x4+0.010x5+0.0x66.00.001x1+0.005x2+0.003x3+0.100x4+0.150x5+0.0x62.00.002x1+0.005x2+0.007x3+0.002x4+0.008x5+0.0x60.4

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

参考文献

  1. 整数线性规划——pulp指南
  2. 优化模型(一)
  3. 使用python做线性规划求解
  4. The_Whiskas_Problem (猫粮配料比例问题)
posted @   郝hai  阅读(6702)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示