以下是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
答案 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
是两个索引操作,一个循环,会使您的运行速度大大降低。
像这样的优化机会更多,但是重写整个函数不在此答案的范围之内。
我尚未尝试运行代码,请在使用建议的更改时告诉我是否有错误。