【轉】2018年全國大學生數學建模大賽B題簡要分析(附代碼)

  今天早上跟學姐室友去復旦把論文答辯作掉了,雖然整個項目基本上是我承擔了主要的思路與代碼部分,可是今天答辯我跟室友居然連一句有用的話都沒說出來,全場都靠學姐開場流暢地引入,臨場隨機應變,從而得以與答辯教授歡聚喜散。主要緣由是教授居然準確地問到了我代碼裏一個細節卻至關致命的問題(是一個隨機初始化問題,我下面代碼部分會詳細提到),正好學姐室友都不是特別熟悉個人隨機初始化方法,我又不能當場跟他們兩個解釋這個隨機初始化的問題。我差點當場就要以「這樣隨機初始化可以減小代碼量」這種蹩腳的理由跟教授爭辯了。好在姜仍是老的辣,辯論隊隊長出身的學姐一頓 Speech Art 操做成功忽悠掉了兩位教授,最終兩位答辯教授仍是承認了咱們的模擬仿真方法[捂臉]。過後細想之後我成功也好,失敗也罷,恐怕也是成也言語,敗也言語。也許我確實可以成爲一個有能力的人,可是說話藝術確實是一門很大的學問。不過看我運氣一直這麼差,大機率仍是凡人一個落入俗套吧[攤手]。算法

  言歸正傳,本文主要介紹咱們小組解決2018年全國大學生B題的思路分析,不表明標準答案。固然我仍是有自知之明,自己水平不是很高,再加上三天時間限制,本身作出來的模型以及算法確定是比較差的。這裏僅僅從我我的的思考角度出發寫一些參考思路做爲分享討論,但願各位讀者朋友輕噴。app

問題分析

  今年的B題確實與往年有很大的不一樣。往年的數學建模問題每每具備比較好的開放性,問題解決存在較大的建模空間。今年的B題的題幹自己就幾乎是一個明確的模型(8臺CNC+1臺RGV+CNC定址),加上第二道任務要求咱們根據給定三組數據完成八小時內的RGV詳細調度方案,並寫入四張Excel表格,給人的感受就是要求咱們去完成一道填空題,而後附帶寫一篇論文[尷尬]。dom

  爲了方便各位讀者對賽題的閱讀,這裏給出連接:https://download.csdn.net/download/cy19980216/10708725佈局

  問題一共有四種不一樣的狀況:一道工序無端障,一道工序有故障,兩道工序無端障,兩道工序有故障。學習

一道工序無端障

  第一種狀況是最簡單的,直觀上直接不停地1234567812345678……按順序上料差很少就是最優了。但嚴謹地來講,雖然題目中給的三組數據確實都是用這種最幼稚的策略可以達到最優,可是若是對於通常的狀況而言,好比最極端的狀況下,RGV移動時間無窮大,那RGV顯然就只會不停地在121212121212……這樣原地上下料了。spa

  然而咱們發現不管參數怎麼變化,最終RGV給CNC上下料的過程始終是一個週期性過程。固然這個彷佛很「顯然」的事實倒是至關難以經過數學嚴格證實的(參數已知的狀況下通常比較容易證實,可是全部的參數都是未知的狀況下是很難嚴格說明的)。我賽後也仔細的思考過,可是也沒有得出很漂亮的證實。我最終僅僅是針對給定的三組數據使用了遺傳算法對RGV前17次上下料(17次是考慮從初始狀態開始循環兩圈的最短路徑)的最優路徑進行了搜索,而且利用窮舉證實了這是前17步最優的上下料次序。以後基本上就是不斷地循環。.net

  這裏的模擬退火遺傳算法比較雞肋,因此我不詳細說明,在第三種狀況我會詳細說明模擬退火遺傳算法的原理。code

  如下給出第一種狀況的模擬退火遺傳算法算法以及對應的窮舉最優證實 ↓↓↓orm

 1 # -*- coding:UTF-8 -*-
 2 """
 3  做者:囚生CY  4  平臺:CSDN  5  時間:2018/10/09  6  轉載請註明原做者  7  創做不易,僅供分享  8 """
 9  
 10 import math  11 import random  12 import itertools  13  
 14 """ 選取一組數據 """
 15 T = 580
 16 d1 = 23
 17 d2 = 41
 18 d3 = 59
 19 Te = 35
 20 To = 30
 21 Tc = 30
 22  
 23 CNCT = [To,Te,To,Te,To,Te,To,Te]                                         # CNC上下料時間
 24  
 25 N = 50
 26 L = 17
 27  
 28 varP = 0.1
 29 croP = 0.6
 30  
 31 croL = 4
 32 e = 0.99
 33  
 34 tm = [  35  [0,0,d1,d1,d2,d2,d3,d3],  36  [0,0,d1,d1,d2,d2,d3,d3],  37  [d1,d1,0,0,d1,d1,d2,d2],  38  [d1,d1,0,0,d1,d1,d2,d2],  39  [d2,d2,d1,d1,0,0,d1,d1],  40  [d2,d2,d1,d1,0,0,d1,d1],  41  [d3,d3,d2,d2,d1,d1,0,0],  42  [d3,d3,d2,d2,d1,d1,0,0],  43 ]  44  
 45 def update_state(state,t):  46     length = len(state)  47     for i in range(length):  48         if state[i] < t:  49             state[i] = 0  50         else:  51             state[i] -= t  52     return state  53  
 54 def time_calc(seq):  55     state = [0 for i in range(8)]                                           # 記錄CNC狀態
 56     isEmpty = [1 for i in range(8)]                                         # CNC是否爲空?
 57     currP = 0  58     total = 0  59     length = len(seq)  60     for No in seq:  61         nextP = No  62         t = tm[currP][nextP]  63         total += t                                                         # rgv移動
 64         state = update_state(state,t)                                     # 更新state
 65         if state[No]==0:                                                 # 代表CNC等待
 66             if isEmpty[No]:                                                 # 當前CNC空
 67                 t = CNCT[No]  68                 isEmpty[No] = 0  69             else:  70                 t = CNCT[No]+Tc  71             total += t  72             state = update_state(state,t)  73             state[No] = T  74         else:                                                             # 當前CNC忙
 75             total += state[No]                                             # 先等當前CNC結束
 76             state = update_state(state,state[No])  77             t = CNCT[No]+Tc  78             total += t  79             state = update_state(state,t)  80             state[No] = T  81         currP = No  82     total += tm[currP][0]  83     return total  84  
 85 def init_prob(sample):  86     prob = []  87     for seq in sample:  88  prob.append(time_calc(seq))  89     maxi = max(prob)  90     prob = [maxi-prob[i]+1 for i in range(N)]  91     temp = 0  92     for p in prob:  93         temp += p  94     prob = [prob[i]/temp for i in range(N)]  95     for i in range(1,len(prob)):  96         prob[i] += prob[i-1]  97     prob[-1] = 1                                                         # 精度有時候很出問題
 98     return prob  99  
100 def minT_calc(sample): 101     minT = time_calc(sample[0]) 102     index = 0 103     for i in range(1,len(sample)): 104         t = time_calc(sample[i]) 105         if t < minT: 106             index = i 107             minT = t 108     return minT,index 109     
110 def init(): 111     sample = [] 112     for i in range(N): 113  sample.append([]) 114         for j in range(L): 115             sample[-1].append(random.randint(0,7)) 116     return sample 117  
118 def select(sample,prob):                                                 # 選擇
119     sampleEX = [] 120     for i in range(N):                                                     # 取出N個樣本
121         rand = random.random() 122         for j in range(len(prob)): 123             if rand<=prob[j]: 124  sampleEX.append(sample[j]) 125                 break
126     return sampleEX 127  
128 def cross(sample,i):                                                     # 交叉
129     for i in range(len(sample)-1): 130         for j in range(i,len(sample)): 131             rand = random.random() 132             if rand<=croP*(e**i):                                         # 執行交叉
133                 loc = random.randint(0,L-croL-1) 134                 temp1 = sample[i][loc:loc+croL] 135                 temp2 = sample[j][loc:loc+croL] 136                 for k in range(loc,loc+croL): 137                     sample[i][k] = temp2[k-loc] 138                     sample[j][k] = temp1[k-loc] 139     return sample 140         
141 def variance(sample,i):                                                     # 變異算子 
142     for i in range(len(sample)): 143         rand = random.random() 144         if rand<varP*(e**i): 145             rand1 = random.randint(0,L-1) 146             rand2 = random.randint(0,L-1) 147             temp = sample[i][rand1] 148             sample[i][rand1] = sample[i][rand2] 149             sample[i][rand2] = temp 150     return sample 151     
152 def main(): 153     sample = init() 154     mini,index = minT_calc(sample) 155     best = sample[index][:] 156     print(best) 157     for i in range(10000): 158         print(i,'\t',minT_calc(sample),end="\t") 159         prob = init_prob(sample) 160         sample = select(sample,prob) 161         sample = cross(sample,i) 162         sample = variance(sample,i) 163         mi,index = minT_calc(sample) 164         if mi>mini and random.random()<e**i:                             # 精英保留策略
165             rand = random.randint(0,N-1) 166             sample[rand] = best[:] 167         mini,index = minT_calc(sample) 168         best = sample[index][:] 169         print(best) 170     print(sample) 171  
172 if __name__ == "__main__": 173  main1() 174     """ 窮舉搜索驗證 """
175     a = list(itertools.permutations([1,2,3,4,5,6,7],7)) 176     ts = [] 177     first = [0,1,2,3,4,5,6,7,0] 178     for i in a: 179         temp = first+list(i) 180  temp.append(0) 181         t = time_calc(temp) 182  ts.append(t) 183     print(min(ts)) 184     print(time_calc([0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0]))

