import numpy as np
from scipy.optimize import linprog
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
%matplotlib inline
We can write out the LP as:
$$\max 6x_1 + 3x_2 + 4x_3$$$$s.t.$$$$3x_1 + x_2 + 4x_3 \le b_1$$$$2x_1 + 2x_2 + x_3 \le b_2$$$$x_1, x_2, x_3 \ge 0$$The dual can be formulated as:
$$\min b_1 u_1 + b2 u_2$$$$s.t.$$$$3u_1 + 2u_2 \ge 6$$$$u_1 + 2u_2 \ge 3$$$$4u_1 + u_2 \ge 4$$$$u_1, u_2 \ge 0$$#creating arrays
c_a1 = np.array([6, 3, 4]) #objective function
A_a1 = np.array([[3, 1, 4], #constraints
[2, 2, 1]])
b_a1 = np.array([100,100]) #bvalues
# Solve the problem
res_a1 = linprog(-c_a1, A_ub=A_a1, b_ub=b_a1, method='revised simplex')
res_a1
con: array([], dtype=float64) fun: -225.00000000000003 message: 'Optimization terminated successfully.' nit: 2 slack: array([-2.84217094e-14, 0.00000000e+00]) status: 0 success: True x: array([25., 25., 0.])
# max profit:
-res_a1.fun
225.00000000000003
#Now with the new machine
c_a2 = np.array([6, 3, 4]) #objective function is unchanged
A_a2 = np.array([[1.5, .5, .5], #constraints
[1, .5, 1],
[1,1,.5]])
b_a2 = np.array([66.7,66.7, 66.7]) #bvalues
res_a2 = linprog(-c_a2, A_ub=A_a2, b_ub=b_a2, method='revised simplex')
res_a2
con: array([], dtype=float64) fun: -346.84000000000003 message: 'Optimization terminated successfully.' nit: 3 slack: array([0., 0., 0.]) status: 0 success: True x: array([26.68, 26.68, 26.68])
#profit
-res_a2.fun
346.84000000000003
-(res_a2.fun - res_a1.fun)
121.84
#Now with the new machine and 100 hours per machine
c_a3 = np.array([6, 3, 4]) #objective function is unchanged
A_a3 = np.array([[1.5, .5, .5], #constraints
[1, .5, 1],
[1,1,.5]])
b_a3 = np.array([100,100, 100]) #bvalues
res_a3 = linprog(-c_a3, A_ub=A_a3, b_ub=b_a3, method='revised simplex')
res_a3
con: array([], dtype=float64) fun: -520.0 message: 'Optimization terminated successfully.' nit: 3 slack: array([-1.42108547e-14, 0.00000000e+00, 0.00000000e+00]) status: 0 success: True x: array([40., 40., 40.])
#The extra profit:
-(res_a3.fun-res_a2.fun)
#comes from the loosened constraint on the time - basically increasing the number of hours
173.15999999999997
Comes from the loosened constraint on the time for each machine - basically increasing the number of hours that each machine can be operated from 66.7 to 100.
Which model is more realistic would depend on the particulars of the company. If you needed someone to operate the machine continuously and you only have a total of 200 hours of labor available then splitting up the 200 hours into 66.7 for each machine makes sense. But if it is not necessary to man the machines, and that the 100 hours of machine running time is dictated by, for example, the factory time, then perhaps the constraint where each machine can run 100 hours would make more sense.