www.pudn.com > mtsp_ga.rar > mtsp_ga.m


function [opt_rte,opt_brk,min_dist] = mtsp_ga(xy,dmat,salesmen,... 
    pop_size,num_iter,singles,show_plots,show_waitbar) 
% MTSP_GA Multiple Traveling Salesman Problem (M-TSP) Genetic Algorithm (GA) 
%   Finds a (near) optimal solution to the M-TSP by setting up a GA to search 
%   for the shortest route (least distance needed for the salesmen to travel 
%   to each city exactly once and return to their starting locations) 
% 
% Input: 
%     XY (float) is an Nx2 matrix of city locations, where N is the number of cities 
%     DMAT (float) is an NxN matrix of city-to-city distances or costs 
%     SALESMEN (scalar integer) is the number of salesmen to visit the cities 
%     POP_SIZE (scalar integer) is the size of the population (should be divisible by 8) 
%     NUM_ITER (scalar integer) is the number of desired iterations for the algorithm to run 
%     SINGLES (scalar logical) is a flag that, if zero, forces the salesmen to 
%         visit at least 2 cities 
%     SHOW_PLOTS (scalar logical) is a flag that, if non-zero, generates a couple plots 
%     SHOW_WAITBAR (scalar logical) is a flag that, if non-zero, displays a waitbar 
% 
% Output: 
%     OPT_RTE (integer array) is the best route found by the algorithm 
%     OPT_BRK (integer array) is the list of route break points (these specify the indices 
%         into the route used to obtain the individual salesman routes) 
%     MIN_DIST (scalar float) is the total distance traveled by the salesmen 
% 
% Route/Breakpoint Details: 
%     If there are 10 cities and 3 salesmen, a possible route/break 
%     combination might be: rte = [5 6 9 1 4 2 8 10 3 7], brks = [3 7] 
%     Taken together, these represent the solution [5 6 9][1 4 2 8][10 3 7], 
%     which designates the routes for the 3 salesmen as follows: 
%         . Salesman 1 travels from city 5 to 6 to 9 and back to 5 
%         . Salesman 2 travels from city 1 to 4 to 2 to 8 and back to 1 
%         . Salesman 3 travels from city 10 to 3 to 7 and back to 10 
% 
% Example: 
%     n = 35; dims = 2; 
%     xy = 10*rand(n,dims); 
%     salesmen = 5; 
%     pop_size = 80; 
%     num_iter = 5e3; 
%     singles = 0; 
%     show_plots = 1; 
%     show_waitbar = 1; 
%     a = reshape(xy,1,n,dims); 
%     b = reshape(xy,n,1,dims); 
%     dmat = sqrt(sum((a(ones(n,1),:,:)-b(:,ones(n,1),:)).^2,3)); 
%     [opt_rte,opt_brk,min_dist] = mtsp_ga(xy,dmat,salesmen,pop_size,... 
%       num_iter,singles,show_plots,show_waitbar); 
% 
% Author: Joseph Kirk 
% Email: jdkirk630 at gmail dot com 
% Release: 1.0 
% Release Date: 3/4/08 
 
if ~nargin % Initialize Example Inputs 
    n = 50; dims = 2; 
    xy = 10*rand(n,dims); 
 
 
    salesmen = 7; 
    pop_size = 80; 
    num_iter = 1e4; 
    singles = 0; 
    show_plots = 1; 
    show_waitbar = 1; 
    try % Compute the Distance Matrix 
        dmat = distmat(xy); % File Exchange Contribution #15145 
    catch 
        a = reshape(xy,1,n,dims); 
        b = reshape(xy,n,1,dims); 
        dmat = sqrt(sum((a(ones(n,1),:,:)-b(:,ones(n,1),:)).^2,3)); 
    end 
else % Process the Given Inputs 
    n = size(xy,1); 
    [nr,nc] = size(dmat); 
    if nr ~= n || nc ~= n 
        error('Invalid inputs XY and/or DMAT'); 
    end 
end 
 
% Verify Inputs 
salesmen = max(1,min(n,round(real(salesmen(1))))); 
if ~singles 
    salesmen = min(floor(n/2),salesmen); 
end 
pop_size = max(8,8*ceil(pop_size(1)/8)); 
num_iter = max(2,round(real(num_iter(1)))); 
singles = logical(singles(1)); 
show_plots = logical(show_plots(1)); 
show_waitbar = logical(show_waitbar(1)); 
 
% Plot the Cities and the Distance Matrix 
if show_plots 
    hfig = figure('Name','MTSPGA','Numbertitle','off'); 
    subplot(2,2,1); 
    plot(xy(:,1),xy(:,2),'.'); 
    for k = 1:n 
        text(xy(k,1),xy(k,2),[' ' num2str(k)],'FontWeight','b'); 
    end 
    title('City Locations') 
    subplot(2,2,2); 
    imagesc(dmat); 
    colormap(flipud(gray)); 
    title('Distance Matrix'); 
end 
 
% Initializations for Route Break Point Selection 
num_brks = salesmen-1; 
addto = ones(1,n-2*num_brks-1); 
for k = 2:num_brks 
    addto = cumsum(addto); 
end 
cum_prob = cumsum(addto)/sum(addto); 
 
% Initialize the Populations 
pop_rte = zeros(pop_size,n);          % population of routes 
pop_brk = zeros(pop_size,num_brks);   % population of breaks 
for k = 1:pop_size 
    pop_rte(k,:) = randperm(n); 
    pop_brk(k,:) = randbreaks(); 
end 
tmp_pop_rte = zeros(8,n); 
tmp_pop_brk = zeros(8,num_brks); 
new_pop_rte = zeros(pop_size,n); 
new_pop_brk = zeros(pop_size,num_brks); 
 
