julia系列17: tsp問題代碼整理

1. 常用庫和基礎函數

這里是優化版的函數:

using TSPLIB,LKH,Distances,PyPlot
MaxNum = 10000
tsp=readTSPLIB(:att48)
dist = [round.(Int,euclidean(tsp.nodes[i,:],tsp.nodes[j,:])) for i in 1:tsp.dimension,j in 1:tsp.dimension];
pos(tsp::TSP,t::Vector{Int},i::Int)=tsp.nodes[t[i]==n+1 ? 1 : t[i],:]
total_length(tsp::TSP,t::Vector{Int64})=sum([round.(Int,euclidean(pos(tsp,t,i),pos(tsp,t,i+1))) for i in 1:length(t)-1])
function minimum2(vec)i2 = (-1,-1);v2=(MaxNum,MaxNum);for (i,v) in enumerate(vec);if v2[1]>v;v2=(v,v2[1]);i2=(i,i2[1]);elseif v2[2]>v;v2=(v2[1],v);i2=(i2[1],i);end;endreturn i2,v2
end
function greedyConstruct(dist)path = [1];for _ in 1:size(dist)[1];c_dist = dist[path[end],:];c_dist[path].=MaxNum;next_id = findmin(c_dist)[2];push!(path,next_id);endreturn path
end
function plot_path(tsp,path)t = tsp.nodes[path,:];for p in path;text(tsp.nodes[p,1],tsp.nodes[p,2],p);end;scatter(t[:,1],t[:,2]);plot(t[:,1],t[:,2])
end
function plot_tree(tsp,mst)s = tsp.nodes;for p in 1:tsp.dimension;text(s[p,1],s[p,2],p);end;scatter(s[:,1],s[:,2]);for m in mst;plot(s[[m...],1],s[[m...],2],c="b");end
end
function minspantree(dm::AbstractMatrix{T}) where {T<:Real} # accepts viewsmst_edges = Vector{Tuple{Int, Int}}();mst_cost = zero(T);n = size(dm, 1)tree_dists = dm[1,:];closest_tree_verts = ones(Int, n);tree_dists[1] = MaxNumfor _ in 1:(n-1) # need to add n - 1 other verts to treecost, newvert = findmin(tree_dists)treevert = closest_tree_verts[newvert];mst_cost += costpush!(mst_edges, tuple(sort([treevert, newvert])...))tree_dists[newvert] = MaxNumfor i in 1:nif tree_dists[i] >= MaxNum;continue;endif tree_dists[i] > dm[i, newvert];tree_dists[i] = dm[i, newvert];closest_tree_verts[i] = newvert;endendendreturn mst_edges, mst_cost
end

這里是老版的函數

using TSPLIB
using LKH
using Distances
using Randomfunction pos(tsp::TSP,t::Vector{Int},i::Int)n = length(t)i = mod(i, n)if i == 0return tsp.nodes[t[n],1:2]elsereturn tsp.nodes[t[i],1:2]end
endfunction pos(b::Vector{Int},i::Int)n_b = length(b)i = mod(i, n_b)if i == 0return b[n_b]elsereturn b[i]end
endfunction tour_length(tsp::TSP,t::Vector{Int64})l = 0for i in 1:length(t)l += Int.(round.(euclidean(pos(tsp,t,i),pos(tsp,t,i+1))))endl
endfunction greedyConstruct(tsp)n = tsp.dimensionuv = Set{Int}(2:n)t = Array{Int64}(undef, n)t[1] = 1for i in 2:ncur = t[i-1]mindist = Infind = 1for j in collect(uv)dis = round.(Int, euclidean(tsp.nodes[cur,1:2],tsp.nodes[j,1:2]))if dis < mindistmindist = disind = jendendt[i] = indpop!(uv,ind)endreturn t
endnum = 30
f = "bbz25234"
tsp = readTSP("/Users/chen/Downloads/vlsi/"*f*".tsp")
n = tsp.dimension# 解析問題文件
t = parse.(Int, readlines("xrb14233.tour")[6:end-3])
totaldist(t)

