Sparse matrix conversion

I feel silly, but I can’t get this to work:

functions {
  matrix sparse_matrix(){
    int m = 2;
    vector[3] a = [1, 2, 3]';
    int b[3] = {1, 2, 2};
    int c[3] = {1, 1, 2};
    
    matrix[m, m] d = csr_to_dense_matrix(m, m, a, b, c);
    
    return(d);
  }
}

Which I thought would give me the matrix d = \begin{bmatrix} 1 & 2 \\ 0 & 3\end{bmatrix} but instead I get:

> expose_stan_functions("model/csr_matrix.stan")
> sparse_matrix()
Error in sparse_matrix() : 
  Exception: csr_to_dense_matrix: u/z (1) and v (3) must match in size  (in 'unknown file name' at line 8)

The way you set up indices does not follow the compressed sparse row (csr) format: https://mc-stan.org/math/dc/d79/group__csr__format.html. In this format, elements are listed row-wise, and rowstarts lists the index at which a new row starts (plus the last element which is the number of rows + 1).

This works:

functions {
  matrix sparse_matrix(){
    int m = 2;
    vector[3] x = [1, 2, 3]';
    int colidx[3] = {1, 2, 2};
    int rowstarts[3] = {1, 3, 4};

    matrix[m, m] d = csr_to_dense_matrix(m, m, x, colidx, rowstarts);

    return(d);
  }
}
1 Like

Aaah, rowstarts (or u in the doc) is indexing which element of the dense matrix is at the begining of each row?

Nope. From your link -

u: index of where each row starts in w, length is equal to the number of rows plus one. Last entry [of u] is one-past-the-end in w.

So the second entry of u says which element of w goes on the second row. The last element of u is then the length of w + 1.

Thanks for the link to Stan math docs, that’s much more informative than the function references I was working from.

rowstarts indexes which element in the sparse matrix starts a new row.
Take this example:

[ 0  2  0  4
  5  0  0  8
  0 10  0  0
 13  0 15  0]

Here, nz = {2, 4, 5, 8, 10, 13, 15}, colidx = {2, 4, 1, 4, 2, 1, 3}, and rowstarts would be {1, 3, 5, 6, 8}. Which means that row 1 starts at the first nonzero element (the 2), row 2 starts at the 3rd (the 5), and so on. The last element is one plus the total number of nonzeros in the matrix.

It seems that the documentation of csr_to_dense_matrix in the functions reference is wrong, in that it says that u and v must have the same size, which is clearly not the case an in my example before. I’ll post a patch to fix it.

1 Like