% Select the Colors for the Plotted Routes 
clr = [1 0 0; 0 0 1; 0.67 0 1; 0 1 0; 1 0.5 0]; 
if salesmen > 5 
    clr = hsv(salesmen); 
end 
 
% Run the GA 
global_min = Inf; 
total_dist = zeros(1,pop_size); 
dist_history = zeros(1,num_iter); 
if show_plots 
    pfig = figure('Name','Current Best Solution','Numbertitle','off'); 
end 
if show_waitbar 
    wb = waitbar(0,'Searching ... Please Wait'); 
end 
for iter = 1:num_iter 
    % Evaluate Members of the Population 
    for p = 1:pop_size 
        d = 0; 
        p_rte = pop_rte(p,:); 
        p_brk = pop_brk(p,:); 
        rng = [[1 p_brk+1];[p_brk n]]'; 
        for m = 1:salesmen 
            d = d + dmat(p_rte(rng(m,2)),p_rte(rng(m,1))); 
            for k = rng(m,1):rng(m,2)-1 
                d = d + dmat(p_rte(k),p_rte(k+1)); 
            end 
        end 
        total_dist(p) = d; 
    end 
 
    % Find the Best Route in the Population 
    [min_dist,index] = min(total_dist); 
    dist_history(iter) = min_dist; 
    if min_dist < global_min 
        global_min = min_dist; 
        opt_rte = pop_rte(index,:); 
        opt_brk = pop_brk(index,:); 
        rng = [[1 opt_brk+1];[opt_brk n]]'; 
        % Plot the Best Route 
        if show_plots 
            figure(pfig); hold off; 
            for m = 1:salesmen 
                rte = [opt_rte(rng(m,1):rng(m,2)) opt_rte(rng(m,1))]; 
                plot(xy(rte,1),xy(rte,2),'.-','Color',clr(m,:)); 
                title(sprintf('Total Distance = %1.4f',min_dist)); 
                hold on; 
            end 
        end 
    end 
 
    % Genetic Algorithm Operators 
    rand_grouping = randperm(pop_size); 
    for p = 8:8:pop_size 
        rtes = pop_rte(rand_grouping(p-7:p),:); 
        brks = pop_brk(rand_grouping(p-7:p),:); 
        dists = total_dist(rand_grouping(p-7:p)); 
        [ignore,idx] = min(dists); 
        best_of_8_rte = rtes(idx,:); 
        best_of_8_brks = brks(idx,:); 
        rte_ins_pts = sort(ceil(n*rand(1,2))); 
        I = rte_ins_pts(1); 
        J = rte_ins_pts(2); 
        for k = 1:8 % Generate New Solutions 
            tmp_pop_rte(k,:) = best_of_8_rte; 
            tmp_pop_brk(k,:) = best_of_8_brks; 
            switch k 
                case 2 % Flip 
                    tmp_pop_rte(k,I:J) = fliplr(tmp_pop_rte(k,I:J)); 
                case 3 % Swap 
                    tmp_pop_rte(k,[I J]) = tmp_pop_rte(k,[J I]); 
                case 4 % Slide 
                    tmp_pop_rte(k,I:J) = tmp_pop_rte(k,[I+1:J I]); 
                case 5 % Modify Breaks 
                    tmp_pop_brk(k,:) = randbreaks(); 
                case 6 % Flip, Modify Breaks 
                    tmp_pop_rte(k,I:J) = fliplr(tmp_pop_rte(k,I:J)); 
                    tmp_pop_brk(k,:) = randbreaks(); 
                case 7 % Swap, Modify Breaks 
                    tmp_pop_rte(k,[I J]) = tmp_pop_rte(k,[J I]); 
                    tmp_pop_brk(k,:) = randbreaks(); 
                case 8 % Slide, Modify Breaks 
                    tmp_pop_rte(k,I:J) = tmp_pop_rte(k,[I+1:J I]); 
                    tmp_pop_brk(k,:) = randbreaks(); 
                otherwise % Do Nothing 
            end 
        end 
        new_pop_rte(p-7:p,:) = tmp_pop_rte; 
        new_pop_brk(p-7:p,:) = tmp_pop_brk; 
    end 
    pop_rte = new_pop_rte; 
    pop_brk = new_pop_brk; 
    if show_waitbar, waitbar(iter/num_iter,wb); end 
end 
if show_waitbar, close(wb); end 
 
% Plot the Results 
if show_plots 
    rng = [[1 opt_brk+1];[opt_brk n]]'; 
    figure(hfig); subplot(2,2,3); hold off; 
    for m = 1:salesmen 
        rte = [opt_rte(rng(m,1):rng(m,2)) opt_rte(rng(m,1))]; 
        plot(xy(rte,1),xy(rte,2),'.-','Color',clr(m,:)); 
        title(sprintf('Total Distance = %1.4f',min_dist)); 
        hold on; 
    end 
    subplot(2,2,4); 
    plot(dist_history,'r','LineWidth',2); 
    title('Best Solution History'); 
    set(gca,'XLim',[1 num_iter],'YLim',[0 1.1*max(dist_history)]); 
end 
 
    % Generate Random Set of Break Points 
    function breaks = randbreaks() 
        if singles % No Constraints on Breaks 
            tmp_brks = randperm(n-1); 
            breaks = sort(tmp_brks(1:num_brks)); 
        else % Force Breaks to be At Least Two Apart 
            num_adjust = find(rand < cum_prob,1)-1; 
            spaces = ceil(num_brks*rand(1,num_adjust)); 
            adjust = zeros(1,num_brks); 
            for kk = 1:num_brks 
                adjust(kk) = sum(spaces == kk); 
            end 
            breaks = 2*(1:num_brks) + cumsum(adjust); 
        end 
    end 
end