从一系列产品中创建矩阵的快速有效方法

时间:2011-06-05 03:20:45

标签: matlab performance matrix large-data

Axe,Ay,Az:[N-by-N]

B = AA(二元产品)

这意味着:

B(i,j)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)]

B(i,j):3x3矩阵。 构建B的一种方法是:

N=2;
Ax=rand(N); Ay=rand(N); Az=rand(N);     %# [N-by-N]
t=1;
F=zeros(3,3,N^2);
for  i=1:N
    for j=1:N
        F(:,:,t)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)];
        t=t+1;                          %# t is just a counter
    end
end
%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)'; 
B = cell2mat(B);

当N很大时,是否有更快的方法。

编辑:

感谢您的回答。 (它更快)  我们来说:  N = 2;  Ax = [1 2; 3 4]; Ay = [5 6; 7 8]; Az = [9 10; 11 12];

B =

 1     5     9     4    12    20
 5    25    45    12    36    60
 9    45    81    20    60   100
 9    21    33    16    32    48
21    49    77    32    64    96
33    77   121    48    96   144

执行命令
???使用==>时出错mtimes 内部矩阵尺寸必须一致。

如果我写:P = Ai*Aj;那么

B  =

 7    19    31    15    43    71
23    67   111    31    91   151
39   115   191    47   139   231
10    22    34    22    50    78
34    78   122    46   106   166
58   134   210    70   162   254

这与上述不同 来自[Ax(1,1)Ay(1,1)Az(1,1)]的(:,:,1)deffer

编辑:

N=100;
Me      :Elapsed time is 1.614244 seconds.
gnovice :Elapsed time is 0.056575 seconds.
N=200;
Me      :Elapsed time is 6.044628 seconds.
gnovice :Elapsed time is 0.182455 seconds.
N=400;
Me      :Elapsed time is 23.775540 seconds.
gnovice :Elapsed time is 0.756682 seconds.
Fast!

rwong: B was not the same.

编辑:

对我的申请进行一些修改后: 通过gnovice代码

 1st code :  19.303310 seconds
 2nd code:  23.128920  seconds
 3rd code:  13.363585  seconds

似乎任何调用ceil,ind2sub的函数......如果可能的话,让thw循环变慢并且应该避免。

symIndex很有意思!谢谢。

2 个答案:

答案 0 :(得分:2)

这是一个相当简单和通用的实现,它使用单个for循环来执行linear indexing并避免处理三维变量或重塑:

%# General solution:
%# ----------------
B = cell(N);
for index = 1:N^2
  A = [Ax(index) Ay(index) Az(index)];
  B{index} = A(:)*A;
end
B = cell2mat(B);

编辑#1:

在回答关于如何减少对称矩阵B的计算次数的附加问题时,您可以使用以上代码的以下修改版本:

%# Symmetric solution #1:
%# ---------------------
B = cell(N);
for index = find(tril(ones(N))).'  %'# Loop over the lower triangular part of B
  A = [Ax(index) Ay(index) Az(index)];
  B{index} = A(:)*A;
  symIndex = N*rem(index-1,N)+ceil(index/N);  %# Find the linear index for the
                                              %#   symmetric element
  if symIndex ~= index       %# If we're not on the main diagonal
    B{symIndex} = B{index};  %#   then copy the symmetric element
  end
end
B = cell2mat(B);

然而,在这种情况下,你可以通过前面的线性索引并使用两个带有下标索引的for循环来获得更好的性能(或至少更简单的代码):

%# Symmetric solution #2:
%# ---------------------
B = cell(N);
for c = 1:N    %# Loop over the columns
  for r = c:N  %# Loop over a subset of the rows
    A = [Ax(r,c) Ay(r,c) Az(r,c)];
    B{r,c} = A(:)*A;
    if r ~= c           %# If we're not on the main diagonal
      B{c,r} = B{r,c};  %#   then copy the symmetric element
    end
  end
end
B = cell2mat(B);

编辑#2:

通过将对角线计算移动到内部循环外部(不需要条件语句)并用结果A覆盖A(:)*A,可以进一步加快第二个对称解决方案,以便我们可以使用B{c,r}而不是A更新对称单元格条目B{r,c}(即,使用另一个单元格的内容更新一个单元格似乎带来了额外的开销):

%# Symmetric solution #3:
%# ---------------------
B = cell(N);
for c = 1:N    %# Loop over the columns
  A = [Ax(c,c) Ay(c,c) Az(c,c)];
  B{c,c} = A(:)*A;
  for r = c+1:N  %# Loop over a subset of the rows
    A = [Ax(r,c) Ay(r,c) Az(r,c)];
    A = A(:)*A;
    B{r,c} = A;
    B{c,r} = A;
  end
end
B = cell2mat(B);

以下是使用以下样本对称矩阵AxAyAz的3个对称解的一些时序结果:

N = 400;
Ax = tril(rand(N));     %# Lower triangular matrix
Ax = Ax+triu(Ax.',1);  %'# Add transpose to fill upper triangle
Ay = tril(rand(N));     %# Lower triangular matrix
Ay = Ay+triu(Ay.',1);  %'# Add transpose to fill upper triangle
Az = tril(rand(N));     %# Lower triangular matrix
Az = Az+triu(Az.',1);  %'# Add transpose to fill upper triangle

%# Timing results:
%# --------------
%# Solution #1 = 0.779415 seconds
%# Solution #2 = 0.704830 seconds
%# Solution #3 = 0.325920 seconds

解决方案3的大幅加速主要是通过使用局部变量B更新A的单元格内容而不是使用另一个单元格的内容更新一个单元格。换句话说,使用B{c,r} = B{r,c};之类的操作复制单元格内容会带来比我预期更多的开销。

答案 1 :(得分:1)

A = cat(3, Ax, Ay, Az);   % [N-by-N-by-3]
F = zeros(3, 3, N^2);
for i = 1:3, 
  for j = 1:3,
    Ai = A(:,:,i);
    Aj = A(:,:,j);
    P = Ai(:) .* Aj(:);
    F(i,j,:) = reshape(P, [1, 1, N^2]);
  end
end

%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)'; 
B = cell2mat(B);