TypeError:稀疏矩阵长度有歧义;在scipy中调用lil_matrix.diagonal()时使用getnnz(



我尝试使用以下代码获得以lil_matrix格式存储的稀疏矩阵的对角线之和:

sm1 = np.sum(board.diagonal(k=i1-row1))
sm2 = np.sum(board.diagonal(k=i2-row2))

但是这给了我一个

TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]

type(board)返回<class 'scipy.sparse._lil.lil_matrix'>

row1, row2, i1, i2均为整数。有趣的是,如果我调用print(np.sum(board.diagonal(k=i1-row1)),它会在抛出类型错误之前打印正确的结果。

我怀疑这个错误与csr矩阵的转换有关,因为在错误消息中提到了return self.tocsr().diagonal(k=k),调用board.tocsr()会抛出同样的错误。

提前感谢!

下面是整个错误日志:

Traceback (most recent call last):
File "/usr/lib/python3.8/code.py", line 90, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
File "/snap/pycharm-professional/285/plugins/python/helpers/pydev/_pydev_bundle/pydev_umd.py", line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
File "/snap/pycharm-professional/285/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"n", file, 'exec'), glob, loc)
File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 94, in <module>
y.run()
File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 63, in run
self.swap(newSol)
File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 34, in swap
newCost = self.calcFastCost(board.board, row1, row2)
File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 47, in calcFastCost
sm1 = np.sum(board.diagonal(k=i1-row1))
File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_base.py", line 1214, in diagonal
return self.tocsr().diagonal(k=k)
File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_lil.py", line 459, in tocsr
_csparsetools.lil_get_lengths(self.rows, indptr[1:])
File "_csparsetools.pyx", line 111, in scipy.sparse._csparsetools.lil_get_lengths
File "_csparsetools.pyx", line 117, in scipy.sparse._csparsetools._lil_get_lengths_int32
File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_base.py", line 345, in __len__
raise TypeError("sparse matrix length is ambiguous; use getnnz()"
TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]

你们的scipy版本是什么?在当前设置中,我可以创建lil并获得对角线:

In [16]: M = sparse.lil_matrix(np.eye(3))
In [17]: M
Out[17]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
with 3 stored elements in List of Lists format>    
In [18]: M.A
Out[18]: 
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])

转换为csr没有问题,对角线也没有问题:

In [19]: M.tocsr()
Out[19]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
with 3 stored elements in Compressed Sparse Row format>    
In [20]: M.diagonal()
Out[20]: array([1., 1., 1.])

但问len,给你的错误:

In [21]: len(M)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [21], in <cell line: 1>()
----> 1 len(M)
File ~anaconda3libsite-packagesscipysparsebase.py:291, in spmatrix.__len__(self)
290 def __len__(self):
--> 291     raise TypeError("sparse matrix length is ambiguous; use getnnz()"
292                     " or shape[0]")
TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]

对于这个lil,其他的步骤是好的:

In [22]: M.nnz         
Out[22]: 3    
In [23]: M.getnnz()
Out[23]: 3
In [24]: M.shape
Out[24]: (3, 3)

lil将值存储在两个对象类型数组中:

In [26]: M.data
Out[26]: array([list([1.0]), list([1.0]), list([1.0])], dtype=object)
In [27]: M.rows
Out[27]: array([list([0]), list([1]), list([2])], dtype=object)

如果我通过删除一个rows元素来破坏矩阵,我会得到一个非常不同的错误。

看起来错误发生在tocsr中,在这个块中,它从rows元素的长度创建indptr:

M, N = self.shape
if M*N <= np.iinfo(np.int32).max:
# fast path: it is known that 64-bit indexing will not be needed.
idx_dtype = np.int32
indptr = np.empty(M + 1, dtype=idx_dtype)
indptr[0] = 0
_csparsetools.lil_get_lengths(self.rows, indptr[1:])
np.cumsum(indptr, out=indptr)
nnz = indptr[-1]

lil_get_lengths是经过编译的代码,遍历rows的元素,并将它们的长度放在第二个参数中。