一道工序有故障

這部分是學姐作的,學姐用了偏數學的思考方式,仍然從循環的角度去考慮,主要考慮故障發生是否會影響當前循環,是否須要創建新的循環。所以就沒有寫代碼處理問題了。具體的思路我確實不是很能講清楚。可是這裏面有一個很是大的問題,就是若是出現多臺CNC同時發生故障怎麼辦。關於多臺機器同時發生故障的機率,咱們經過估算認爲以給定的三組數據8小時內會出現這種特殊狀況的可能性大約爲30%。這個問題是我沒法很好嚴格處理的(固然若是用貪心算法也就沒這麼多事了)。blog

兩道工序無端障 & 兩道工序有故障
這兩個部分都是我來處理的,由於使用的方法大體相同,就並在一塊兒說了。

兩道工序與一道工序最大的區別在於三點:

一、開始要處理CNC任務分配:分配給第一道工序幾臺CNC,分配給第二道工序幾臺CNC?具體怎麼佈局?

二、加工過程可能仍然是一個循環,可是這個循環將可能會很是的龐大以致於不可能直觀的看出來。

三、兩道工序的分配已是一個嚴格的NP難問題了(即理論上沒法在多項式時間內求得最優解)。

第一點個人想法很單純——窮舉,沒錯,就是窮舉,除了顯然不合適的分配方案外,其餘方案都試一遍(雖然真的很蠢,可是我真的想不出到底能怎麼辦了)

第二點由於不存在循環則使用遺傳算法須要設定一個至關長的染色體長度(咱們設定的染色體是RGV爲各臺CNC上下料的次序,若是要考慮全過程的模擬退火遺傳算法,則染色體長度大約在300~400左右)。事實上我也嘗試了這個方法,結果從我寫完這個算法我開始跑,一直跑到比賽結束算法依舊沒有收斂[捂臉]。這裏給出代碼僅供參考(各位朋友要是有好意見也能夠提出) ↓↓↓

 1 # -*- coding:UTF-8 -*-
 2 """
 3  做者:囚生CY  4  平臺:CSDN  5  時間:2018/10/09  6  轉載請註明原做者  7  創做不易,僅供分享  8 """
 9 import random  10  
 11 # 第1組
 12 """
 13 d1 = 20  14 d2 = 33  15 d3 = 46  16 T1 = 400  17 T2 = 378  18 To = 28  19 Te = 31  20 Tc = 25  21 """
 22  
 23 # 第2組
 24 """
 25 d1 = 23  26 d2 = 41  27 d3 = 59  28 T1 = 280  29 T2 = 500  30 To = 30  31 Te = 35  32 Tc = 30  33 """
 34  
 35 # 第3組
 36 d1 = 18
 37 d2 = 32
 38 d3 = 46
 39 T1 = 455
 40 T2 = 182
 41 To = 27
 42 Te = 32
 43 Tc = 25
 44  
 45 cncT = [To,Te,To,Te,To,Te,To,Te]  46 tm = [  47  [0,0,d1,d1,d2,d2,d3,d3],  48  [0,0,d1,d1,d2,d2,d3,d3],  49  [d1,d1,0,0,d1,d1,d2,d2],  50  [d1,d1,0,0,d1,d1,d2,d2],  51  [d2,d2,d1,d1,0,0,d1,d1],  52  [d2,d2,d1,d1,0,0,d1,d1],  53  [d3,d3,d2,d2,d1,d1,0,0],  54  [d3,d3,d2,d2,d1,d1,0,0],  55 ]  56 Type = [1,0,1,0,1,0,0,0]                                                 # CNC刀具分類
 57  
 58 N = 64
 59 L = 100
 60 varP = 0.1
 61 croP = 0.6
 62 croL = 2
 63 e = 0.99
 64  
 65 def init_first_round():                                                     # 第一圈初始化(默認把全部第一道CNC按順序加滿再回到當前位置所有加滿)
 66     state = [0 for i in range(8)]                                           # 記錄CNC狀態(還剩多少秒結束,0表示空閒)
 67     isEmpty = [1 for i in range(8)]                                         # CNC是否爲空
 68     rgv = 0                                                                 # rgv狀態(0表示空車,1表示載着半成品)
 69     currP = 0  70     total = 0  71     seq = []  72     flag = False  73     for i in range(len(Type)):  74         if Type[i]==0:  75  seq.append(i)  76             flag = True  77     currP = seq[0]  78  seq.append(currP)  79     rgv,currP,total = time_calc(seq,state,isEmpty,rgv,currP,total)  80     return state,isEmpty,rgv,currP,total,seq  81  
 82 def update(state,t):  83     for i in range(len(state)):  84         if state[i] < t:  85             state[i] = 0  86         else:  87             state[i] -= t  88  
 89 def time_calc(seq,state,isEmpty,rgv,currP,total):                         # 事實上sequence多是無效的,因此可能須要
 90     index = 0  91     temp = 0  92     while index<len(seq):  93         """ 先移動到下一個位置 """
 94         nextP = seq[index]  95         t = tm[currP][nextP]  96         total += t  97  update(state,t)  98         if Type[nextP]==0:                                                 # 若是下一個位置是第一道工做點
 99             if rgv==1:                                                     # 然而載着半成品
