From 5b7bcbb996b0f7c8fc4d7776a29d03285069a248 Mon Sep 17 00:00:00 2001 From: "mhsatman@gmail.com" Date: Fri, 2 Aug 2024 21:05:55 +0300 Subject: [PATCH] implement traveling salesman problem solver with using the random key genetic algorithm --- CHANGELOG.md | 1 + src/OperationsResearchModels.jl | 4 +++ src/travelingsalesman.jl | 38 ++++++++++++++++++++++++ test/runtests.jl | 2 ++ test/testtravelingsalesman.jl | 51 +++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 src/travelingsalesman.jl create mode 100644 test/testtravelingsalesman.jl diff --git a/CHANGELOG.md b/CHANGELOG.md index 91afedb..6329e16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Implement Random key genetic algorithm for permutation optimization problems - Implement a GA based search for Job-Shop Scheduling problems that can't be solved by Johnson's rule +- Implement traveling salesman problem solver with using the random key genetic algorithm ### 0.2.2 diff --git a/src/OperationsResearchModels.jl b/src/OperationsResearchModels.jl index 9ab481d..4828957 100644 --- a/src/OperationsResearchModels.jl +++ b/src/OperationsResearchModels.jl @@ -21,6 +21,7 @@ include("knapsack.jl") include("latex.jl") include("randomkeyga.jl") include("johnsons.jl") +include("travelingsalesman.jl") import .Network import .Transportation @@ -37,6 +38,7 @@ import .Latex import .Utility import .RandomKeyGA import .Johnsons +import .TravelingSalesman import .Transportation: @@ -55,6 +57,7 @@ import .Knapsack: KnapsackResult, KnapsackProblem import .Latex: latex import .Johnsons: JohnsonResult, johnsons, JohnsonException, makespan, johnsons_ga import .RandomKeyGA: Chromosome, run_ga +import .TravelingSalesman: TravelinSalesmenResult, travelingsalesman export TransportationProblem, TransportationResult, balance, isbalanced, northwestcorner export Connection, ShortestPathResult, MaximumFlowResult, nodes @@ -71,6 +74,7 @@ export Utility export latex export Chromosome, run_ga export JohnsonResult, johnsons, JohnsonException, makespan, johnsons_ga +export TravelinSalesmenResult, travelingsalesman export JuMP, HiGHS diff --git a/src/travelingsalesman.jl b/src/travelingsalesman.jl new file mode 100644 index 0000000..91823a1 --- /dev/null +++ b/src/travelingsalesman.jl @@ -0,0 +1,38 @@ +module TravelingSalesman + +import ..RandomKeyGA: run_ga + +export TravelinSalesmenResult +export travelingsalesman + +struct TravelinSalesmenResult + route::Vector{Int} + cost::Float64 +end + +function travelingsalesman(distancematrix::Matrix{TType}; + popsize = 100, ngen = 1000, pcross = 0.8, pmutate = 0.01, nelites = 1):: TravelinSalesmenResult where {TType<:Float64} + + n, _ = size(distancematrix) + + function costfn(route::Vector{Int})::Float64 + cost = 0.0 + for i in 1:length(route)-1 + cost += distancematrix[route[i], route[i+1]] + end + cost += distancematrix[route[end], route[1]] + return cost + end + + + # popsize::Int, chsize::Int, costfn::F, ngen::Int, pcross::Float64, pmutate::Float64, nelites::Int + garesult = run_ga(popsize, n, costfn, ngen, pcross, pmutate, nelites) + + best = garesult.chromosomes[1] + cost = costfn(sortperm(best.values)) + + return TravelinSalesmenResult(sortperm(best.values), cost) +end + + +end # end of module TravelingSalesman \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index b29b558..7fb086b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,7 +2,9 @@ using Test using OperationsResearchModels using OperationsResearchModels.Simplex + include("testrandomkeyga.jl") +include("testtravelingsalesman.jl") include("testjohnsons.jl") include("testutility.jl") include("testjump.jl") diff --git a/test/testtravelingsalesman.jl b/test/testtravelingsalesman.jl new file mode 100644 index 0000000..0483674 --- /dev/null +++ b/test/testtravelingsalesman.jl @@ -0,0 +1,51 @@ +@testset "Traveling Salesman with Random Key GA" verbose = true begin + + @testset "Points in a rectangle" begin + + # + # * * * * * * + # * * + # * * * * * * + pts = Float64[ + 0 0; + 0 1; + 0 2; + 1 2; + 2 2; + 3 2; + 4 2; + 5 2; + 5 1; + 5 0; + 4 0; + 3 0; + 2 0; + 1 0; + ] + + n = size(pts, 1) + + distmat = zeros(n, n) + + # create the distance matrix + for i in 1:n + for j in 1:n + distmat[i, j] = sqrt(sum((pts[i, :] .- pts[j, :]).^2)) + end + end + + bestval = Inf64 + + for i in 1:10 + result = travelingsalesman(distmat, ngen = 1000, popsize = 100, pcross = 1.0, pmutate = 0.10) + if result.cost < bestval + bestval = result.cost + bestresult = result + end + end + + @test bestval == 14.0 + end + + +end # end of whole @testset \ No newline at end of file