coin-or / pulp

A python Linear Programming API
http://coin-or.github.io/pulp/
Other
2k stars 376 forks source link

LP model sensitivity analysis - slack and shadow price overview #589

Open gufokick opened 1 year ago

gufokick commented 1 year ago

What is your question

Hello there,

I was trying to run the same code that my teacher uploaded since i was expecting the same result but the sensitivity analysis that i run gave me "none" output as slack variable and so. Is there any thing that i missed?

Import PuLP modeler functions

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}

Create the 'prob' variable to contain the problem data

prob = LpProblem("Blending_Model", 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

ingredient_vars

The objective function is added to 'prob' first

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

The five constraints are added to 'prob'

prob += lpSum([ingredient_vars[i] for i in Ingredients]) == 100, "GramsSum" 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"

prob

The problem is solved using PuLP's choice of Solver

prob.solve()

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 the Cat Food = ", value(prob.objective))

import pandas as pd

Report Sensitivity Analysis

print("\nSensitivity Analysis") Cons_Sensitivity_Report=[{'Constraint_Name':name,'Slack':c.slack,"Shadow_Price":c.pi} for name, c in prob.constraints.items()] print(pd.DataFrame(Cons_Sensitivity_Report)) print("\n") Variable_Sensitivity_Report = [{'Variable_Name': v.name, 'Value':v.varValue,'Reduced_Cost': v.dj} for v in prob.variables()]

print(pd.DataFrame(Variable_Sensitivity_Report)[['Variable_Name','Value','Reduced_Cost']])

Sensitivity analysis report output is looks like below: Sensitivity Analysis Constraint_Name Slack Shadow_Price 0 GramsSum None None 1 ProteinRequirement None None 2 FatRequirement None None 3 FibreRequirement None None 4 SaltRequirement None None

Variable_Name Value Reduced_Cost 0 Ingr_BEEF 60.0 None 1 Ingr_CHICKEN 0.0 None 2 Ingr_GEL 40.0 None 3 Ingr_MUTTON 0.0 None 4 Ingr_RICE 0.0 None 5 Ingr_WHEAT 0.0 None

Kiofor commented 1 year ago

I have the same issue. Running a very simple LP:

import pulp
prob = pulp.LpProblem("test080", pulp.LpMinimize)
x = pulp.LpVariable("x", 0, 5)
y = pulp.LpVariable("y", -1, 1)
z = pulp.LpVariable("z", 0)
c1 = x+y <= 5
c2 = x+z >= 10
c3 = -y+z == 7

prob += x + 4*y + 9*z, "obj"
prob += c1, "c1"
prob += c2,"c2"
prob += c3,"c3"

prob.solve()

print(c1.pi, c2.pi, c3.pi)

I get None None None as result. Python 3.9.13 pulp 2.6.0

However, when I downgrade to Python 3.7.7 and pulp 1.6.8, this MWE works with no issues.