Python解決非線性規劃問題(運籌學作業)
題目描述
幫一個小夥伴寫的運籌學實驗作業,這類問題一般好像都是使用lingo這類統計軟件來求解,查了一下發現scipy的優化模塊也可以完成
題目如圖:
求解思路
代碼實現
其實就是簡單的優化問題,理清題目,設置9個決策變量,分別表示前中後三艙中各放ABC三種商品的數量,然後拆解出1個目標函數表達式,12個約束條件表達式
使用scipy.optimize
中的minimize函數,將決策變量、目標函數表達式、約束條件表達式代入即可,由於本題中含有非線性約束條件,需要自定義約束條件表達式,如果題目中全部爲線性約束,可以直接使用scipy.optimize
中的linprog方法求解,代碼量較少
需要注意的一點是,minimize函數是最小化目標函數,所以這裏將改爲-minimize(target_F)
全部代碼如下:
import math
import numpy as np
from scipy.optimize import minimize
MAX_H_FRONT = 2200 # 前艙最大載重
M_FRONT = 4200 # 前艙容量
MAX_H_MIDDLE = 3200 # 中艙最大載重
M_MIDDLE = 5400 # 中艙容量
MAX_H_BOTTOM = 1200 # 後艙最大載重
M_BOTTOM = 1200 # 後艙容量
M_A = 11 # A商品體積
M_B = 6 # B商品體積
M_C = 8 # C商品體積
H_A = 9 # A商品重量
H_B = 8 # B商品重量
H_C = 6 # C商品重量
PRICE_A = 1200 # A商品運費
PRICE_B = 800 # B商品運費
PRICE_C = 700 # C商品運費
ALL_A = 650 # A商品數量
ALL_B = 1100 # B商品數量
ALL_C = 900 # C商品數量
def target_F(x):
"""
目標函數,決策變量共9個,分別表示每種商品在前中後船艙的數量
:param x:
:return:
"""
return -x[0] * PRICE_A - x[1] * PRICE_A - x[2] * PRICE_A - x[3] * PRICE_B - x[4] * PRICE_B - x[5] * PRICE_B - x[
6] * PRICE_C - x[7] * PRICE_C - x[8] * PRICE_C
def cons1(x):
"""
約束條件1,前艙體積條件
:param x:
:return:
"""
return -(x[0] * M_A + x[3] * M_B + x[6] * M_C - M_FRONT)
def cons2(x):
"""
約束條件2,中艙體積條件
:param x:
:return:
"""
return -(x[1] * M_A + x[4] * M_B + x[7] * M_C - M_MIDDLE)
def cons3(x):
"""
約束條件3,後艙體積條件
:param x:
:return:
"""
return -(x[2] * M_A + x[5] * M_B + x[8] * M_C - M_BOTTOM)
def cons4(x):
"""
約束條件4,前艙重量條件
:param x:
:return:
"""
return -(x[0] * H_A + x[3] * H_B + x[6] * H_C - MAX_H_FRONT)
def cons5(x):
"""
約束條件5,中艙重量條件
:param x:
:return:
"""
return -(x[1] * H_A + x[4] * H_B + x[7] * H_C - MAX_H_MIDDLE)
def cons6(x):
"""
約束條件6,後艙重量條件
:param x:
:return:
"""
return -(x[2] * H_A + x[5] * H_B + x[8] * H_C - MAX_H_BOTTOM)
def cons7(x):
"""
約束條件7,商品A數量條件
:param x:
:return:
"""
return -(x[0] + x[1] + x[2] - ALL_A)
def cons8(x):
"""
約束條件8,商品B數量條件
:param x:
:return:
"""
return -(x[3] + x[4] + x[5] - ALL_B)
def cons9(x):
"""
約束條件9,商品C數量條件
:param x:
:return:
"""
return -(x[6] + x[7] + x[8] - ALL_C)
def cons10(x):
return -(abs((x[0] * H_A + x[3] * H_B + x[6] * H_C) / (x[1] * H_A + x[4] * H_B + x[7] * H_C)) - 0.16)
def cons11(x):
return -(abs((x[2] * H_A + x[5] * H_B + x[8] * H_C) / (x[1] * H_A + x[4] * H_B + x[7] * H_C)) - 0.16)
def cons12(x):
return -(abs((x[0] * H_A + x[3] * H_B + x[6] * H_C) / (x[2] * H_A + x[5] * H_B + x[8] * H_C)) - 0.12)
con1 = {'type': 'ineq', 'fun': cons1}
con2 = {'type': 'ineq', 'fun': cons2}
con3 = {'type': 'ineq', 'fun': cons3}
con4 = {'type': 'ineq', 'fun': cons4}
con5 = {'type': 'ineq', 'fun': cons5}
con6 = {'type': 'ineq', 'fun': cons6}
con7 = {'type': 'ineq', 'fun': cons7}
con8 = {'type': 'ineq', 'fun': cons8}
con9 = {'type': 'ineq', 'fun': cons9}
con10 = {'type': 'ineq', 'fun': cons10}
con11 = {'type': 'ineq', 'fun': cons11}
con12 = {'type': 'ineq', 'fun': cons12}
# 約束條件集合
cons_dict = ([con1, con2, con3, con4, con5, con6, con7, con8, con9, con10, con11, con12])
# 決策變量的符號約束(大於等於0)
b = (0.0, None)
bnds = (b, b, b, b, b, b, b, b, b)
# 定義決策變量初值
x0 = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1])
solution = minimize(target_F, x0, method='SLSQP', bounds=bnds, constraints=cons_dict)
x = solution.x
print(solution)
print('目標最大運費爲: {}'.format(int(-target_F(x))))
print('最優解爲: \n 前艙商品A:{}, 中艙商品A: {}, 後艙商品B: {} \n 前艙商品B:{}, 中艙商品B: {}, 後艙商品B: {} \n '
'前艙商品C:{}, 中艙商品C: {}, 後艙商品C: {}'.format(int(x[0]), int(x[1]), int(x[2]), int(x[3]), int(x[4]),
int(x[5]), int(x[6]), int(x[7]), int(x[8])))
輸出結果:
fun: -727505.7899115854
jac: array([-1200., -1200., -1200., -800., -800., -800., -700., -700.,
-700.])
message: 'Positive directional derivative for linesearch'
nfev: 76
nit: 10
njev: 6
status: 8
success: False
x: array([131.54613602, 356.7186423 , 70.79420437, 0. ,
0. , 70.79376337, 0. , 0. ,
0. ])
目標最大運費爲: 727505
最優解爲:
前艙商品A:131, 中艙商品A: 356, 後艙商品B: 70
前艙商品B:0, 中艙商品B: 0, 後艙商品B: 70
前艙商品C:0, 中艙商品C: 0, 後艙商品C: 0