在此代码段中可以进行预分配吗?

时间:2018-12-06 09:30:27

标签: algorithm matlab

以下是Ant Colony Optimization的代码段。我已经删除了我认为绝对不需要理解代码的任何内容。其余的我不确定,因为我不熟悉在matlab上编码。但是,我正在500个蚂蚁和1000次迭代的500多个城市上运行此算法,与matlab上的其他算法实现相比,该代码的运行速度非常慢。就我的项目而言,我只需要数据集,而不需要演示在matlab上的编码能力,而且我有时间限制,根本不允许我从头开始学习matlab,因为截止日期到来时既没有考虑也没有期望给定了,所以我从网上获得了算法。

Matlab建议在循环内预分配两个变量,因为它们是会改变大小的数组。但是,我没有完全理解代码的这两部分的目的,因此我无法做到这一点。我相信这两个数组在循环的每次迭代中都会增加一个新项,因此从技术上讲,它们都应为零,并且可以基于for循环条件预先分配两个预期的最终大小,但我不确定。我已经尝试过将零预分配给两个数组,但是由于Matlab仍然显示为速度建议而预分配,因此它似乎无法解决任何问题。

我对MATLAB建议的两个变量添加了两个注释,以便在下面进行预分配。如果有人愿意跳过它,让我知道是否有可能,将不胜感激。

    x = 10*rand(50,1);
    y = 10*rand(50,1);
    n=numel(x);
    D=zeros(n,n);

    for i=1:n-1
        for j=i+1:n
            D(i,j)=sqrt((x(i)-x(j))^2+(y(i)-y(j))^2);
            D(j,i)=D(i,j);
        end
    end

    model.n=n;
    model.x=x;
    model.y=y;
    model.D=D;

nVar=model.n;

MaxIt=100;     
nAnt=50;

Q=1;

tau0=10*Q/(nVar*mean(model.D(:)));

alpha=1;
beta=5;
rho=0.6;

eta=1./model.D;
tau=tau0*ones(nVar,nVar);
BestCost=zeros(MaxIt,1);

empty_ant.Tour=[];
empty_ant.Cost=[];

ant=repmat(empty_ant,nAnt,1);

BestSol.Cost=inf;

for it=1:MaxIt

    for k=1:nAnt
        ant(k).Tour=randi([1 nVar]);

        for l=2:nVar
            i=ant(k).Tour(end);
            P=tau(i,:).^alpha.*eta(i,:).^beta;
            P(ant(k).Tour)=0;
            P=P/sum(P);
            r=rand;
            C=cumsum(P);
            j=find(r<=C,1,'first');
            ant(k).Tour=[ant(k).Tour j];
        end

        tour = ant(k).Tour;
        n=numel(tour);
        tour=[tour tour(1)]; %MatLab recommends preallocation here
        ant(k).Cost=0;

        for i=1:n
        ant(k).Cost=ant(k).Cost+model.D(tour(i),tour(i+1));
        end

        if ant(k).Cost<BestSol.Cost
            BestSol=ant(k);
        end

    end

    for k=1:nAnt
        tour=ant(k).Tour;
        tour=[tour tour(1)];

        for l=1:nVar
            i=tour(l);
            j=tour(l+1);
            tau(i,j)=tau(i,j)+Q/ant(k).Cost;
        end

    end

    tau=(1-rho)*tau;

    BestCost(it)=BestSol.Cost;

    figure(1);
    tour=BestSol.Tour;
    tour=[tour tour(1)];  %MatLab recommends preallocation here
    plot(model.x(tour),model.y(tour),'g.-');
end

2 个答案:

答案 0 :(得分:3)

如果更改数组的大小,则意味着将其复制到内存中的新位置。对于小型阵列来说,这不是一个大问题,但是对于大型阵列,这极大地降低了代码的速度。您使用的游览数组是固定大小的(在这种情况下为51或n + 1),因此您应该将它们预先分配为零数组。唯一要做的就是再次将游览的第一个元素添加到末尾,因此您要做的就是设置数组的最后一个元素。

