使用PuLP优化线性编程沙拉混合物

时间:2016-11-11 18:58:05

标签: python optimization linear-programming pulp

我设置了以下LP问题,除了沙拉绿的质量约束百分比外,一切似乎都有效。我希望沙拉绿色的质量至少达到40%,但我在PuLP lpSum中遇到语法错误,我不确定如何调和它。

我对每种沙拉都有以下限制:

至少15克蛋白质

至少2克,最多8克脂肪

至少4克碳水化合物

最多200毫克的钠

质量至少40%绿叶蔬菜。

from pulp import *

# Creates a list of the Ingredients
Ingredients = ['TOMATO', 'LETTUCE', 'SPINACH', 'CARROT', 'SUNFLOWER', 'TOFU', 'CHICKPEAS', 'OIL']

kcal = {'TOMATO': 21, 
         'LETTUCE': 16, 
         'SPINACH': 40, 
         'CARROT': 41, 
         'SUNFLOWER': 585, 
         'TOFU': 120,
         'CHICKPEAS': 164,
         'OIL': 884}

protein = {'TOMATO': 0.85, 
         'LETTUCE': 1.62, 
         'SPINACH': 2.86, 
         'CARROT': 0.93, 
         'SUNFLOWER': 23.4, 
         'TOFU': 16,
         'CHICKPEAS': 9,
         'OIL': 0}

fat = {'TOMATO': 0.33, 
         'LETTUCE': 0.20, 
         'SPINACH': 0.39, 
         'CARROT': 0.24, 
         'SUNFLOWER': 48.7, 
         'TOFU': 5.0,
         'CHICKPEAS': 2.6,
         'OIL': 100.0}

carbs = {'TOMATO': 4.64, 
         'LETTUCE': 2.37, 
         'SPINACH': 3.63, 
         'CARROT': 9.58, 
         'SUNFLOWER': 15.0, 
         'TOFU': 3.0,
         'CHICKPEAS': 27.0,
         'OIL': 0.0}

sodium = {'TOMATO': 9.0, 
         'LETTUCE': 28.0, 
         'SPINACH': 65.0, 
         'CARROT': 69.0, 
         'SUNFLOWER': 3.80, 
         'TOFU': 120.0,
         'CHICKPEAS': 78.0,
         'OIL': 0.0}

cost = {'TOMATO': 1.0, 
         'LETTUCE': 0.75, 
         'SPINACH': 0.50, 
         'CARROT': 0.50, 
         'SUNFLOWER': 0.45, 
         'TOFU': 2.15,
         'CHICKPEAS': 0.95,
         'OIL': 2.00}

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

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

# The objective function is added to 'prob' first
prob += lpSum([kcal[i]*ingredient_vars[i] for i in Ingredients]), "Total kCal of Ingredients per salad"

# The constraints are added to 'prob'
prob += lpSum([protein[i] * ingredient_vars[i] for i in Ingredients]) >= 15.0, "ProteinRequirement"
prob += 8.0 >= lpSum([fat[i] * ingredient_vars[i] for i in Ingredients]) >= 2.0, "FatRequirement"
prob += lpSum([carbs[i] * ingredient_vars[i] for i in Ingredients]) >= 4.0, "CarbRequirement"
prob += lpSum([sodium[i] * ingredient_vars[i] for i in Ingredients]) <= 200.0, "SodiumRequirement"
prob += lpSum(prob.variables()[2].varValue + prob.variables()[4].varValue) / lpSum([prob.variables()[i].varValue for i in range(8)]) >= 0.40, "GreensRequirement"

prob.solve()

# The status of the solution is printed to the screen
print("Status:", LpStatus[prob.status])

# Each of the variables is printed with it's resolved optimum value
for v in prob.variables():
    print(v.name, "=", v.varValue)

# The optimised objective function value is printed to the screen
print("Total kCal of Ingredients per salad = ", value(prob.objective))

这是给我这个问题的约束:

prob += lpSum(prob.variables()[2].varValue + prob.variables()[4].varValue) / lpSum([prob.variables()[i].varValue for i in range(8)]) >= 0.40, "GreensRequirement"

这会在NoneType上使用+运算符时出错,因为变量还没有值。我只是不确定如何设置这种约束。我已经通过PuLP文档了解了这一点,但我没有抓住这个问题的运气。

1 个答案:

答案 0 :(得分:2)

一些评论

  • 正如您自己所说,您无法构建基于某些尚未优化的决策变量值的约束!
    • 无法使用.varValue进行约束
  • 我不会像以前那样获得prob.variables()[2]的概念,而不像之前那样访问ingredient_vars[i](但我不知道prob.variables究竟返回了什么将忽略这一点)
  • 如果您替换.varValue访问权限并直接使用变量,那么您正在构建一个除法的约束,该约束不是线性的,而且纸浆不接受此
    • 即使纸浆会接受这个,解决者也无法解决这个问题(LP解算器)

怎么做

我们需要:

  • 构建线性约束以表示您的比率约束

理论

我们使用lpsolve here文档中描述的重新制定。摘录:

enter image description here lpsolve文档的屏幕截图(http://lpsolve.sourceforge.net/5.1/ratio.htm

在实践中

备注:由于我不熟悉prob.variables()[2] - 就像访问变量一样,而且懒得检查文档,我猜这里果岭是:LETTUCE + SPINACH 。如果我误解了这个,请随意改变它!

约束看起来是硬编码的(不是很好,但可能适用于你的例子),如下所示:

prob += (0 - 0.4) * ingredient_vars['TOMATO'] + (1 - 0.4) * ingredient_vars['LETTUCE'] + \
        (1 - 0.4) * ingredient_vars['SPINACH'] + (0 - 0.4) * ingredient_vars['CARROT'] + \
        (0 - 0.4) * ingredient_vars['SUNFLOWER'] + (0 - 0.4) * ingredient_vars['TOFU'] + \
        (0 - 0.4) * ingredient_vars['CHICKPEAS'] + (0 - 0.4) * ingredient_vars['OIL'] >= 0.0, 'GreensRequirement'

这是lpsolve文档制定的直接翻译。检查我们必须做出的假设!

示例输出

使用替换约束完全使用代码的两个示例(假设我的成分为绿色):

比率0.4(在上面的代码中描述)

('Status:', 'Optimal')
('Ingr_CARROT', '=', 0.0)
('Ingr_CHICKPEAS', '=', 0.0)
('Ingr_LETTUCE', '=', 0.58548009)
('Ingr_OIL', '=', 0.0)
('Ingr_SPINACH', '=', 0.0)
('Ingr_SUNFLOWER', '=', 0.0)
('Ingr_TOFU', '=', 0.87822014)
('Ingr_TOMATO', '=', 0.0)
('Total kCal of Ingredients per salad = ', 114.75409824)

比率0.9

('Status:', 'Optimal')
('Ingr_CARROT', '=', 0.0)
('Ingr_CHICKPEAS', '=', 0.0)
('Ingr_LETTUCE', '=', 4.4146501)
('Ingr_OIL', '=', 0.0)
('Ingr_SPINACH', '=', 0.0)
('Ingr_SUNFLOWER', '=', 0.0)
('Ingr_TOFU', '=', 0.49051668)
('Ingr_TOMATO', '=', 0.0)
('Total kCal of Ingredients per salad = ', 129.4964032)