矢量化5个嵌套的FOR循环

时间:2013-11-29 16:15:54

标签: matlab matrix vectorization nested-loops dft

我正在MATLAB中编写一个程序,作为基于DFT的项目的一部分。

N x N数据矩阵为X且相应的DFT矩阵为Y,则DFT系数可表示为

 Y(k1,k2) = ∑(n1=0:N-1)∑(n2=0:N-1)[X(n1,n2)*(WN^(n1k1+n2k2))]               (1)

            0≤k1,k2≤N-1
            Where WN^k=e^((-j2πk)/N)

由于旋转因子WN是周期性的,(1)可以表示为

Y(k1,k2)=∑(n1=0:N-1)∑(n1=0:N-1)[X(n1,n2)*(WN^([(n1k1+n2k2)mod N) ]          (2)

指定((n1k1 +n2k2)) N = p由给定(n1,n2)的一组(k1,k2)满足。因此,通过对此类数据进行分组并应用WN^(p+N /2) = -(WN^P)

的属性

(2)可以表示为

 Y(k1,k2)= ∑(p=0:M-1)[Y(k1,k2,p)*(WN^p)]                                    (3)

哪里

 Y(k1,k2,p)= ∑(∀(n1,n2)|z=p)X(n1,n2) - ∑(∀(n1,n2)|z=p+M)X(n1,n2)           (4)

 z=[(n1k1+n2k2)mod N]                                                       (5)

我正在编写一个程序来查找Y(k1,k2,p)。即我需要从给定的2D方阵(即矩阵)创建2d矩阵的切片(即每个切片是2D矩阵的3D矩阵) X).. X的维度最高可达512。

基于上面的等式,我编写了如下代码。我需要对它进行矢量化。

N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
for k2 = 1:N
   for p= 1:M
       for n1=1:N
           for n2=1:N
               N1=n1-1; N2=n2-1; P=p-1; K1=k1-1; K2=k2-1;
             z=mod((N1*K1+N2*K2),N); 
             if (z==P)                                       
               Y(k1,k2,p)= Y(k1,k2,p)+ X(n1,n2);
           elsif (z==(P+M))
               Y(k1,k2,p)= Y(k1,k2,p)- X(n1,n2);
            end
           end
       end
    end
   end

由于有5个FOR循环,对于N的大尺寸,执行时间非常大。因此,请为我提供一个消除FOR循环和矢量化代码的解决方案。我需要使代码以最大速度执行。 ..再次感谢..

1 个答案:

答案 0 :(得分:2)

这是第一个对最内层循环进行矢量化的提示。

从您的代码中,我们可以注意到n1N1PK1K2在此循环中是常量。 所以我们可以将z重写为掩码向量,如下所示:

z = mod(N1*K1+K2*(0:N-1));

然后你的if语句相当于添加X中所有元素的总和,使z==P减去X中所有元素的总和,使z==P+M。重写这很简单:

Y(k1,k2,p)= Y(k1,k2,p)+sum(X(n1,z==P))-sum(X(n1,z==P+M));

所以你的程序可以按如下方式编写:

N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
  for k2 = 1:N
    for p= 1:M
      for n1=1:N
        N1=n1-1; P=p-1; K1=k1-1; K2=k2-1;
        z=mod(N1*K1+K2*(0:N-1),N); 
        Y(k1,k2,p) = sum(X(n1,z==P))-sum(X(n1,z==P+M));
      end
    end
  end
end

然后你可以用n1做同样的事情;为此,您需要为z构建一个2D数组,例如:

z = mod(K1*repmat(0:N-1,N,1)+K2*repmat((0:N-1).',1,N));

注意size(z)==size(X)。然后Y的2D总和变为:

Y(k1,k2,p) = Y(k1,k2,p)+sum(X(z==P))-sum(X(z==P+M));

此处不再需要+=操作,因为您只能访问Y的每个元素一次:

Y(k1,k2,p)= sum(X(n1,z==P))-sum(X(n1,z==P+M));

所以我们再放弃一个循环:

N=size(X,1);
M=N/2;
Y(1:N,1:N,1:M)=0;
for k1 = 1:N
  for k2 = 1:N
    for p= 1:M
      P=p-1; K1=k1-1; K2=k2-1;
      z = mod(K1*repmat(0:N-1,N,1)+K2*repmat((0:N-1).',1,N)); 
      Y(k1,k2,p) = sum(X(z==P))-sum(X(z==P+M));
    end
  end
end

关于其他循环,我认为它不值得对它们进行矢量化,因为你必须构建一个5D数组,这可能是非常庞大的内存。我的建议是将z保留为2D数组,因为它的大小为X.如果它不适合内存,只需向量化最内层循环。