Where spfun meets bsxfun

Viewed 355

Is there way to perform element-wise operations like bsxfun does, but only operate on the non-zero elements of a sparse matrix?

In particular, for each non-zero element in matrix A at position (i,j) I want to find the product of all of the non-zero elements in the i-th row, except for element (i,j).

For example if the i-th row looks like this:

0   5   3   0   0   4   0  0

The result should look like this:

0   12  20  0   0   15  0  0

The most obvious solution seem to be to take the product of the non-zero elements along each row, and then divide each element back out of the row product. So, in the above example, the row product is 5 x 3 x 4 = 60, and then I just divide out 5 3 and 4 at their respective locations.

Given a sparse matrix A, this is my best solution so far:

[M N] = size(A);
[row col vals] = find(A);
row_prod = accumarray(row,vals,[],@prod);
B = bsxfun(@ldivide, A, row_prod);
B = sparse(row,col,B(sub2ind([M N],row,col)),M,N);

The first three lines achieve what I want: a column vector representing the product of the non-zero elements of each row. However, there are quite a few problems with the last two lines.

  • bsxfun is going to return a non-sparse matrix the size of A
  • It is going to waste a LOT of cycles dividing by zero unnecessarily.
  • The result is a matrix comprised mostly of Inf or -Inf where I really just want zeros.
  • I can't mask out the Infs because Matlab defines zero times infinity to be NaN.
  • Do I just need to bite the bullet and write a for-loop for this? Or is there another way to approach it?

    1 Answers
    Related