0

I'm having the following problem: I have a matrix which is 20 x 1000 and I want to divide it into four submatrices of size 20 x 250.

After that, I want to make operation to each submatrix assume that I have a vector P of length equal to the number of the submatrices, 4.

P= [ 3 4 5 6] 

What I am aiming to do for each submatrix (A) is as follows:

For the first submatrix: A(:,1:P(1))=1

As well as the second submatrix: A(:,1:P(2))=1 and so on and so forth.

How could I do this without loops?

Divakar
  • 218,885
  • 19
  • 262
  • 358

1 Answers1

0

One vectorized approach could be with a combination of cumsum and bsxfun, which could be a little memory intensive though -

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;"

Another slightly different approach -

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;

Please note that to really see the benefits of vectorized solutions, you need to use it when your original loopy code has a lot of iterations going. Otherwise, the overhead associated with the preparatory work to setup vectorized approaches would be a waste. Thus, I am assuming your actual case involves more than just 4 submatrices.


Another cumsum based approach and this one must be interesting to try out and might even prove to be the best of the lot -

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)
Divakar
  • 218,885
  • 19
  • 262
  • 358