☰
高等代数实战笔记:用Python拆解丘维声151讲核心概念
2026/10/17 6:34:50 网站建设 项目流程

简介:本资源是面向数学专业本科生及高等代数自学者的系统性学习笔记,深度对标丘维声教授北京大学《高等代数》课程(B站151讲视频),聚焦线性方程组、行列式、线性空间三大核心模块,解决概念抽象、逻辑链条长、证明与计算脱节等典型学习难点。笔记以清晰框架重构知识体系:第一章详述矩阵消元法与解的存在性/唯一性判别准则;第二章从n元排列出发,严谨推导行列式定义、性质、展开定理及克莱姆法则;第三章完整覆盖线性空间、子空间、线性相关性、秩、基与维数等基石概念,并延伸至矩阵秩与方程组解集结构分析。资源为1个PDF文件,体积1.21MB,排版紧凑、公式规范、例证穿插,便于打印精读或碎片化复习。已有1171人学习下载,是夯实代数基础、衔接线性映射与抽象代数的重要过渡材料。

1. 这不是速成口诀,是丘维声《高等代数》151讲视频的“解压包”:把抽象定义嚼碎、把证明逻辑拆成可执行步骤、把每道习题背后隐藏的思维断点标出来

你有没有试过:看着“线性无关”的定义——“不存在不全为零的数使得线性组合为零”——点头说“懂了”,结果一做习题3.2第2题,发现行列式算出来是0,却死活想不通“为什么这组向量就线性相关了?”;或者对着“极大线性无关组”的定义反复读三遍,合上书,面对一个含5个三维向量的集合,手足无措,不知从哪下手挑?这不是你数学差,是教材和视频在讲“是什么”,而你真正卡住的地方,是“怎么想、怎么动、怎么验证”。这份《大佬整理的丘维声高等代数笔记1》,就是专治这种“表面听懂、实操瘫痪”的解压包。它不是丘维声教授原课的PPT搬运工,而是某位坚持刷完全部151讲B站视频、同步手写推演、反复比对教材与例题、把每个证明的跳跃步骤都补全的实战派学习者,用工程师拆模块的思路,把整门课拆成了可逐行复现的“思维脚本”。它覆盖第一章线性方程组的消元法本质(为什么初等行变换不改变解集?)、第二章行列式所有性质的底层代码级解释(比如“两行互换,行列式变号”这个结论,笔记里直接用2×2矩阵的几何面积缩放+方向翻转来可视化)、第三章线性空间中“基”与“维数”的判定流程图(给定一个子集,三步判断它是不是基)。它不承诺让你跳过思考,但能确保你每一次卡壳,都能在笔记对应位置找到那个被省略的中间步骤、那个被默认的隐含前提、那个老师没说出口的“我们自然会想到……”——而这,恰恰是自学路上最昂贵的“后悔药”。


2. 把“矩阵消元”从黑匣子变成可调试的流程:从增广矩阵到阶梯形,每一步变换都有明确目的与可验证输出

2.1 矩阵初等行变换的三种操作,不是规则,是解方程的“手术刀”

在笔记第一章1.1节,它没有一上来就列三条变换规则,而是先还原场景:解方程组 $ \begin{cases} 2x + y = 5 \ x - y = 1 \end{cases} $。你本能地会用加减消元——把第二个方程乘以2,再与第一个相减,消掉 $x$。笔记立刻指出:“看,这就是‘把一行的倍数加到另一行’;把两个方程调换顺序,就是‘两行互换’;把一个方程两边同乘非零数,就是‘一行乘以非零系数’。” 这三把“手术刀”,每一刀下去,目标都极其具体:第一刀(倍加)是为了制造零;第二刀(互换)是为了把主元(非零首项)挪到最上面;第三刀(倍乘)是为了把主元标准化为1。它强调,变换不是为了好看,而是为了服务“阶梯形”这个终极形态——左下角全为0,且每行首个非零元(主元)严格右移。

提示:初学者常误以为“化成阶梯形”就是最终目的。笔记一针见血:阶梯形只是中间态,它的价值在于暴露解的结构。主元所在列对应“主变量”,其余列为“自由变量”。这个判断,必须在完成变换后,立刻对增广矩阵进行“目视扫描”,而不是凭感觉。

2.2 手动实现高斯消元:一个Python函数,把你的笔算过程翻译成可复现的代码

笔记在1.1节末尾,附了一个极简但功能完整的Python函数,它不依赖numpy.linalg,完全模拟人工消元逻辑:

