Python解決非線性規劃問題(運籌學作業)

Python解決非線性規劃問題(運籌學作業)

題目描述

幫一個小夥伴寫的運籌學實驗作業,這類問題一般好像都是使用lingo這類統計軟件來求解,查了一下發現scipy的優化模塊也可以完成
題目如圖:
EFC178E1333D3E1AB2615C20A670B52A.jpg

求解思路

CE0B2D5F429D6B593A7DD602FFC31482.jpg

代碼實現

其實就是簡單的優化問題,理清題目,設置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

參考

  1. https://www.kesci.com/home/project/5dc28179080dc3003720037b
  2. https://wenku.baidu.com/view/c8e5afd180eb6294dd886cff
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章