Reputation: 53
I'm trying to replicate this simple optimisation problem in order to get started with Scipy.optimize. The problem is a classic product mix-problem, where the objective is to maximize profit given some production and ingredients constraints, in this case it is a coffee shop with three coffee types.
Constraints:
Objective function
Here is my code (please note that I run it in a notebook):
from scipy.optimize import minimize
#profit / cup
Reg = 1.25
Lat = 2.00
Moc = 2.25
#objective function to maximize
def objective(x):
return (x[0]*Reg + x[1]*Lat + x[2]*Moc)
#constraints
def cons_total_production(x):
return (sum(x))-500
def cons_choc(x):
return (x[2])-125
def cons_milk(x):
return (sum(x[1:]))-350
cons1 = {'type':'ineq', 'fun':cons_total_production}
cons2 = {'type':'ineq', 'fun':cons_choc}
cons3 = {'type':'ineq', 'fun':cons_milk}
cons = [cons1,cons2,cons3]
#boundries
bnds = ((0,None),(0,None),(0,None))
#initial guess
x0 = [250,150,100]
#let scipy do its magic
sol = minimize(objective, x0, constraints=cons, bounds=bnds)
This produces the correct output. How is that even possible when i use scipy minimize?
fun: 918.7499999999358
jac: array([ 1.25, 2. , 2.25])
message: 'Optimization terminated successfully.'
nfev: 50
nit: 10
njev: 10
status: 0
success: True
x: array([ 150., 225., 125.])
But when I try to add one more constrain, the output is wrong. If I for instance would make a constrain that states that x0 must be equal to x1, I would change the following and run the model again:
def cons_eq(x):
return x[0]-x[1]
cons4 = {'type':'eq', 'fun':cons_eq}
cons = [cons1, cons2, cons3, cons4]
But now my constrain x2<=125 is ignored:
fun: 937.4999999999934
jac: array([ 1.25, 2. , 2.25])
message: 'Optimization terminated successfully.'
nfev: 35
nit: 7
njev: 7
status: 0
success: True
x: array([ 150., 150., 200.])
Any suggestions? thx...
Upvotes: 0
Views: 372
Reputation: 189
The problem lies in both your objective function and the constraints. Since you are using scipy's minimize function, you must minimize the negative of the objective function to find the maximum of the function (It is slightly tricky).
#objective function to maximize
def objective(x):
return -1.0*(x[0]*Reg + x[1]*Lat + x[2]*Moc)
You have also incorrectly typed the inequality functions. If you look at the scipy documentation, all inequalities are in the form g(x)>=0. So, for example, if you want x2 <= 125, you must multiply by negative 1 (to switch the inequality), then add 125 which gets: g(x) = 125-x2 >= 0. So for the rest of your constraints:
#constraints
def cons_total_production(x):
return (-1.0*sum(x))+500
def cons_choc(x):
return (-1.0*x[2])+125
def cons_milk(x):
return (-1.0*sum(x[1:]))+350
Which will give you the outputs:
fun: -918.7499999999989
jac: array([-1.25, -2. , -2.25])
message: 'Optimization terminated successfully.'
nfev: 35
nit: 7
njev: 7
status: 0
success: True
x: array([ 150., 225., 125.])
fun: -890.62499998809
jac: array([-1.25, -2. , -2.25])
message: 'Optimization terminated successfully.'
nfev: 10
nit: 2
njev: 2
status: 0
success: True
x: array([ 187.5, 187.5, 125. ])
Linear programming is so cool!
Hope it helps :)
Upvotes: 3