def gauss_elimination(A_aug): """ 对增广矩阵A_aug进行高斯消元,返回阶梯形矩阵(行最简形前一步) A_aug: 二维列表,如 [[2, 1, 5], [1, -1, 1]] 返回: 消元后的二维列表 """ m, n = len(A_aug), len(A_aug[0]) # m行,n列(最后一列为常数项) mat = [row[:] for row in A_aug] # 深拷贝,避免修改原数据 pivot_row = 0 # 当前行(主元行) for col in range(n-1): # 遍历除最后一列外的所有列(变量列) # 步骤1:找主元——在当前列及以下行中,找第一个非零元素 pivot_found = False for r in range(pivot_row, m): if mat[r][col] != 0: # 将该行与pivot_row行互换 mat[pivot_row], mat[r] = mat[r], mat[pivot_row] pivot_found = True break if not pivot_found: continue # 该列全为0,跳过,检查下一列 # 步骤2:将主元行的主元标准化为1(可选,但便于后续计算) pivot_val = mat[pivot_row][col] for j in range(col, n): mat[pivot_row][j] /= pivot_val # 步骤3:用主元行消去下方所有行在该列的元素(倍加) for r in range(pivot_row + 1, m): factor = mat[r][col] # 要消去的系数 for j in range(col, n): mat[r][j] -= factor * mat[pivot_row][j] pivot_row += 1 # 主元行下移 return mat # 示例:解上面的二元方程组 A_aug = [[2, 1, 5], [1, -1, 1]] result = gauss_elimination(A_aug) print("阶梯形矩阵:") for row in result: print([round(x, 4) for x in row])

逻辑说明与参数说明:

  • A_aug是输入的增广矩阵,格式为[[a11, a12, ..., b1], [a21, a22, ..., b2], ...]。
  • 函数核心是三层嵌套循环:外层for col控制处理哪一列;中层for r在当前列找主元;内层for j执行具体的数值运算。
  • pivot_row是关键状态变量,记录当前正在处理的“主元行”索引。每次成功找到并处理完一个主元,它就+=1,指向下一个待处理行。
  • factor = mat[r][col]是消元的关键系数,它代表“第r行在第col列的值,需要被第pivot_row行的主元‘吃掉’多少倍”。
  • 为什么不用numpy?笔记明确指出:np.linalg.solve是个黑匣子,它不告诉你“为什么这一步要互换”,而手动实现能让你看清,当某列找不到主元时,程序会continue,这正是“自由变量”出现的代码信号。

2.3 解的情况判别:从“有解/无解”到“唯一解/无穷解”,一张表锁定所有可能性

笔记将1.2节的判别逻辑,浓缩为一张可直接查表的决策树。它不满足于教材的“若出现0=d则无解”,而是把判别过程拆解为对阶梯形矩阵的两步原子操作:

检查项操作含义后续动作
Step 1: 查“矛盾行”扫描每一行,看是否存在形如[0, 0, ..., 0, d]的行,其中d ≠ 0这表示0 = d,逻辑矛盾立即判定:无解。无需再看其他行。
Step 2: 查“主元数”若无矛盾行,则统计非零行的数量r(即主元个数),并与未知数个数n比较r是有效约束的数量若r == n→ 唯一解;若r < n→ 有n - r个自由变量 → 无穷多解

这个表格的价值在于,它把一个需要“综合判断”的模糊问题,变成了两个清晰、可编程、无歧义的布尔判断。笔记还给出了一个反直觉的提醒:“r < n时,自由变量的个数是n - r,但它们不一定是最后n - r个变量!必须根据主元所在列来确定。” 例如,阶梯形矩阵为[[1, 0, 2, 3], [0, 0, 1, 4], [0, 0, 0, 0]],r=2,n=3,自由变量个数是1,但主元在第1列和第3列,所以自由变量是x2,而非x3。


3. 行列式不是神秘符号,是“有向体积”的计算器:从2阶几何意义到n阶递归展开的完整链路

3.1 二阶行列式:从平行四边形面积到克莱姆法则的直观起源

笔记在2.1节开篇,就用坐标系画出了向量 $\vec{a} = (a_{11}, a_{21})$ 和 $\vec{b} = (a_{12}, a_{22})$。它指出,由这两个向量张成的平行四边形的有向面积,其绝对值就是 $|a_{11}a_{22} - a_{21}a_{12}|$,而符号取决于 $\vec{a}$ 到 $\vec{b}$ 是逆时针(正)还是顺时针(负)旋转。这个几何图像,是理解一切行列式性质的基石。

注意:很多教程把“行列式为0”解释为“向量共线”,这没错,但笔记补充了更本质的视角:“有向体积坍缩为0”。这为后续理解高维行列式(如3阶是平行六面体体积)埋下伏笔,并自然引出克莱姆法则——当系数矩阵行列式非零,意味着其列向量张成的空间是“满秩”的,因此方程组的解向量必然能被唯一地“分解”到这些基向量上。

3.2 行列式性质的“代码注释版”:每条性质都对应一个可验证的Python操作

笔记对2.3节的七条性质,没有罗列定义,而是用Python代码作为“活注释”。例如,性质4“两行互换,行列式变号”,它给出的验证代码如下:

import numpy as np # 构造一个3x3矩阵 A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) det_A = np.linalg.det(A) print(f"原矩阵A的行列式: {det_A:.2f}") # 互换第0行和第1行,得到B B = A.copy() B[0], B[1] = B[1].copy(), B[0].copy() det_B = np.linalg.det(B) print(f"互换行后B的行列式: {det_B:.2f}") print(f"det_B / det_A ≈ {det_B/det_A:.2f}") # 应该约等于 -1

参数说明与深层逻辑:

  • A.copy()确保不修改原矩阵,这是工程实践的基本素养。
  • B[0], B[1] = B[1].copy(), B[0].copy()中的.copy()至关重要,避免浅拷贝导致的引用错误,这是新手踩坑高频点。
  • 最后一行det_B/det_A的计算,是笔记强调的“验证思维”:不只看绝对值,更要看相对关系是否符合理论预期(此处应为-1)。这种“比例验证法”,比单纯看两个数字是否相反,更能抵抗浮点误差的干扰。

同样,对于性质7“一行的倍数加到另一行,行列式不变”,笔记的代码会构造一个C矩阵,将A的第0行乘以k=2.5加到第1行,并打印det_C与det_A的差值,结果会是一个接近1e-15的极小数,从而直观印证“不变”在数值计算中的真实含义。

3.3 按行展开:代数余子式不是公式,是“降维打击”的递归策略

笔记在2.4节,把“按第i行展开”这个操作,重新命名为“选择一个支点,把n维问题折叠成(n-1)维子问题”。它用一个3×3矩阵为例:

$$ \begin{vmatrix} a & b & c \ d & e & f \ g & h & i \ \end{vmatrix} = a \cdot \begin{vmatrix} e & f \ h & i \ \end{vmatrix}

  • b \cdot \begin{vmatrix} d & f \ g & i \ \end{vmatrix}
  • c \cdot \begin{vmatrix} d & e \ g & h \ \end{vmatrix} $$

笔记指出,这里的+,-,+符号序列,就是(-1)^{i+j}的体现,它保证了“有向体积”的符号一致性。而每一个2阶子式,就是原矩阵去掉第i行第j列后剩下的部分——这正是“降维”的物理操作。

它提供了一个递归计算行列式的Python函数,清晰展示了这一思想:

def det_recursive(matrix): """递归计算行列式,完美体现“按行展开”思想""" n = len(matrix) if n == 1: return matrix[0][0] if n == 2: return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0] det = 0 # 固定第一行(i=0)进行展开 for j in range(n): # 计算余子式:去掉第0行和第j列 minor = [] for r in range(1, n): # 从第1行开始 row = [] for c in range(n): if c != j: # 跳过第j列 row.append(matrix[r][c]) minor.append(row) # 代数余子式 = (-1)^(0+j) * det(minor) cofactor = ((-1) ** j) * det_recursive(minor) det += matrix[0][j] * cofactor return det # 测试 M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(f"递归计算结果: {det_recursive(M)}") print(f"numpy计算结果: {np.linalg.det(M):.2f}")

关键点说明:

  • 函数名det_recursive直接点明其核心是递归,而非迭代。
  • minor的构建是重点:双重循环,外层for r in range(1, n)跳过第0行,内层for c in range(n)并if c != j跳过第j列,精准实现“划去”操作。
  • ((-1) ** j)是(-1)^{i+j}在i=0时的简化,代码简洁且不易出错。
  • 性能警告:笔记坦率指出,此函数时间复杂度为 $O(n!)$,仅用于教学理解。实际应用必须用LU分解等 $O(n^3)$ 算法。这体现了笔记的务实精神——教原理,也教边界。

