From 1202cf41a9e34c8f4371a9aff257c01de3666b06 Mon Sep 17 00:00:00 2001 From: Gelieza K Date: Mon, 21 Aug 2023 11:58:19 +0200 Subject: [PATCH] Fix TSP serial and parallel implementation --- notebooks/tsp-paralllel.jl | 117 +++++++++++++++++++++++++++++++++++++ notebooks/tsp-serial.jl | 66 +++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 notebooks/tsp-paralllel.jl create mode 100644 notebooks/tsp-serial.jl diff --git a/notebooks/tsp-paralllel.jl b/notebooks/tsp-paralllel.jl new file mode 100644 index 0000000..cf8d4d9 --- /dev/null +++ b/notebooks/tsp-paralllel.jl @@ -0,0 +1,117 @@ +using Distributed + +if procs() == workers() + addprocs(4) +end + +@everywhere function visited(city,hops,path) + for i = 1:hops + if path[i] == city + return true + end + end + return false +end + +# solution [1, 4, 5, 2, 3, 6], distance = 222 +connections = [ + [(1,0),(4,39),(5,76), (6,78),(3,94),(2,97)], + [(2,0),(5,25),(4,58),(3,62),(1,97),(6,109)], + [(3,0),(6,58),(2,62),(4,68),(5,70),(1,94)], + [(4,0),(5,38),(1,39),(2,58),(3,68),(6,78)], + [(5,0),(2,25),(4,38),(3,70),(1,76),(6,104)], + [(6,0),(3,58),(1,78),(4,78),(5,104),(2,109)] +] + +# Shortest route with start 1: 1-3-2-4 (distance: 7) +con2 = [ + [(1,0), (2,2), (3,3), (4,4)], + [(2,0), (4,1), (1,2), (3,3)], + [(3,0), (1,3), (2,3), (4,10)], + [(4,0), (2,1), (1,4), (3,10)] +] + + +## TSP distributed +@everywhere function tsp_dist_impl(connections,hops,path,current_distance,min_dist_chnl, max_hops,jobs_chnl,ftr_result) + num_cities = length(connections) + if hops == num_cities + min_distance = fetch(min_dist_chnl) + if current_distance < min_distance + take!(min_dist_chnl) + # Wait until results are written to future + if ftr_result !== nothing + @spawnat 1 begin + result = fetch(ftr_result) + result.path .= path + result.min_distance_ref[] = current_distance + end |> wait + end + # Unblock waiting processes + put!(min_dist_chnl, current_distance) + end + elseif hops <= max_hops + current_city = path[hops] + next_hops = hops + 1 + for (next_city,distance_increment) in connections[current_city] + if !visited(next_city,hops,path) + path[next_hops] = next_city + next_distance = current_distance + distance_increment + min_distance = fetch(min_dist_chnl) + if next_distance < min_distance + tsp_dist_impl(connections,next_hops,path,next_distance,min_dist_chnl,max_hops,jobs_chnl,ftr_result) + end + end + end + else + if jobs_chnl !== nothing + # Allocate new memory so paths are not overwritten in queue + path_copy = copy(path) + put!(jobs_chnl,(;hops,path=path_copy,current_distance)) + end + end +end + +function tsp_dist(connections,city) + max_hops = 2 + num_cities = length(connections) + path=zeros(Int,num_cities) + result_path=zeros(Int, num_cities) + hops = 1 + path[hops] = city + current_distance = 0 + min_distance = typemax(Int) + jobs_chnl = RemoteChannel(()->Channel{Any}(10)) + # Initialize min distance channel with Intmax + min_dist_chnl = RemoteChannel(()->Channel{Int}(1)) + put!(min_dist_chnl, min_distance) + # Future to store overall result + ftr_result = @spawnat 1 (;path=result_path,min_distance_ref=Ref(min_distance)) + @async begin + tsp_dist_impl(connections,hops,path,current_distance,min_dist_chnl,max_hops,jobs_chnl,nothing) + for w in workers() + put!(jobs_chnl,nothing) + end + end + @sync for w in workers() + @spawnat w begin + path = zeros(Int, num_cities) + max_hops = typemax(Int) + jobs_channel = nothing + while true + job = take!(jobs_chnl) + if job == nothing + break + end + hops = job.hops + path = job.path + current_distance = job.current_distance + tsp_dist_impl(connections,hops,path,current_distance,min_dist_chnl,max_hops,jobs_channel,ftr_result) + end + end + end + result = fetch(ftr_result) + (;path = result.path, distance = result.min_distance_ref[]) +end +city = 1 +tsp_dist(con2,city) \ No newline at end of file diff --git a/notebooks/tsp-serial.jl b/notebooks/tsp-serial.jl new file mode 100644 index 0000000..196d64a --- /dev/null +++ b/notebooks/tsp-serial.jl @@ -0,0 +1,66 @@ +using Distributed + +connections = [ + [(1,0),(4,39),(5,76), (6,78),(3,94),(2,97)], + [(2,0),(5,25),(4,58),(3,62),(1,97),(6,109)], + [(3,0),(6,58),(2,62),(4,68),(5,70),(1,94)], + [(4,0),(5,38),(1,39),(2,58),(3,68),(6,78)], + [(5,0),(2,25),(4,38),(3,70),(1,76),(6,104)], + [(6,0),(3,58),(1,78),(4,78),(5,104),(2,109)] +] + +# Shortest route with start 1: 1-3-2-4 (distance: 7) +con2 = [ + [(1,0), (2,2), (3,3), (4,4)], + [(2,0), (4,1), (1,2), (3,3)], + [(3,0), (1,3), (2,3), (4,10)], + [(4,0), (2,1), (1,4), (3,10)] +] + +@everywhere function visited(city,hops,path) + for i = 1:hops + if path[i] == city + return true + end + end + return false +end + +## TSP serial +function tsp_serial_impl(connections,hops,path,current_distance, min_path, min_distance) + num_cities = length(connections) + if hops == num_cities + if current_distance < min_distance + min_path .= path + return min_path, current_distance + end + else + current_city = path[hops] + next_hops = hops + 1 + for (next_city,distance_increment) in connections[current_city] + if !visited(next_city,hops,path) + path[next_hops] = next_city + next_distance = current_distance + distance_increment + if next_distance < min_distance + min_path, min_distance = tsp_serial_impl(connections,next_hops,path,next_distance,min_path,min_distance) + end + end + end + end + return min_path, min_distance +end + +function tsp_serial(connections,city) + num_cities = length(connections) + path=zeros(Int,num_cities) + hops = 1 + path[hops] = city + min_path = zeros(Int, num_cities) + current_distance = 0 + min_distance = typemax(Int) + min_path, min_distance = tsp_serial_impl(connections,hops,path,current_distance, min_path, min_distance) + (;path=min_path,distance=min_distance) +end + +city = 1 +tsp_serial(connections,city)