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.mzph.cn/diannao/42499.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp跨域问题解决

找到menifest文件&#xff0c;在文件的最后添加如下代码&#xff1a; // h5 解决跨域问题"h5":{"devServer": {"proxy": {"/adminapi": {"target": "https://www.demo.com", // 目标访问网址"changeOrigin…

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篇区块链文章 请点击此…

C++面向对象的常见面试题目(一)

1. 面向对象的三大特征 &#xff08;1&#xff09;封装&#xff1a;隐藏对象的内部状态&#xff0c;只暴露必要的接口。 #include <iostream> #include <string>// 定义一个简单的类 Person class Person { private: // 私有成员&#xff0c;外部不可直接访问std…

华为机试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_…

【AI资讯】可以媲美GPT-SoVITS的低显存开源文本转语音模型Fish Speech

Fish Speech是一款由fishaudio开发的全新文本转语音工具&#xff0c;支持中英日三种语言&#xff0c;语音处理接近人类水平&#xff0c;使用Flash-Attn算法处理大规模数据&#xff0c;提供高效、准确、稳定的TTS体验。 Fish Audio

机器学习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;即不是新增功能…

计算机网络之令牌环

1.令牌环工作原理 令牌环&#xff08;Token Ring&#xff09;是一种局域网&#xff08;LAN&#xff09;的通信协议&#xff0c;最初由IBM在1984年开发并标准化为IEEE 802.5标准。在令牌环网络中&#xff0c;所有的计算机或工作站被连接成一个逻辑或物理的环形拓扑结构。网络中…

排序(2)

我们在排序&#xff08;1&#xff09;中说到选择排序的代码&#xff1a; void SelectSort(int* a,int n) {int begin0,endn-1;int minibegin,maxbegin;for(int ibegin1;i<end;i){if(a[i]>a[max]){maxii;}if(a[i]<a[mini]){minii;}begin;--end;}Swap(&a[beign],&a…

SKF轴承故障频率查询

1&#xff0c;第一步&#xff1a;搜索轴承型号 skf官网 2&#xff0c;第二步&#xff1a;查询故障频率。 第三步&#xff1a;

尚品汇-(十四)

&#xff08;1&#xff09;提交git 商品后台管理到此已经完成&#xff0c;我们可以把项目提交到公共的环境&#xff0c;原来使用svn&#xff0c;现在使用git 首先在本地创建ssh key&#xff1b; 命令&#xff1a;ssh-keygen -t rsa -C "your_emailyouremail.com" I…

落日余晖映晚霞

落日余晖映晚霞&#xff0c;立于海滨&#xff0c;望夕阳余晖洒于波光粼粼之上&#xff0c;金光跳跃&#xff0c;若繁星闪烁&#xff0c;耀人心目。 海风轻拂&#xff0c;心境宁静&#xff0c;凡尘俗务皆于此刹那消散&#xff0c;思绪万干&#xff0c;或忆往昔点滴&#xff0c;或…

刷爆leetcode第十期

题目一 相同的树 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 首先我们要来判断下它们的根是否相等 根相等的话是否它们的左子树相等 是否…

在CMD中创建虚拟环境并在VSCode中使用和管理

1. 使用Conda创建虚拟环境 在CMD或Anaconda Prompt中执行以下代码以创建一个新的虚拟环境&#xff1a; conda create -n my_env python 3.8 这样会创建一个名为 my_env 的环境&#xff0c;并在Anaconda环境目录下生成一个相应的文件夹&#xff0c;包含该虚拟环境所需的所有…

GD32实战篇-双向数控BUCK-BOOST-BOOST升压理论基础

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

MySQL之备份与恢复(八)

备份与恢复 还原逻辑备份 如果还原的是逻辑备份而不是物理备份&#xff0c;则与使用操作系统简单地复制文件到适当位置的方式不同&#xff0c;需要使用MySQL服务器本身来加载数据到表中。在加载导出文件之前&#xff0c;应该先花一点时间考虑文件有多大&#xff0c;需要多久加…

C++ 函数高级——函数的占位参数

C中函数的形参列表里可以有占位参数&#xff0c;用来做占位&#xff0c;调用函数时必须填补改位置 语法&#xff1a; 返回值类型 函数名&#xff08;数据类型&#xff09;{ } 在现阶段函数的占位参数存在意义不大&#xff0c;但是后面的课程中会用到该技术 示例&#xff1a;…

STM32快速复习(八)SPI通信

文章目录 前言一、SPI是什么&#xff1f;SPI的硬件电路&#xff1f;SPI发送的时序&#xff1f;二、库函数二、库函数示例代码总结 前言 SPI和IIC通信算是我在大学和面试中用的最多&#xff0c;问的最多的通信协议 IIC问到了&#xff0c;一般SPI也一定会问到。 SPI相对于IIC多了…

含并行连结的网络

一、Inception块 1、白色部分通过降低通道数来控制模型复杂度&#xff0c;蓝色做特征提取工作&#xff0c;每条路上的通道数可能不同&#xff0c;大概我们会把更重要的那部分特征分配更多的通道数 2、Inception只改变高宽&#xff0c;不改变通道数 3、在不同的情况下需要选择…