今天早上跟學姐室友去復旦把論文答辯作掉了,雖然整個項目基本上是我承擔了主要的思路與代碼部分,可是今天答辯我跟室友居然連一句有用的話都沒說出來,全場都靠學姐開場流暢地引入,臨場隨機應變,從而得以與答辯教授歡聚喜散。主要緣由是教授居然準確地問到了我代碼裏一個細節卻至關致命的問題(是一個隨機初始化問題,我下面代碼部分會詳細提到),正好學姐室友都不是特別熟悉個人隨機初始化方法,我又不能當場跟他們兩個解釋這個隨機初始化的問題。我差點當場就要以「這樣隨機初始化可以減小代碼量」這種蹩腳的理由跟教授爭辯了。好在姜仍是老的辣,辯論隊隊長出身的學姐一頓 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