【问题标题】:How to avoid for loops for multiplication of all permutations of a matrix?如何避免用于矩阵所有排列相乘的for循环?
【发布时间】:2019-11-04 09:37:30
【问题描述】:

我有以下代码:

  N=8;
  K=10;
  a=zeros(1,N^(K-1));
  b=zeros(1,N^(K-1));

  for ii=1:K
    p0{ii}=rand(1,N);
    p1{ii}=rand(1,N);
  end

  k=1;
  for j1=1:N
    for j3=1:N
      for j4=1:N
        for j5=1:N
          for j6=1:N
            for j7=1:N
              for j8=1:N
                for j9=1:N
                  for j10=1:N
                    a(k)=p0{1}(j1)*p0{3}(j3)*p0{4}(j4)*p0{5}(j5)*p0{6}(j6)*p0{7}(j7)*p0{8}(j8)*p0{9}(j9)*p0{10}(j10);
                    b(k)=p1{1}(j1)*p1{3}(j3)*p1{4}(j4)*p1{5}(j5)*p1{6}(j6)*p1{7}(j7)*p1{8}(j8)*p1{9}(j9)*p1{10}(j10);
                    k=k+1;
                  end
                end
              end
            end
          end
        end
      end
    end
    end

我无法为N=8 评估此代码,因为它需要很多时间。 p0p1 是大小为 KxN 的矩阵。嵌套的for循环省略了p0p1的一行,这里第二行对应索引j2。其余的矩阵元素相互相乘。所以总共有N^(K-1) 乘法以获得向量ab

有没有办法在不使用 for 循环的情况下或至少在某个合理的时间内完成这件事?

【问题讨论】:

  • p0p1 是单元格重要吗?
  • @Irreducible 是和否。一般来说是的,因为N实际上可能是N1,N2,..等,对于每个循环来说都是不同的,因为大多数情况下N是固定的,并且单元格可以被视为大小为K的矩阵由 N.
  • 让我们假设 N 是固定的,而不是看起来你想要选择从向量 (1:N) 中提取的 K 个元素的排列,并重复。 (代表感兴趣的行来计算您的产品)

标签: matlab for-loop simplification


【解决方案1】:

基本上,您只需将每个p0(或p1)单元格中的每个元素相乘即可。使用reshapeelement-wise multiplication 的一些魔法,这可以简化为一个循环。

让我们看看下面的代码:

N = 3;
K = 10;

for ii = 1:K
  p0{ii} = rand(1, N);
  p1{ii} = rand(1, N);
end  

a = zeros(1, N^(K-1));
b = zeros(1, N^(K-1));

%for ii = 1:K
%  p0{ii} = rand(1, randi(N));
%  p1{ii} = rand(1, randi(N));
%end

tic;
k = 1;
for j1 = 1:N
  for j3 = 1:N
    for j4 = 1:N
      for j5 = 1:N
        for j6 = 1:N
          for j7 = 1:N
            for j8 = 1:N
              for j9 = 1:N
                for j10 = 1:N
                  a(k) = p0{1}(j1)*p0{3}(j3)*p0{4}(j4)*p0{5}(j5)*p0{6}(j6)*p0{7}(j7)*p0{8}(j8)*p0{9}(j9)*p0{10}(j10);
                  b(k) = p1{1}(j1)*p1{3}(j3)*p1{4}(j4)*p1{5}(j5)*p1{6}(j6)*p1{7}(j7)*p1{8}(j8)*p1{9}(j9)*p1{10}(j10);
                  k = k+1;
                end
              end
            end
          end
        end
      end
    end
  end
end
toc;

tic;
aa = p0{1};
bb = p1{1};
% For MATLAB versions R2016 and newer:
for jj = 3:K
  aa = reshape(aa .* p0{jj}.', 1, numel(aa) .* numel(p0{jj}));
  bb = reshape(bb .* p1{jj}.', 1, numel(bb) .* numel(p1{jj}));
end
% For MATLAB versions before R2016b: 
%for jj = 3:K
%  aa = reshape(bsxfun(@times, aa, p0{jj}.'), 1, numel(aa) .* numel(p0{jj}));
%  bb = reshape(bsxfun(@times, bb, p1{jj}.'), 1, numel(bb) .* numel(p1{jj}));
%end
toc;

numel(find(aa ~= a))
numel(find(bb ~= b))

输出:

Elapsed time is 2.39744 seconds.
Elapsed time is 0.00070405 seconds.
ans = 0
ans = 0

看来,aaa 以及 bbb 实际上是相等的,并且建议的解决方案要快得多。我测试了N = 8 只是为了我的解决方案:

Elapsed time is 1.54249 seconds.

如果您通过取消注释相应的行来替换p0p1 的初始化,您会看到我的解决方案还允许每个p0(或p1)单元格的长度不同。注意:由于硬编码,这不适用于您的初始解决方案,因此无法在此处进行比较。

另外,请注意,jj = 3:N 在这里也是硬编码的。如果需要省略其他部分,则必须相应修改!

希望有帮助!

【讨论】:

  • 对不起。但似乎这段代码不起作用。我只是复制和粘贴。这是我得到的:使用错误。*矩阵尺寸必须一致。
  • @SeyhmusGüngören 在提及可能的错误时,请始终提供完整的堆栈跟踪。尽管如此,我猜它是numel(aa) * numel(p0{jj}) 和另一行。将其更改为 numel(aa) .* numel(p0{jj}) 以显式获取元素乘法。如果这不是错误,请提供所提到的完整堆栈跟踪。
  • 没有。我也是这么想的。但这不是问题。我想知道你是如何运行这段代码的?所以 numel(aa) * numel(p0{jj}) 不是问题。它给出了 9。我看过这部分 aa .* p0{jj}。它实际上是给出错误的部分。我试图纠正它如下:(aa .* p0{jj})。'然后它正在工作,但只给出 3 个元素。所以 reshape 不能从 3 x 1 生成 1,9 矢量并 reshape 崩溃。
  • @SeyhmusGüngören 您是否使用旧版本的 MATLAB,特别是 R1026b 之前的任何版本?在那个版本中,引入了implicit expansion,它允许对数组进行多项操作。我将尝试使用bsxfun 设置一个版本,它明确允许这些操作。
  • 较旧是相对的。对我来说 matlab 2015a 是非常新的版本。所以我认为您将 2019 年以下的所有版本都称为旧版本?:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2017-08-16
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
相关资源
最近更新 更多