%TSP_GA Traveling Salesman Problem (TSP) Genetic Algorithm (GA)+ I5 H$ U. J( G* `4 }8 J& e
% Finds a (near) optimal solution to the TSP by setting up a GA to search3 O* Q0 ~+ v1 i( X+ f9 ~$ W
% for the shortest route (least distance for the salesman to travel to9 B3 u, T* @* H6 t# ?; m* ?
% each city exactly once and return to the starting city)2 l3 M( {5 w4 ]1 K. o, {! V& s" Y. E1 L
%9 y: s- w. K) B) H
% Summary:5 ~" N! L' A/ N
% 1. A single salesman travels to each of the cities and completes the 6 A% ]& V. j. R6 X: x* T% route by returning to the city he started from 8 W+ l% X" ` z% 2. Each city is visited by the salesman exactly once# G# J/ m! `: t8 @4 O: o9 F* H
%/ q- s% y: s2 Q9 X7 T3 w$ u
% Input:( @+ U1 o. R/ _& R8 C
% XY (float) is an Nx2 matrix of city locations, where N is the number of cities7 Y" L! L! ?0 ~! c/ d$ F, O6 H
% DMAT (float) is an NxN matrix of point to point distances/costs5 d7 y! e1 T* A) ~6 T) g
% POPSIZE (scalar integer) is the size of the population (should be divisible by 4) ! Q( }& C% O. A& O; z' J* J% NUMITER (scalar integer) is the number of desired iterations for the algorithm to run! M/ Q% y8 Q. W" f/ q6 g
% SHOWPROG (scalar logical) shows the GA progress if true. k) U+ t1 Y2 |3 \+ ]* ?
% SHOWRESULT (scalar logical) shows the GA results if true * [3 b% c* Z, Y; e7 F%2 l R, j+ e1 q: S$ g* O' Y
% Output: , E" O; Q9 I- h% o5 p% OPTROUTE (integer array) is the best route found by the algorithm, S* y$ @. c8 Z6 T) j
% MINDIST (scalar float) is the cost of the best route9 c. N2 l' w" L+ X- e O1 Z
% x0 w# T! y& o* G7 ^0 @) e; L. L% Example:/ J9 S2 M* @9 n( y ?1 {- V, T" I+ {" c
% n = 50; a1 o6 y- I/ B5 z
% xy = 10*rand(n,2); . I- q9 N6 J* o' |% popSize = 60;' D; B, U' p# N8 b. M, l
% numIter = 1e4; " J. f4 J, m, P1 R% Y% showProg = 1; , }( o! L8 Q9 R& ^8 l; Z+ l3 h' l& z% showResult = 1;& v6 R6 a0 Z% K
% a = meshgrid(1:n);! Z/ A; W5 P! d, C1 V: V
% dmat = reshape(sqrt(sum((xy(a,-xy(a',).^2,2)),n,n); ! B" N5 Y$ p9 H, t% [optRoute,minDist] = tsp_ga(xy,dmat,popSize,numIter,showProg,showResult); % L+ d/ v% o8 _, a0 `% & Y% W! `: l! k6 J. M. b3 s% Example: 3 M2 B, k9 b* m. z% n = 100; * n, q5 u+ [+ O K. g2 U" Q% phi = (sqrt(5)-1)/2;* i4 C. U5 n+ z @) t2 b, q
% theta = 2*pi*phi*(0:n-1);6 p/ B8 N& p6 d% P& x) _7 G3 B
% rho = (1:n).^phi; - |* W, c) L7 r+ T; B% [x,y] = pol2cart(theta(,rho(); % R c! q0 O9 C& w3 v- [- M% xy = 10*([x y]-min([x;y]))/(max([x;y])-min([x;y]));. O. U+ ~. {# I
% popSize = 60;9 |- j7 C( s. V6 l1 U
% numIter = 2e4;$ U" |' h6 ]( {& {6 N* L
% a = meshgrid(1:n);7 y& |1 [8 [/ Q9 f
% dmat = reshape(sqrt(sum((xy(a,-xy(a',).^2,2)),n,n); 5 _& s0 b# j5 r7 }3 [% [optRoute,minDist] = tsp_ga(xy,dmat,popSize,numIter,1,1);+ L6 W# S* O; f/ B; `; G
%: g# }; t* D8 O5 f; C' m$ z1 Q
% Example: s, u3 F9 A/ W- f) M& ]
% n = 50;7 I5 x6 f- l( D4 X4 t0 M/ m' p
% xyz = 10*rand(n,3);% E# k+ h" b, R2 o) g1 V. z+ E
% popSize = 60;+ g2 h0 b n! e! B
% numIter = 1e4; , P3 ]+ J- Y( q& [& ~% showProg = 1;2 b; L6 b q$ Q+ F3 U) m
% showResult = 1;1 @/ B/ M l3 [) I4 d6 J
% a = meshgrid(1:n); ! a/ b9 R0 e( z9 k' G8 ]7 a% dmat = reshape(sqrt(sum((xyz(a,-xyz(a',).^2,2)),n,n); $ w% ~ R v9 F- g. h+ [3 T% r% [optRoute,minDist] = tsp_ga(xyz,dmat,popSize,numIter,showProg,showResult); , K* q: Q. ]' g- U( b4 G3 P$ O% 2 \! C' W+ o6 b9 u" A' L% See also: mtsp_ga, tsp_nn, tspo_ga, tspof_ga, tspofs_ga, distmat% e o" ^/ ^ X
%* T3 x8 O0 H m' l
% Author: Joseph Kirk5 ^4 o, v' d6 l& s0 F' i+ e* X
% Email: jdkirk630@gmail.com # ^: B; j+ a6 L8 U* ] X% Release: 2.34 @* e H4 p s% Y4 j
% Release Date: 11/07/112 o& u# L; N) F6 E, ]9 ^
function varargout = tsp_ga(xy,dmat,popSize,numIter,showProg,showResult)# r1 U9 q6 |$ F( b
/ k" F: t2 L3 f [! ]+ |0 z
% Process Inputs and Initialize Defaults - j& G* W9 `" H8 j! \8 ?nargs = 6; 4 P1 K. c! G; M' M0 f' H( ffor k = nargin:nargs-1 S% ^9 j, j+ r' U switch k # \( M; @/ \- c- i( B( w2 r9 ] case 0" s5 X0 C' P8 y3 o j/ \
xy = 10*rand(50,2); 0 b+ q1 H7 N7 m: j7 A case 18 `( U7 ^( I' W3 x! v) C; V+ y
N = size(xy,1); * M! @ }3 l/ J a = meshgrid(1:N);1 u$ _! ?' Z H2 E1 }! Y
dmat = reshape(sqrt(sum((xy(a,-xy(a',).^2,2)),N,N); 1 j# i8 \$ a6 v2 q8 z case 2 1 a) L+ @: q( p$ [7 {( f# W popSize = 100;, v2 c+ h- [8 z% g
case 3 ! ?/ c. `" x+ L6 i! z! j( v numIter = 1e4; % _" `5 s8 s8 Z- a2 | ~! k case 4 7 R( a. y) y5 A3 P/ t+ W. L showProg = 1;7 C* P. X9 k6 x6 q/ S
case 5, T6 C( @$ G0 n- M, ~! q
showResult = 1; " W" ~7 B1 ?4 D7 l otherwise / m' }' P% N; _# }6 t% b end" O7 s# x: {& ^6 s; A
end 4 U X+ l( m5 O: P/ Y9 K- Z# A I - V; W( A6 m2 _/ F* t: {% Verify Inputs # w6 H, N; l7 M5 ?- b[N,dims] = size(xy); 9 E. k3 Y0 J/ M# M( X5 x[nr,nc] = size(dmat);& P$ j J4 S! a3 U3 ]
if N ~= nr || N ~= nc/ X9 b$ N t% [; `% Z1 j% R( H6 p2 x9 H
error('Invalid XY or DMAT inputs!')7 t7 ^ a% i6 K- y; J6 A
end % J: ?4 @& G5 zn = N;& y/ j' G3 o7 {( K
0 W% y" M3 u# T( I% Sanity Checks) @, M0 w" k5 j! [
popSize = 4*ceil(popSize/4);5 b, [/ f+ t J# {
numIter = max(1,round(real(numIter(1))));( h- D* D0 R- T& n/ v
showProg = logical(showProg(1));& s2 ^+ ~6 C$ h& U) T* S
showResult = logical(showResult(1)); 0 ^5 V8 h: v! I: Z) e) d5 ] r; d! G' P5 I# c9 t; ?- E* y
% Initialize the Population3 P# m3 t Z0 ^4 X2 K- R+ s
pop = zeros(popSize,n); ) _% p, c8 J. e3 C( [ ypop(1, = (1:n);- d) [" v7 C+ T% |
for k = 2:popSize9 j) Y" z: C* r7 ?- R/ j; r
pop(k, = randperm(n);4 M4 u" l3 S$ W J! b: T4 y# r
end) m9 u/ }1 J, p! R8 s4 o
9 c9 A. g# H+ M5 j6 ]% Run the GA1 G1 _: L: y% Y! t2 w) b
globalMin = Inf; 3 j' D6 y6 g4 z" M7 ptotalDist = zeros(1,popSize); $ P4 D1 k& g" }% y8 v7 w3 fdistHistory = zeros(1,numIter);; @/ d$ \8 w p1 y/ L; L
tmpPop = zeros(4,n); * t. Q+ H7 O- j9 e) L$ D0 G9 @newPop = zeros(popSize,n); " b0 s2 |4 E: `+ @5 wif showProg % R9 h( L( v; @6 R pfig = figure('Name','TSP_GA | Current Best Solution','Numbertitle','off'); 1 f! ^8 v) K) k/ K0 D7 _: Lend / X& @9 v* J$ r) a, sfor iter = 1:numIter, w& Z* M# I* x* @& m* }
% Evaluate Each Population Member (Calculate Total Distance) - E, G* j3 S( d; A& k for p = 1:popSize' ~& N4 i2 P9 v: ^; n
d = dmat(pop(p,n),pop(p,1)); % Closed Path ' E# R- @/ G; v5 ]) H for k = 2:n . ~! u7 L$ q+ ]/ t- d3 [9 g d = d + dmat(pop(p,k-1),pop(p,k));- F( W0 t0 \- U9 B
end 4 Y! F5 m4 o6 L- N# l D totalDist(p) = d; 2 h: j5 r! V9 l0 B8 x3 e3 Q5 f end z" B; E4 V; H" }
. ?2 u" m k. h9 D: e) G
% Find the Best Route in the Population: l/ u1 C5 O9 X/ f/ }
[minDist,index] = min(totalDist); # G: {, j) S$ p9 M2 }) D9 P distHistory(iter) = minDist;) D9 _$ }# X$ n
if minDist < globalMin8 [4 g3 t, N& d! J! _
globalMin = minDist; `: ^, s' B& C$ X; E optRoute = pop(index,;. m+ P7 w% D2 N3 a
if showProg / M5 b V; O8 [ @1 p o( u1 E % Plot the Best Route$ i# q. a1 W- F) k
figure(pfig);5 H' E+ m* P$ I2 `+ }
rte = optRoute([1:n 1]); 5 H: b/ h5 r1 s( q' [& w if dims > 2, plot3(xy(rte,1),xy(rte,2),xy(rte,3),'r.-'); $ O5 e! T, o" o. c else plot(xy(rte,1),xy(rte,2),'r.-'); end + z: }+ t5 ^2 t' l title(sprintf('Total Distance = %1.4f, Iteration = %d',minDist,iter));9 J! A' z0 Q: `. S) [/ v# E& @) Q
end 9 S5 Y* d/ A0 \ end & m2 X$ K& D. u+ S) m/ A1 p1 E 5 p) R; K/ [: b6 \ % Genetic Algorithm Operators" q- f/ }& i$ ]3 N: Q5 t
randomOrder = randperm(popSize);8 e* a% u4 X( _: J, e8 C! U! G
for p = 4:4:popSize- g! b( s8 z, J( I" k
rtes = pop(randomOrder(p-3:p),;4 E3 N- y3 p( S: w( k
dists = totalDist(randomOrder(p-3:p)); 0 u" g9 `( k: K1 k$ Q# |& O [ignore,idx] = min(dists); %#ok5 s' ?3 v6 i' B0 u G' j( \0 x5 W& i
bestOf4Route = rtes(idx,; 2 \5 _3 }8 ~+ V! T/ I' [; O routeInsertionPoints = sort(ceil(n*rand(1,2)));% p1 v$ I2 u- O, m& D4 Y) T
I = routeInsertionPoints(1);) u% [/ S+ f4 P: z8 s# d& k
J = routeInsertionPoints(2);+ |4 _) `+ e; T
for k = 1:4 % Mutate the Best to get Three New Routes $ K( m1 |4 k5 x tmpPop(k, = bestOf4Route; : B- h0 Y8 @7 ~; T6 u1 g switch k / c$ h+ v7 |& `0 S. D: V0 {! Z case 2 % Flip" S! Z: K& G7 c5 f
tmpPop(k,I:J) = tmpPop(k,J:-1:I);* J; S9 {- c w! }
case 3 % Swap! m8 O3 u9 F- y& C9 A
tmpPop(k,[I J]) = tmpPop(k,[J I]);9 c/ x l0 h( q' D& z% n! r) v
case 4 % Slide + v) ?: ^+ O4 o, n' d7 I tmpPop(k,I:J) = tmpPop(k,[I+1:J I]); / n4 y- Q* u& y w4 t/ Y$ Y otherwise % Do Nothing 2 i+ R, @) D/ x `) b/ w end & ?8 t4 t/ R6 f3 R* P2 a2 A1 ] end " N' s: p) q- L, o+ z L8 q newPop(p-3:p, = tmpPop;, Q% x' [, R% F
end * j0 p8 \3 @1 T" u pop = newPop;) k2 |2 c% R c* E
end : B0 M+ F4 |( C: F7 ^ 4 P, b' t2 C2 c2 v; R' Mif showResult 1 Z. f% _) F( j& ]9 w( Q/ d0 | % Plots the GA Results+ s6 u( G7 j; O, g2 u7 i
figure('Name','TSP_GA | Results','Numbertitle','off');! `5 W/ S; h* X# I0 k! k: e% J
subplot(2,2,1); : y6 ^. ~; N( h- b' `2 D; t8 p+ ~ pclr = ~get(0,'DefaultAxesColor'); ; P, O# I0 V/ c0 t8 ^ if dims > 2, plot3(xy(:,1),xy(:,2),xy(:,3),'.','Color',pclr);+ J7 l" [" \; q) d+ U* m
else plot(xy(:,1),xy(:,2),'.','Color',pclr); end' ]9 ~9 X1 ]1 Q9 E. B
title('City Locations');- r3 ~0 O; b6 j) E- ^5 F$ `" H
subplot(2,2,2); 1 w$ S% M) ?$ x1 O) J+ n) d imagesc(dmat(optRoute,optRoute));( G% F4 T, B9 `8 T2 z$ E: P* A! G
title('Distance Matrix');# `0 g# u) X: [9 w6 U
subplot(2,2,3);: k) Q4 _: Q, Q/ Z/ f5 ~% e
rte = optRoute([1:n 1]); # x4 k& h) L# k0 r if dims > 2, plot3(xy(rte,1),xy(rte,2),xy(rte,3),'r.-');- x1 m$ [" H9 x7 B7 j9 g: V& d
else plot(xy(rte,1),xy(rte,2),'r.-'); end ! Y4 F+ B9 a5 f! T. F9 @ title(sprintf('Total Distance = %1.4f',minDist)); + \( i1 j1 Z( I5 M- f subplot(2,2,4);$ ^& b/ t5 m9 A$ b- |2 e
plot(distHistory,'b','LineWidth',2);5 p' l& z5 f9 ~/ u
title('Best Solution History'); / k% H, _ O" c set(gca,'XLim',[0 numIter+1],'YLim',[0 1.1*max([1 distHistory])]);" [2 p4 S. j7 ^' d
end , }0 S% ^* f! ^. P* M 8 U9 D1 H2 K4 H9 Z% Return Outputs4 o9 d; R6 l3 L( i
if nargout 3 L" U/ V) @7 t% d$ { varargout{1} = optRoute;/ I; n+ ^0 H# S
varargout{2} = minDist;9 X* N8 D" ~ r$ ?8 M
end# N2 k1 x9 P& y( Y0 g; X) T( C