用LKH求解器先給出一些初始解:

println("start...")
for i in 1:num@time t,v = solve_tsp("/Users/chen/Downloads/vlsi/"*f*".tsp";RUNS=1,MAX_TRIALS =150, MAX_SWAPS=100,SEED=i,PI_FILE="pi.txt",TIME_LIMIT=100,CANDIDATE_FILE = "cand.txt") #@printf("%d",v)ts[i,:]=tresults[i]= v
end
println("end")io = open("route.out","w")
for i in 1:size(ts)[1]write(io, string(ts[i,:])*"\n")
end
close(io)# route是初始路線合集,格式如下圖
ts = Array{Int32}(undef, (num,n))
results = Array{Int32}(undef,num)
lines = readlines("route.out")
println("start...")
for i in 1:numts[i,:]=Meta.parse(lines[i]) |> evalresults[i]= totaldist(ts[i,:])
end
println("end")

在這里插入圖片描述
接下來設計一下基本數據結構。上述路徑使用Array來存儲的,

2. 使用MPS GPU加速的2-opt算法

核函數如下:

using Metal
function twooptkernel(dist, t, x, y, z)k = thread_position_in_grid_1d()n = Int32(size(z)[1])if k <= ni = x[k]j = y[k]z[k] = dist[t[i], t[j]]+ dist[t[i==n ? 1 : i+1], t[j==n ? 1 : j+1]] - dist[t[i], t[i==n ? 1 : i+1]] - dist[t[j], t[j==n ? 1 : j+1]]endreturn
end

與cpu版本進行對比:

using Random
m = 4000000
x = rand(1:n, m)
y = rand(1:n, m)
z = similar(x)
mx = MtlArray{Int32}(x);
my = MtlArray{Int32}(y);
mz = similar(mx);
mt = MtlArray{Int32}(t);
@time @metal threads=64 grid=6250  twooptkernel(mdist, mt, mx,my,mz)function cpu(x,y,z)for k in 1:mi = x[k]j = y[k]z[k] = dist[t[i], t[j]]+ dist[t[i==n ? 1 : i+1], t[j==n ? 1 : j+1]] - dist[t[i], t[i==n ? 1 : i+1]] - dist[t[j], t[j==n ? 1 : j+1]]end
end
@time cpu(x,y,z)

分別為
0.000656 seconds (254 allocations: 6.031 KiB)
以及
5.414779 seconds (74.26 M allocations: 1.168 GiB, 0.61% compilation time)
m = 40000

完整GPU調用代碼如下:

for i in 1:200000m = 400000mx = MtlArray{Int32}(rand(1:n, m));my = MtlArray{Int32}(rand(1:n, m));mz = similar(mx);mt = MtlArray{Int32}(t);@metal threads=64 grid=6250  twooptkernel(mdist, mt, mx,my,mz)z = Array(mz)v,ind = findmin(z)if v < 0st,ed = mx[ind], my[ind]if st>edst,ed = ed,st endreverse!(t, st+1, ed)endif i % 1000 == 0println(i,":",totaldist(t))end
end

3. LKH算法包

調用方式極其簡單:

using LKH
opt_tour, opt_len = solve_tsp(dist)
opt_tour, opt_len = solve_tsp(x, y; dist="EUC_2D")
opt_tour, opt_len = solve_tsp("gr17.tsp")
opt_tour, opt_len = solve_tsp(dist; INITIAL_TOUR_ALGORITHM="GREEDY", RUNS=5)

可用參數參考這篇:https://blog.csdn.net/kittyzc/article/details/114388836
一些常用參數:

RUNS=1, 重復運行次數
MAX_TRIALS =1000, 每次運行最多嘗試交換的次數,默認值等于點數。
MAX_SWAPS=1000, 每次交換最多運行swap的次數。
INITIAL_TOUR_FILE = "temp.out", 初始化路徑地址
SEED=inum, 每次運行給一個新的seed
PI_FILE="pi-"*f*".txt", 新的cost,計算一次后重復調用
TIME_LIMIT=100, 時間限制
CANDIDATE_FILE = "cand-"*f*".txt", 每個點的近鄰,計算一次后重復調用即可

4. 簡單遺傳算法

每次隨機選兩條路徑(t_ids),并隨機從第一條路徑t1上選兩個點(e_ids),將其中的點按照第二條路徑t2的順序重新排列,產生新的路徑t3,對此路徑使用LKH算法進行優化,如果距離比t1或者t2短,則進行替換。

iter = 500
t_ids = rand(1:size(ts)[1], (iter,2))
e_ids = rand(1:n, (iter,2))
for inum in 1:itert1i,t2i = t_ids[inum,1], t_ids[inum,2] i1, i2 = e_ids[inum,1], e_ids[inum,2] if i1>i2i1,i2 = i2,i1end t1 = ts[t1i,:]t2 = ts[t2i,:]t3 = Array{Int32}(undef, n)t3[1:i1] = t1[1:i1]t3[i2:end] = t1[i2:end]t2ind = 1for t3ind in i1:i2while !(t2[t2ind] in t1[i1:i2])t2ind += 1endt3[t3ind] = t2[t2ind]t2ind+=1endio = open("temp.out","w")write(io, "TYPE : TOUR\nDIMENSION : "*string(n)*"\nTOUR_SECTION\n")for i in t3write(io, string(i)*"\n")endwrite(io, "-1\nEOF\n")close(io)t3, s3 = solve_tsp("/Users/chen/Downloads/vlsi/"*f*".tsp";RUNS=1,MAX_TRIALS =1000, MAX_SWAPS=1000,INITIAL_TOUR_FILE = "temp.out",SEED=inum,PI_FILE="pi.txt",TIME_LIMIT=100,CANDIDATE_FILE = "cand.txt") #sk, skind = findmin(results)# replace parentsif s3 < skprint("*",inum,": from ",sk," to ",s3,", ")io = open("best"*string(s3)*".out","w")write(io, "TYPE : TOUR\nDIMENSION : "*string(n)*"\nTOUR_SECTION\n")for i in t3write(io, string(i)*"\n")endwrite(io, "-1\nEOF\n")close(io)elseprint(" ",inum,":")enda,b = t1i,t2iif s3 < results[a] <= results[b]ts[b,:]=t3results[b] = s3println(" replace ",b)elseif s3 < results[b] <= results[a] ts[a,:]=t3results[a] = s3println(" replace ",a)elseif findmin(results)[1]==findmax(results)[1]println(" finish")breakelseprintln(" pass")end
end

5. ALNS算法

核心代碼如下,首先生成breaks,打斷這些點位連接的邊,然后使用solve_tsp_part重新進行組合:

b_try_num = 1000
b_point_num = 400
@assert b_point_num*2 <= tsp.dimension
b_id_lists = sort(rand(0:tsp.dimension - 2*b_point_num, (b_try_num,b_point_num)),dims = 2)for i in 1:b_try_numb = b_id_lists[i,:] + 2*Vector(1:b_point_num)t_imp,v_imp = solve_tsp_part(tsp,t,b)if v_imp>0t = t_impendif i % 100 == 0println(tour_length(tsp,t_imp))end
end

用于重構的solve_tsp_part和恢復路徑的restore_tour代碼如下:

