详细介绍:直接法 读书笔记 01 第1章 引言

第 1 章 引言

本书阐述了用于直接求解稀疏线性系统的稀疏矩阵算法基础,内容涵盖从理论到算法、数据结构乃至实际可运行代码。本书选取算法时遵循以下目标:算法必须体现稀疏矩阵算法背后的重要理论;算法必须在运行时间和内存使用上达到渐进最优,或在实际应用中快速高效;算法必须简洁明了,易于理解,且篇幅足够简短以便在本书完整呈现;算法必须涵盖广泛的矩阵运算;算法必须精确且稳健

本书算法以伪代码、MATLAB 和 C 语言的混合形式呈现,因此假定读者具备这些知识。同时,还要求具备线性代数、图论、算法和数据结构的基础知识。这些背景知识将在下文及关于 C 语言的附录中进行回顾。

第 2 章介绍基本的数据结构和算法,包括矩阵乘法、加法、转置和数据结构操作。第 3 章讨论三角方程组的求解。第 4 至第 6 章介绍三种最常用的分解:Cholesky 分解、QR 分解和 LU 分解。专门针对对称不定矩阵的分解方法不在讨论之列。4.10 节介绍在低秩更新后,对稀疏 Cholesky 分解进行更新和降级的方法。第 7 章讨论能够减少计算量和内存需求的排序方法。第 8 章利用第 1 至第 7 章介绍的理论和算法来求解稀疏线性系统Ax = b,其中 A 可以是对称正定、非对称或矩形的,类似于 MATLAB 中的反斜杠运算符 x=A\b(当 A 稀疏且 b 是稠密列向量时)。第 9 章总结了 CSparse 稀疏矩阵软件包。结果,第 10 章解释如何在 MATLAB 中使用稀疏矩阵

为避免打断论述的流畅性,各章节正文中极少引用文献。相关讨论置于每章末尾的“延伸阅读”部分,该部分概述了与该章节相关的软件、书籍和论文。书中陈述的定理是此规则的特例。每章的最后一部分是该章的习题。

1.1 线性代数

下文简要描述线性代数的定义和符号。一个 m×n 矩阵用大写字母表示,A \in \mathbb{R}^{m \times n},其中 \mathbb{R}^{m\times n}表示元素为实数的 m×n 矩阵集合。对应的小写字母加下标a_{ij}较小的常数(例如就是表示矩阵 A 的第 i 行、第 j 列的元素。它也可以表示 A 的行向量、列向量或块子矩阵(如下所述),但在此种情况下,i 和 j 通常a_{12})。L 是下三角矩阵,U 和 R 是上三角矩阵,I 表示单位矩阵(除了(I)_{ii} = 1外其他元素为零)。若当i < ja_{ij}=0,则矩阵 A 是下三角矩阵;若当 i > j 时a_{ij} = 0,则是上三角矩阵。小写字母表示向量(b, x, y, z),可是字母 i 到 n 则始终表示整数标量。行向量用上标表示,x^T。带有下标时,x_i可以表示标量或向量,具体取决于上下文。小写希腊字母(\alpha, \beta)表示标量。矩阵 A 的第 j 列记为A_{*j},或在 MATLAB 中记为 A(:,j)。类似地,A_{i*}表示 A 的第 i 行,或在 MATLAB 中记为 A(i,:)

实数矩阵 A 的转置A^T 定义为 (A^T)_{ij} = a_{ji}。矩阵加法 C = A + B 定义为 C_{ij} = a_{ij} + b_{ij}。标量行与矩阵相乘;C=\alpha A 定义为 C_{ij} = \alpha a_{ij}。矩阵乘法,C = AB,定义为:

c_{ij}=\sum_{k=1}^{s}a_{ik}b_{kj}\ , \ \ \ \ \ \ \ \ (1.1)

