构造稀疏矩阵后,从稀疏转换为稠密再变为稀疏

时间:2019-03-14 18:04:27

标签: python matrix scipy sparse-matrix

我正在使用scipy生成稀疏的有限差分矩阵,首先从块矩阵构造它,然后编辑对角线以说明边界条件。所得的稀疏矩阵为BSR类型。我发现,如果我使用scipy.sparse.BSR_matrix函数将矩阵转换为密集矩阵,然后又返回到稀疏矩阵,那么剩下的将是稀疏矩阵。这是我用来生成矩阵的代码:

size = (4,4)

xDiff = np.zeros((size[0]+1,size[0]))
ix,jx = np.indices(xDiff.shape)
xDiff[ix==jx] = 1
xDiff[ix==jx+1] = -1

yDiff = np.zeros((size[1]+1,size[1]))
iy,jy = np.indices(yDiff.shape)
yDiff[iy==jy] = 1
yDiff[iy==jy+1] = -1

Ax = sp.sparse.dia_matrix(-np.matmul(np.transpose(xDiff),xDiff))
Ay = sp.sparse.dia_matrix(-np.matmul(np.transpose(yDiff),yDiff))

lap = sp.sparse.kron(sp.sparse.eye(size[1]),Ax) + sp.sparse.kron(Ay,sp.sparse.eye(size[0]))

#set up boundary conditions
BC_diag = np.array([2]+[1]*(size[0]-2)+[2]+([1]+[0]*(size[0]-2)+[1])*(size[1]-2)+[2]+[1]*(size[0]-2)+[2])

lap += sp.sparse.diags(BC_diag)

如果我检查此矩阵的稀疏性,则会看到以下内容:

lap
<16x16 sparse matrix of type '<class 'numpy.float64'>'
with 160 stored elements (blocksize = 4x4) in Block Sparse Row format>

但是,如果将其转换为密集矩阵,然后又恢复为相同的稀疏格式,则会看到稀疏矩阵:

sp.sparse.bsr_matrix(lap.todense())
<16x16 sparse matrix of type '<class 'numpy.float64'>'
with 64 stored elements (blocksize = 1x1) in Block Sparse Row format>

我怀疑发生这种情况的原因是因为我使用sparse.kron函数构造了矩阵,但我的问题是是否有一种方法可以在不首先转换为密集模式的情况下到达较小的稀疏矩阵,例如,如果我结束想要模拟一个非常大的域。

2 个答案:

答案 0 :(得分:1)

BSR将数据存储在密集块中:

In [167]: lap.data.shape                                                        
Out[167]: (10, 4, 4)

在这种情况下,这些块有很多零。

In [168]: lap1 = lap.tocsr() 
In [170]: lap1                                                                  
Out[170]: 
<16x16 sparse matrix of type '<class 'numpy.float64'>'
    with 160 stored elements in Compressed Sparse Row format>
In [171]: lap1.data                                                             
Out[171]: 
array([-2.,  1.,  0.,  0.,  1.,  0.,  0.,  0.,  1., -3.,  1.,  0.,  0.,
        1.,  0.,  0.,  0.,  1., -3.,  1.,  0.,  0.,  1.,  0.,  0.,  0.,
        1., -2.,  0.,  0.,  0.,  1.,  1.,  0.,  0.,  0., -3.,  1.,  0.,
        0.,  1.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  1., -4.,  1.,  0., 
        ...
        0.,  0.,  1., -2.])

就地清理:

In [172]: lap1.eliminate_zeros()                                                
In [173]: lap1                                                                  
Out[173]: 
<16x16 sparse matrix of type '<class 'numpy.float64'>'
    with 64 stored elements in Compressed Sparse Row format>

如果在使用csr时指定了kron格式:

In [181]: lap2 = sparse.kron(np.eye(size[1]),Ax,format='csr') + sparse.kron(Ay,n
     ...: p.eye(size[0]), format='csr')                                         
In [182]: lap2                                                                  
Out[182]: 
<16x16 sparse matrix of type '<class 'numpy.float64'>'
    with 64 stored elements in Compressed Sparse Row format>

答案 1 :(得分:-1)

[我被告知我的答案不正确。据我了解,原因是Scipy没有使用Lapack创建矩阵,而是为此使用了自己的代码。有趣。该信息尽管出乎意料,却具有权威性。我会顺从的!

[我将答案留作参考,但不再断言答案是正确的。]

通常来说,当涉及稀疏矩阵之类的复杂数据结构时,有两种情况:

  1. 构造函数事先知道结构的全部内容;或
  2. 该结构被设计为逐步构建,以便仅在结构完成后才能知道结构的全部内容。

复杂数据结构的经典情况是二叉树的情况。完成后,可以通过复制二进制树来提高效率。否则,树的标准红黑实现会留下一些搜索路径,其长度是其他搜索路径的两倍,这通常是可以的,但并非最佳选择。

现在,您可能知道所有这些,但是我提到它是有原因的。 Scipy取决于Lapack。 Lapack带来了几种不同的存储方案。其中两个是

  • 稀疏和
  • 联合

方案。看起来Scipy首先将您的矩阵存储为稀疏矩阵,然后在其中显式存储每个非零元素的索引;但是,从表面上看,Scipy注意到带状表示更合适-因为矩阵毕竟是带状的。