function restore_tour(t::Vector{Int64},b::Vector{Int64},b_imp::Vector{Int64})n = length(t)n_b = length(b)t_imp = zeros(Int64,n)cur_imp = 1for i in 1:n_bb_i = div(b_imp[2*i]+1,2) # 在b中的下標r = falseif b_imp[2*i]%2==1r = trueendst = pos(b,b_i)ed = pos(b,b_i+1)-1if ed > stmov_imp = ed - stif rt_imp[cur_imp:cur_imp+mov_imp] = reverse(t[st:ed])# for j in reverse(st:ed)#     print(t[j],",")# endelse   t_imp[cur_imp:cur_imp+mov_imp] = t[st:ed]# for j in st:ed#     print(t[j],",")# endendcur_imp += mov_imp+1elseif rmov_imp = ed - 1t_imp[cur_imp:cur_imp+mov_imp] = reverse(t[1:ed])cur_imp += mov_imp+1mov_imp = n - stt_imp[cur_imp:cur_imp+mov_imp] = reverse(t[st:n])cur_imp += mov_imp+1# for j in reverse(1:ed)#     print(t[j],",")# end# for j in reverse(st:n)#     print(t[j],",")# endelsemov_imp = n - stt_imp[cur_imp:cur_imp+mov_imp] = t[st:n]cur_imp += mov_imp+1mov_imp = ed - 1t_imp[cur_imp:cur_imp+mov_imp] = t[1:ed]cur_imp += mov_imp+1# for j in st:n#     print(t[j],",")# end# for j in 1:ed#     print(t[j],",")# endendendendt_imp
endfunction check_bimp(b_imp::Vector{Int64})n_b = div(length(b_imp),2)for i in 1:n_bif abs(b_imp[2*i]-b_imp[2*i-1])!=1 || div(b_imp[2*i]+1,2)!= div(b_imp[2*i-1]+1,2)print(i,":",b_imp[2*i],",",b_imp[2*i-1])return falseendendreturn true
endfunction solve_tsp_part(tsp::TSP,t::Vector{Int64},b::Vector{Int64}) # b for breaks# cal distance matrixn = length(t)n_b = length(b)dist_matrix_b = zeros(Int64,2*n_b,2*n_b)for i in 1:n_bfor j in i+1:n_bdist_matrix_b[2*i-1,2*j-1] = dist_matrix_b[2*j-1,2*i-1] = Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t,pos(b,j)))))dist_matrix_b[2*i-1,2*j] = dist_matrix_b[2*j,2*i-1] = Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t, pos(b,j+1)-1 ))))dist_matrix_b[2*i,2*j-1] = dist_matrix_b[2*j-1,2*i] = Int(round(euclidean(pos(tsp,t,pos(b,i+1)-1  ),pos(tsp,t,b[j]))))dist_matrix_b[2*i,2*j] = dist_matrix_b[2*j,2*i] = Int(round(euclidean(pos(tsp,t,pos(b,i+1)-1 ),pos(tsp,t,pos(b,j+1)-1 ))))endendmax_element = maximum(dist_matrix_b)for i in 1:n_bfor j in i+1:n_bdist_matrix_b[2*i-1,2*j-1] += max_elementdist_matrix_b[2*j-1,2*i-1] += max_elementdist_matrix_b[2*i-1,2*j] += max_elementdist_matrix_b[2*j,2*i-1] += max_elementdist_matrix_b[2*i,2*j-1] += max_elementdist_matrix_b[2*j-1,2*i] += max_elementdist_matrix_b[2*i,2*j] += max_elementdist_matrix_b[2*j,2*i] += max_elementendend# for i in 1:n_b-1#     dist_matrix_b[2*i,2*i-1] = dist_matrix_b[2*i-1,2*i] = -max_element# endb_imp,v_imp = solve_tsp(dist_matrix_b;runs = 1,MAX_TRIALS =50, MAX_SWAPS=400)v_imp -= max_element*n_bif check_bimp(b_imp)v = 0for i in 1:n_bv +=  Int(round(euclidean(pos(tsp,t,pos(b,i)),pos(tsp,t, pos(b,i)-1 ))))endimp = v-v_impif imp > 0return restore_tour(t,b,b_imp), impelsereturn t, 0endelsereturn b_imp, -1end
end

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42499.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42499.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42499.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Groovy中,多種循環方式

