Search code examples
matlabsparse-matrix

Create blockwise shifted sparse matrix in matlab directly


I struggle to create a sparse matrix efficiently in matlab.

The problem looks like this:

Let's take a square matrix

a = 4; b = 2;

t = rand(a,a);

What I want is equivalent to P = sparse(kron(eye(a),ones(1,b)).*repmat(t,1,b))

Only that will be a = 12*2^10 and b = 2^10 (i.e. first creating the element wise multiplication between the kroneker product and the repmat of t is too memory intensive).

I've been browsing around and couldn't find a related question. My idea is to implement this matrix directly using the sparse(B,d,m,n) or spidag() syntax.

Would be amazing if someone had an idea.

Cheers

I expect a matrix like this:

P = sparse(kron(eye(a),ones(1,b)).*repmat(t,1,b))


Solution

  • Tested with your example and b=3.

    r = repelem(1:a,1,b)
    c = mod( repmat(0:(b-1),1,a) + (r-1)*b, a ) + 1;
    P = sparse( r, 1:a*b, t(sub2ind([a,a],r,c)) );
    

    Logic:

    • r is the row index, which is the same for the sparse output and row input from t; each row repeated b times.
    • c is the column index within t to take the value from. This appears to start as 1:b, and then take the next b elements starting from the following column, wrapping round to column 1.

    Then you can directly form the sparse matrix extracting elements from t using a linear index from r and c.

    Output:

    >> P = sparse(kron(eye(a),ones(1,b)).*repmat(t,1,b))
    
    P =
    
       (1,1)       0.8147
       (1,2)       0.6324
       (2,3)       0.9649
       (2,4)       0.4854
       (3,5)       0.1270
       (3,6)       0.2785
       (4,7)       0.9706
       (4,8)       0.1419
    
    >> s = sparse( r, 1:a*b, t(sub2ind([a,a],r,c)) )
    
    s =
    
       (1,1)       0.8147
       (1,2)       0.6324
       (2,3)       0.9649
       (2,4)       0.4854
       (3,5)       0.1270
       (3,6)       0.2785
       (4,7)       0.9706
       (4,8)       0.1419