其中 C\in \mathbb{R}^{m\times n}A \in \mathbb{R}^{m\times s}B\in \mathbb{R}^{s\times n}。矩阵乘法要求 A 的列数等于 B 的行数。两个向量 x 和 y 的点积是标量x^T y。两个向量 x 和 y 的外积是矩阵x y^T;计算 A = A + \alpha x y^T称为秩 1 更新。如果 X 和 Y 是具有 k 列的矩阵,X Y^T被称为秩 k 外积(即使 X 和 Y 的数值秩不为 k,也常用此术语)。计算A = A + \alpha X Y^T称为秩 k 更新。

分块矩阵是指每个元素可以是矩阵、向量或标量的矩阵。假设 m×n 矩阵 A 的行被划分为 r 个子集,列被划分为 c 个子集;A 可以写成一个 r×c 的分块矩阵,

A=\begin{bmatrix} A_{11} & \dots & A_{1c} \\ \vdots & & \vdots\\ A_{r1} & \cdots & A_{rc} \end{bmatrix}\ ,

其中如果 m_i是第 i 个行子集的大小,n_j是第 j 个列子集的大小,则 A_{ij}m_i \times n_j的矩阵。两个分块矩阵若是划分方式完全相同,则许可相加。两个分块矩阵许可相乘C = AB A 的列和 B 的行的划分数,则矩阵乘法公式变为:就是,如果 A 的列的划分方式与 B 的行的划分方式完全相同;C 的行与 A 的行的划分方式相同,C 的列与 B 的列的划分方式相同。要是 C(此处 C 应理解为划分的数量,为免混淆,假设 A 的列和 B 的行被划分为 N 块)

C_{ij}=\sum_{k=1}^{c}A_{ik}B_{kj} \ .

一组向量 a_1, a_2, ... \ , a_n线性无关,当且仅当 "\sum_j\alpha_j a_j = 0 意味着所有 \alpha_j为零 "。一组向量的张成空间是可以写成该组向量的线性组合的所有向量的集合:

span(a_1, a_2, ..., a_n) = { \sum_j \alpha_j a_j }

矩阵 A 的值域是其列向量的张成空间。矩阵 A 的秩是其列向量中线性无关子集的最大规模。一个 n×n 矩阵如果秩小于 n,则是奇异的。一个 m×n 矩阵如果秩小于 min(m, n),则是秩亏的;否则,它是满秩的

列向量 x 或行向量 x^T1-范数||x||_1 = \sum |x_i|,其 2-范数||x||_2 = \sqrt { \sum x_i^2 },其 \infty-范数是 ||x||_{\infty} = max |x_i|其就是。矩阵的 1-范数列向量 1-范数中的最大值。矩阵的 \infty-范数是其行向量 1-范数中的最大值

矩阵 A 的逆是 A^{-1},其中 A A^{-1} = A^{-1} A = I 。仅当 A是方阵且非奇异时才存在。两个向量xy 如果 x^T y = 0正交的。矩阵就是,则Q 如果满足 Q^T Q = I,则是标准正交的。一个实数方阵标准正交矩阵Q称为正交矩阵,此时Q^T Q = Q Q^T= I(即,若 Q 正交,则 Q^T = Q^{-1})。如果 Q是正交矩阵,向量x的 2-范数与其乘积Qx的 2-范数相同

m×n 矩阵A第 k 条对角线是一个向量 d,由满足j - i = k 的元素集合 \{a_ij\}组成。术语“对角线”单独使用时,指第 0 条对角线或主对角线。A的第 k 个对角元是a_{kk}

矩阵或向量中非零元素(简称非零元)的数量记为|A|,而 |\alpha| 表示标量 \alpha 的绝对值。

