笔记4-《程序员的数学3:线性代数》良性问题与可逆矩阵  

目录
  1. 良性问题与可逆矩阵
  2. 可逆矩阵的性质
  3. 解法的选择
  4. Ruby 验证:高斯消元
  5. 良性问题的前提

良性问题与可逆矩阵

  • 2.1 问题设定:逆问题

    • 第 1 章强调「矩阵本身就是映射」,用矩阵 AA 作用在向量上,结果是 y=Ax\mathbf{y} = A\mathbf{x}
    • 已知原因预测结果 y=Ax\mathbf{y} = A\mathbf{x},叫顺问题
    • 已知结果推测原因,叫逆问题
      • 已知地表重力场分布(结果),推测地球内部资源分布(原因)
      • 由画质受损的图像(结果)推测原图像(原因)
    • 现实中还要考虑噪声:y=Ax+(噪声)\mathbf{y} = A\mathbf{x} + \text{(噪声)}
    • 通过考察物理体系的输入输出,可以推测出矩阵 AA 本身
  • 2.2 良性问题(可逆矩阵)

    • 可逆性与逆矩阵

      • 设 x\mathbf{x} 和 y\mathbf{y} 是同维向量,则 AA 是方阵

      • 如果 AA 的逆矩阵存在,问题可以直接用公式表达:

        x=A−1y(2.1)\mathbf{x} = A^{-1}\mathbf{y} \qquad (2.1)

      • 存在逆矩阵的方阵 AA 称为可逆矩阵(非奇异矩阵、正则矩阵)

      • 不是可逆矩阵的称为奇异矩阵

      • 非方阵没有逆矩阵的定义

      • 但对于具体给定的 AA 和 y\mathbf{y},不会直接求 A−1A^{-1} 再乘,因为有更快捷的办法

    • 线性方程组的笔算解法

      • 先把线性代数抛在脑后,看普通的多元一次方程组怎么解
      • 核心手法是消元:用一个方程去消去另一个方程里的某个变量
      • 从一个方程出发,反复使用这个原理,规模逐渐缩小,最终得到一元一次方程
      • 然后回溯:按来时的顺序原路返回,把求出的解逐个代入
      • 这个过程可以用分块矩阵的形式写出来
    • 选主元

      • 消元时如果主元为 0 就没法继续,所以要「像交换第 1 行和第 2 行一样」把非 0 元素换到对角线位置
      • 再对第 1 行乘以 1/31/3,让对角元素变成 1
      • 选主元的操作不会影响最终的解,因为交换行的效果在矩阵形式里被完整记录了下来
    • 解方程的基本步骤(逐列处理)

      • 为了让对角元素 ⋆\star 变成 1,整行除以 ⋆\star
      • 用这一行去消去下面各列的对应元素
  • 术语说明(译者注)

    • 本书的「良性」「恶性」是非正式说法,描述的是矩阵本身的性质
    • 与数值分析中的「良态」「病态」概念完全没有关系
      • 数值分析中的病态是与具体问题有关的
      • 某些矩阵对解线性方程组是病态的,对求特征值却是良态的
    • 现实中遇到的逆问题**大多都是恶性(病态)**的
      • 所以有时候甚至不把这些良性问题称为逆问题

可逆矩阵的性质

可逆矩阵有几条直接能用的性质:

  • AA 可逆 ⇔det⁡A≠0\Leftrightarrow \det A \neq 0

  • 若 AA 可逆,则 A−1A^{-1} 也可逆,且 (A−1)−1=A(A^{-1})^{-1} = A

  • (AB)−1=B−1A−1(AB)^{-1} = B^{-1}A^{-1}(顺序反过来了)

  • (A−1)T=(AT)−1(A^{-1})^T = (A^T)^{-1}

  • A−1xA^{-1}\mathbf{x} 满足 A(A−1x)=xA(A^{-1}\mathbf{x}) = \mathbf{x},这是它作为「复合映射的逆」的含义

从映射的角度看,A−1A^{-1} 存在意味着映射 AA 是双射:

  • 单射:不同的输入映到不同的输出

  • 满射:目标空间的每个点都有对应的来源

  • 两者都成立 → 双射 → 有逆映射

解法的选择

书里明确说了:不要为了求一个 x\mathbf{x} 就去求整个 A−1A^{-1}。

  • 求 A−1A^{-1} 需要 O(n3)O(n^3) 的运算量,而且算出的是一整个矩阵

  • 解一个方程组用消元只要 O(n3)O(n^3)(其实是 O(n3/3)O(n^3/3)),而且只得到一个向量

  • 解 nn 个方程组(同一个 AA,不同的 y\mathbf{y})时,消元只需做一次,之后每次只做回代

所以实践中是:先消元得到上三角形式,再回代求解。逆矩阵只在需要反复使用、或者需要分析结构时才显式计算。

Ruby 验证:高斯消元

# 高斯消元解 A x = y
def solve(a, y)
n = a.size
m = a.map(&:dup)
b = y.dup

n.times do |i|
# 选主元:找绝对值最大的行
piv = (i...n).max_by { |r| m[r][i].abs }
m[i], m[piv] = m[piv], m[i]
b[i], b[piv] = b[piv], b[i]

# 消元
((i + 1)...n).each do |r|
f = m[r][i] / m[i][i].to_f
n.times { |c| m[r][c] -= f * m[i][c] }
b[r] -= f * b[i]
end
end

# 回代:从最后一行往上,每行依赖下标更大的 x
x = Array.new(n, 0.0)
(n - 1).downto(0) do |i|
s = b[i] - ((i + 1)...n).sum { |c| m[i][c] * x[c] }
x[i] = s / m[i][i]
end
x
end

a = [[2.0, 1.0, -1.0], [-3.0, -1.0, 2.0], [-2.0, 1.0, 2.0]]
y = [8.0, -11.0, -3.0]
x = solve(a, y)
# 验证 A x = y
puts "解 = #{x.map { |v| v.round(6) }}" # 解 = [2.0, 3.0, -1.0]
puts "A*x = #{a.each_index.map { |i| a[i].each_index.sum { |j| a[i][j] * x[j] }.round(6) }}" # A*x = [8.0, -11.0, -3.0]

良性问题的前提

这一节的所有结论都建立在「AA 可逆」这个前提上。而现实中的大多数逆问题不满足这个前提 —— 噪声会让矩阵变得接近奇异,解变得极其敏感。

下一节讲恶性问题:AA 不可逆时会发生什么,为什么「知道结果」未必能推出「唯一的原因」。

123.8k