100                 seq.pop(index)                                             # 去掉這個元素並停止當次循環進入下一個循環
101                 continue                
102             if isEmpty[nextP]:                                             # 若是下一個位置是空的
103                 t = cncT[nextP] 104                 total += t 105  update(state,t) 106                 state[nextP] = T1                                         # 更新當前的CNC狀態
107                 isEmpty[nextP] = 0                                         # 就不空閒了
108             else:                                                         # 若是沒有空閒
109                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
110                     t = state[nextP] 111                     total += t 112  update(state,t) 113                 t = cncT[nextP]                                             # 完成一次上下料
114                 total += t 115  update(state,t) 116                 state[nextP] = T1 117                 rgv = 1
118         else:                                                             # 若是下一個位置是第二道工做點
119             if rgv==0:                                                     # 若是是個空車
120                 seq.pop(index)                                             # 刪除當前節點
121                 continue
122             if isEmpty[nextP]:                                             # 若是下一個位置是空的
123                 t = cncT[nextP] 124                 total += t 125  update(state,t) 126                 state[nextP] = T2 127                 isEmpty[nextP] = 0 128             else:                                                         # 若是沒有空閒
129                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
130                     t = state[nextP] 131                     total += t 132  update(state,t) 133                 t = cncT[nextP]+Tc 134                 total += t 135  update(state,t) 136                 state[nextP] = T2 137             rgv = 0 138         currP = nextP 139         temp = total 140         index += 1    
141     total += tm[currP][Type.index(0)]                                     # 最後歸零
142     return rgv,currP,total 143  
144 def init_prob(sample,state,isEmpty,rgv,currP,total):                     # 計算全部sample的
145     prob = [] 146     for seq in sample: 147         t = time_calc(seq,state[:],isEmpty[:],rgv,currP,total)[-1] 148  prob.append(t) 149     maxi = max(prob) 150     prob = [maxi-prob[i]+1 for i in range(N)] 151     temp = 0 152     for p in prob: 153         temp += p 154     prob = [prob[i]/temp for i in range(N)] 155     for i in range(1,len(prob)): 156         prob[i] += prob[i-1] 157     prob[-1] = 1                                                         # 精度有時候很出問題
158     return prob 159  
160 def minT_calc(sample,state,isEmpty,rgv,currP,total): 161     minT = time_calc(sample[0],state[:],isEmpty[:],rgv,currP,total)[-1] 162     index = 0 163     for i in range(1,len(sample)): 164         t = time_calc(sample[i],state[:],isEmpty[:],rgv,currP,total)[-1] 165         if t < minT: 166             index = i 167             minT = t 168     return minT,index 169     
170 def init():                                                                 # 初始化種羣(按照第二道工序,第一道工序,第二道工序,第一道工序順序排列便可)
171     sample = [] 172     refer0 = [] 173     refer1 = [] 174     for i in range(8): 175         if Type[i]==0: 176  refer0.append(i) 177         else: 178  refer1.append(i) 179     for i in range(N): 180  sample.append([]) 181         for j in range(L): 182             if j%2==0: 183                 sample[-1].append(refer1[random.randint(0,len(refer1)-1)]) 184             else: 185                 sample[-1].append(refer0[random.randint(0,len(refer0)-1)]) 186     return sample 187  
188 def select(sample,prob):                                                 # 選擇算子
189     sampleEX = [] 190     for i in range(N):                                                     # 取出N個樣本
191         rand = random.random() 192         for j in range(len(prob)): 193             if rand<=prob[j]: 194  sampleEX.append(sample[j]) 195                 break
196     return sampleEX 197  
198 def cross(sample,i):                                                     # 交叉算子
199     for i in range(len(sample)-1): 200         for j in range(i,len(sample)): 201             rand = random.random() 202             if rand<=croP*(e**i):                                         # 執行交叉
203                 loc = random.randint(0,L-croL-1) 204                 temp1 = sample[i][loc:loc+croL] 205                 temp2 = sample[j][loc:loc+croL] 206                 for k in range(loc,loc+croL): 207                     sample[i][k] = temp2[k-loc] 208                     sample[j][k] = temp1[k-loc] 209     return sample 210         
211 def variance(sample,i):                                                     # 變異算子 
212     for i in range(len(sample)): 213         rand = random.random() 214         if rand<varP*(e**i): 215             rand1 = random.randint(0,L-1) 216             randTemp = random.randint(0,int(L/2)-1) 217             rand2 = 2*randTemp if rand1%2==0 else 2*randTemp+1
218             temp = sample[i][rand1] 219             sample[i][rand1] = sample[i][rand2] 220             sample[i][rand2] = temp 221     return sample 222  
223 if __name__ == "__main__": 224     state,isEmpty,rgv,currP,total,seq = init_first_round() 225     print(state,isEmpty,rgv,currP,total) 226     sample = init() 227     mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 228     best = sample[index][:] 229     for i in range(100000): 230         f = open("GA.txt","a") 231         tmin = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)[0] 232         f.write("{}\t{}\n".format(i,tmin)) 233         print(i,"\t",tmin,end="\t") 234         prob = init_prob(sample,state[:],isEmpty[:],rgv,currP,total) 235         sample = select(sample,prob) 236         sample = cross(sample,i) 237         sample = variance(sample,i) 238         mi,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 239         if mi>mini and random.random()<e**i:                             # 精英保留策略
240             rand = random.randint(0,N-1) 241             sample[rand] = best[:] 242         mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 243         best = sample[index][:] 244         print(best) 245  f.close() 246     print(sample)

遺傳算法這條路被堵死後我一度陷入俗套,用最直接的貪心搞了一陣子,以爲用貪心算法(即考慮下一步的最優策略)實在是對不起這種比賽。而後我就變得——更貪心一點了。

我試圖去尋找接下來K步最優的策略,而後走一步。K=1時算法退化爲貪心算法,最終咱們設置爲K=4(當K>=8時算法速度已經至關緩慢,而4~7的結果大體相同,且K=4的速度基本能夠作到2秒內獲得結果)。

值得注意的是我假設RGV在兩道工序下只能由第一道工序的CNC到第二道工序的CNC(忽略清洗時間狀況下),而後回到第一道工序的CNC,這樣往復移動(這裏我不說明爲何必定要這樣,可是我認爲確實應該是這樣)。在這個規律的引導下我大大減縮了代碼量以及計算複雜度。

而後到第四種狀況咱們已經沒有多餘時間了,只能延續使用狀況三的算法,進行了隨機模擬的修改,完成了第四種狀況的填表。

如下是第三種狀況的代碼(第四種相似就不上傳了)↓↓↓

 1 #coding=gbk
 2 import random  3 # -*- coding:UTF-8 -*-
 4 """
 5  做者:囚生CY  6  平臺:CSDN  7  時間:2018/10/09  8  轉載請註明原做者  9  創做不易,僅供分享  10 """
 11 from tranToXls import *
 12  
 13 # 第1組
 14 """
 15 d1 = 20  16 d2 = 33  17 d3 = 46  18 T1 = 400  19 T2 = 378  20 To = 28  21 Te = 31  22 Tc = 25  23 """
 24 # 第2組
 25  
 26 d1 = 23
 27 d2 = 41
 28 d3 = 59
 29 T1 = 280
 30 T2 = 500
 31 To = 30
 32 Te = 35
 33 Tc = 30
 34  
 35  
 36 # 第3組
 37  
 38 """
 39 d1 = 18  40 d2 = 32  41 d3 = 46  42 T1 = 455  43 T2 = 182  44 To = 27  45 Te = 32  46 Tc = 25  47 """
 48  
 49 cncT = [To,Te,To,Te,To,Te,To,Te]  50 tm = [  51  [0,0,d1,d1,d2,d2,d3,d3],  52  [0,0,d1,d1,d2,d2,d3,d3],  53  [d1,d1,0,0,d1,d1,d2,d2],  54  [d1,d1,0,0,d1,d1,d2,d2],  55  [d2,d2,d1,d1,0,0,d1,d1],  56  [d2,d2,d1,d1,0,0,d1,d1],  57  [d3,d3,d2,d2,d1,d1,0,0],  58  [d3,d3,d2,d2,d1,d1,0,0],  59 ]  60 Type = [0,1,0,1,1,1,0,1]                                                 # CNC刀具分類
 61  
 62 A = []                                                                     # 儲存第一道工序的CNC編號
 63 B = []                                                                     # 儲存第二道工序的CNC編號
 64 for i in range(len(Type)):  65     if Type[i]:  66  B.append(i)  67     else:  68  A.append(i)  69  
 70 def init_first_round():                                                     # 第一圈初始化(默認把全部第一道CNC按順序加滿再回到當前位置所有加滿)
 71     state = [0 for i in range(8)]                                           # 記錄CNC狀態(還剩多少秒結束,0表示空閒)
 72     isEmpty = [1 for i in range(8)]                                         # CNC是否爲空
 73     log = [0 for i in range(8)]                                             # 記錄每臺CNC正在加工第幾件物料
 74     count1 = 0  75     rgv = 0                                                                 # rgv狀態(0表示空車,1表示載着半成品)
 76     currP = 0  77     total = 0  78     seq = []  79     flag = False  80     for i in range(len(Type)):  81         if Type[i]==0:  82  seq.append(i)  83             flag = True  84     currP = seq[0]  85  seq.append(currP)  86     count1,rgv,currP,total = simulate(seq,state,isEmpty,log,count1,rgv,currP,total)  87     return state,isEmpty,log,count1,rgv,currP,total,seq  88  
 89 def update(state,t):  90     for i in range(len(state)):  91         if state[i] < t:  92             state[i] = 0  93         else:  94             state[i] -= t  95  
 96 def simulate(seq,state,isEmpty,log,count1,rgv,currP,total,fpath="log.txt"):    # 給定了一個序列模擬它的過程以及返回結果(主要用於模擬並記錄)
 97     index = 0  98     temp = 0  99     pro1 = {}                                                             # 第一道工序的上下料開始時間
