如何在不知道如何向量化的情况下进行向量化:
首先,我将只讨论对第一个双循环进行矢量化,您可以对第二个循环遵循相同的逻辑。
我试图从头开始展示一个思考过程,所以虽然最终答案只有 2 行长,但值得看看初学者如何尝试获得它。
首先,我建议在简单的情况下“按摩”代码,以感受一下。例如,我使用n=3
并v=1:6
运行了第一个循环一次,B
如下所示:
[N M]=size(B)
N =
9
M =
27
imagesc(B);
所以你可以看到我们得到了一个像矩阵一样的楼梯,这是非常规则的!我们需要的只是将正确的矩阵索引分配给正确的值,v
就是这样。
有很多方法可以实现这一点,有些方法比其他方法更优雅。最简单的方法之一是使用函数find
:
pos=[find(B==v(1)),find(B==v(2)),find(B==v(3)),...
find(B==v(4)),find(B==v(5)),find(B==v(6))]
pos =
1 10 19 28 37 46
29 38 47 56 65 74
57 66 75 84 93 102
85 94 103 112 121 130
113 122 131 140 149 158
141 150 159 168 177 186
169 178 187 196 205 214
197 206 215 224 233 242
上面的值是找到值的矩阵的线性索引。每列表示in的特定值的线性索引。例如,索引都包含值等...每一行都包含完整,因此,索引 [29 38 47 56 65 74] 包含。您可以注意到,对于每一行,索引之间的差异为 9,或者,每个索引以步长 分隔,其中有 6 个,这只是向量的长度(也是由 获得的)。对于列,相邻元素之间的差异为 28,或者步长为。 B
v
v
B
[1 29 57 ...]
v(1)
v
v=[v(1) v(2) ... v(6)]
N
v
numel(v)
M+1
我们只需要v
根据这个逻辑在适当的索引中分配 的值。一种方法是编写每个“行”:
B([1:N:numel(v)*N]+(M+1)*0)=v;
B([1:N:numel(v)*N]+(M+1)*1)=v;
...
B([1:N:numel(v)*N]+(M+1)*(N-2))=v;
但这对于 big 是不切实际的N-2
,所以如果你真的想要,你可以在 for 循环中做到这一点:
for kk=0:N-2;
B([1:N:numel(v)*N]+(M+1)*kk)=v;
end
Matlab 提供了一种更有效的方法来一次获取所有索引bsxfun
(这取代了 for 循环),例如:
ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]')
所以现在我们可以使用ind
分配v
到矩阵N-1
时间。为此,我们需要“展平”ind
为行向量:
ind=reshape(ind.',1,[]);
并连接 v
到自身 N-1 次(或再制作 N-1 个 的副本v
):
vec=repmat(v,[1 N-1]);
最终我们得到了答案:
B(ind)=vec;
长话短说,写得紧凑,我们得到一个 2 行解决方案(已知大小B
:)[N M]=size(B)
:
ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]');
B(reshape(ind.',1,[]))=repmat(v,[1 N-1]);
因为n=9
矢量化代码在我的机器上要快约 850 倍。(小将n
不那么重要)
由于获得的矩阵主要由 zeros 组成,因此您无需将它们分配给完整矩阵,而是使用稀疏矩阵,这是完整的代码(非常相似):
N=3^(n-1);
M=3^n;
S=sparse([],[],[],N,M);
ind=bsxfun(@plus,1:N:N*numel(v),[0:(M+1):M*(N-1)+1]');
S(reshape(ind.',1,[]))=repmat(v,[1 N-1]);
因为n=10
我只能运行稀疏矩阵代码(否则内存不足),而在我的机器上大约需要 6 秒。
现在尝试将其应用于第二个循环...