2
votes

I have a sparse matrix

obj.resOp = sparse(row,col,val); 

and a vector containing the sums of each row in the matrix

sums = sparse(sum(obj.resOp,2));

Now what I want to do is

obj.resOp = obj.resOp ./ sums;

which would scale every row in the matrix so that the rowsum in each row is 1.

However in this last line, MATLAB internally seems to construct a full matrix from obj.resOp and hence I get this error:

Error using ./ Requested 38849x231827 (17.5GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference panel for more information.

for sufficiently large matrices.

In theory I think that expanding to a full matrix is not necessary. Is there any MATLAB formulation of what I want to achieve while keeping the sparsity of obj.resOp?

2
It's likely relevant to know which version of MATLAB you're using? - Wolfie
I'm using MATLAB 2017a. - fpnick
obj.resOp = inv(diag(sums)) * obj.resOp; should give me the same result, but is killed. That could be a bug in my vectors though. - fpnick
Some of the entries in sum were zero which is why the above didn't work. After fixing this, everything works fine! Anyway, thank you for your suggestion, @Wolfie - fpnick

2 Answers

2
votes

You can do this with a method similar to the one described in this answer.

Start with some sparse matrix

% Random sparse matrix: 10 rows, 4 cols, density 20%
S = sprand(10,4, 0.2);

Get the row sums, note that sum returns a sparse matrix from sparse inputs, so no need for your additional conversion (docs).

rowsums = sum(S,2);

Find all non-zero indices and their values

[rowidx, colidx, vals] = find(S)

Now create a sparse matrix from the element-wise division

out = sparse(rowidx, colidx, vals./rowsums(rowidx), size(S,1), size(S,2));
0
votes

The equivalent calculation

obj.resOp = inv(diag(sums)) * obj.resOp;

works smoothly.