天天看点

python Pulp求解线性规划问题(含实例)

问题描述

python Pulp求解线性规划问题(含实例)

上图所示的Whiskas猫粮由Ben生产。Ben希望尽可能便宜地生产其猫粮,同时确保它们满足罐头上所示的规定的营养分析要求。因此,他们希望改变每种成分的使用量(主要成分是鸡肉,牛肉,羊肉,大米,小麦和凝胶),同时仍要满足其营养标准。

python Pulp求解线性规划问题(含实例)

鸡肉,牛肉和羊肉的成本分别为0.013美元,0.008美元和0.010美元,而大米,小麦和凝胶的成本分别为0.002美元,0.005美元和0.001美元。(所有成本均为每克。)在此练习中,我们将忽略维生素和矿物质成分。(无论如何,这些的任何费用都可能很小。)

每种成分都有助于最终产品中蛋白质,脂肪,纤维和盐的总重量。下表列出了每克成分的贡献(以克计)。

东西 蛋白 脂肪 纤维
0.100 0.080 0.001 0.002
牛肉 0.200 0.100 0.005 0.005
羊肉 0.150 0.110 0.003 0.007
白饭 0.000 0.010 0.100 0.002
麦麸 0.040 0.010 0.150 0.008
凝胶 0.000 0.000 0.000 0.000

简化模型的建立

首先,我们将考虑一个简化的问题,以构建一个简单的Python模型。

定义决策变量

假设Whiskas希望仅使用两种成分制作猫食:鸡肉和牛肉。我们将首先定义决策变量:

  • x1 = 一罐猫粮中鸡肉的百分比
  • x2 = 一罐猫粮中牛肉的比例

制定目标函数

  • min 0.013x1+0.008x2

约束条件

这些变量的约束条件是它们必须总计为100,并且满足营养要求:

1.000x1 + 1.000x2 = 100.0
			0.100x1 + 0.200x2 >= 8.0
			0.080x1 + 0.100x2 >= 6.0
			0.001x1 + 0.005x2 <= 2.0
			0.002x1 + 0.005x2 <= 0.4
           

解决方案

要获得此线性程序的解决方案,我们可以使用Python编写一个简短的程序来调用PuLP的建模函数,然后将其调用求解器。这将逐步解释如何编写此Python程序。

pulp.LpProblem(name='NoName', sense=LpMinimize)

,用来建立优化问题,其函数的参数为name:

在lp文件中写入的问题名称;sense:最大或者最小,可为LpMinimize\LpMaximize二者之一。

pulp.LpVariable(name, lowBound=None, upBound=None, cat='Continuous', e=None)

,其函数参数为name:

变量名;lowBound变量下界;upBound变量上界;cat变量类型,可以为LpInteger\LpBinary\LpContinuous三者之一;

e指明变量是否在目标函数和约束中存在,主要用来实现列生成算法。

例如:

LpVariable(“example”, None, 100)

或LpVariable(“example”, upBound = 100)

  • 针对此问题的Code
# 1. 建立问题
prob = LpProblem("Bleding Problem", LpMinimize)

# 2. 建立变量
x1 = LpVariable("ChickenPercent", 0, None, LpInteger)
x2 = LpVariable("BeefPercent", 0)

# 3. 设置目标函数
prob += 0.013*x1 + 0.008*x2, "Total Cost of Ingredients per can"

# 4. 施加约束
prob += x1 + x2 == 100, "PercentagesSum"
prob += 0.100*x1 + 0.200*x2 >= 8.0, "ProteinRequirement"
prob += 0.080*x1 + 0.100*x2 >= 6.0, "FatRequirement"
prob += 0.001*x1 + 0.005*x2 <= 2.0, "FibreRequirement"
prob += 0.002*x2 + 0.005*x2 <= 0.4, "SaltRequirement"

# 5.求解
prob.solve()

# 6.打印求解状态
print("Status:",LpStatus[prob.status])

# 7. 打印出每个变量的最优值
for v in prob.variables():
    print(v.name, "=", v.varValue)

# 打印最优解的目标函数值
print("Total Cost of Ingredient per can = ", value(prob.objective))
           

全模型建立

现在,我们将使用所有变量完全解决问题。尽管可以在上面的方法中添加很少的内容来将其实现到Python中,但我们将寻找一种更好的方法,该方法不将问题数据和公式混为一谈。这将使更改其他测试的任何问题数据变得更加容易。我们将通过代数定义问题开始相同的方法:

定义决策变量

确定Whiskas猫食问题的决策变量决策变量是我们罐头中所含不同成分的百分比。
由于罐头为100克,因此这些百分比还代表所含每种成分的克含量。
我们必须正式定义决策变量,并确保陈述我们使用的单位。
           
  • x1 = 一罐猫粮中鸡肉的比例
  • x2 = 一罐猫粮中牛肉的比例
  • x3 = 一罐猫粮中羊肉的比例
  • x4 = 一罐猫粮中白饭的比例
  • x5 = 一罐猫粮中麦麸的比例
  • x6 = 一罐猫粮中凝胶 的比例

制定目标函数

制定Whiskas猫食问题的目标函数,目的是使每罐猫食的成分总成本最小化。我们知道每种成分每克的成本。我们确定每种成分在罐中的百分比,因此我们必须除以100,再乘以以g为单位的罐的重量。这将使我们获得每种成分的重量(克)
           
  • min 0.013x1+0.008x2 + 0.010x3 + 0.002x4 + 0.005x5 + 0.001x6

约束条件

制定约束Whiskas猫粮问题的约束是:
百分比之和必须组成整个罐(= 100%)。
满足规定的营养分析要求。
“整个罐头”的约束是:
           
  • x1 + x2 + x3 + x4 + x5 + x6 = 100
为了满足营养分析的要求,每100克中至少要有8克蛋白质,6克脂肪,但不超过2克纤维和0.4克盐。
为了制定这些约束条件,我们利用了每种成分的上一个贡献表。这使我们能够对成分中蛋白质,
脂肪,纤维和盐的总贡献制定以下约束条件:
           
  • 0.100x1 + 0.200x2 + 0.150x3 + 0.000x4 + 0.040x5 + 0.0x6 >= 8.0
  • 0.080x1 + 0.100x2 + 0.110x3 + 0.010x4 + 0.010x5 + 0.0x6 >= 6.0
  • 0.001x1 + 0.005x2 + 0.003x3 + 0.100x4 + 0.150x5 + 0.0x6 <= 2.0
  • 0.002x1 + 0.005x2 + 0.007x3 + 0.002x4 + 0.008x5 + 0.0x6 <= 0.4

解决方案

在prob定义问题的变量或类型之前,将关键问题数据输入字典。其中包括成分列表,其次是每种成分的成本,
以及四种营养素中每种成分的百分比。这些值是明确列出的,对编程知识很少的人很容易更改。成分是参考键
,数字作为数据。
           
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)

# Create the 'prob' variable to contain the problem data
prob = LpProblem("The Whiskas Problem", LpMinimize)

# A dictionary called 'ingredient_vars' is created to contain the referenced Variables
ingredient_vars = LpVariable.dicts("Ingr",Ingredients,0)

prob += lpSum([costs[i]*ingredient_vars[i] for i in Ingredients]), "Total Cost of Ingredients per can"

# The five constraints are added to 'prob'
prob += lpSum([ingredient_vars[i] for i in Ingredients]) == 100, "PercentagesSum"
prob += lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 8.0, "ProteinRequirement"
prob += lpSum([fatPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 6.0, "FatRequirement"
prob += lpSum([fibrePercent[i] * ingredient_vars[i] for i in Ingredients]) <= 2.0, "FibreRequirement"
prob += lpSum([saltPercent[i] * ingredient_vars[i] for i in Ingredients]) <= 0.4, "SaltRequirement"

# 此后代码和前面相同,这里略写
           

附上pulp官网来链接