【原】总(tu)结(cao)粒子群算法(PSO)解决旅行商问题(TSP)

粒子群算法(PSO)是一套比较经典的算法, 旅行商问题(TSP)同样是一个经典的问题。如果想用PSO去解决TSP问题的话,那么应该如何去解决呢?

于是就有查资料,找到PSO解决TSP问题论文一文。

初看之下一阵欣喜,因为我发现,如果按照论文中的方法能够成功的话,那么包括布谷鸟,萤火虫都可以通过类似的办法进行有意义的尝试。

按照论文的思路,我撰写了如下代码

% main.m
% 调用
clc
clear
close all

number = 14; % 14个城市
global cities
cities = rand(number,2) * 200 - 100; % 假设城市分布在 [-100,-100] ,[100,100]的平面内

[best,par,ItorMean,ItorBest] = PSO4TSP_v1(cities);

netplot(cities,best.loc);
figure
itor = length(ItorMean);
plot(1:itor,ItorMean,'r',1:itor,ItorBest,'g');
% PSO 算法,globalBest为全局最优,par是最终的粒子信息,ItorMean是每次迭代平均适应度,ItorBest是每次迭代最佳适应度
function [globalBest,par,ItorMean,ItorBest] = PSO4TSP_v1(cities)
    %% 参数设置
    number_cities = size(cities,1); % 城市数
    number_pars = 50; % 粒子个数
    maxItor = 2000; % 最大迭代次数
    initSSnumber = number_cities;
    ss = zeros(initSSnumber,2);
    globalBest.fitness = -inf;
    ItorMean = zeros(1,maxItor);
    ItorBest = zeros(1,maxItor);
    %% 粒子初始化
    for i = 1 : number_pars     
        % 初始化粒子位置
        par(i).loc = randperm(number_cities); 
        % 初始化交换
        for j = 1 : initSSnumber
            ss(j,:) = randperm(number_cities,2);
        end
        par(i).v = ss;
        par(i).best = par(i);
        par(i).fitness = fitness(par(i).loc);
        if globalBest.fitness < par(i).fitness
            globalBest = par(i);
        end
    end
    %% 迭代求优
    eachItor = zeros(1,number_pars);
    for i = 1 : maxItor        
        for j = 1 : number_pars
            t = rand;
            u = rand;
            ssLoc = getSS(par(j).best.loc,par(j).loc);
            ssLocLen = size(ssLoc,1);
            ssGlo = getSS(globalBest.loc,par(j).loc);
            ssGloLen = size(ssGlo,1);
            temp1 = rand(1,ssLocLen);
            Item2 = ssLoc(temp1rand(1,ssGloLen);
            Item3 = ssGlo(temp2j).loc = doSS(par(j).loc,par(j).v);
            ss = unionSS(unionSS(par(j).v,Item2),Item3);
            par(j).v = ss;
            myfitness = fitness(par(j).loc);
            eachItor(j) = myfitness;
            if myfitness > par(j).fitness
                par(j).fitness = myfitness;
                par(j).best = par(j);
                if myfitness > globalBest.fitness
                    globalBest = par(j);
                end
            else
                par(j).fitness = myfitness;
            end
        end
        ItorMean(i) = mean(eachItor);
        ItorBest(i) = max(eachItor);
    end
end
% netplot.m
function netplot(city,n)        %连线各城市,将路线画出来
    figure
    hold on
    plot(city(:,1),city(:,2),'*');
    line([city(:,1);city(1,1)],[city(:,2);city(1,2)]);
end
% fitness.m
% 计算城市间的距离
function z = fitness(n)
    global cities
    tstart = n;
    tend = [n(2:end),n(1)];
    z = sum(distance(cities(tstart,1),cities(tstart,2),cities(tend,1),cities(tend,2)));
    z=1/z;
end
% getSS.m
function ss = getSS(v1,v2)
% 求SS算子
% v1,v2是一组向量,v1,v2所包含的元素应该相同。
% 若v1,v2顺序相同,则返回ss = [];
% 若顺序不同,则返回一个ss算子,即v2通过ss变换可以得到v1
ss = [];
while 1
    idx = find(v1 ~= v2);
    if isempty(idx)
        break;
    end
    idx2 = find(v2 == v1(idx(1)));
    so = [idx(1),idx2];
    ss = [ss;so];
    v2 = doSO(v2,so);
end
% doSS.m
function v = doSS(v,ss)
% SS操作函数
% v:之前的方案
% ss:SS算子,用作交换(n*2)的矩阵
% v:SS操作之后的结果
if ~isempty(ss)
    [m,n] = size(ss);
    if m == 2 && n ~= 2
        ss = ss';
        m = n;
        n = 2;
    end
    if n ~= 2
        help doSS
        error('ss must be n*2 matrix');
    end

    for i = 1 : m
        v = doSO(v,ss(i,:));
    end
end
end
% doSO.m
function v = doSO(v,so)
% SO操作函数
% v:之前的方案
% so:SO算子,用作交换
% v:SO操作之后的结果
if ~isempty(so)
    if length(so) ~= 2
        help doSO
        error('length of "so" iso must equals 2');
    else
        len = length(v);
        if so(1) > len || so(2) > len || so(1) < 1 || so(2) < 1
            help doSO
            error('"so" iso is not the index of v');
        else
            v(so(1)) = v(so(1)) + v(so(2));
            v(so(2)) = v(so(1)) - v(so(2));
            v(so(1)) = v(so(1)) - v(so(2));
        end 
    end
end
end
% getSS.m
% 论文中的减法操作
function ss = getSS(v1,v2)
% 求SS算子
% v1,v2是一组向量,v1,v2所包含的元素应该相同。
% 若v1,v2顺序相同,则返回ss = [];
% 若顺序不同,则返回一个ss算子,即v2通过ss变换可以得到v1
ss = [];
while 1
    idx = find(v1 ~= v2);
    if isempty(idx)
        break;
    end
    idx2 = find(v2 == v1(idx(1)));
    so = [idx(1),idx2];
    ss = [ss;so];
    v2 = doSO(v2,so);
end
% unionSS.m
% 论文中的⊕操作
function ss = unionSS(ss1,ss2)
% ss1,ss2算子合并操作

vm1 = max(max(ss1));
vm2 = max(max(ss2));
if isempty(ss1)
    if isempty(ss2)
        ss = [];
    else
        ss = ss2;
    end
elseif isempty(ss2)
    ss = ss1;
else
    vm = max(vm1,vm2);
    v = 1 : vm;
    v2 = doSS(doSS(v,ss1),ss2);
    ss = getSS(v,v2);
end
end

当我信心满满的运行的时候,效果却令人大跌眼镜。
【原】总(tu)结(cao)粒子群算法(PSO)解决旅行商问题(TSP)_第1张图片
【原】总(tu)结(cao)粒子群算法(PSO)解决旅行商问题(TSP)_第2张图片

虽然从迭代的图中能看出来,算法确实是取寻优了而且也收敛,但是得到的最终效果却不能令人满意。

后来,我又查阅了相关资料,发现这两篇帖子java版本的PSO求解TSP问题,C++版本的PSO求解TSP问题参考的同一篇文献,而且结果同样有不能令人接受,所以只能暂时认为这篇古老的文献的公式出错。

展望下未来的情况,也许可以找到更好的文献取代这篇文献,亦或者把之前的迭代公式改正确。
如果是后者,我们可以通过经典PSO问题类比推理出求解TSP的V’id可能需要在原先的公式加上一个随机速度Vir。推测Vir为一个SO或者是随着迭代次数增加而算子长度向0收敛的SS。笔者正向这个方向进行尝试。

你可能感兴趣的:(matlab,智能算法,pso算法,pso解决tsp,pso算法,tsp问题,算法)