基于 python pulp 库求解船舶泊位调度线性规划问题
生活随笔
收集整理的這篇文章主要介紹了
基于 python pulp 库求解船舶泊位调度线性规划问题
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
目錄
- 基于 python pulp 庫(kù)求解船舶泊位調(diào)度線性規(guī)劃問(wèn)題
- 泊位調(diào)度問(wèn)題建模
- 代碼實(shí)現(xiàn)
- 準(zhǔn)備包
- 代碼講解
- 繪制圖像
- 完整代碼
- 題外話
基于 python pulp 庫(kù)求解船舶泊位調(diào)度線性規(guī)劃問(wèn)題
泊位調(diào)度問(wèn)題建模
- 船舶泊位調(diào)度問(wèn)題指將進(jìn)港的船舶有序規(guī)劃, 使各個(gè)船舶進(jìn)港, 離港時(shí)間和位置都不沖突
- 由于是幫朋友做的, 他直接把模型給了我, 建模本人也不太了解, 下面就直接放一下模型.
min?f(x,y,z)=∑i=1T{c1i∣xi?pi∣+c2i(yi+bi?di)+}s.t.{xi+li≤L,i=1,2,?,Lxi+li≤xj+M(1?Zijx),i=1,?,l;j=1,?,l;i≠jyi+bi≤yj+M(1?Zijy),i=1,?,l;j=1,?,l;i≠jZijx+Zijy+Zjix+Zjiy≥1,i=1,?,l;j=1,?,l;i<jyi≥ai,i=1,?,lxi≥0,i=1,?,lZijx,Zijy=0,1,i=1,?,l;j=1,?,l;i≠j\min f(x, y, z)=\sum_{i=1}^{T}\left\{c_{1 i}\left|x_{i}-p_{i}\right|+c_{2 i}\left(y_{i}+b_{i}-d_{i}\right)^{+}\right\} \\ s.t. \left\{ \begin{array}{l} x_{i}+l_{i} \leq L, i=1,2, \cdots, L \\ x_{i}+l_{i} \leq x_{j}+M\left(1-Z_{i j}^{x}\right), i=1, \cdots, l ; j=1, \cdots, l ; i \neq j \\ y_{i}+b_{i} \leq y_{j}+M\left(1-Z_{i j}^{y}\right), i=1, \cdots, l ; j=1, \cdots, l ; i \neq j \\ Z_{i j}^{x}+Z_{i j}^{y}+Z_{j i}^{x}+Z_{j i}^{y} \geq 1, i=1, \cdots, l ; j=1, \cdots, l ; i<j \\ y_{i} \geq a_{i}, i=1, \cdots, l \\ x_{i} \geq 0, i=1, \cdots, l \\ Z_{i j}^{x}, Z_{i j}^{y}=0,1, i=1, \cdots, l ; j=1, \cdots, l ; i \neq j \\ \end{array} \right. minf(x,y,z)=i=1∑T?{c1i?∣xi??pi?∣+c2i?(yi?+bi??di?)+}s.t.????xi?+li?≤L,i=1,2,?,Lxi?+li?≤xj?+M(1?Zijx?),i=1,?,l;j=1,?,l;i=jyi?+bi?≤yj?+M(1?Zijy?),i=1,?,l;j=1,?,l;i=jZijx?+Zijy?+Zjix?+Zjiy?≥1,i=1,?,l;j=1,?,l;i<jyi?≥ai?,i=1,?,lxi?≥0,i=1,?,lZijx?,Zijy?=0,1,i=1,?,l;j=1,?,l;i=j?- 其中pi,ai,bi,di,li,c1i,c2ip_i,a_i,b_i,d_i,l_i,c_{1i},c_{2i}pi?,ai?,bi?,di?,li?,c1i?,c2i?均為隨機(jī)生成的參數(shù)
代碼實(shí)現(xiàn)
準(zhǔn)備包
- Pulp 庫(kù)安裝: pip install PuLP(anaconda 不能使用conda install PuLP, conda 庫(kù)里沒有 Pulp 包)
- Pulp 庫(kù)的使用可以看看 YouCans 大大的文章, 這里就不過(guò)多介紹了
- matplotlib: conda install matplotlib
- pandas: conda install pandas
代碼講解
- createPara(l)隨機(jī)生成模型中的參數(shù)并存儲(chǔ)到 dataframe 中
- createVar(l)函數(shù)根據(jù)船只數(shù)生成對(duì)應(yīng)變量(根據(jù)模型,船只數(shù)變化時(shí),變量數(shù)量是要變化的)
- createPulpVar(x_variables, y_variables, zx_variables, zy_variables, abs_variables)函數(shù)將createVar(l)函數(shù)生成的變量轉(zhuǎn)換為pulp庫(kù)中的變量PulpVar
- main(l)主函數(shù), 輸入船只數(shù), 調(diào)用上述函數(shù), 生成模型并進(jìn)行求解
繪制圖像
- getColor()函數(shù)以及draw(model, l, df)用于可視化結(jié)果.
- 單純看結(jié)果的'Optimal'(有最優(yōu)解)或'Infeasible'(無(wú)解)不夠直觀
- 設(shè)計(jì)了兩個(gè)函數(shù), 用于在有最優(yōu)解時(shí), 繪制出最優(yōu)解對(duì)應(yīng)的船舶調(diào)度方案和目標(biāo)值, 給出更直觀的圖像
- getColor()函數(shù)用以給各個(gè)船舶隨機(jī)生成顏色
- draw(model, l, df)用于繪制結(jié)果
- 生成圖像展示
- 五輛船舶時(shí)有最優(yōu)解
- 輸出結(jié)果--------------------船舶數(shù)量為5-------------------- 參數(shù)列表:vessel p_i a_i b_i d_i l_i c_{1i} c_{2i} 0 0 520 73 8 2 276 5 9 1 1 323 21 8 55 199 9 9 2 2 297 0 6 0 287 5 5 3 3 174 13 11 34 159 5 5 4 4 38 23 11 29 236 5 7 求解狀態(tài): Optimal BerthLocation: [520.0, 323.0, 297.0, 174.0, 38.0] BerthTime: [73.0, 47.0, 0.0, 34.0, 23.0]
- 結(jié)果圖像
- 25輛船時(shí)無(wú)解--------------------船舶數(shù)量為25-------------------- 參數(shù)列表:vessel p_i a_i b_i d_i l_i c_{1i} c_{2i} 0 0 535 11 11 87 198 8 6 1 1 537 73 7 68 278 6 5 2 2 103 7 8 34 171 5 7 3 3 19 17 7 33 199 5 5 4 4 138 64 7 21 208 5 9 5 5 455 74 10 54 198 8 6 6 6 543 45 9 7 247 9 7 7 7 479 33 9 71 268 9 8 8 8 176 20 8 40 284 8 8 9 9 364 59 8 100 179 7 9 10 10 367 29 10 56 275 7 6 11 11 280 39 8 88 286 9 7 12 12 411 63 8 38 280 9 7 13 13 475 71 11 96 205 8 9 14 14 154 29 6 88 174 7 8 15 15 98 8 11 78 258 7 9 16 16 100 62 9 64 238 7 5 17 17 303 45 9 97 265 6 6 18 18 407 50 9 34 232 9 7 19 19 113 55 6 75 286 7 7 20 20 538 3 10 99 176 5 7 21 21 309 46 8 72 223 9 7 22 22 358 26 11 22 208 8 5 23 23 456 61 9 63 172 6 7 24 24 33 11 8 69 259 5 8 求解狀態(tài): Infeasible
完整代碼
# -*- encoding: utf-8 -*-import random import pulp import pandas as pd import matplotlib.pyplot as plt# 常量 L = 900 # 總泊位長(zhǎng)度 M = 9999999 # 大M法def createPara(l):'''用df存儲(chǔ)隨機(jī)生成的參數(shù)Args:l (int): number of vesselsReturns:dataframe: 參數(shù)表格'''df = pd.DataFrame() # 創(chuàng)建一個(gè)空dataframe(空表格)df['vessel'] = list(range(l)) # 船只的編號(hào):0-l-1, 共l搜船只# random.randint(x,y): 生成一個(gè)x到y(tǒng)之間的隨機(jī)整數(shù)# [random.randint(x,y) for i in range(l)]: 生成一個(gè)長(zhǎng)度為l的列表,列表中的元素均為x到y(tǒng)之間的隨機(jī)整數(shù)# df['列名'] = 列表: 將列表賦值給df的列df['p_i'] = [random.randint(0, 550) for i in range(l)] # best berth location of vessel idf['a_i'] = [random.randint(0, 75) for i in range(l)] # expected arrival time of vessel idf['b_i'] = [random.randint(6, 11) for i in range(l)] # ship operational time required for vessel idf['d_i'] = [random.randint(0, 100) for i in range(l)] # requested departure time of vessel idf['l_i'] = [random.randint(150, 300) for i in range(l)] # length of vessel idf['c_{1i}'] = [random.randint(5, 9) for i in range(l)] # additonal travel cost of vessel idf['c_{2i}'] = [random.randint(5, 9) for i in range(l)] # penalty cost of vessel ireturn dfdef createVar(l):'''創(chuàng)建變量Args:l (int): number of vesselsReturns:list: 每個(gè)列表存儲(chǔ)不同種類的變量'''x_variables = ['x_' + str(i) for i in range(l)] # berth location of vessel iy_variables = ['y_' + str(i) for i in range(l)] # berthing time of vessel izx_variables = [[f'zx_{i}{j}' for j in range(l)] for i in range(l)] # zx_{ij} = 1 if vessel i located to the left_hand of vessel jzy_variables = [[f'zy_{i}{j}' for j in range(l)] for i in range(l)] # zy_{ij} = 1 if vessel i located below vessel jabs_variables = [f'abs_{i}' for i in range(l)] # 目標(biāo)函數(shù)中有絕對(duì)值, 然而線性規(guī)劃中是不支持絕對(duì)值的, 所以需要新增一個(gè)變量來(lái)代替絕對(duì)值return x_variables, y_variables, zx_variables, zy_variables, abs_variablesdef createPulpVar(x_variables, y_variables, zx_variables, zy_variables, abs_variables):'''將變量轉(zhuǎn)換為pulp變量直接創(chuàng)建變量是不能用在pulp中的, 需要將變量轉(zhuǎn)換為pulp的變量, 在目標(biāo)函數(shù)和約束條件中必須使用pulp變量Args:x_variables (lsit): berth locationy_variables (list): berthing timezx_variables (list): if vessel i located to the left_hand of vessel jzy_variables (list): if vessel i located below vessel jabs_variables (list): a variable to replace the absolute value'''# lowBound=0: 變量的下界為0, cat='Integer': 變量的類型為整數(shù), cat='Binary': 變量值為0或1BerthLocation = pulp.LpVariable.dicts('BerthLocation', x_variables, lowBound=0, cat='Integer') # 將x_variables轉(zhuǎn)換為pulp變量BerthTime = pulp.LpVariable.dicts('BerthTime', y_variables, lowBound=0, cat='Integer') # 將y_variables轉(zhuǎn)換為pulp變量LeftSide = pulp.LpVariable.dicts('LeftSide',[item for row in zx_variables for item in row],lowBound=0,cat='Binary',) # 將zx_variables轉(zhuǎn)換為pulp變量Below = pulp.LpVariable.dicts('Below',[item for row in zy_variables for item in row],lowBound=0,cat='Binary',) # 將zy_variables轉(zhuǎn)換為pulp變量Abs = pulp.LpVariable.dicts('Abs', abs_variables, lowBound=0, cat='Integer') # 將abs_variables轉(zhuǎn)換為pulp變量return BerthLocation, BerthTime, LeftSide, Below, Absdef getColor():'''生成隨機(jī)顏色以上色'''color1 = random.randint(16, 255)color2 = random.randint(16, 255)color3 = random.randint(16, 255)color1 = hex(color1)color2 = hex(color2)color3 = hex(color3)ans = "#" + color1[2:] + color2[2:] + color3[2:]return ansdef draw(model, l, df):'''繪制圖像直觀顯示結(jié)果'''x_list, y_list = [0 for i in range(l)], [0 for i in range(l)] # 初始化兩個(gè)列表分別用以存儲(chǔ)x,y的值for v in model.variables():if 'BerthLocation' in v.name:x_list[int(v.name[-1])] = v.varValue # 將變量的值按順序存儲(chǔ)if 'BerthTime' in v.name:y_list[int(v.name[-1])] = v.varValueprint('BerthLocation:', x_list)print('BerthTime:', y_list)plt.figure()for i in range(l):# 繪制每個(gè)船只的矩形color = getColor() # 隨機(jī)生成顏色rect = plt.Rectangle((x_list[i], y_list[i]), # 矩形左下角坐標(biāo)為(BerthLocation, BerthTime)df.iloc[i, 5], # 矩形的寬度為length of vesseldf.iloc[i, 3], # 矩形的高度為ship operational timecolor=color,fill=False,)plt.gca().add_patch(rect)plt.scatter(df.iloc[i, 1], df.iloc[i, 4], color=color) # 在圖上標(biāo)出該船只的(best location, required departure time)plt.title(f'BerthAllocation of {l} vessels') # 標(biāo)題plt.legend(['vessel', 'best location and required departure time']) # 圖例plt.grid(True) # 顯示網(wǎng)格plt.axis('auto') # 使x,y軸比例相同plt.xlabel('Berths')plt.ylabel('Date')plt.show()def main(l):'''線性規(guī)劃模型Args:l (int): number of vessels'''model = pulp.LpProblem('BerthAllocation', pulp.LpMinimize)# 用dataframe存儲(chǔ)隨機(jī)生成的系數(shù)df = createPara(l) # 隨機(jī)生成參數(shù)print('參數(shù)列表:')print(df) # 打印隨機(jī)生成的參數(shù)x_variables, y_variables, zx_variables, zy_variables, abs_variables = createVar(l) # 創(chuàng)建變量BerthLocation, BerthTime, LeftSide, Below, Abs = createPulpVar(x_variables, y_variables, zx_variables, zy_variables, abs_variables) # 將變量轉(zhuǎn)換為pulp變量# 創(chuàng)建目標(biāo)函數(shù)model += pulp.lpSum([df.iloc[i, 6]* (Abs[abs_variables[i]]) # 使用絕對(duì)值變量代替|x_i-p_i|, 并在約束中增加對(duì)絕對(duì)值變量的約束保證取到了絕對(duì)值+ df.iloc[i, 7]* (BerthTime[y_variables[i]] + df.iloc[i, 3] - df.iloc[i, 4])for i in range(l)])# 增加約束for i in range(l):# 絕對(duì)值變量約束: 絕對(duì)值變量要大于等于(x_i-p_i)和(p_i-x_i), 從而保證取到了絕對(duì)值model += (Abs[abs_variables[i]] >= BerthLocation[x_variables[i]] - df.iloc[i, 1]) # 絕對(duì)值變量要大于等于(x_i-p_i)model += (Abs[abs_variables[i]] >= -BerthLocation[x_variables[i]] + df.iloc[i, 1]) # 絕對(duì)值變量要大于等于(p_i-x_i)# 其他約束# x_i >= 0 和 zx_ij, zy_ij 只能為0或1 在定義變量時(shí)已經(jīng)限制了, 約束中不需要寫了model += BerthLocation[x_variables[i]] + df.iloc[i, 5] <= L # x_i + l_i <= Lmodel += BerthTime[y_variables[i]] >= df.iloc[i, 2] # y_i >= a_imodel += (BerthTime[y_variables[i]] + df.iloc[i, 3] - df.iloc[i, 4] >= 0) # y_i + b_i - d_i >= 0 (目標(biāo)函數(shù)中的加號(hào)項(xiàng))for j in range(l):if i < j:model += (LeftSide[zx_variables[i][j]]+ Below[zy_variables[i][j]]+ LeftSide[zx_variables[j][i]]+ Below[zy_variables[j][i]]>= 1) # zx_ij + zy_ij + zx_ji + zy_ji >= 1if i != j:model += (BerthLocation[x_variables[i]] + df.iloc[i, 5]<= BerthLocation[x_variables[j]]+ (1 - LeftSide[zx_variables[i][j]]) * M) # x_i + l_i <= x_j + M * (1-zx_ij)model += (BerthTime[y_variables[i]] + df.iloc[i, 3]<= BerthTime[y_variables[j]] + (1 - Below[zy_variables[i][j]]) * M) # y_i + t_i <= y_j + M * (1-zy_ij)model.solve(pulp.apis.PULP_CBC_CMD(msg=False)) # 求解線性規(guī)劃模型(pulp.apis.PULP_CBC_CMD(msg=False)的作用為不顯示log)print("求解狀態(tài):", pulp.LpStatus[model.status]) # 打印求解狀態(tài), Optimal: 存在最優(yōu)解; Infeasible: 無(wú)解if pulp.LpStatus[model.status] == 'Optimal':# 若有最優(yōu)解, 則打印最優(yōu)解并繪制圖像draw(model, l, df)print("最優(yōu)總成本 = ", pulp.value(model.objective))if __name__ == '__main__':for number in range(5, 30, 5): # 分別生成船只數(shù)量為5,10,15,20,25時(shí)的最優(yōu)解print(f'--------------------船舶數(shù)量為{number}--------------------')main(number)題外話
- 幫學(xué)弟做的一門課程的大作業(yè), 我自認(rèn)為做的不錯(cuò), 然而他老師給他大作業(yè)打了 0 分, 不知道什么原因, 可能是因?yàn)樗蠋熣{(diào)研過(guò)班里并沒有人會(huì) python, 覺得第一次用 python 不可能寫成這樣? 還是確實(shí)哪里做錯(cuò)了, 請(qǐng)大家指正.
總結(jié)
以上是生活随笔為你收集整理的基于 python pulp 库求解船舶泊位调度线性规划问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: unittest测试mms医药系统登录模
- 下一篇: 武汉理工转专业计算机笔试,计算机学院武汉