4. 线性空间的“存在性证明”落地为可执行的判定算法:从抽象定义到基、维数、子空间的三步检验法

4.1 “线性空间”定义的八条公理,如何转化为一个Python类的__init__和__add__方法?

笔记在3.1节,没有陷入公理的哲学讨论,而是提出一个尖锐问题:“给你一个集合V和一个数域K,你怎么证明它是一个线性空间?” 答案是:你必须为V上的加法和数乘运算,写出具体的、可执行的算法,并验证这八条公理是否成立。为此,它以“所有2×2实矩阵的集合”为例,定义了一个Python类:

class MatrixSpace2x2: """一个具体的线性空间实例:所有2x2实矩阵""" def __init__(self, a, b, c, d): # 矩阵 [[a, b], [c, d]] self.data = [[a, b], [c, d]] def __add__(self, other): """加法运算:对应元素相加""" return MatrixSpace2x2( self.data[0][0] + other.data[0][0], self.data[0][1] + other.data[0][1], self.data[1][0] + other.data[1][0], self.data[1][1] + other.data[1][1] ) def __rmul__(self, scalar): """数乘运算:标量乘以每个元素""" return MatrixSpace2x2( scalar * self.data[0][0], scalar * self.data[0][1], scalar * self.data[1][0], scalar * self.data[1][1] ) def is_zero(self): """零元:全零矩阵""" return (self.data[0][0] == 0 and self.data[0][1] == 0 and self.data[1][0] == 0 and self.data[1][1] == 0) def negative(self): """负元:每个元素取反""" return MatrixSpace2x2( -self.data[0][0], -self.data[0][1], -self.data[1][0], -self.data[1][1] ) # 验证公理1(交换律):A + B == B + A A = MatrixSpace2x2(1, 2, 3, 4) B = MatrixSpace2x2(5, 6, 7, 8) sum_AB = A + B sum_BA = B + A # 只需比较data即可,因为__eq__未重写,但逻辑上应相等 print("A+B == B+A?", sum_AB.data == sum_BA.data) # True

参数与设计逻辑:

  • __init__接收四个参数,强制要求用户以“坐标”的形式输入,这对应了线性空间中“向量”的概念——它需要一组基来表示。
  • __add__和__rmul__是核心,它们的实现就是公理1-8的“操作手册”。例如,公理3(零元存在)的验证,就是调用is_zero()方法;公理4(负元存在)的验证,就是调用negative()方法并检查A + A.negative()是否为零元。
  • 这种写法,把抽象的“存在性证明”,转化为了具体的“代码能否编译、运行、返回True”的工程问题。

4.2 判定“子空间”的黄金三步法:封闭性检查的自动化脚本

笔记在3.2节,将“W是V的子空间”的充要条件(加法与数乘封闭),提炼为一个可编程的三步检验法,并配以伪代码:

  1. 非空检查:0_V ∈ W? (零向量必须在W中)
  2. 加法封闭检查:任取u, v ∈ W,计算u + v,验证u + v ∈ W?
  3. 数乘封闭检查:任取u ∈ W和k ∈ K,计算k*u,验证k*u ∈ W?

它提供了一个通用的检验函数框架:

def check_subspace(W_elements, V_add, V_scalar_mult, V_zero, K=[0, 1, -1, 2, 0.5]): """ 检验W_elements是否构成V的一个子空间 W_elements: W中的一组典型元素(列表) V_add, V_scalar_mult: V上的加法和数乘函数 V_zero: V的零元 K: 用于测试的数域K中的几个代表性标量 """ # Step 1: 非空检查 if V_zero not in W_elements: print("❌ 失败:零元不在W中") return False # Step 2: 加法封闭检查(取W中所有两两组合) from itertools import combinations for u, v in combinations(W_elements, 2): w_sum = V_add(u, v) if w_sum not in W_elements: print(f"❌ 失败:u+v 不在W中,u={u}, v={v}, u+v={w_sum}") return False # Step 3: 数乘封闭检查(取W中每个元素与K中每个标量) for u in W_elements: for k in K: w_scaled = V_scalar_mult(k, u) if w_scaled not in W_elements: print(f"❌ 失败:k*u 不在W中,k={k}, u={u}, k*u={w_scaled}") return False print("✅ 通过所有子空间检验") return True # 示例:检验R^2中所有形如(a, 0)的向量是否为子空间 W = [(1, 0), (2, 0), (-1, 0), (0, 0)] # 一些典型元素 V_zero = (0, 0) # 定义R^2上的加法和数乘 def R2_add(u, v): return (u[0]+v[0], u[1]+v[1]) def R2_scalarmult(k, u): return (k*u[0], k*u[1]) check_subspace(W, R2_add, R2_scalarmult, V_zero)

避坑 / 常见问题 / 排查

  1. 现象:check_subspace函数返回False,但你确信W是子空间。
    原因:W_elements列表太小,未能覆盖所有可能的线性组合。例如,W是所有(a, 0),但你只给了[(1,0), (0,0)],那么2*(1,0)=(2,0)就不在列表中,导致误判。
    解决:W_elements必须是W的一个生成集(如基),或使用更智能的采样策略(如随机生成大量点),而非几个孤立点。

  2. 现象:在V_scalar_mult中,使用了浮点数k=0.1,结果k*u因精度问题无法精确匹配W_elements中的元素。
    原因:浮点数的二进制表示不精确,0.1*10可能不等于1.0。
    解决:对浮点数结果使用math.isclose()进行近似比较,或限定K为有理数(如分数fractions.Fraction)。

  3. 现象:combinations(W_elements, 2)生成的组合数爆炸,函数运行极慢。
    原因:W_elements包含了太多冗余元素,而子空间的封闭性只需验证其基的线性组合即可。
    解决:先对W_elements进行线性无关性筛选,提取一个极大线性无关组(即基),再用这个基进行检验,效率呈指数级提升。

  4. 现象:函数通过了检验,但W其实不是子空间,因为W_elements的定义本身就有问题(例如,它只包含了整数坐标,但W实际包含所有实数坐标)。
    原因:W_elements是W的有限采样,永远无法穷举无限集。函数只能证伪,不能绝对证实。
    解决:函数的正确用途是“快速排除明显错误的候选集”。要严格证明,仍需回到数学定义,用符号推导。此脚本是“侦察兵”,不是“法官”。


5. 从“解空间”到“基础解系”:齐次方程组解集结构的可视化与自动化求解

5.1 解空间W的维数公式dim(W) = n - r,如何从消元结果中“数”出来?

笔记在3.8节,把抽象的维数公式,变成了一张消元后的“解构地图”。它以一个具体的4元齐次方程组为例,其系数矩阵经高斯消元后得到阶梯形:

$$ \begin{bmatrix} 1 & 2 & 0 & 3 \ 0 & 0 & 1 & 4 \ 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 \ \end{bmatrix} $$

笔记标注:

  • n = 4(未知数个数,即矩阵列数)。
  • r = 2(非零行数,即主元个数)。
  • 主元位于第1列和第3列 → 主变量是x1, x3。
  • 自由变量是x2, x4(共n - r = 2个)。
  • 基础解系的向量个数 = 自由变量个数 = 2。

它强调,dim(W) = n - r不是一个需要记忆的公式,而是对消元结果的直接计数。你不需要知道什么是“解空间”,只要会数“主元列”和“总列数”,就能得到维数。

5.2 自动生成基础解系:一个函数,把自由变量的“单位向量赋值”自动化

笔记在3.8节末尾,给出了一个能自动生成基础解系的Python函数。其核心思想是:让每个自由变量依次取1,其余自由变量取0,然后回代求出主变量的值。

def null_space_basis(A): """ 计算齐次方程组 Ax=0 的基础解系(解空间的一组基) A: m x n 系数矩阵 返回: 一个列表,每个元素是一个n维解向量(列表) """ import numpy as np from numpy.linalg import matrix_rank A = np.array(A, dtype=float) m, n = A.shape r = matrix_rank(A) # 实际主元数 if r == 0: return [np.eye(n)[i].tolist() for i in range(n)] # 全零矩阵,解空间是整个R^n # 对A进行行最简形变换(RREF) A_rref = np.array(A, dtype=float) # 这里调用numpy的rref,或自行实现(略) # 为简洁,假设已有rref结果 # A_rref = compute_rref(A) # 找出主元列和自由列索引 pivot_cols = [] free_cols = list(range(n)) for i in range(m): for j in range(n): if abs(A_rref[i][j]) > 1e-10: # 找到主元 pivot_cols.append(j) free_cols.remove(j) break # 基础解系个数 num_basis = n - r basis = [] # 对每个自由变量,构造一个解向量 for idx, free_col in enumerate(free_cols): # 初始化解向量为全零 sol = [0.0] * n # 将该自由变量设为1 sol[free_col] = 1.0 # 回代求解主变量 # 从最后一行主元开始向上 for i in range(len(pivot_cols)-1, -1, -1): pivot_row = i pivot_col = pivot_cols[i] # sol[pivot_col] = - (该行其他项的和) s = 0.0 for j in range(pivot_col + 1, n): s += A_rref[pivot_row][j] * sol[j] sol[pivot_col] = -s basis.append([round(x, 6) for x in sol]) # 四舍五入,提高可读性 return basis # 示例:求解 Ax=0,A为上面的阶梯形矩阵 A_example = [[1, 2, 0, 3], [0, 0, 1, 4], [0, 0, 0, 0], [0, 0, 0, 0]] basis = null_space_basis(A_example) print("基础解系:") for vec in basis: print(vec)

逻辑说明与参数说明:

  • A是输入的系数矩阵,函数内部会将其化为行最简形(RREF),这是获得标准基础解系的前提。
  • pivot_cols和free_cols的识别,是整个算法的“眼睛”。它通过扫描RREF矩阵,精确找出哪些列有主元(主变量),哪些没有(自由变量)。
  • for idx, free_col in enumerate(free_cols)循环,是生成基础解系的核心。每一次循环,都固定一个自由变量为1,其余为0,然后利用RREF的“上三角”结构,从下往上逐行回代,解出所有主变量。
  • round(x, 6)是一个实用主义技巧,它把1.000000000000001这样的浮点误差显示为1.0,大幅提升输出的可读性和可验证性。

5.3 非齐次方程组的通解:特解 + 齐次解空间,一个函数封装全部逻辑

笔记在3.9节,将非齐次方程组Ax = b的通解结构x = x_p + x_h,封装为一个端到端的求解函数。它巧妙地复用了前面的null_space_basis和gauss_elimination:

def solve_nonhomogeneous(A, b): """ 求解非齐次线性方程组 Ax = b 的通解 A: m x n 系数矩阵 b: m维常数向量 返回: (特解x_p, 基础解系列表) 或 None(若无解) """ import numpy as np # 构造增广矩阵 A_aug = [row + [bi] for row, bi in zip(A, b)] # 高斯消元 A_aug_rref = gauss_elimination(A_aug) # 复用2.2节的函数 # 检查是否有解(Step 1: 查矛盾行) has_solution = True for row in A_aug_rref: if all(abs(x) < 1e-10 for x in row[:-1]) and abs(row[-1]) > 1e-10: has_solution = False break if not has_solution: return None # 提取RREF系数矩阵和常数项 A_rref = [row[:-1] for row in A_aug_rref] b_rref = [row[-1] for row in A_aug_rref] # 求特解x_p:令所有自由变量为0,回代求主变量 n = len(A[0]) x_p = [0.0] * n # 找出主元列 pivot_cols = [] for i, row in enumerate(A_rref): for j, val in enumerate(row): if abs(val) > 1e-10: pivot_cols.append(j) break # 回代求特解 for i in range(len(pivot_cols)-1, -1, -1): if i < len(b_rref): # 确保行存在 pivot_col = pivot_cols[i] x_p[pivot_col] = b_rref[i] for j in range(pivot_col + 1, n): x_p[pivot_col] -= A_rref[i][j] * x_p[j] # 求齐次解空间的基础解系 basis_h = null_space_basis(A) return ([round(x, 6) for x in x_p], basis_h) # 示例 A_nh = [[1, 2, 0, 3], [0, 0, 1, 4], [0, 0, 0, 0]] b_nh = [5, 6, 0] result = solve_nonhomogeneous(A_nh, b_nh) if result: x_p, basis_h = result print(f"特解: {x_p}") print("齐次解空间基础解系:") for vec in basis_h: print(f" {vec}") else: print("方程组无解")

关键设计点:

  • 函数首先调用gauss_elimination对增广矩阵消元,然后立即执行无解判别,这是严谨性的第一步。
  • 特解x_p的计算,是“令所有自由变量为0”这一策略的代码实现。它复用了与null_space_basis相同的回代逻辑,只是初始值不同。
  • 最终返回的是一个元组(x_p, basis_h),这直接对应了教材中x = x_p + k1*v1 + k2*v2 + ...的通解形式,让理论与代码一一映射。

6. 把“数域”从一个抽象概念,变成可

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询