为什么 PulP returns 混合问题的负值而 lowBound 设置为零?

Why PulP returns negative values for blending problem while the lowBound is set to zero?

我正在使用 Python PulP 来解决混合问题。输出很奇怪它 returns 负值。我想做什么


from pulp import *
import pandas as pd 

data = pd.read_csv('feed.csv')

# Get required data from user
Ingredients = ['CORN', 'SBM', 'LIMESTONE', 'SALT', 'BONE_MEAL', 'PALM_OIL']


def cost():
    costs = {}
    for i in Ingredients:
        costs[i] = data.loc[data['feed'] == i, 'cost'].iloc[0]
    return costs

def protein():
    proteinPercent = {}
    for i in Ingredients:
        proteinPercent[i] = data.loc[data['feed'] == i, 'protein'].iloc[0]
    return proteinPercent

def energy():
    energyKcal = {}
    for i in Ingredients:
        energyKcal[i] = data.loc[data['feed'] == i, 'energy'].iloc[0]
    return energyKcal


def calcium():
    cal = {}
    for i in Ingredients:
        cal[i] = data.loc[data['feed'] == i, 'calcium'].iloc[0]
    return cal

def sodium():
    sod = {}
    for i in Ingredients:
        sod[i] = data.loc[data['feed'] == i, 'sodium'].iloc[0]
    return sod

def minimum():
    min = {}
    for i in Ingredients:
        min[i] = data.loc[data['feed'] == i, 'min'].iloc[0]
    return min

def maximum():
    max = {}
    for i in Ingredients:
        max[i] = data.loc[data['feed'] == i, 'max'].iloc[0]
    return max

# Initialize
costs = cost()
proteinPercent = protein()
energyKcal = energy()
cal = calcium()
sod = sodium()
L = minimum()
U = maximum()

# Create the 'prob' variable to contain the problem data
prob = LpProblem("Broiler Ration Formulation", LpMinimize)

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

for i in Ingredients:
    prob += ingredient_vars[i] >= L[i]
    prob += ingredient_vars[i] <= U[i]


# The objective function is added to 'prob' first
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, "Percentages Sum"
prob += lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 19.0, "Min Protein Requirement"
prob += lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) <= 21.0, "Max Protein Requirement"
prob += lpSum([energyKcal[i] * ingredient_vars[i] for i in Ingredients]) >= 3100.0, "Min Energy Requirements"
prob += lpSum([energyKcal[i] * ingredient_vars[i] for i in Ingredients]) <= 3300.0, "Max Energy Requirements"
prob += lpSum([cal[i] * ingredient_vars[i] for i in Ingredients]) <= 1.1, "Calcium Requirements"
prob += lpSum([sod[i] * ingredient_vars[i] for i in Ingredients]) <= 0.2, "Sodium Requirements"


# The problem is solved using PuLP's choice of Solver
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 Cost of Ingredients per feed= ", value(prob.objective))
File feed.csv content
feed    min max cost    energy  protein calcium sodium
BONE_MEAL   0   10  0.7 1600    0   30.32   1
CORN    0   60  0.5 3350    9.4 0.05    0
.
.
.

一些输出变量是负数:

Status: Infeasible

Ingr_BONE_MEAL = 1.0

Ingr_CORN = 37.862563

Ingr_FISH_MEAL = 1.0

Ingr_LIMESTONE = -0.81506256

Ingr_PALM_OIL = 60.0

Ingr_SALT = -0.0475

Ingr_SBM = 1.0

Total Cost of Ingredients per Feed =  32.988153372

我搜索了可能的解决方案,但找不到任何解释,或者我的代码可能有误,但无法弄清楚究竟出了什么问题。

当您有一个 Infeasible 解决方案时,就会发生这种情况,这就是您在这里所拥有的。由于解决方案不可行,pulp 只是抛出一个解决方案,在该解决方案下可能会违反某些约束。您需要找出哪些约束与其他约束不兼容并更改它们。例如,也许您需要扩大卡路里范围。

您添加到 LpProblem 实例的第一件事将始终是 objective 函数,如 the PuLP documentation 中所述。您当前在代码中的顺序是:

for i in Ingredients:
   prob += ingredient_vars[i] >= L[i]
   prob += ingredient_vars[i] <= U[i]


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

你的问题实例的 objective 函数是 ingredient_vars[i] >= L[i] 这是没有意义的。

正确的方法是在约束之前添加 objective 函数部分,如下所示:

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

for i in Ingredients:
   prob += ingredient_vars[i] >= L[i]
   prob += ingredient_vars[i] <= U[i]

调试线性程序的一个好方法是使用 prob.writeLP('blendingprob') 方法,它会写出一个显示实际线性程序的 .lp 文件