gabe
gabe

Reputation: 2511

sparse lil_matrix cannot assign data

When trying to directly set the data attribute of a sparse lil_matrix, I encounter very unexpected behavior. Can someone explain what is going on in the following simple example?

My particular use case is I want to set the row modulo 2; i.e. in dense-matrix-speak I just want to do matrix[0] %= 2.

from scipy import sparse
import numpy as np
np.random.seed(0)

matrix = sparse.rand(10**3,10**3).tolil()
num_entries = len(matrix[0].data[0])
print num_entries
# 9

# this throws no errors...
matrix[0].data[0] = [2]*num_entries
# but does nothing!

assert (np.array(matrix[0].data) == 2).all() # FAILS

# in fact nothing can be done to alter .data directly...
matrix[0].data[0].pop() # returns the last float from the row
# but does not actually pop it from the row!
assert (len(matrix[0].data[0]) == num_entries-1) # FAILS

Upvotes: 1

Views: 226

Answers (2)

gabe
gabe

Reputation: 2511

@vlsd found the bug, but I'm adding this to say more.

The issue with the code I posted is that I assign (throughout) to matrix[0].data. The problem is that matrix[0] doesn't work the same as dense-arrays; it's not simply pointing to the same object, but making a new object (I think). So assigning data to this new object is fine, but it just doesn't affect matrix. That's the problem.

So the following code works fine:

matrix.data[0] = [2]*num_entries
assert (np.array(matrix.data[0]) == 2).all() # passes
matrix.data[0].pop()
assert (len(matrix.data[0]) == num_entries-1) # passes

NB That popping from the list is generally a bad idea as this probably ruins the integrity of the sparse-matrix. But this was just to demo. And it now makes sense.

Upvotes: 0

vlsd
vlsd

Reputation: 945

I'm not quite sure what kind of object matrix[0] is, but I think you mean to drop the indexing on matrix and only keep it on data:

num_entries = len(matrix.data[0])
matrix.data[0] = [2]*num_entries

Upvotes: 1

Related Questions