100     pro2 = {}                                                             # 第二道工序的上下料開始時間
101     f = open(fpath,"a") 102     while index<len(seq): 103         print(isEmpty) 104         nextP = seq[index] 105         t = tm[currP][nextP] 106         total += t 107  update(state,t) 108         if Type[nextP]==0:                                                 # 若是下一個位置是第一道工做點
109             count1 += 1
110             if isEmpty[nextP]:                                             # 若是下一個位置是空的
111                 f.write("第{}個物料的工序一上料開始時間爲{}\tCNC編號爲{}號\n".format(count1,total,nextP+1)) 112                 t = cncT[nextP] 113                 total += t 114  update(state,t) 115                 state[nextP] = T1                                         # 更新當前的CNC狀態
116                 isEmpty[nextP] = 0                                         # 就不空閒了
117             else:                                                         # 若是沒有空閒
118                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
119                     t = state[nextP] 120                     total += t 121  update(state,t) 122                 f.write("第{}個物料的工序一下料開始時間爲{}\tCNC編號爲{}號\n".format(log[nextP],total,nextP+1)) 123                 f.write("第{}個物料的工序一上料開始時間爲{}\tCNC編號爲{}號\n".format(count1,total,nextP+1)) 124                 t = cncT[nextP]                                             # 完成一次上下料
125                 total += t 126  update(state,t) 127                 state[nextP] = T1 128                 rgv = log[nextP] 129             log[nextP] = count1 130         else:                                                             # 若是下一個位置是第二道工做點
131             if isEmpty[nextP]:                                             # 若是下一個位置是空的
132                 f.write("第{}個物料的工序二上料開始時間爲{}\tCNC編號爲{}號\n".format(rgv,total,nextP+1)) 133                 t = cncT[nextP] 134                 total += t 135  update(state,t) 136                 state[nextP] = T2 137                 isEmpty[nextP] = 0 138             else:                                                         # 若是沒有空閒
139                 f.write("第{}個物料的工序二下料開始時間爲{}\tCNC編號爲{}號\n".format(log[nextP],total,nextP+1)) 140                 f.write("第{}個物料的工序二上料開始時間爲{}\tCNC編號爲{}號\n".format(rgv,total,nextP+1)) 141                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
142                     t = state[nextP] 143                     total += t 144  update(state,t) 145                 t = cncT[nextP]+Tc 146                 total += t 147  update(state,t) 148                 state[nextP] = T2 149             log[nextP] = rgv 150             rgv = 0 151         currP = nextP 152         temp = total 153         index += 1    
154  f.close() 155     total += tm[currP][Type.index(0)]                                     # 最後歸到起始點
156     return count1,rgv,currP,total 157  
158 def time_calc(seq,state,isEmpty,rgv,currP,total):                         # 主要用於記錄時間
159     index = 0 160     temp = 0 161     while index<len(seq): 162         nextP = seq[index] 163         t = tm[currP][nextP] 164         total += t 165  update(state,t) 166         if Type[nextP]==0:                                                 # 若是下一個位置是第一道工做點
167             if rgv==1:                                                     # 然而載着半成品
168                 seq.pop(index)                                             # 去掉這個元素並停止當次循環進入下一個循環
169                 continue                
170             if isEmpty[nextP]:                                             # 若是下一個位置是空的
171                 t = cncT[nextP] 172                 total += t 173  update(state,t) 174                 state[nextP] = T1                                         # 更新當前的CNC狀態
175                 isEmpty[nextP] = 0                                         # 就不空閒了
176             else:                                                         # 若是沒有空閒
177                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
178                     t = state[nextP] 179                     total += t 180  update(state,t) 181                 t = cncT[nextP]                                             # 完成一次上下料
182                 total += t 183  update(state,t) 184                 state[nextP] = T1 185                 rgv = 1
186         else:                                                             # 若是下一個位置是第二道工做點
187             if rgv==0:                                                     # 若是是個空車
188                 seq.pop(index)                                             # 刪除當前節點
189                 continue
190             if isEmpty[nextP]:                                             # 若是下一個位置是空的
191                 t = cncT[nextP] 192                 total += t 193  update(state,t) 194                 state[nextP] = T2 195                 isEmpty[nextP] = 0 196             else:                                                         # 若是沒有空閒
197                 if state[nextP] > 0:                                     # 若是還在工做就等待結束
198                     t = state[nextP] 199                     total += t 200  update(state,t) 201                 t = cncT[nextP]+Tc 202                 total += t 203  update(state,t) 204                 state[nextP] = T2 205             rgv = 0 206         currP = nextP 207         temp = total 208         index += 1    
209     return rgv,currP,total 210  
211 def forward1(state,isEmpty,currP):                                         # 一步最優
212     lists = [] 213     if currP in A: 214         rgv = 1
215         for e1 in B: 216  lists.append([e1]) 217     
218     else: 219         rgv = 0 220         for e1 in A: 221  lists.append([e1]) 222     
223     minV = 28800
224     for i in range(len(lists)): 225         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 226         if t<minV: 227             minV = t 228             index = i 229     return lists[index][0] 230  
231 def forward4(state,isEmpty,currP):                                         # 四步最優
232     lists = [] 233     """ 遍歷全部的可能性 """
234     if currP in A:                                                         # 若是當前在第二道工序CNC的位置
235         rgv = 1
236         for e1 in B: 237             for e2 in A: 238                 for e3 in B: 239                     for e4 in A: 240  lists.append([e1,e2,e3,e4]) 241     else: 242         rgv = 0 243         for e1 in A: 244             for e2 in B: 245                 for e3 in A: 246                     for e4 in B: 247  lists.append([e1,e2,e3,e4]) 248     minV = 28800
249     for i in range(len(lists)): 250         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 251         if t<minV: 252             minV = t 253             index = i 254     return lists[index][0]                                                 # 給定下一步的4步計算最優
255  
256 def forward5(state,isEmpty,currP):                                         # 五步最優
257     lists = [] 258     """ 遍歷全部的可能性 """
259     if currP in A:                                                         # 若是當前在第二道工序CNC的位置
260         rgv = 1
261         for e1 in B: 262             for e2 in A: 263                 for e3 in B: 264                     for e4 in A: 265                         for e5 in B: 266  lists.append([e1,e2,e3,e4,e5]) 267     else: 268         rgv = 0 269         for e1 in A: 270             for e2 in B: 271                 for e3 in A: 272                     for e4 in B: 273                         for e5 in A: 274  lists.append([e1,e2,e3,e4,e5]) 275     minV = 28800
276     for i in range(len(lists)): 277         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 278         if t<minV: 279             minV = t 280             index = i 281     return lists[index][0]                                                 # 給定下一步的5步計算最優
282  
283 def forward6(state,isEmpty,currP):                                         # 六步最優
284     lists = [] 285     """ 遍歷全部的可能性 """
286     if currP in A:                                                         # 若是當前在第二道工序CNC的位置
287         rgv = 1
288         for e1 in B: 289             for e2 in A: 290                 for e3 in B: 291                     for e4 in A: 292                         for e5 in B: 293                             for e6 in A: 294  lists.append([e1,e2,e3,e4,e5,e6]) 295     else: 296         rgv = 0 297         for e1 in A: 298             for e2 in B: 299                 for e3 in A: 300                     for e4 in B: 301                         for e5 in A: 302                             for e6 in B: 303  lists.append([e1,e2,e3,e4,e5,e6]) 304     minV = 28800
305     for i in range(len(lists)): 306         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 307         if t<minV: 308             minV = t 309             index = i 310     return lists[index][0]                                                 # 給定下一步的6步計算最優
311  
312 def forward7(state,isEmpty,currP):                                         # 七步最優
313     lists = [] 314     """ 遍歷全部的可能性 """
315     if currP in A:                                                         # 若是當前在第二道工序CNC的位置
316         rgv = 1
317         for e1 in B: 318             for e2 in A: 319                 for e3 in B: 320                     for e4 in A: 321                         for e5 in B: 322                             for e6 in A: 323                                 for e7 in B: 324  lists.append([e1,e2,e3,e4,e5,e6,e7]) 325     else: 326         rgv = 0 327         for e1 in A: 328             for e2 in B: 329                 for e3 in A: 330                     for e4 in B: 331                         for e5 in A: 332                             for e6 in B: 333                                 for e7 in A: 334  lists.append([e1,e2,e3,e4,e5,e6,e7]) 335     minV = 28800
336     for i in range(len(lists)): 337         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 338         if t<minV: 339             minV = t 340             index = i 341     return lists[index][0]                                                 # 給定下一步的7步計算最優
342  
343 def forward8(state,isEmpty,currP):                                         # 八步最優
344     lists = [] 345     """ 遍歷全部的可能性 """
346     if currP in A:                                                         # 若是當前在第二道工序CNC的位置
347         rgv = 1
348         for e1 in B: 349             for e2 in A: 350                 for e3 in B: 351                     for e4 in A: 352                         for e5 in B: 353                             for e6 in A: 354                                 for e7 in B: 355                                     for e8 in A: 356  lists.append([e1,e2,e3,e4,e5,e6,e7,e8]) 357     else: 358         rgv = 0 359         for e1 in A: 360             for e2 in B: 361                 for e3 in A: 362                     for e4 in B: 363                         for e5 in A: 364                             for e6 in B: 365                                 for e7 in A: 366                                     for e8 in B: 367  lists.append([e1,e2,e3,e4,e5,e6,e7,e8]) 368     minV = 28800
369     for i in range(len(lists)): 370         t = time_calc(lists[i],state[:],isEmpty[:],rgv,currP,0)[-1] 371         if t<minV: 372             minV = t 373             index = i 374     return lists[index][0]                                                 # 給定下一步的8步計算最優
375  
376 def greedy(state,isEmpty,rgv,currP,total):                                 # 貪婪算法
377     line = [] 378     count = 0 379     while True: 380         #nextP = forward4(state[:],isEmpty[:],currP) 
381         nextP = forward5(state[:],isEmpty[:],currP) 382  line.append(nextP) 383         rgv,currP,t = time_calc([nextP],state,isEmpty,rgv,currP,0) 384         total += t 385         count += 1
386         if total>=28800: 387             break
388     return line 389  
390 if __name__ == "__main__": 391     state,isEmpty,log,count1,rgv,currP,total,seq = init_first_round() 392     print(state,isEmpty,log,count1,rgv,currP,total,seq) 393     line = greedy(state[:],isEmpty[:],rgv,currP,total) 394  simulate(line,state,isEmpty,log,count1,rgv,currP,total) 395     
396     write_xlsx()

後記

此次博客有點趕,因此質量有點差,不少點沒有具體說清楚。主要最近事情比較多。原本也沒想寫這篇博客,可是以爲人仍是要有始有終,雖然沒有人來閱讀,可是學習的路上仍是要多作小結,另外也是萬一有須要的朋友也能夠給一些參考。雖然個人水平不好勁,可是我但願可以經過交流學習提升更多人包括我本身的水平。不喜勿噴!

--------------------- 版權聲明:本文爲CSDN博主「囚生CY」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/CY19980216/article/details/82893846

相關文章
相關標籤/搜索