稀疏数组的运用
矩阵的稀疏表示非常有用,因为不用存储每个元素. 如果一个特定值出现得非常频繁,使用稀疏表示将非常有利. Wolfram 语言通过 SparseArray 提供了矩阵、向量和张量的稀疏表示.
本教程讨论的是如何 在 Wolfram 语言中创建和使用 SparseArray 对象. 如果您对关于稀疏矩阵上进行线性代数计算感兴趣的话,您需要参考"矩阵计算"一节.
基本运算
在 Wolfram 语言中表示稀疏矩阵的基本对象是 SparseArray.
SparseArray[list] | 一个普通列表的 SparseArray 形式 |
SparseArray[{{i1,j1}->v1,{i2,j2}->v2,…},{m,n}] | |
元素{ik,jk} 取值为 vk 的 m×n 稀疏数组 | |
SparseArray[{{i1,j1},{i2,j2},…}->{v1,v2,…},{m,n}] | |
相同的稀疏数组 | |
SparseArray[data,{m,n},def] | 一个默认元素为 def 的 m×n 稀疏数组 |
SparseArray[Band[b]->v,{m,n}] | 一个 m×n 带状稀疏数组 |
Normal[array] | 对应于一个SparseArray 的普通列表 |
ArrayRules[m] | 非零元素的位置 |
SparseArray
有关这两种形式相对优越性的更完全讨论在"SparseArray 的规则输入"一节中给出.
Wolfram 语言使用符号化的代数技术来简化某些构建稀疏疏组的模式. 这允许构建稀疏疏组时不用测试每一个潜在元素,来看其是否确实在数组中出现,这样做显著节省了计算时间.
一般原则是:SparseArray 中所用的规则与 Wolfram 语言中所有规则的通常使用方式相同.
SparseArray 的规则输入
如果想要混合显式的模式指标,使用存在多个规则的第一种形式是方便的. 对于小型数组来说,这种方式也通常更具可读性. 如果您只有显式指标(例如在从一个文件中读取数据后),则第二种形式更加有效.
关于压缩数组的更多信息参见"压缩数组".
带状稀疏数组
如果想要构建具有某种类型带状结构的稀疏矩阵,可以通过 Band 实现.
SparseArray[Band[b]->v,{m,n}] | 一个 m×n 带状稀疏数组 |
Band[{i,j}] | 开始于位置{i,j}的对角矩阵带 |
Band[{imin,jmin},{imax,imax}] | 从 {imin,jmin} 到 {imax,imax}的对角矩阵带 |
Band[{imin,jmin},{imax,imax}{di,dj}] | 从{imin,jmin} 开始,以步长{di,dj}移动的对角矩阵带 |
一般地,使用 Band 来创建稀疏数组将更加有效.
单位矩阵和对角稀疏矩阵
在 Wolfram 语言中有许多创建单位矩阵和对角稀疏矩阵的方法.
IdentityMatrix[n,Sparse->True] | 稀疏单位矩阵 |
DiagonalMatrix[SparseArray[{a,b,c,d}]] | |
稀疏对角矩阵 |
注意矩阵所有项是如何均为机器精度数值的. 这对改善你的计算效率会有所帮助. 关于 Wolfram 语言可以操作的不同矩阵类型在"矩阵类型"一节中有更详细的介绍.
Normal
ArrayRules
结构化操作
得到矩阵的一部分
通过 Wolfram 语言函数 Part 可以非常直接地提取一个稀疏矩阵的元素、行和列. 通常 Part 的输入符号是[[ ]].
m[[i,j]] | 第 i,j 项 |
m[[i]] | 第 i 行 |
m[[i;;j]] | i 至 j 行 |
m[[All,i]] | 第 i 列 |
m[[All,i;;j]] | i 至 j 行 |
m[[{i1,…,ir},{j1,…,js}]] | 由行标为 ik 及列标为 jk 的元素组成的 r×s 子矩阵 |
Tr[m,List] | m 的对角元素列表 |
得到多个部分
设置矩阵的一部分
在赋值式左端通过 Wolfram 语言函数 Part 可以非常直接地设置稀疏矩阵的元素、行和列.
m={{a11,a12,…},{a21,a22,…},…} | 指定 m 为一个矩阵 |
m[[i,j]]=v | 将元素{i,j}的值重置为 v |
m[[i]]=v | 将行 i 的全部元素重置为 v |
m[[i]]={v1,v2,…} | 将行 i 的元素重置为{v1,v2,…} |
m[[All,j]]=v | 将列 j 的全部元素重置为 v |
m[[All,j]]={v1,v2,…} | 将列 j 的元素重置为{v1,v2,…} |
设置多个部分
提取子矩阵
m[[i0;;i1,j0;;j1]] | 提取由行 i0 至 i1、列 j0 至 j1组成的子矩阵 |
m[[i0;;i1]] | 提取由行 i0 至 i1 组成的子矩阵 |
m[[All,j0;;j1]] | 提取由列 j0 至 j1 组成的子矩阵 |
删除行和列
如果想要删除行或列,可以使用 Drop.
Drop[m,{i0,i1}] | 删除行 i0 至 i1 |
Drop[m,{},{j0,j1}] | 删除列 j0 至 j1 |
Drop[m,{i0,i1},{j0,j1}] | 删除行 i0 至 i1 以及列 j0 至 j1 |
插入行和列
如果想要插入一个行,可以使用 Insert.
Insert[m,r,i] | 将行 r 插入矩阵 m 的位置 i 处 |
扩展矩阵
转置
元素的轮换
测试矩阵
Wolfram 语言提供了一些函数来测试稀疏矩阵和提取尺寸信息.
VectorQ[expr] | 如果 expr 是向量的形式则给出 True,否则给出 False |
MatrixQ[expr] | 如果 expr 是矩阵的形式则给出 True,否则给出 False |
ArrayQ[t,n] | 测试 t 是否是一个秩为 n 的张量 |
Dimensions[expr] | 一个向量或矩阵的尺寸列表 |
ArrayDepth[t] | 找到一个张量的秩 |
mi==mj | 比较两个矩阵的等价性 |
应该注意的是,Equal 可用于任何 Wolfram 语言表达式. 如果想要使用矩阵的整体性质来比较两个矩阵的等价性,比较矩阵范数的效果可能更好. 这在"矩阵范数"一节中讨论.
进一步的结构化操作
Flatten[m] | 展平 m 中的嵌套列表 |
Flatten[m,n] | 展平 m 中的嵌套列表至第 n 层 |
Partition[m,n] | 将 m 分成长度为 n 的子列表 |
Join[m1,m2] | 连接 m1 和 m2 |
Append[m,r] | 在 m 的末端插入行 r |
Prepend[m,r] | 在 m 的开始插入行 r |
应该注意的是这也可以通过 Insert 实现. 这将在"插入行和列"一节中说明.
面向元素的操作
所有这些运算都非常快,因为它们只需要对实际存储的元素(包括默认元素)进行运算.
可列表性
当可列表运算应用于稀疏数组时,它仅对实际存储的元素(包括默认元素)进行运算,因此 fun[0]的值仅计算了一次.
Map
通过 Map 将一个函数应用于一个稀疏数组时,它仅对实际存储的元素(包括默认元素)进行运算.
稀疏矩阵的可视化
本节将回顾关于稀疏矩阵格式化与绘图的可用函数. 由于稀疏矩阵已经很好地集成到系统中,本节中的大部分例子与稠密矩阵的工作方式非常相似. 稠密矩阵的可视化技术在"矩阵的可视化"一节中介绍.
MatrixForm[mat] | 输出一个矩阵,其中元素以二维数组方式排列 |
MatrixPlot[mat] | 显示 mat 的结构模式 |
稀疏矩阵的格式化
由 MatrixForm 得到的视图是稠密型的,它可以帮助您看到稀疏模式. 但是,它可以迅速导致非常大的输出,尤其是在数组的秩增加时.
稀疏矩阵的绘图
绘制稀疏矩阵的一种方便的途径是通过函数 MatrixPlot,它将在"矩阵的绘图"一节中更详尽地介绍.
稀疏矩阵的导入和导出
Wolfram 语言提供了一些用于I/O的不同工具. 您可以将您的数据保存至一个文件,从而使您或同事能在日后继续在 Wolfram 语言中使用. 要实现此目的切,您或许可考虑使用一些表达式 I/O 函数,这将在"表达式的导入和导出"中讨论.
如果希望使用指定的数据格式来操作外部的矩阵,函数 Import 和 Export 是很有用的. 函数 Import 支持各种不同格式,其中一些格式与稀疏矩阵相关.
有关 Harwell–Boeing 和 Matrix Market 格式的矩阵的许多例子可以在http://math.nist.gov/MatrixMarket/index.html 得到.
矩阵乘法
外积
如果想要使用稀疏数组作为通用的稀疏数据结构,稀疏外积的生成是非常有利的.
矩阵置换
许多矩阵技术依赖于矩阵按某种特殊方式的排序. 例如,有些技术试图对矩阵排序,以将元素放在对角线上,而另外一些技术则试图将一定元素组合到稠密矩阵块上. Wolfram 语言函数 Part 非常适合对矩阵的行与列进行置换.
m[[perm]] | 对矩阵的行应用置换 |
m[[All,perm]] | 对矩阵的列应用置换x |
m[[perm,perm]] | 对矩阵的行与列应用置换 |
m[[perm]]=m | 对矩阵的行应用逆置换 |
m[[All,perm]]=m | 对矩阵的列应用逆置换 |
将方程转化为稀疏数组
矩阵在许多科技领域如此重要的原因是矩阵可以有效表示线性方程组. 与其它技术型计算系统相比,Wolfram 语言的独特性在于它将有效操作矩阵与矩阵所表示的方程的各种方式结合在了一起. 它可以轻松地从矩阵到方程组或从方程组回归到矩阵. 在这里,一个稀疏矩阵与一个未知向量相乘,形成了一个方程组.
这种直接用于线性方程组的能力对于某些应用是非常有利的. 例如,生成有限个不同解. 这将在"有限个不同解"的例子中进行说明.
SparseArray 数据格式
有几种用于存储稀疏数组的不同格式. 每一种都各有利弊. Wolfram 语言使用压缩稀疏行(CSR)格式作为内部存储格式. 这可以通过一个示范矩阵进行说明.
这种格式对于描述任意秩张量来说具有足够一般的通用性. 这种格式的另一个优点是,在同一行中存储的数据元素彼此相邻,从而提供更好的缓存性能. 缺点是,对于在矩阵中插入新元素,它不是最优化的.