## Create sparse matrix with zig-zag diagonal

on 3 Feb 2013

### Cedric Wannaz (view profile)

Is there a way to shift every column c by (c-1)*n rows down, where n is size(A,1) in the following example, without a loop and without excessive memory usage? So to get

```   A = [
a11 a12 a13 a14 ...
a21 a22 a23 a24 ...
... ... ... ... ...
]```

```    B = [
a11   0   0   0 ...
a21   0   0   0 ...
... ... ... ... ...
0 a12   0   0 ...
0 a22   0   0 ...
... ... ... ... ...
0   0 a13   0 ...
0   0 a23   0 ...
... ... ... ... ...
0   0   0 a14 ...
0   0   0 a24 ...
... ... ... ... ...
]```

I tried diag and sparse with no luck so far. I need Matrix A in an operation X=J\A afterwards. It is crucial that the zero elements do not consume memory as A can have up to 20e6 columns and probably 10 rows.

## Products

No products are associated with this question.

### Cedric Wannaz (view profile)

on 3 Feb 2013
Edited by Cedric Wannaz

### Cedric Wannaz (view profile)

on 3 Feb 2013

You could use sparse(), building appropriate vectors of indices and values, e.g.:

``` nCol = size(A, 2) ;
nRow = nCol * size(A, 1) ;
I = (1:nRow).' ;
J = reshape(repmat(1:nCol, size(A, 1), 1), [], 1) ;
B = sparse(I, J, A(:), nRow, nCol) ;```

(that you can write in two lines actually, but I wanted to keep it clear)

Florian

### Florian (view profile)

on 3 Feb 2013

Outstanding! It works!

I still need to figure out the magic behind this, though... sparse and especially reshape are still a closed book to me :(. I didn't manage to get behind the syntax, not to mention the usage of []...

Cedric Wannaz

### Cedric Wannaz (view profile)

on 3 Feb 2013

Well, one way to use sparse() is to provide 5 args: a vector or row indices, a vector of column indices, a vector of values, the number of rows and the number of columns. Here we build these "things", using one "trick" that simplifies a bit the problem: we create the vector of values using linear indexing on A (in this case, it means lining up columns of A and reading that as a vector). Example:

``` >> A = [1, 2, 3; 4, 5, 6]
A =
1     2     3
4     5     6
>> A(:)
ans =
1
4
2
5
3
6```

Knowing that we will pass A(:) to sparse() as a vector of values, we have to build appropriate vectors of row and column indices..

Looking at what you depicted, row indices will just increase linearly, so we build I as 1:nRow, transposed so it is a column vector (same dim. as A(:)).

For column indices, it is a little more tricky as it will be something like

1 1 1 ... 2 2 2 ... etc, with the number of each integer being the number of rows of A. We can obtain this by creating a matrix

``` 1 2 3 4 ...
1 2 3 4 ...
. . . .
. . . .```

that we ultimately index linearly. This matrix is actually the vertical repetition of (1:nCol) a number of times that matches the number of rows of A. You obtain that with repmat(). Example:

``` >> repmat(1:4, 3, 1)
ans =
1     2     3     4
1     2     3     4
1     2     3     4```

Now I could have written

``` ...
J = repmat(1:nCol, size(A, 1), 1)) ;
B = sparse(I, J(:), A(:), nRow, nCol) ;```

and avoid the reshape, but you would have had I given as a vector, and J as a matrix indexed linearly, which I thought would have brought confusion. The reshape transforms the output of repmat() into a column vector (last arg = 1). As reshape() is flexible, it allows to specify only one size (the other is left to an empty array), and computes the other. The reshape does therefore essentially what J(:) would have done.

Florian

### Florian (view profile)

on 5 Feb 2013

Pretty cool, thank's a lot!

### bym (view profile)

on 3 Feb 2013
```s = spdiags(A',[0,-1],c*(n-1),c);
```

Florian

### Florian (view profile)

on 3 Feb 2013

Unfortunately it didn't do the trick. Actually no specific value is assign to "c". In my question it was meant to be a variable to describe that the first column (c=1) should be moved (c-1)*n=0 rows down, the second column (c=2) should be moved by (c-2)*n=n rows down, the third column (c=3) should be moved (c-2)*n=2n rows down, etc.

From what I see, diags or spdiags places its elements only on true diagonals, shifted or not. In my case, however, the elements are not placed on a straight diagonal line but in a rather zig-zag way.

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi