Sam Ang
Sam Ang

Reputation: 3

Scipy.optimize violating/not respecting constraint

The problem definition is as follows:

This is done as follow in Python:

# import libraries
import numpy as np
import scipy.optimize as so

# Initialization
bnds = ((0, 550), (0, 550))
initial = np.asarray([400, 150])

# objective function
def maxZ(x_in, sign=1.0):
    x1, x2 = x_in[0:2]
    return sign * (45 * x1 + 20 * x2)

# constraints
def Cmaterial(x_in):
    x1, x2 = x_in[0:2]
    return 20 * x1 + 5 * x2 - 9500

def Ctime(x_in):
    x1, x2 = x_in[0:2]
    return 0.04 * x1 + 0.12 * x2 - 40

def Cstorage(x_in):
    x1, x2 = x_in[0:2]
    return x1 + x2 - 550

# constraint terms
con1 = {'type':'ineq', 'fun':Cmaterial}
con2 = {'type':'ineq', 'fun':Ctime}
con3 = {'type':'ineq', 'fun':Cstorage}
cons = [con1, con2, con3]

# Optimization
out = so.minimize(maxZ, initial, method='SLSQP', bounds=bnds, constraints=cons, args=(1.0,))
print(f"Optimum solution occurs at {out.x}, where Z = {out.fun}")
print(f"Material: {Cmaterial(out.x) + 9500}")
print(f"Production time: {Ctime(out.x) + 40}")
print(f"Storage: {Cstorage(out.x) + 550}")

The outcome is:

Optimum solution occurs at [427.27272727 190.90909091], where Z = 23045.45454545614
Material: 9500.00000000076
Production time: 40.00000000000009
Storage: 618.1818181818464

I have verified through graphical method and Excel verification that the expected result should be x1 = 450, x2 = 100.

The result from Scipy.optimize is x1 = 427.27, x2 = 190.91.

My question: the storage constraint of x1 + x2 ≤ 550 is clearly violated since the result is 618.18. What could be the reason for this?

Upvotes: 0

Views: 1054

Answers (1)

joni
joni

Reputation: 7157

First, you need to transform your maximization problem into a minimization problem, i.e. the sign argument inside maxZ should be -1.0, not 1.0. Note also that scipy.optimize.minimize expects inequality constraints with g(x) >= 0, not g(x) <= 0. Hence, you have to transform your constraints accordingly:

con1 = {'type':'ineq', 'fun': lambda x: -1.0*Cmaterial(x)}
con2 = {'type':'ineq', 'fun': lambda x: -1.0*Ctime(x)}
con3 = {'type':'ineq', 'fun': lambda x: -1.0*Cstorage(x)}
cons = [con1, con2, con3]

out = so.minimize(maxZ, initial, method='SLSQP', bounds=bnds, constraints=cons, args=(-1.0,))

yields your expected solution. Last but not least, this is a linear optimization problem (LP) and thus, should be solved with scipy.optimize.linprog. However, this requires that you formulate the problem in the standard LP form .

Upvotes: 2

Related Questions