Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solve problem by coordinates and .tsp file #3

Merged
merged 1 commit into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ Currently, this package works in 64-bit operations systems of Windows 10, macOS,

# Usage

Currently, only support symmetric problems.
Only symmetric problems are supported.


## Using a distance matrix

```julia
M = [
Expand All @@ -32,9 +35,28 @@ M = [
]
opt_tour, opt_len = solve_tsp(M)
```

The distance matrix `M` must be integer-valued.

## Using coordinates

```julia
n_nodes = 10
x = rand(n_nodes) .* 10000
y = rand(n_nodes) .* 10000
opt_tour, opt_len = solve_tsp(x, y; dist="EUC_2D")
```
where `dist` is a choice of the distance function.

Available `dist` functions are listed in `[TSPLIB_DOC.pdf](http://akira.ruc.dk/~keld/research/LKH/LKH-2.0/DOC/TSPLIB_DOC.pdf)`. (Some may have not been implemented in this package.)

## Using an input file

Using the [TSPLIB format](http://akira.ruc.dk/~keld/research/LKH/LKH-2.0/DOC/TSPLIB_DOC.pdf):
```julia
opt_tour, opt_len = solve_tsp("gr17.tsp")
```
The returned `opt_len` value is `-1`. At this moment, it is a user's responsibility to calculate the length of the optimal tour.

# Related Projects

- [Concorde.jl](https://github.com/chkwon/Concorde.jl): Julia wrapper of the [Concorde TSP Solver](http://www.math.uwaterloo.ca/tsp/concorde/index.html).
Expand Down
59 changes: 59 additions & 0 deletions src/Concorde.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Concorde
using Random, LinearAlgebra

include("../deps/deps.jl")
include("dist.jl")
# Write your package code here.

function read_solution(filepath)
Expand Down Expand Up @@ -89,6 +90,64 @@ function solve_tsp(dist_mtx::Matrix{Int})
end


function solve_tsp(x::Vector{Float64}, y::Vector{Float64}; dist="EUC_2D")
n_nodes = length(x)
@assert length(x) == length(y)

name = randstring(10)
filepath = name * ".tsp"

open(filepath, "w") do io
write(io, "NAME: $(name)\n")
write(io, "TYPE: TSP\n")
write(io, "COMMENT: $(name)\n")
write(io, "DIMENSION: $(n_nodes)\n")
write(io, "EDGE_WEIGHT_TYPE: $(dist)\n")
write(io, "EDGE_WEIGHT_FORMAT: FUNCTION \n")
write(io, "NODE_COORD_TYPE: TWOD_COORDS \n")
write(io, "NODE_COORD_SECTION\n")
for i in 1:n_nodes
write(io, "$i $(x[i]) $(y[i])\n")
end
write(io, "EOF\n")
end

status = run(`$(Concorde.CONCORDE_EXECUTABLE) $(filepath)`, wait=false)
while !success(status)
#
end

sol_filepath = name * ".sol"
opt_tour = read_solution(sol_filepath)
opt_len = tour_length(opt_tour, dist_matrix(x, y, dist=dist))

cleanup(name)

return opt_tour, opt_len
end

function solve_tsp(tsp_file::String)
if !isfile(tsp_file)
error("$(tsp_file) is not a file.")
end

name = randstring(10)
filepath = name * ".tsp"
cp(tsp_file, filepath)

status = run(`$(Concorde.CONCORDE_EXECUTABLE) $(filepath)`, wait=false)
while !success(status)
#
end

sol_filepath = name * ".sol"
opt_tour = read_solution(sol_filepath)
opt_len = - 1 # Need to implement the calculation of the obj function

cleanup(name)

return opt_tour, opt_len
end


export solve_tsp
Expand Down
63 changes: 63 additions & 0 deletions src/dist.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
function nint(x::Float64)
return round(Int, x)
end

function geo_coordinate(x, y)
PI = 3.141592

deg = nint(x)
m = x - deg
latitude = PI * (deg + 5.0 * m / 3.0) / 180.0

deg = nint(y)
m = y - deg
longitude = PI * (deg + 5.0 * m / 3.0) / 180.0

return latitude, longitude
end

function distance2D(xi, yi, xj, yj; dist="EUC_2D")
if dist == "EUC_2D"
xd = xi - xj
yd = yi - yj
return nint(sqrt(xd*xd + yd*yd))
elseif dist == "MAN_2D"
xd = abs(xi - xj)
yd = abs(yi - yj)
return nint(xd + yd)
elseif dist == "MAX_2D"
xd = abs(xi - xj)
yd = abs(yi - yj)
return max(nint(xd), nint(yd))
elseif dist == "GEO"
lat_i, long_i = geo_coordinate(xi, yi)
lat_j, long_j = geo_coordinate(xj, yj)
RRR = 6378.388
q1 = cos(long_i - long_j)
q2 = cos(lat_i - lat_j)
q3 = cos(lat_i + lat_j)
dij = RRR * acos( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) ) + 1.0
return floor(Int, dij)
else
error("Distance function $dist is not supported.")
end
end

function dist_matrix(x::Vector{Float64}, y::Vector{Float64}; dist="EUC_2D")
n_nodes = length(x)
@assert length(x) == length(y)

M = Matrix{Int}(undef, n_nodes, n_nodes)

for i in 1:n_nodes
for j in i:n_nodes
if i == j
M[i, j] = 0
else
M[i, j] = distance2D(x[i], y[i], x[j], y[j]; dist=dist)
M[j, i] = M[i, j]
end
end
end
return M
end
20 changes: 12 additions & 8 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
using Concorde
using Test

# @testset "Concorde.jl" begin
# A = Cint.([4, 2, 5, 7, 2, 1, 3, 5])
# ccall((:CCutil_int_array_quicksort, Concorde.LIB_CONCORDE), Cvoid, (Ref{Cint}, Cint), A, length(A))
# @test A[1] == minimum(A)
# @test A[end] == maximum(A)
# end


@testset "Concorde.jl" begin
@testset "Symmetric TSP" begin
M = [
Expand All @@ -31,4 +23,16 @@ using Test
]
@test_throws ErrorException solve_tsp(M)
end

@testset "Coordinates" begin
n_nodes = 10
x = rand(n_nodes) .* 10000
y = rand(n_nodes) .* 10000
opt_tour, opt_len = solve_tsp(x, y; dist="EUC_2D")
end

@testset "Input File" begin
opt_tour, opt_len = solve_tsp("gr17.tsp")
@test opt_len == -1
end
end