在 MATLAB 中跨列切片稀疏矩阵比跨行切片要快得多。所以你应该更喜欢访问M(:,i) 而不是M(i,:)。
MATLAB 内部使用Compressed Sparse Column (CSC) 存储:
- 非零元素存储在长度为
nzmax 的一维双精度数组中,排列在column-major order 中(pr 用于实部,pi 用于虚部,如果矩阵很复杂)
-
ir 具有相应行索引的整数数组
-
jc 一个长度为n+1(其中n 是列数)的整数数组,其中包含列索引信息。根据定义,jc 的最后一个值包含 nnz(存储的非零数)。
以下面的稀疏矩阵为例:
>> M = sparse([1 3 5 3 4 1 5], [1 1 1 2 2 4 4], [1 7 5 3 4 2 6], 5, 4);
这就是它存储在内存中的样子(我对 ir 和 jc 使用基于 0 的索引):
1 . . 2
. . . .
7 3 . .
. 4 . .
5 . . 6
pr = 1 7 5 3 4 2 6
ir = 0 2 4 2 3 0 4
jc = 0 3 5 5 7
nzmax = at least 7
nnz = 7
m = 5
n = 4
要检索稀疏矩阵M(:,i) 的第 i 列,只需执行以下操作:pr(jc(i):jc(i+1)-1)(为简单起见,我不关注基于 0 和 1 的索引)。另一方面,访问矩阵行涉及更多的计算和数组遍历(它不再对spatial-locality 友好)。
这里有一些指向 MATLAB 文档的链接以获取更多信息:Sparse Matrices、Manipulating Sparse Matrices
值得查看 John R. Gilbert、Cleve Moler 和 Robert Schreiber 撰写的 original paper:“Matlab 中的稀疏矩阵:设计和实现”,(SIAM 矩阵分析和应用杂志,13:1 , 333–356 (1992)).
以下是上述论文中的一些引用,用于回答您关于稀疏存储开销的问题:
简单数组运算的计算复杂度应该是
与nnz 成正比,也许还线性依赖于m 或n,
但要独立于产品m*n。更多的复杂性
复杂的操作涉及到订购和填写等因素,
但是一个好的稀疏矩阵算法的目标应该是:
稀疏矩阵运算所需的时间应该成正比
对非零量的算术运算次数。
我们称之为“时间与失败成正比”规则;它是一个
我们设计的基本原则。
和
这个(面向列的稀疏矩阵)方案效率不高
一次操作元素上的矩阵:访问单个
元素花费的时间至少与
其列的长度;插入或删除非零可能需要
广泛的数据移动。但是,逐个元素的操作是
在 MATLAB 中很少见(即使在完整的 MATLAB 中也很昂贵)。它最常见
应用程序将创建一个稀疏矩阵,但这更多
通过构建矩阵元素列表[i,j,s] 来有效地完成
任意顺序,然后使用sparse(i,j,s) 创建矩阵。
稀疏数据结构允许在
矩阵最后一列的结尾。因此,建立了一个算法
一次一列的矩阵可以通过以下方式有效地实现
一开始就为所有预期的非零值分配足够的空间。
第 3.1.4 节“渐近复杂性分析”也应该很有趣(这里引用太长了)。