1

I have a matrix F of size D-by-N and a vector A of length N of random integers in the range [1,a]. I want to create a matrix M of size D * a such that each colum M(:,i) has the vector F(:,i) starting from the index (A(i)-1)*D+1 to (A(i)-1)*D+D.

Example:

F = [1 2 3 10
     4 5 6 22]

A = [3 2 1 2]

a = 4

M = [0 0 3 0
     0 0 6 0
     0 2 0 10
     0 5 0 22
     1 0 0 0
     4 0 0 0
     0 0 0 0
     0 0 0 0]

I can do it with a simple loop

        for i = 1 : N
            M((A(i)-1)*D+1:(A(i)-1)*D+D,i) = F(:,i);
        end

but for large N this might take a while. I am looking for a way to do it without loop.

Divakar
  • 218,885
  • 19
  • 262
  • 358
Simon
  • 5,070
  • 5
  • 33
  • 59
  • I'd argue that this is quite fast. Did you even time it for large values of `a / N` to check to see if your statement is correct? – rayryeng Oct 24 '15 at 21:22
  • Well, it's not really slow, but I would like something faster if possible, because this part of my code is run at each iteration of my main algorithm. On my computer it takes `3s` when `a = 3`, `D = 6` and `N = 1e6`. – Simon Oct 24 '15 at 21:27
  • How can `a` be `4` if `A = [3 2 1 2]`? `A` has elements from `1` to `3`. – Divakar Oct 24 '15 at 22:13
  • @Divakar Some values can be missing, since they are randomly sampled. In that case (4 is missing) the bottom part of the matrix will be 0 (in the example, the last two rows). – Simon Oct 24 '15 at 22:23
  • Makes sense I guess. – Divakar Oct 24 '15 at 22:28

1 Answers1

2

You can use bsxfun for a linear-indexing based approach -

[D,N] = size(F);    %// Get size of F

start_idx = (A-1)*D+1 + [0:N-1]*D*a;          %// column start linear indices
all_idx = bsxfun(@plus,start_idx,[0:D-1]');   %//'# all linear indices

out = zeros(D*a,N); %// Initialize output array with zeros
out(all_idx) = F;   %// Insert values from F into output array

Sample run -

F =
     1     2     3    10
     4     5     6    22
A =
     3     2     1     2
a =
     4
out =
     0     0     3     0
     0     0     6     0
     0     2     0    10
     0     5     0    22
     1     0     0     0
     4     0     0     0
     0     0     0     0
     0     0     0     0
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • Thanks, your code is really fast (10 times faster than my loop). However, it gives incorrect results if, for instance, all elements of `A` are ones. I am testing using `D = 2; N = 1e2; a = 4; F = rand(D,N); A = ones(1,N);` – Simon Oct 24 '15 at 21:57
  • @Simon Oh I assumed `A` would be `1:N`, my bad! Could you add an example with something not as simple as `[1,2,3]` into the question as sample? – Divakar Oct 24 '15 at 21:59
  • You are right, the example in the question was too trivial and did not make clear that `A` contains random integer in the range `[1,a]`. I edited my question. – Simon Oct 24 '15 at 22:04
  • @Simon Edited my solution accordingly. – Divakar Oct 24 '15 at 22:30
  • Thanks! The larger `N`, the faster your code is compared to my loop. For `N = 1e6` it is 10 times faster! – Simon Oct 24 '15 at 23:10
  • Nice job buddy. Another example of a question with an initially oversimplified example. I couldn't figure out how to do it with `sparse` with the new formulation so I just deleted my answer. – rayryeng Oct 24 '15 at 23:12
  • @rayryeng Yup and that's why I had to change my solution too entirely. – Divakar Oct 25 '15 at 13:22