如何避免在稀疏稀疏矩阵中插入不必要的零

问题描述

我正在处理一个由线性系统建模的问题,该系统可以写成正方形块-三对角矩阵。这些块的大小为b = 4n + 8,整个矩阵的大小为Nb; N可以任意大(当然是合理的),而n可以保持很小(通常小于10)。

块本身是稀疏的,每个块的第一个对角线仅是单位矩阵,第二个对角线仅具有n + 1个非零列(所以3n + 7列为零)。这些列是连续的,或者为零然后为非零,或者相反。

在内存中构建所有这些块会导致3N-2 x b x b数组,该数组可以使用scipy.sparse.bsr_matrix转换为稀疏矩阵,然后转换为CSR格式并修剪掉多余的零。它很好用,但是我宁愿跳过这个临时的大而稀疏的数组(对于N = 1e4,n = 5,每个相关条目都是5.6个零!)。

  • 我查看了建议用于切片和增量构建的scipy.sparse.dok_matrix。创建我的条目很整齐,但此过程比将bsr_matrix与不必要的密集数组配合使用要长10倍左右,这对将来的用例有害。
  • 似乎bsr_matrix不能直接用于scipy稀疏矩阵作为输入。
  • 使用不包含对角线块的bsr_matrix ,然后添加稀疏的眼睛大大减少了零的数量(在我的测试配置中,每个相关条目为3.5)与原始解决方案相比,处理过程减少了三分之一。得分!

关于我可以做些什么来进一步减少此矩阵的原始痕迹的任何线索?显而易见的目标是给我更多选择N的自由。

编辑

通过分别构造三个块对角线,我设法进一步改善了某些情况。这样,我需要减少对第二条对角线的填充(n + 3而不是3n + 7;每个相关条目1.3个零),将我的原始块分为两个垂直块(一个全为零)我一次只需要一个对角线,就可以将存储成本降低一半。主要对角线用眼图法构造。锦上添花:与我的第三个项目符号要点相比,速度提高了25%,这可能是因为将两个第二对角线分开可以节省使用bsr_matrix之前所需的一些数组重塑操作。与原始方法相比,对于我的(N,n)=(1e4,5)测试用例,在修整之前比较矩阵时节省了约2000万个零。每个128位,已经是一个不错的增益!

我现在能想到的唯一可能的改进是,分别构建这些对角线,不进行任何填充,然后插入零列(可能是通过具有标识块矩阵的乘积),最后将所有内容加在一起。 我还阅读了一些有关使用字典更新空的dok_matrix的内容,但就我而言,我认为我需要扩展索引列表,采用其笛卡尔积来构造键,并且我块的每个元素都需要是一个单独的值因为显然不能使用切片作为字典键。

解决方法

我最终实现了我在上一段中提出的解决方案。 对于每个第二对角线,我构造一个没有任何填充的块稀疏矩阵,然后通过右侧积与块相同的块矩阵将其变换为适当形状的矩阵。我要做需要在此处存储零以使用bsr_matrix(我首先尝试了scipy.sparse.block_diag方法,但速度非常慢),但与半填充解决方案相比,它们的数量较少:(4n + 7)(n + 1)与(4n + 8)(n + 3);并且可以用8位而不是128位表示。执行时间增加了约40%,但我可以接受(与第一个解决方案相比,它减少了20%)。

我可能在这里丢失了一些东西,但是现在我对这种解决方案非常满意。

编辑

在影响产品之前修剪RHS矩阵的零点时,与以前最有效的解决方案相比,执行时间减少了 30%;一切顺利,一切顺利。