简体   繁体   中英

sparse matrix matlab unexpected behavior

I am creating a sparse matrix

sp = sparse(I,J,Val,X,Y)

My Val matrix is a ones matrix. Much to my surprise the sp matrix does not contain only zeros and ones. I suppose that this happens because in some cases there are duplicates in I , J . I mean the sp(1,1) is set to 1 2 times, and this makes it 2.

Question 1: Is my assumption true? Instead of overwriting the value, does MATLAB really add it?

Question 2: How can we get around this, given that it would be very troublesome to manipulate I and J . Something I can think of, is to use find (thus guaranteeing uniqueness) and then recreate the matrix using ones once more. Any better suggestion?

Question 1: Is my assumption true? Instead of overwriting the value, does Matlab really add it?

Correct. If you have duplicate row and column values each with their own values, MATLAB will aggregate them all into the same row and column location by adding them.

This is clearly seen in the documentation but as a reproducible example, suppose I have the following row and column locations and their associated values at these locations:

i = [6 6 6 5 10 10 9 9].';
j = [1 1 1 2 3 3 10 10].';
v = [100 202 173 305 410 550 323 121].';

Note that these are column vectors as this shape is the expected input. In a neater presentation:

>> [i j v]

ans =

     6     1   100
     6     1   202
     6     1   173
     5     2   305
    10     3   410
    10     3   550
     9    10   323
     9    10   121

We can see that there are three values that get mapped to location (6, 1) , two values that get mapped to location (10, 3) and finally two that get mapped to location (9, 10) .

By creating the sparse matrix and displaying it, we thus get:

>> S = sparse(i,j,v)

S =

   (6,1)      475
   (5,2)      305
  (10,3)      960
   (9,10)     444

As you can see, the three values mapped to (6, 1) are summed: 100 + 202 + 173 = 475. You can verify this with the other duplicate row and column locations.


Question 2: How can we get around this, given that it would be very troublesome to manipulate I and J. Something I can think of, is to use find (thus guaranteeing uniqueness) and then recreate the matrix using ones once more. Any better suggestion?

There are two possible ways to mitigate this if it is truly your desire to only have a binary matrix.

The first way which may be more preferable to you as you mentioned that manipulating the row and column locations is troublesome is to create the matrix that you have now, but then convert it to logical so that any values that are non-zero are set to 1:

>> S = S ~= 0

S =

  10×10 sparse logical array

   (6,1)      1
   (5,2)      1
  (10,3)      1
   (9,10)     1

If you require that the precision of the matrix be back in its original double form, cast the result after you convert to logical :

>> S = double(S ~= 0)

S =

   (6,1)        1
   (5,2)        1
  (10,3)        1
   (9,10)       1

The second way if you wish is to work on your row and column locations so that you filter out any indices that are non-unique, then create a vector of ones for val that is as long as the unique row and column locations. You can use the unique function to help you do that. Concatenate the row and column locations in a two column matrix and specify that you want to operate on 'rows' . This means that each row is considered an input rather than individual elements in a matrix. Once you find the unique row and column locations, use these as input for creating the sparse matrix:

>> unique_vals = unique([i j], 'rows')

unique_vals =

     5     2
     6     1
     9    10
    10     3

>> vals = ones(size(unique_vals, 1));
>> S = sparse(unique_vals(:, 1), unique_vals(:, 2), vals)

S =

   (6,1)        1
   (5,2)        1
  (10,3)        1
   (9,10)       1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM