小刘呀の博客

返回

用 C# 学数值方法(一):高斯-约当消元解线性方程组#

化工过程计算的底层往往是解线性系统 A⋅x=bA \cdot x = b。不管是物料衡算、能量衡算、管网水力平衡,还是 Newton-Raphson 迭代,最后都绕不开它。地基不稳,后续的高维非线性系统和全局优化无从谈起。

这里从最基础的算法开始:高斯-约当消元法(Gauss-Jordan Elimination / Reduction Method)。不用黑盒第三方库,直接用 C#(.NET 10)手写纯算法实现。重点拆解它在化工蒸汽管网衡算、多工况矩阵求逆、动力学参数拟合中的实际应用和性能取舍。


算法逻辑架构#

高斯消元(Gauss Elimination)和高斯-约当消元(Gauss-Jordan Reduction)的区别很明确:

  • 普通高斯消元:只向下消元。增广矩阵变成上三角矩阵(Upper Triangular Matrix),需要跑一遍**后向回代(Back Substitution)**才能拿到解。
  • 高斯-约当消元:遍历列时,对角项归一化为 1,同时把主元上下的非零元素全干掉。系数矩阵直接变成单位矩阵(Identity Matrix II)。完事后,最后一列就是解向量。彻底省去了回代步骤。

💡 交互式架构看板:可在浏览器中打开 01-gauss-jordan.workflow.html 查看基于 Archify 生成的动态架构控制流。

flowchart LR
    A["构建增广矩阵 [A | b] 或 [A | b | I]"] --> B{"列主元选择 (Pivoting)<br/>寻找 |M[i, k]| 最大行"}
    B -->|行交换| C["主元归一化<br/>Row_k /= M_kk"]
    C --> D["全行全消元 (i != k)<br/>Row_i -= M_ik * Row_k"]
    D --> E{"遍历完全部列?"}
    E -->|否| B
    E -->|是| F["直接提取解向量 x<br/>或伴随逆矩阵 A⁻¹"]
    F --> G["物理衡算闭合检验 / 残差验算 r = Ax - b"]
mermaid

算法数学推导:公式形式、矩阵形式与矩阵求逆#

理解高斯-约当算法可以从三个角度切入:公式、初等矩阵变换和伴随求逆。

1. 规范三步公式推导(三段式)#

设 nn 阶线性系统 Ax=bA x = b,将其表示为 n×(n+1)n \times (n+1) 增广矩阵 M(0)=[A∣b]M^{(0)} = [A \mid b]:

  1. 初始化公式(Initialization): aij(0)=aij(j=1,…,n),ai,n+1(0)=bi(i=1,…,n)a_{ij}^{(0)} = a_{ij} \quad (j = 1, \dots, n), \qquad a_{i, n+1}^{(0)} = b_i \qquad (i = 1, \dots, n)

  2. 主元归一化公式(Normalization)(对第 kk 列主元,假定选主元后 akk(k−1)≠0a_{kk}^{(k-1)} \neq 0): akj(k)=akj(k−1)akk(k−1),j=n+1,n,…,ka_{kj}^{(k)} = \frac{a_{kj}^{(k-1)}}{a_{kk}^{(k-1)}}, \quad j = n+1, n, \dots, k

  3. 全行消元公式(Reduction)(注意行指标 ii 遍历 1∼n1 \sim n 但跳过主元行 i≠ki \neq k): aij(k)=aij(k−1)−aik(k−1)⋅akj(k),j=n+1,n,…,k(i=1,…,n, i≠k)a_{ij}^{(k)} = a_{ij}^{(k-1)} - a_{ik}^{(k-1)} \cdot a_{kj}^{(k)}, \quad j = n+1, n, \dots, k \quad (i = 1, \dots, n, \, i \neq k)

遍历 k=1,…,nk = 1, \dots, n 结束,矩阵化为 [I∣x][I \mid x],第 n+1n+1 列直接出解。

2. 矩阵乘法形式与行变换算子#

代数上,高斯-约当等价于左乘一系列初等消元矩阵 L‾k\overline{L}_k 和置换矩阵 PkP_k: L‾nPn⋯L‾2P2L‾1P1A=I\overline{L}_n P_n \cdots \overline{L}_2 P_2 \overline{L}_1 P_1 A = I

以 4 阶系统在第 2 步消元为例,算子矩阵 L‾2\overline{L}_2 为:

L‾2=[1−a12(1)a22(1)0001a22(1)000−a32(1)a22(1)100−a42(1)a22(1)01]\overline{L}_2 = \begin{bmatrix} 1 & -\frac{a_{12}^{(1)}}{a_{22}^{(1)}} & 0 & 0 \\ 0 & \frac{1}{a_{22}^{(1)}} & 0 & 0 \\ 0 & -\frac{a_{32}^{(1)}}{a_{22}^{(1)}} & 1 & 0 \\ 0 & -\frac{a_{42}^{(1)}}{a_{22}^{(1)}} & 0 & 1 \end{bmatrix}

和 LU 分解里严格下三角的初等矩阵 LkL_k 不同,L‾k\overline{L}_k 在主对角线上下方都有非零项,对角线元素是主元的倒数。记 L‾=∏L‾kPk\overline{L} = \prod \overline{L}_k P_k,显然: L‾A=I  ⟹  L‾=A−1\overline{L} A = I \implies \overline{L} = A^{-1}

3. 一石二鸟:增广伴随矩阵求逆 [A∣b∣I][A \mid b \mid I]#

上述代数关系揭示了一个工程特性:高斯-约当本质就是个就地求逆算法。 将增广矩阵扩展到 n×(2n+1)n \times (2n+1): M=[A∣b∣I]M = [A \mid b \mid I] 做同样的行归一化和双向消元,左侧 AA 变成 II,中间列是解 x=A−1bx = A^{-1} b,右侧的单位矩阵 II 同步变身为 A−1A^{-1}。 [A∣b∣I]→Gauss-Jordan[I∣x∣A−1][A \mid b \mid I] \xrightarrow{\text{Gauss-Jordan}} [I \mid x \mid A^{-1}]


算力账本:高斯-约当 vs 普通高斯消元#

直觉上:“高斯-约当省了回代,代码短,应该更快吧?” 未必。按 Wiley(2020)给出的模型算一笔浮点运算(FLOPs)的账:

步骤普通 Gauss 消元 (带回代)高斯-约当消元 (直接化单位阵)
消元阶段乘除法∑k=1n−1(n−k)(n−k+2)≈13n3+n2\sum_{k=1}^{n-1} (n-k)(n-k+2) \approx \frac{1}{3} n^3 + n^2∑k=1n(n−1)(n−k+2)+n≈12n3+n2\sum_{k=1}^n (n-1)(n-k+2) + n \approx \frac{1}{2} n^3 + n^2
求解/回代阶段12n2+12n\frac{1}{2} n^2 + \frac{1}{2} n00(已直接在增广矩阵末列)
总计算复杂度≈13n3+O(n2)\approx \frac{1}{3} n^3 + O(n^2)≈12n3+O(n2)\approx \frac{1}{2} n^3 + O(n^2)
n=100n = 100 浮点乘除量约 338,350338,350 次约 505,000505,000 次 (多消耗 ~50% 算力)
矩阵求逆 A−1A^{-1} 运算量需解 nn 次回代:≈43n3\approx \frac{4}{3} n^3同步变换 [A∣I][A \mid I]:≈n3\approx n^3

工程结论:

  1. 单次右端项求解:高斯-约当每步带向上消元,算力多吃 50%。只解一次,老老实实用普通高斯消元或 LU 分解。
  2. 显式矩阵求逆:高斯-约当求逆耗时 ≈n3\approx n^3。用 LU 分解跑 nn 次前/回代需要 ≈43n3\approx \frac{4}{3} n^3。在构造逆矩阵这件事上,高斯-约当反倒更快。

工业与工程实战案例#

来看几个具体场景。

案例一:三元经典算例与手工演算基准#

经典的物料衡算三元系统(来源 Gelmi & Jorquera 2026, 例 1.1 和 2.9):

2x+y−3z=−1−x+3y+2z=123x+y−3z=0\begin{aligned} 2x + y - 3z &= -1 \\ -x + 3y + 2z &= 12 \\ 3x + y - 3z &= 0 \end{aligned}

构建初始增广矩阵:

M(0)=[21−3∣−1−132∣1231−3∣0]M^{(0)} = \begin{bmatrix} 2 & 1 & -3 & \mid & -1 \\ -1 & 3 & 2 & \mid & 12 \\ 3 & 1 & -3 & \mid & 0 \end{bmatrix}
  1. 第 1 列消元:主元行归一化(除以 2),清空第 2、3 行第 1 列。
  2. 第 2 列消元:主元行归一化,同时清空第 1、3 行第 2 列。
  3. 第 3 列消元:归一化并清空上方对应的列。

化简结束,最后一列直接给出解向量 x=[1,3,2]Tx = [1, 3, 2]^T。


案例二:化工厂多压级蒸汽管网复杂衡算系统#

大型石化装置里,蒸汽管网是能量调度的核心。参考 Mostoufi(1999)例 2.2,某管网覆盖 4 个压力等级,包含减温减压器、透平、除氧器等 14 个工艺节点。

写出稳态质量和能量衡算方程(未知量 x1∼x14x_1 \sim x_{14} 是支路流量,单位 103 lb/h10^3\text{ lb/h}):

(1)x1+x2+x3=43.93(680 psia 蒸汽总管衡算)(2)1.17x1−x4=0(减温减压器 Desuperheater)(3)x5=95.798(发电机透平抽出级指定流量)(4)x3+x5−x6−x7−x8+x13=99.1(170 psia 分配管网)(5)x6+x7+x8+x9−x10−x11=−8.4(37 psia 低压平衡)(6)x4−x13=24.2(215 psia 中压蒸汽)(7)x1−x4+x10+x14=189.14(高压锅炉给水平衡)(8)4.594x10+0.11x14=146.55(冷凝液急冷罐热量平衡)(9)x9=10.56(排污闪蒸罐指定负荷)(10)x2=2.9056(锅炉雾化蒸汽量)(11)x6−0.0147x14=0(化学处理给水泵动力消耗)(12)x3−0.07x12=0(主给水泵透平耗汽平衡)(13)x7=14.6188(锅炉引风机透平消耗)(14)x10−x12+x14=−97.9(除氧急冷器 Deaerator)\begin{aligned} (1)\quad & x_1 + x_2 + x_3 = 43.93 && \text{(680 psia 蒸汽总管衡算)} \\ (2)\quad & 1.17 x_1 - x_4 = 0 && \text{(减温减压器 Desuperheater)} \\ (3)\quad & x_5 = 95.798 && \text{(发电机透平抽出级指定流量)} \\ (4)\quad & x_3 + x_5 - x_6 - x_7 - x_8 + x_{13} = 99.1 && \text{(170 psia 分配管网)} \\ (5)\quad & x_6 + x_7 + x_8 + x_9 - x_{10} - x_{11} = -8.4 && \text{(37 psia 低压平衡)} \\ (6)\quad & x_4 - x_{13} = 24.2 && \text{(215 psia 中压蒸汽)} \\ (7)\quad & x_1 - x_4 + x_{10} + x_{14} = 189.14 && \text{(高压锅炉给水平衡)} \\ (8)\quad & 4.594 x_{10} + 0.11 x_{14} = 146.55 && \text{(冷凝液急冷罐热量平衡)} \\ (9)\quad & x_9 = 10.56 && \text{(排污闪蒸罐指定负荷)} \\ (10)\quad & x_2 = 2.9056 && \text{(锅炉雾化蒸汽量)} \\ (11)\quad & x_6 - 0.0147 x_{14} = 0 && \text{(化学处理给水泵动力消耗)} \\ (12)\quad & x_3 - 0.07 x_{12} = 0 && \text{(主给水泵透平耗汽平衡)} \\ (13)\quad & x_7 = 14.6188 && \text{(锅炉引风机透平消耗)} \\ (14)\quad & x_{10} - x_{12} + x_{14} = -97.9 && \text{(除氧急冷器 Deaerator)} \end{aligned}

这个系统有典型的工程特征:

  • 矩阵里一堆 0,既非规则带状,也不严苛对角占优。
  • 混杂着直接赋值(如 x5=95.798x_5 = 95.798)和跨压级的强耦合约束。
  • 盲目消元容易撞上主对角线零元,导致数值崩溃。

引入列主元选择(Partial Pivoting),高斯-约当法能直接把这 14 阶非良态系统拍成对角单位阵,全厂蒸汽流率一次出表。


案例三:固相热分解动力学拟合中的 Gauss-Jordan Condensation#

化学动力学里(参考 House 2007 第 8 章),固体热重分析(TGA/DSC)非等温通式为: dαdT=Aβ⋅αm⋅(1−α)n⋅[−ln⁡(1−α)]p⋅e−Ea/(RT)\frac{d\alpha}{dT} = \frac{A}{\beta} \cdot \alpha^m \cdot (1-\alpha)^n \cdot [-\ln(1-\alpha)]^p \cdot e^{-E_a / (RT)} 取对数转成多元线性回归: ln⁡(dαdT)=ln⁡(Aβ)+mln⁡α+nln⁡(1−α)+pln⁡[−ln⁡(1−α)]−EaR(1T)\ln\left(\frac{d\alpha}{dT}\right) = \ln\left(\frac{A}{\beta}\right) + m \ln\alpha + n \ln(1-\alpha) + p \ln[-\ln(1-\alpha)] - \frac{E_a}{R} \left(\frac{1}{T}\right) 未知参数 5 个:指前因子 AA、活化能 EaE_a、机理指数 m,n,pm, n, p。 拿 NN 组实验数据攒出最小二乘正规方程(Normal Equations): (XTX)⋅θ=XTY(X^T X) \cdot \theta = X^T Y 法方程矩阵 A=XTXA = X^T X 维度 5×55 \times 5。这里常带入 Gauss-Jordan Condensation with Pivotal Rotation(主元旋转约当压缩,Lowery 1986):

  • 能灵活把特定行/列强制归零降维(比如强制 m=p=0m=p=0 切成 Coats-Redfern 方程,或 m=n=0m=n=0 走 Avrami 晶核生长模型),在同一个求解器内核里自如切换。
  • 一次求解拿到参数 θ\theta 和协方差矩阵 (XTX)−1(X^T X)^{-1},顺带输出参数置信区间。

C# 工业级实现:带列主元与伴随逆矩阵#

工程代码讲究抗造。我们在 C# 实现里加了这几道保险:

  1. 部分选主元(Partial Pivoting):防止主元逼近 0 带来除法舍入灾难。
  2. 伴随逆矩阵同步求解:拼出增广阵 [A∣b∣I][A \mid b \mid I],消完元同时出解 xx 和逆矩阵 A−1A^{-1}。
  3. 就地浮点除法保护:预留临时变量缓存主元,阻断原地行遍历污染。
  4. 验证机制:带入化工蒸汽管网案例跑残差。

完整代码实现 (code/01-gauss-jordan/Program.cs)#


运行与实测验证#

进入目录 blog/code/01-gauss-jordan/ 执行 dotnet run,程序输出如下:

工程结果解读:

  1. 算出的 14 个支路流量和文献(Mostoufi 1999)原书 Table E2.2 一字不差。
  2. x10x_{10} 和 x15x_{15} 跑出来是 10−3∼10−410^{-3} \sim 10^{-4} 级别,物理上是微量回流和放空,工艺上就是零流量,拓扑没问题。
  3. 残差范数卡在 10−1410^{-14}。带选主元的约当法吃这种多尺度管网,数值自洽性很稳。

踩坑记录:C# 浮点消元的经典陷阱#

公式转代码,容易掉进两个隐蔽的坑:

1. 就地除法主元自身被改写的灾难#

顺手就容易写成这样:

// 致命错误:原地除法
for (int j = col; j < totalCols; j++)
    M[col, j] /= M[col, col];
csharp

到了第 1 步(j=colj = col),M[col, col] 直接变成了 1.0。接着往下走,分母全成了 1.0,不再是真正的主元值。整行数据直接拉胯。主元必须提前用只读变量存起来:

double pivot = M[col, col];
for (int c = col; c < totalCols; c++)
    M[col, c] /= pivot;
csharp

2. 未开启选主元时,稀疏管网遭遇对角线零元#

化工管网矩阵空洞很多。看刚才那张蒸汽管网表,第 2 行主对角线 A[1,1]=0A[1, 1] = 0。如果不带选主元机制,顺着消下去第二步立马除零崩溃。在稠密消元代码里挂上 Partial Pivoting(按绝对值找最大主元行互换)是工业落地的硬红线。


工业延展:现代流程模拟器(DWSIM)为何与何时选择消元法#

代码撸完,拔高一下视角:工业流程模拟器什么时候用 Gauss-Jordan?什么时候坚决躲开?

以开源模拟器 DWSIM(GPLv3)为例:

  1. 单次前向求解:LU 分解统治天下 解常规单元操作,DWSIM 靠 LAPACK 的 DGESV(列选主元 LU 分解 + 三角代入)打底。算力消耗 13n3\frac{1}{3} n^3 比高斯的 12n3\frac{1}{2} n^3 划算得多。而且 LU 分解能把矩阵因式分解跟常数向量解耦,物料参数频繁迭代时效率拉满。

  2. 何时 Gauss-Jordan 大显身手?

    • 多工况逆矩阵缓存:流程拓扑不动,却要跑成百上千种负荷(像电网潮流、管网灵敏度分析)。拿 Gauss-Jordan 砸个 O(n3)O(n^3) 算出伴随逆矩阵 A−1A^{-1} 存起来。后面的海量工况只需做做 O(n2)O(n^2) 的乘法 x=A−1bx = A^{-1} b。
    • 回归分析与参数辨识:像上面说的动力学拟合,法方程很小(3∼63 \sim 6 阶)。用带主元消元的 Gauss-Jordan condensation 一套代码连参数带协方差矩阵全出了,省得去搬重型代数库。
    • 硬件加速与符号计算:纯线性前推逻辑,不用理会后向回代栈。写 FPGA/GPU 并行消元内核时,管线很容易对齐。

参考文献与知识库溯源#

本文底层理论和算例深度绑定了这些工业文献:

  1. Mostoufi, N., & Constantinides, A. (1999). Numerical Methods for Chemical Engineers with MATLAB Applications. Prentice Hall.
    • 第 2.6 节公式推导及求逆,例 2.2 14 节点蒸汽管网系统。
  2. Wiley. (2020). Applied Numerical Methods Using MATLAB.
    • 第 2.2.3 节与第 2.3 节(FLOPs 算力清点)。
  3. Engineering Mathematics with MATLAB (2018).
    • 第 1.26 节部分选主元策略。
  4. Jorquera, H., & Gelmi, C. A. (2026/2027). Numerical Methods in Chemical Process Engineering Using Python: Tools for Modeling, Simulation, and Optimization. Springer Cham.
    • Chapter 01 & 02 代数系统基准。
  5. House, J. E. (2007). Principles of Chemical Kinetics (2nd Edition). Academic Press.
    • 第 8 章非等温动力学拟合降维技巧。
用 C# 学数值方法(一):高斯-约当消元解线性方程组
https://blog.simliu.com/%E5%8C%96%E5%B7%A5%E5%A4%A9%E5%9D%91/01-%E9%AB%98%E6%96%AF-%E7%BA%A6%E5%BD%93%E6%B6%88%E5%85%83%E6%B3%95/
作者 小刘呀
发布于 2025年12月25日
许可协议 CC BY-NC 4.0

评论

评论由 GitHub Discussions 提供,登录 GitHub 后即可参与。