这是您应该更改的内容:

x = 10*rand(50,1);
y = 10*rand(50,1);
n=numel(x);
D=zeros(n,n);

for i=1:n-1
    for j=i+1:n
        D(i,j)=sqrt((x(i)-x(j))^2+(y(i)-y(j))^2);
        D(j,i)=D(i,j);
    end
end

model.n=n;
model.x=x;
model.y=y;
model.D=D;

nVar=model.n;

MaxIt=1000;     
nAnt=50;

Q=1;

tau0=10*Q/(nVar*mean(model.D(:)));

alpha=1;
beta=5;
rho=0.6;

eta=1./model.D;
tau=tau0*ones(nVar,nVar);
BestCost=zeros(MaxIt,1);

empty_ant.Tour=zeros(n, 1);
empty_ant.Cost=[];

ant=repmat(empty_ant,nAnt,1);

BestSol.Cost=inf;

for it=1:MaxIt

    for k=1:nAnt
        ant(k).Tour=randi([1 nVar]);

        for l=2:nVar
            i=ant(k).Tour(end);
            P=tau(i,:).^alpha.*eta(i,:).^beta;
            P(ant(k).Tour)=0;
            P=P/sum(P);
            r=rand;
            C=cumsum(P);
            j=find(r<=C,1,'first');
            ant(k).Tour=[ant(k).Tour j];
        end
        tour = zeros(n+1,1);
        tour(1:n) = ant(k).Tour;
        n=numel(ant(k).Tour);
        tour(end) = tour(1); %MatLab recommends preallocation here
        ant(k).Cost=0;

        for i=1:n
        ant(k).Cost=ant(k).Cost+model.D(tour(i),tour(i+1));
        end

        if ant(k).Cost<BestSol.Cost
            BestSol=ant(k);
        end

    end

    for k=1:nAnt
        tour(1:n)=ant(k).Tour;
        tour(end) = tour(1);

        for l=1:nVar
            i=tour(l);
            j=tour(l+1);
            tau(i,j)=tau(i,j)+Q/ant(k).Cost;
        end

    end

    tau=(1-rho)*tau;

    BestCost(it)=BestSol.Cost;

    figure(1);
    tour(1:n) = BestSol.Tour;
    tour(end) = tour(1);  %MatLab recommends preallocation here
    plot(model.x(tour),model.y(tour),'g.-');
end

答案 1 :(得分:0)

我认为在这种情况下,MATLAB Editor发出的警告被放错了位置。数组不会重复调整大小,而只是调整一次。原则上,tour(end+1)=tour(1)tour=[tour,tour(1)]更有效率,但是在这种情况下,您可能不会注意到成本上的差异。

如果要加快此代码的速度,可以考虑将其某些循环向量化,并减少执行的索引操作的数量。例如本节:

tour = ant(k).Tour;
n=numel(tour);
tour=[tour tour(1)]; %MatLab recommends preallocation here
ant(k).Cost=0;

for i=1:n
   ant(k).Cost=ant(k).Cost+model.D(tour(i),tour(i+1));
end

if ant(k).Cost<BestSol.Cost
   BestSol=ant(k);
end

可以写为:

tour = ant(k).Tour;
ind = sub2ind(size(model.D),tour,circshift(tour,-1));
ant(k).Cost = sum(model.D(ind));
if ant(k).Cost < BestSol.Cost
   BestSol = ant(k);
end

这段重新编写的代码没有循环,通常使循环变快,并且不会重复执行复杂的索引(ant(k).Cost是两个索引操作,一个循环,会使您的运行速度大大降低。

像这样的优化机会更多,但是重写整个函数不在此答案的范围之内。

我尚未尝试运行代码,请在使用建议的更改时告诉我是否有错误。