置换矩阵 P是单位矩阵的行置换列置换P的任意给定行或列包含一个等于 1 的非零元。一个方阵非奇异矩阵ALU 分解形式为 LU = A,其中 L是下三角矩阵,U是上三角矩阵。带有部分选主元和行交换时,分解为L U = P A矩阵 A是正定的,当且仅当对于所有非零向量x,都有 x^T A x > 0。如果 x^T A x \ge 0,则是半正定的。一个方阵对称正定矩阵A的 Cholesky 分解形式为 L L^T = A,其中 L下三角矩阵且对角元为正。出于稳定性考虑不需要选主元。一个方阵A按行对角占优,如果对所有 i 满足|a_{ii}| \ge \sum_{j\ne i} |a_{ij}|。如果对所有 i 满足|a_{ii}| > \sum_{j\ne i} |a_{ij}|,则是严格按行对角占优。假设A^T是(严格)按行对角占优,则A 是(严格)按列对角占优一个严格对角占优的方阵是非奇异的对于任何对角占优矩阵(按行或按列),无需选主元的高斯消元法(LU 分解的一种形式)是稳定的

一个矩形矩阵A的 QR 分解是Q R = A,其中 Q是正交矩阵,R是上三角矩阵。对于一个方阵AA x = \lambda x 对特征值 \lambda及其特征向量x 成立。

集合用花体字母表示:\mathcal{A}, \mathcal{B}, \mathcal{C}, \mathcal{L}, \mathcal{R}, \mathcal{V}, \mathcal{W}, \mathcal{X}, \mathcal{Y}。这些通常来源于相应矩阵或向量的非零元模式。例如,\mathcal{A}_{*j}=\{i | a_{ij}\ne 0\}\mathcal{X}=\{ i | x_i\ne 0\}。当下文明确时,下标中的 * 号可以省略。

术语“稠密”和“稀疏”指用于存储矩阵的数据结构。一个矩阵A\in \mathbb{R}^{m\times n}作为具有 mn 个元素的 m 行 n 列的完整数组存储,则是就是如果稠密的。这在 MATLAB 中称为满矩阵。所有元素都被存储,即使其中一些为零。稀疏矩阵存储在一个可以利用稀疏性的数据结构中,不存储数值为零的元素。数值为零的元素也可能存储在稀疏矩阵中,通常是由于数值消去造成的。

1.2 图论、算法和数据结构

G=(V,\ E) 由节点集 V = \{1, ..., n\}和连接这些节点的边集E = \{ (i, j) | i, j \in V \} 组成。

在无向图中,(i, j)(j, i)是同一条边;在有向图中,它们是不同的边。在有向图中,可以存在边(i, j)而没有边 (j, i)

节点 i的邻居,或者说i的邻接集,是Adj(i) = \{ j | (i, j) \in E \}节点就是。对于有向图,这i的出邻接。节点i 的入邻接是 InAdj(i) = \{ j | (j, i) \in E \}。在无向图中,节点的出邻接和入邻接是相同的。

G 的邻接矩阵 A是一个二进制的 n×n 矩阵,要是(i, j) \in Ea_{ij} = 1,否则 a_{ij} = 0。如果 G是无向的,则A对称;否则可能不对称。图也可以用一组 n 个邻接表来表示,A_{i*} = \{ j | a_{ij} \ne 0 \}A_{*j} = \{ i | a_{ij} \ne 0 \}。这建立了 n×n 矩阵A的稀疏模式与其对应的无向或有向图G_A之间的联系。对角元a_{kk} 是自环边 (k, k);它通常从 G_A中排除。无向图中节点的度是其邻接表的大小,|A_{*i}| = |A_{i*}| = |Adj(i)|。如果两个图可以通过对其节点重新编号而变得相同,则它们是同构的。

如果 a = i 或 b = i,则节点 i 与边 (a, b) 关联;边 (a, b) 也被称为与节点 i 关联。图G的节点诱导子图G' = (V', E') 由节点子集 V' \subseteq V 定义,其中 E' = \{ (i, j) | (i, j) \in E \wedge i \in V' \wedge j \in V' \}。边诱导子图G' = (V', E') 由边集 E' \subseteq E定义,其中节点集V' 是所有与 E'中任何边关联的节点。

如果一个图满足E = V \times V,即每对节点之间都有边,则该图是完全连通的。一个团就是一个完全连通的子图。

长度为 k 的路径v_0 \rightarrow v_k是一个节点序列(v_0, ..., v_k),其中序列中每对相邻节点之间存在边(v_{i-1}, v_i)。如果没有任何节点出现超过一次,则该路径是简单的。如果图中存在路径i \rightarrow j通过,则节点 j 能够从节点 i 到达。在图G中从节点 i 可到达的所有节点集合是Reach_G(i)。如果一个图中存在从任何节点到任何其他节点的路径,则该图是强连通的。也就是说,对于任何节点 i,Reach_G(i)连通的。图就是是整个图。如果一个图的底层无向图是强连通的,则该图G的底层无向图与 G 相同,但忽略所有边的方向。

节点 k-d 到 k-1。就是一个圈是一条路径 i → ... → i,其中第一个和结果一个节点相同。假如除了 i 本身之外,没有任何边或节点出现超过一次,则它是一个简单圈。没有圈的图是无环的。有向无环图常简称为 DAG。无向无环图是森林。树是连通的森林。在树中,每对节点之间存在唯一的便捷路径。在有根树中,指定一个节点为根 r。在路径 i → r 中,跟在节点 i 后面的那种唯一节点称为 i 的父节点 p;根节点本身没有父节点。节点 i 是 p 的子节点;一个节点最多有一个父节点,但可以有多个子节点。没有子节点的节点是叶子节点。路径 i → ... → r 是节点 i 的祖先集合。节点 i 是所有在路径 i → ... → r 上的节点的后代。节点 i 的真祖先或真后代集合不包括节点 i 本身。以节点 i 为根的子树由节点 i 及其后代诱导的子图构成。在后序排序的树中,任何节点 k 的 d 个真后代

二分图是一种无向图,其节点被划分为两个子集,并且每条边都连接两个不同子集中的节点。节点分离器是图 G = (V, E) 的节点子集 S ⊆ V,使得由节点 V \ S 诱导的图是不连通的。边分离器是图 G = (V, E) 的边子集 S ⊆ E,使得图 G' = (V, E \ S) 是不连通的。节点覆盖是节点集 S ⊆ V,使得所有边 E 都至少与 S 中的一个节点关联。

非正式地说,渐进符号描述了函数f(x)的本质:它作为 x 的函数增长有多快。标量因子和低阶项被忽略。例如,所有二次多项式a x^2 + b x + c 都是 O(x^2),除非 a = 0。更正式地说,函数f(x)O(g(x)),如果存在正常数 c 和x_0,使得对于所有x \ge x_0,有 0 \le f(x) \le c g(x)。这提供了一个渐进上界。渐进下界的定义类似。函数f(x)\Omega (g(x)),倘若存在正常数 c 和x_0,使得对于所有x \ge x_0,有 0 \le c g(x) \le f(x)。如果 f(x) 同时是 O(g(x))\Omega(g(x)),那么它有一个紧的渐进界\Theta(g(x))

算法分析指的是确定算法运行时间、内存使用等方面渐进界的方法。运行时间和其他统计量通常表示为输入大小的函数。最坏情况分析找到一个常常成立的上界(O(...)),无论输入如何。平均情况分析着眼于典型情况。这两者通常是相同的,但并非总是如此。算法的时间复杂度是其运行时间的渐进界。

序列中一次管理时间复杂度的更有用的描述。就是摊还分析考虑一系列相关操作的总运行时间。如果 n 次操控的时间是 T(n),那么一次管理的摊还时间是 T(n)/n。例如,如果一个函数被调用 n 次,n-1 次花费 1 个单位时间,但有一次花费 n+1 个单位时间,则对于该函数的任何一次使用,最坏情况时间复杂度是 O(n)。然而,要是将 n 次操作的所有开销加在一起,并分摊到所有管理上,每次管理的平均开销仅为 2,即 O(1)。后者

摊还时间复杂度有用的一个例子是动态表算法。考虑一个初始大小为 k = 1 的表,以及一个在表末尾插入项的操作。如果表的大小 k 不足,则将其大小加倍,花费O(k)时间来制作更大的副本。对于 n 次插入,可能看起来总时间会是O(n^2),但情况并非如此。即使有复制表这项额外工作,单次插入的摊还成本也是O(1),因为只有在 i 是 2 的幂加 1 时的第 i 次插入才必须完整地复制表。对于 n 次插入,时间为:

n+ \sum_{i=0}^{\left \lfloor log_{_2}(n-1) \right \rfloor} 2^i \le 3n
其中 \left \lfloor x \right \rfloor 是不大于 x的最大整数。n 次插入的总时间小于或等于 3n。任何一次插入的摊还时间至多为 3。

检查刚访问过的最新节点 i 的出边来递归地探索。当 i 的所有边都被探索后,它回溯到首次发现 i 的节点。节点被标记以避免被重复搜索。深度优先搜索的时间为就是图算法的一个常见类别是遍历图节点和边的方式。图的深度优先搜索从节点 j 开始,找到所有可以从节点 j 到达的节点。它凭借总O(s + e),其中 s = |Reach(i)|,e 是由 s 诱导的子图中的边数。通过其构建方式,该子图是连通的。以深度优先方式遍历整个图得重复遍历直到访问所有节点。深度优先搜索会产生 DAG 节点的拓扑顺序列表;如果 i → j 是 G 中的一条路径,则 i 出现在 j 之前。

广度优先搜索以不同的顺序遍历图。从节点 i 开始,它首先检查所有与 i 相邻的节点。接下来,它检查那些最短路径 i → j 长度为 2 的节点,然后是长度为 3 的节点,依此类推。与深度优先搜索一样,它也遍历Reach_G(i)中的所有节点。与深度优先搜索不同,它按照从 i 出发的最短路径顺序遍历这些节点,而不是拓扑顺序。

图用 G 或 g 表示,T 表示树或森林。E 表示第 7 章讨论的最小度排序算法中的元素列表。

1.3 延伸阅读

Golub 和 Van Loan [114] 深入涵盖了稠密和结构化矩阵的数值线性代数和矩阵计算;Strang [193] 提供了线性代数的介绍。Moler [157] 介绍了数值计算,并着重于 MATLAB。Stewart 深入探讨了矩阵分解 [190] 和特征值困难 [191]。Higham [135] 讨论了有限精度算术中数值算法的行为。

Cormen, Leiserson 和 Rivest [23] 讨论了算法和数据结构及其分析,包括图算法。Kernighan 和 Ritchie [141] 简明地介绍了 C 编程语言。Higham 和 Higham [133]、Davis 和 Sigmon [38] 或 MATLAB 的在线文档是学习 MATLAB 的好资源。

Duff, Erisman 和 Reid [53] 以及 George 和 Liu [89] 的著作都涉及稀疏矩阵的直接解法;后者专注于对称正定矩阵。Gilbert [101] 和 Liu [150] 概述了与稀疏直接方法相关的许多图论内容。Stewart [192] 提供了稀疏 Cholesky 分解的教程级描述。Gould, Hu 和 Scott [116] 调查了用于稀疏对称矩阵分解的各种软件包。稀疏线性系统的迭代途径及其依赖的不完全分解途径由 Saad [178]、Greenbaum [117] 和 Barrett 等人 [15] 讨论。Bjorck [17] 介绍了稀疏最小二乘问题的直接和迭代方法。Parlett [164] 深入研究了稀疏矩阵的对称特征值问题。Demmel [39] 交织讨论了数值线性代数及其在稀疏和稠密问题相关软件方面的描述。

posted @ 2026-03-08 12:32  clnchanpin  阅读(13)  评论(0)    收藏  举报