1.最常規的for循環 for (def i 0; i < 5; i) { //這個i需要聲明println "遍歷輸出${i}" }2.while循環 def j 0 while (j < 5) {println "遍歷輸出 ${j}"j }3.for in 循環 def list [0, 1, 2, 3, 4] //這個l無需聲明 for (l in list) { printl…

uniapp跨域問題解決

找到menifest文件&#xff0c;在文件的最后添加如下代碼&#xff1a; // h5 解決跨域問題"h5":{"devServer": {"proxy": {"/adminapi": {"target": "https://www.demo.com", // 目標訪問網址"changeOrigin…

數據庫的存儲引擎,數據類型,約束條件,嚴格模式

【一】存儲引擎 1.什么是存儲引擎存儲引擎可以理解為處理數據的不同方式 2.查看存儲引擎show engines; 3.須知的引擎MyISAM5.5之前版本MySQL默認的存儲引擎特點:存取數據的速度快 但是功能很少 安全性較低速度快因為自帶索引InnoDB5.5之后版本MySQL默認的存儲引擎特點:有諸多功…

工程施工合同無效但竣工交付,應當參照合同關于工程價款的約定計算折價補償款

審判實踐中&#xff0c;對于建設工程施工合同無效但工程竣工并交付使用的&#xff0c;應以何種標準計算折價補償款的問題&#xff0c;認識不一致。【法官會議意見】&#xff1a;建設工程施工合同是承包人進行工程建設、交付工作成果即建設工程并由發包人支付價款的合同。建設工…

httpd目錄顯示亂碼問題

vim /etc/httpd/conf/httpd.conf 在<Directory “/var/www/html”>下添加&#xff1a; IndexOptions CharsetUTF-8重啟httpd: systemctl restart httpd.service還是不好看&#xff0c;調整下顯示寬度&#xff0c;還是這個位置&#xff1a; <Directory “/var/www/ht…

區塊鏈論文速讀A會-ISSTA 2023(2/2)如何檢測DeFi協議中的價格操縱漏洞

Conference&#xff1a;ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA) CCF level&#xff1a;CCF A Categories&#xff1a;Software Engineering/System Software/Programming Languages Year&#xff1a;2023 第1~5篇區塊鏈文章 請點擊此…

09視圖,觸發器,事務,存儲過程,函數,流程控制,索引,隔離機制,鎖機制,三大范式

【一】視圖 (1)視圖須知概念 1.什么是視圖&#xff1f; 視圖就是通過查詢得到一張虛擬表&#xff0c;然后保存下來&#xff0c;下次可以直接使用 2.為什么要用視圖&#xff1f; 如果要頻繁操作一張虛擬表(拼表組成)&#xff0c;就可以制作成視圖&#xff0c;后續直接操作 注意…

IDEA 創建springboot項目雜記-更新中

一、工具使用雜記 1、使用maven 創建新springboot項目時&#xff0c;因為https://start.spring.io/ 連接不上項目無法創建。直接把腳手架地址換為國內的 http://start.aliyun.com

田忌賽馬 貪心

本題是更難的那道,一場50 最低為o 第一行一個整數 &#x1d45b;n &#xff0c;表示他們各有幾匹馬&#xff08;兩人擁有的馬的數目相同&#xff09;。第二行 &#x1d45b;n 個整數&#xff0c;每個整數都代表田忌的某匹馬的速度值&#xff08;0≤0≤ 速度值 ≤100≤1…

Python】從文本字符串中提取數字、電話號碼、日期、網址的方法

關于從文本字符串中提取數字、電話號碼、日期和網址的方法&#xff1a; 提取數字&#xff1a; 在 Python 中&#xff0c;使用正則表達式 \d 來匹配數字。 \d 表示匹配一個數字字符&#xff08;0-9&#xff09;。如果要匹配連續的數字&#xff0c;可以使用 \d 。 import re def …

C++面向對象的常見面試題目(一)

1. 面向對象的三大特征 &#xff08;1&#xff09;封裝&#xff1a;隱藏對象的內部狀態&#xff0c;只暴露必要的接口。 #include <iostream> #include <string>// 定義一個簡單的類 Person class Person { private: // 私有成員&#xff0c;外部不可直接訪問std…

Mac OS ssh 連接提示 Permission denied (publickey)

這錯誤有點奇葩&#xff0c;MacBook的IDE(vscode和pycharm)遠程都連不上&#xff0c;terminal能連上&#xff0c;windows的pycharm能連上&#xff0c;見鬼了&#xff0c;所以肯定不是秘鑰的問題了&#xff0c;查了好久竟然發現是權限的問題。。 chmod 400 ~/.ssh/id_rsa http…

華為機試HJ37統計每個月兔子的總數

華為機試HJ37統計每個月兔子的總數 題目&#xff1a; 想法&#xff1a; 上述題目實際是一個斐波那契數列&#xff0c;利用斐波那契數列對問題進行求解 input_number int(input())def fib(n):if n < 2:return 1else:n_1 1n_2 1count 2while count < n:n_1, n_2 n_…

【Android】【多屏】多屏異顯異觸調試技巧總結

這里寫目錄標題 如何獲取多屏IDs獲取多屏的size/density如何啟動應用到指定DisplayId多屏截屏/錄屏screencapscreenrecord發送按鍵到指定DisplayId 如何獲取多屏IDs dumpsys display | grep mDisplayIdtrinket:/ # dumpsys display | grep mDisplayIdmDisplayId0mDisplayId2 t…

【AI資訊】可以媲美GPT-SoVITS的低顯存開源文本轉語音模型Fish Speech

Fish Speech是一款由fishaudio開發的全新文本轉語音工具&#xff0c;支持中英日三種語言&#xff0c;語音處理接近人類水平&#xff0c;使用Flash-Attn算法處理大規模數據&#xff0c;提供高效、準確、穩定的TTS體驗。 Fish Audio

區塊鏈技術的應用場景和優勢。

區塊鏈技術具有廣泛的應用場景和優勢。 區塊鏈技術的應用場景&#xff1a; 1. 金融服務&#xff1a;區塊鏈可用于支付、跨境匯款、借貸和結算等金融服務&#xff0c;提高交易效率、降低成本并增強安全性。 2. 物聯網&#xff08;IoT&#xff09;&#xff1a;區塊鏈可以用于物…

機器學習Day12:特征選擇與稀疏學習

1.子集搜索與評價 相關特征&#xff1a;對當前學習任務有用的特征 無關特征&#xff1a;對當前學習任務沒用的特征 特征選擇&#xff1a;從給定的特征集合中選擇出相關特征子集的過程 為什么要特征選擇&#xff1f; 1.任務中經常碰到維數災難 2.去除不相關的特征能降低學習的…

Git注釋規范

主打一個有用 代碼的提交規范參考如下&#xff1a; init:初始化項目feat:新功能&#xff08;feature&#xff09;fix:修補bugdocs:文檔&#xff08;documentation&#xff09;style:格式&#xff08;不影響代碼運行的變動&#xff09;refactor:重構&#xff08;即不是新增功能…

NodeJs獲取文件擴展名

path.extname 是 Node.js 路徑模塊 (path) 中的一個方法&#xff0c;用于獲取文件路徑的擴展名。擴展名是指文件名中最后一個 .&#xff08;點&#xff09;之后的部分&#xff0c;包括這個 .。 const path require(path);const filename example.txt; const ext path.extna…

計算機網絡之令牌環

1.令牌環工作原理 令牌環&#xff08;Token Ring&#xff09;是一種局域網&#xff08;LAN&#xff09;的通信協議&#xff0c;最初由IBM在1984年開發并標準化為IEEE 802.5標準。在令牌環網絡中&#xff0c;所有的計算機或工作站被連接成一個邏輯或物理的環形拓撲結構。網絡中…