Submatrix索引和没有循环的操作

时间:2014-10-22 00:50:11

标签: matlab matrix vectorization submatrix

我遇到以下问题:我有一个20 x 1000的矩阵,我想把它分成四个大小为20 x 250的子矩阵。

之后,我想对每个子矩阵进行操作,假设我有一个长度等于子矩阵数的向量P,4。

P= [ 3 4 5 6] 

我打算为每个子矩阵(A)做的事情如下:

对于第一个子矩阵:A(:,1:P(1))=1

和第二个子矩阵一样:A(:,1:P(2))=1依旧等等。

如果没有循环我怎么能这样做?

1 个答案:

答案 0 :(得分:0)

一种矢量化方法可以使用cumsumbsxfun的组合,但这可能会占用大量内存 -

blocksize = 250;
valid_idx = bsxfun(@le,[1:max(P)],P');
idx_mat = bsxfun(@plus,cumsum(valid_idx,2),[0:numel(P)-1]'*blocksize);
A(:,idx_mat(valid_idx)) = 1; %// You can replace this with "A(:,unique(idx_mat))=1;"

另一种稍微不同的方法 -

blocksize = 250;
maxP = max(P);
valid_idx = bsxfun(@le,[1:maxP],P');
idx_mat = bsxfun(@plus,[0:numel(P)-1]'*blocksize,1:maxP);
A(:,idx_mat(valid_idx))=1;

请注意,要真正了解矢量化解决方案的好处,您需要在原始循环代码进行大量迭代时使用它。否则,与设置矢量化方法的准备工作相关的开销将是浪费。因此,我假设您的实际案例涉及的不仅仅是4个子矩阵。


另一种基于cumsum的方法,这个方法必须有趣才能尝试,甚至可能证明是最好的 -

blocksize = 250;

%//Get monotonically increasing labels within each group, defined by limits from idx
array1 = zeros(1,sum(P));
grp_starts = cumsum(P(1:end-1))+1;
array1(grp_starts) = P(1:end-1);
grp_labels = [1:numel(array1)] - cumsum(array1);

%// Get offsetted indices
array2 = zeros(1,sum(P));
array2(grp_starts) = blocksize;
offsetted_grp_labels = grp_labels + cumsum(array2);

A(:,offsetted_grp_labels)=1; %// perform the operation(s)