Code covered by the BSD License  

Highlights from
TSP solver by CE & BK algorithms

image thumbnail
from TSP solver by CE & BK algorithms by Sebastien PARIS
Solve TSP problems with 2 stochastic solvers : CE & BK algorithms

ce_tsp(L , option)
function out = ce_tsp(L , option)

% Solve the classic Travel Sale Man problem with a Cross Entropy
% (CE) optimization algorithm.
%
% Usage :
%
% out = ce_tsp(L , [option])
%
% Inputs
% -------
%
% L         : Distance/cost matrix (n x n)
% option    : (optional) structure for the option of the CE algorithm
%
%   option.N             : Number of paths to generate for each iteration (default 3*n*n)
%   option.rho           : Threshold for selectionning the best rho*N paths (default 5*10e-3)
%   option.alpha         : Weight for updating Transition Matrix (default 0.8)
%   option.beta          : Determine the fraction of the Nrho*N sample who will be kept for each iteration (default 0.7)
%   option.d             : Indicate how many CE iterations to wait until declaring a solution is found (default 5)
%   option.T_max         : Maximum number of iterations (default 10000)
%   option.epsilon       : Absolute relative difference between 2 consecutives solutions
%   option.P_ini         : Initial Probabilities Transition Matrix (n x n)
%   option.digit         : Truncation digit (default 5)
%   option.verbose       : 1 for real time plot, 2 for text display (default 2);
%   option.V             : Towns coordinates (n x 2). option.verbose = 1 is requiered;
%
% Outputs
%
% out
%               X_opt         Optimal solution. a (n + 1 x 1) index vector.
%               S_opt         Distance associated with the optimal path
%               Pt_opt        Transition Matrix (n x n) estimated at the end of the CE algorithm
%
% Example
%
% n                        = 20;
% V                        = 10*rand(n , 2);
% L                        = distmat(V);
% out                      = ce_tsp(L);
% plot(V(: , 1) , V(: , 2) , 'b+' , V(out.X_opt , 1) , V(out.X_opt , 2) , 'r' ,  'markersize' , 8 , 'linewidth' , 2)
% text(V(: , 1) , V(: , 2) , num2str((1 : n)' , '%0.0f') , 'fontname' , 'times' , 'fontsize' , 13);

%
% Author : Sbastien PARIS
%
% Ref    : "The Cross Entropy method", P-T de Boer, D. P. Kroese, S.
% Mannor, R. Y. Rubinstein.
%
% see    http://iew3.technion.ac.il/CE/about.php


[n , d] = size(L);

X1      = 1;


if((n ~= d))

    error('L must be  a square(n x n)');

end


if ( (nargin < 2) || isempty(option))

    option.N             = round(5*n*n);

    option.rho           = 5*10e-3;        % threshold for selectionning the best rho*N paths

    option.alpha         = 0.7;            % weight for updating Transition Matrix with new paths candidates

    option.beta          = 0.7;            % Determine the fraction of the Nrho*N sample who will be keep in each iteration

    option.d             = 5;              % indicate how many iterations to wait until declaring the solution is reached

    option.T_max         = 10000;          % Maximum number of CE iterations

    option.epsilon       = 100*eps;

    option.digit         = 5;

    option.P_ini         = [];

    option.verbose       = 2;              % Display Best current solution of the CE algorithm

end


if(~any(strcmp(fieldnames(option) , 'N')))

    option.N                     = round(5*n*n);

end

if(~any(strcmp(fieldnames(option) , 'rho')))

    option.rho                   = 5*10e-3;

end

if(~any(strcmp(fieldnames(option) , 'alpha')))

    option.alpha                 = 0.7;

end

if(~any(strcmp(fieldnames(option) , 'beta')))

    option.beta                  = 0.7;

end

if(~any(strcmp(fieldnames(option) , 'd')))

    option.d                     = 5;

end

if(~any(strcmp(fieldnames(option) , 'epsilon')))

    option.epsilon               = 100*eps;

end

if(~any(strcmp(fieldnames(option) , 'P_ini')))

    option.P_ini                = [];

end

if(~any(strcmp(fieldnames(option) , 'T_max')))

    option.T_max                = 10000;

end


if(~any(strcmp(fieldnames(option) , 'verbose')))

    option.verbose               = 2;

end



if (option.verbose == 1)

    if (~any(strcmp(fieldnames(option) , 'V')))

        disp('option.V must be provided tp verbose, switching verbose = 0');

        option.verbose = 0;

    end

    fig1        = figure(1);

    set(fig1 , 'renderer' , 'zbuffer');

    set(fig1 , 'doublebuffer' , 'on');

    subplot(121)

    set(gca , 'nextplot' , 'replace');

    subplot(122)

    set(gca , 'nextplot' , 'replace');

    str_n   = num2str((1 : n)' , '%0.0f');


end


St                        = zeros(1 , option.T_max);

Nrho                      = round(option.rho*option.N);

betaR1                    = round(option.beta*Nrho);


ind_Nrho                  = (1 : Nrho);

ind_betaR1                = (1 : betaR1);

ind_betaR2                = (betaR1 + 1 : option.N);

ind_n                     = (n + 1: -1 : 1);

ctelog                    = 1/log(10);


NN                        = option.N - betaR1;

%%==== Initial Transition Matrix =====%%

if(~isempty(option.P_ini))

    Pt                    = option.P_ini;

else

    cten1                     = 1/(n - 1);

    Pt                        = cten1(ones(n));

    Pt(1 : n + 1 : n*(n + 1)) = 0;

end

P0                        = Pt;

%%===== Initialization iteration ========%%

X                         = generation_TSP(Pt , option.N , X1);

[S , indice]              = sort(cost_TSP(L , X));

Gt                        = S(1);

I                         = indice(ind_Nrho);

tp_X                      = X(: , I);



%a) troncate to the N digits the Nrho first values of S %

x                         = abs(S(ind_Nrho));

m                         = ceil(log(x)*ctelog);

k                         = (x <= 10.^(m - 1));

m(k)                      = m(k) - 1;

f                         = 10.^(option.digit - m);

x                         = fix(x.*f)./f;

%b) Find sequential identical values

ind2                      = find((x(2 : Nrho) - x(1 : Nrho - 1)) == 0) + 1;

if ( ~isempty(ind2) )

    ind1                 = [ind2(1) - 1 , ind2((ind2(2 : end) - ind2(1 : end - 1) ~= 1)) + 1];

    ind3                 = ind2((tp_X(2 , ind2) < tp_X(n , ind2)));

    tp_X(: , ind3)       = tp_X(ind_n , ind3);

    ind4                 = ind1(((tp_X(2 , ind1) ~= tp_X(2 , ind1 + 1))));

    tp_X(: , ind4)       = tp_X(ind_n , ind4);

end


Pt                        = (1 - option.alpha - option.gamma)*update_matrix(tp_X) + option.gamma*P0 + option.alpha*Pt ;

X_opt                     = X(: , I(1));

S_opt                     = S(1);


t                         = 1;

cons                      = 0;

Gt_old                    = Gt;

X(: , ind_betaR1)         = tp_X(: , ind_betaR1);

if (option.verbose == 1)

    maxi             = max(option.V);

    mini             = min(option.V);

    fig1             = figure(1);

    subplot(121);


    p1                = plot(option.V(: , 1) , option.V( : , 2) ,  '+' , 'markersize' , 7);

    text(option.V(: , 1) , option.V(: , 2) , str_n , 'fontname' , 'times' , 'fontsize' , 12)

    axis([mini(1) , maxi(1) , mini(2) , maxi(2)])

    subplot(122);

    bar3(Pt);

    axis([0 , n+1 , 0 , n+1 , 0 , 1])

    view([-50 50]);

    title(sprintf('\\bf{P_{%d}}' ,t ) , 'fontsize' , 12 , 'fontname' , 'times');

    drawnow


end


%%========== Main Loop ==========%%

while( (t < option.T_max) && (cons < option.d))

    X(: , ind_betaR2)    = generation_TSP(Pt , NN , X1);

    [S , indice]         = sort(cost_TSP(L , X));

    Gt_new               = S(1);

    if ((abs(Gt_new - Gt_old) < option.epsilon) && (Gt_new == Gt_old) );

        cons = cons + 1;

    else

        cons = 0;

    end

    I                         = indice(ind_Nrho);

    tp_X                      = X(: , I);

    %a) troncate to the N digits the Nrho first values of S %

    x                         = abs(S(ind_Nrho));

    m                         = ceil(log(x)*ctelog);

    k                         = (x <= 10.^(m - 1));

    m(k)                      = m(k) - 1;

    f                         = 10.^(option.digit - m);

    x                         = fix(x.*f)./f;

    %b) Find sequential identical values

    ind2                      = find((x(2 : Nrho) - x(1 : Nrho - 1)) == 0) + 1;

    if ( ~isempty(ind2) )

        ind3                 = ind2((tp_X(2 , ind2) < tp_X(n , ind2)));

        tp_X(: , ind3)       = tp_X(ind_n , ind3);

        ind1                 = [ind2(1) - 1 , ind2((ind2(2 : end) - ind2(1 : end - 1) ~= 1)) + 1];

        ind4                 = ind1(((tp_X(2 , ind1) ~= tp_X(2 , ind1 + 1))));

        tp_X(: , ind4)       = tp_X(ind_n , ind4);

    end

    Pt                   = (1 - option.alpha - option.gamma)*update_matrix(tp_X) + option.gamma*P0 + option.alpha*Pt ;

    if (S(1) < S_opt)

        X_opt           = X(: , I(1));

        S_opt           = S(1);

    end

    Gt_old            = Gt_new;

    St(t)             = S_opt;

    X(: , ind_betaR1) = tp_X(: , ind_betaR1);

    t                 = t + 1;

    %%===========  Display ===========%%

    if (option.verbose == 1)

        subplot(121);

        p1          = plot(option.V(X_opt , 1) , option.V(X_opt , 2) , 'r' , option.V(: , 1) , option.V( : , 2) ,  '+' , 'markersize' , 8 , 'linewidth' , 2);

        text(option.V(: , 1) , option.V(: , 2) , str_n , 'fontname' , 'times' , 'fontsize' , 13);

        axis([mini(1) , maxi(1) , mini(2) , maxi(2)])

        title(sprintf('\\bf{n = %d, N = %d, \\gamma_{%d}^{opt}=%6.2f , \\gamma_{%d} = %6.2f, cons = %d}' , n , option.N , t ,  S_opt , t , Gt_new , cons) , 'fontsize' , 12 , 'fontname' , 'times');


        subplot(122);

        bar3(Pt);

        axis([0 , n+1 , 0 , n+1 , 0 , 1])

        view([-50 50]);

        title(sprintf('\\bf{P_{%d}}' , t ) , 'fontsize' , 12 , 'fontname' , 'times');


    elseif(option.verbose == 2)

        disp(sprintf('n = %d, N = %d, \\gamma_{%d}^{opt}=%6.2f , \\gamma_{%d} = %6.2f, cons = %d' , n , option.N , t ,  S_opt , t , Gt_new , cons));

    end

    drawnow


end

St(t:option.T_max)      = [];
%gammat(t:option.T_max)  = [];

out.S_opt               = S_opt;
out.X_opt               = X_opt;
out.Pt_opt              = Pt;
out.St                  = St;
%out.gammat              = gammat;

Contact us at files@mathworks.com