简介:Maple 矩阵计算 PDF 是一份面向数学、计算机相关专业学生和科研人员的实用文档,核心讲解 Maple 软件中 LinearAlgebra 函数包在矩阵计算中的完整用法。文档从函数包加载开始,依次介绍线性代数函数包的接口、面板和关联菜单操作,并给出大量命令的调用示例,如 Matrix 定义矩阵、Add 矩阵加减、Adjoint 伴随矩阵、Determinant 行列式、Eigenvalues 特征值、Eigenvectors 特征向量、LU 分解、奇异值分解等;同时也演示了长形式与短形式命令的书写方式,以及在矩阵面板中通过单击、双击查看或导出数据的操作方法。资源还系统梳理了矩阵、向量、线性无关、秩、行空间、零空间、值域空间等基础概念,并结合科学计算、数据分析、机器学习、计算机视觉、图像处理等典型场景说明其用途,便于读者将知识迁移到实际项目中。这份 PDF 共 1 个文件,大小约 974KB,目前已有 370 人浏览学习,适合作为 Maple 线性代数计算与函数包命令的入门学习和日常速查参考。
1. Maple 矩阵计算:从 LinearAlgebra 包切入数值与符号的缝隙
做科学计算的时候,大多数人会条件反射地打开 MATLAB 或者 Jupyter 里的 NumPy。但当你需要处理带符号参数的矩阵、验证一个代数恒等式,或者把高斯消元的过程一步步讲给学生听时,Maple 的 LinearAlgebra 包反而是更顺手的工具。它包含 100 多个以大写字母开头的线性代数函数,采用 rtable 数据结构替代了旧版 linalg,数值部分由 NAG 和 LAPACK 提供底层支持。这里我把常用命令过一遍,重点放在那些“看起来简单,实际容易踩坑”的细节上,比如浮点类型选择、大矩阵的显示限制、Modular 子包的使用场景。
2. rtable 数据结构与矩阵构造:从 linalg 到 LinearAlgebra 的迁移
老用户从 Maple 的 linalg 包迁移过来时,最不适应的就是数据结构。linalg 使用的是旧式的矩阵表达,而 LinearAlgebra 包完全建立在 rtable 之上。rtable 是 Maple 内部对稠密、稀疏、多维数组的统一抽象,它让矩阵的存储和访问更接近编译型语言,也为 NAG 和 LAPACK 的数值例程提供了可以直接对接的内存布局。你不需要直接操作 rtable,但理解这个差异能解释很多现象——比如为什么某些操作在旧包中可行,在新包中却要求先转换类型。
2.1 为什么 rtable 是理解 LinearAlgebra 的关键
rtable 本质上是一种带类型标记的数组描述。Matrix 实际是 rtable 的一个特例,它的索引从 1 开始,支持 datatype 属性。常见的 datatype 包括 anything(默认)、float、complex(float)、integer。当你使用 RandomMatrix(2, datatype=float) 时,生成的矩阵元素就是双精度浮点,后续调用 LAPACK 例程时可以直接传递指针,避免符号推断的开销。这也是 LinearAlgebra 在大规模数值计算上比 linalg 高效的原因。
在命令行中,用 Matrix 命令构造矩阵时,可以显式指定行列数、初值和数据类型。下面这段代码示范了三种不同的构造方式:
with(LinearAlgebra): # 方式1:直接按行列表构造,默认 datatype=anything,适合符号计算 A := Matrix([[1, 2], [3, 4]]); # 方式2:指定行列数,元素通过生成函数填充 B := Matrix(3, 2, (i, j) -> i + j); # 方式3:显式指定浮点数据类型,用于数值计算 C := Matrix(3, 3, datatype = float, shape = symmetric); C[1,1] := 1.0; C[1,2] := 2.0; C[2,2] := 3.0;这里(i, j) -> i+j是 Maple 的箭头运算符,等价于匿名函数,矩阵的每个元素由行列下标确定。第三种方式借助shape=symmetric告诉 Maple 这是一个对称矩阵,内部只需存储上三角部分。需要注意,当给C[1,2]赋值后,C[2,1]会被自动同步为同一个值,这就是 shape 属性的作用。
在构造矩阵时,datatype和shape是两个最常用的属性,直接关系到内存占用和允许调用的算法。下表列出了几个典型的构造命令和适用场景:
| 命令 | 作用 | 典型参数 | 适用场景 |
|---|---|---|---|
Matrix | 按行/列或生成函数构造矩阵 | Matrix(2,3) | 通用 |
IdentityMatrix | 单位矩阵 | IdentityMatrix(4) | 初等变换、初始化 |
ZeroMatrix | 全零矩阵 | ZeroMatrix(2,2) | 占位、累加器 |
RandomMatrix | 随机矩阵 | RandomMatrix(3,3,datatype=float) | 测试算法 |
DiagonalMatrix | 从向量构造对角矩阵 | DiagonalMatrix([1,2,3]) | 对角化示例 |
BandMatrix | 带状矩阵 | BandMatrix([[1,2]],1,3) | 差分方程离散化 |
HilbertMatrix | Hilbert 矩阵 | HilbertMatrix(3) | 病态矩阵测试 |
VandermondeMatrix | Vandermonde 矩阵 | VandermondeMatrix([a,b,c]) | 多项式插值 |
表格中的BandMatrix([[1,2]],1,3)表示主对角线上方偏移 1 个单位放置向量[1,2],矩阵宽度为 3。这些构造函数在教学中会频繁用到,但实际工程中更常见的还是通过导入外部数据构造矩阵。
2.2 基本查询:Dimension、Row、Column 与复制语义
构造完矩阵,第一步通常是想知道它是几乘几的。Dimension(A)返回包含两个整数的列表。Row(A, 1)返回第一行,Column(A, 2)返回第二列。这里有个容易踩的坑:Row返回的是向量,不是矩阵。如果你想把某一行从矩阵中取出后继续参与矩阵乘法,需要先Matrix(Row(A,1))转换,否则在少数命令下会因维数不匹配报错。
另外,Copy命令也值得留意。Maple 的矩阵在赋值时通常共享底层 rtable,直接B := A;后修改B会影响A。要防止这种副作用,用Copy(A)创建真正的独立副本:
with(LinearAlgebra): A := Matrix([[1, 2], [3, 4]]); B := Copy(A); # 显式深拷贝,B 和 A 不共享数据 C := A; # C 与 A 共享 rtable C[1,1] := 99; # 此时 A[1,1] 变为 99,B 保持 1 Dimension(A); # 返回行数和列数 Row(A, 1); # 返回向量 <1,2>我一般会在所有需要“读取后修改”的场景里无脑用Copy,避免后续调试时出现莫名其妙的数据被改掉。Row返回的是向量,可以通过Matrix(Row(A,1))转换回行矩阵。如果需要行数,Dimension(A)[1]是常用写法。
对于初学者,最容易搞混的是Row/Column与SubMatrix的区别。前者取整行或整列,返回向量;后者可以按行索引范围取子块,返回矩阵。比如SubMatrix(A, 1..2, 1..2)取左上角 2x2 子矩阵。如果需要频繁取子矩阵做计算,优先用SubMatrix,它比逐元素复制快得多。
3. 矩阵计算核心:秩、零空间、特征值与分解
有了矩阵,就可以开始做真正的计算。LinearAlgebra 的函数命名很直白,几乎不用查手册就能猜到Determinant是行列式,Rank是秩,NullSpace是零空间。但选哪个命令取决于你想解决什么问题。
3.1 从高斯消元到秩、行空间与零空间
线性代数里最先学的是高斯消元。LinearAlgebra 提供了GaussianElimination和ReducedRowEchelonForm两个命令。前者只把矩阵化为行阶梯形,后者继续化到最简行阶梯形。对于需要手工检查消元过程的场景,我一般直接调用ReducedRowEchelonForm(A),因为它的结果唯一,更容易对比自己算的过程。
有了阶梯形,再求秩和空间基就非常简单。下面这段代码在一个 3x4 矩阵上同时求秩、行空间基、列空间基和零空间基:
with(LinearAlgebra): A := Matrix([ [1, 2, 3, 1], [2, 4, 6, 2], [1, 0, 1, 0] ]); r := Rank(A); # 线性无关的行数 rows := RowSpace(A); # 行空间的一组基 cols := ColumnSpace(A); # 列空间的一组基 nulls := NullSpace(A); # 零空间的一组基RowSpace返回的是一个向量集合(Maple 中的 list),里面每个向量是行空间的一组基;ColumnSpace返回的是列向量集合;NullSpace返回的是满足A x = 0的基础解系。注意它们都返回集合而不是矩阵,所以如果想拿到第一个基向量,需要用nulls[1]。
Rank 的计算底层就是高斯消元。对于整数矩阵,Maple 默认用精确算术,不会因为浮点舍入误差把秩算错。但当你把矩阵元素改成小数(比如输入1.0),Maple 会切换到数值模式,此时判断“零”就依赖容差。这是很多人在实际项目中栽跟头的地方——符号模式下秩为 2 的矩阵,一旦转成浮点可能得到秩 3。解决思路是尽量保留精确输入,或者用GaussianElimination配合fraction检查主元。
| 命令 | 返回内容 | 典型用法 | 备注 |
|---|---|---|---|
Rank | 矩阵的秩 | Rank(A) | 精确/浮点模式不同 |
NullSpace | 零空间的一组基 | NullSpace(A) | 返回集合 |
RowSpace | 行空间的一组基 | RowSpace(A) | 返回集合 |
ColumnSpace | 列空间的一组基 | ColumnSpace(A) | 返回集合 |
Dimension | 行数和列数 | Dimension(A) | 返回列表 |
Basis | 从向量列表中提取基 | Basis([...]) | 可给多个向量 |
SumBasis | 两个子空间直和的基 | SumBasis(S1,S2) | 需要集合参数 |
IntersectionBasis | 两个子空间交的基 | IntersectionBasis(S1,S2) | 需要集合参数 |
在需要手工验证方程组解的结构时,NullSpace的结果比solve更直观,因为它直接给出了基础解系。如果只是求特解,用LinearSolve就够了;如果需要通解,可以把特解加上零空间基的线性组合。
3.2 特征系统:Eigenvalues 和 Eigenvectors 的返回值
Eigenvalues(A)返回的是一个列向量,包含矩阵的所有特征值,可能与复数特征值混在一起。Eigenvectors(A)返回两个值:第一个是特征值向量,第二个是特征向量矩阵。每个特征向量是矩阵的一列。需要注意,数值模式下特征值的顺序不一定稳定,最好结合sort处理。
对于符号矩阵,Maple 会尝试用根式表示特征多项式,结果可能很长。可以加method=robust或method=subs改变算法,但不一定更好。我一般用CharacteristicPolynomial(A, lambda)配合solve自己解,避免特征向量计算中复杂的化简。
with(LinearAlgebra): A := Matrix([[2, 1], [1, 2]]); vals := Eigenvalues(A); vecs := Eigenvectors(A); # 若要单独取第二个特征向量(按 Eigenvectors 返回的列) evals := vecs[1]; # 特征值向量 evecs := vecs[2]; # 特征向量矩阵 second := evecs[.., 2];evecs[..,2]表示取第二列,这是 Maple 的切片语法。..表示从第一行到最后一行。如果想统计特征值个数,可以用numelems(vals)。注意Eigenvalues返回的是数值或符号的列向量,不是集合,所以重复特征值会重复出现。
EigenConditionNumbers可以计算特征值问题的条件数,对病态矩阵很有帮助。工程上判断矩阵是否“病态”,常用ConditionNumber(A)计算 2-范数下的条件数。条件数越大,特征值求解的数值误差越容易被放大。
3.3 LU、QR 分解与线性方程组求解
求解A x = b时,LinearSolve是最直接的入口。内部它会对矩阵做 LU 分解,根据矩阵形状自动选择算法。对于超定方程,用LeastSquares。这两个命令的区别是:LinearSolve要求方程有解,LeastSquares返回最小二乘意义下的解,即使原方程无解也能输出结果。
LU 和 QR 分解属于底层操作,常用于自己实现算法。LUDecomposition(A)默认返回三个矩阵 P, L, U(取决于选项),也可以加output=['P','L','U']显式指定。QRDecomposition(A)返回 Q 和 R。下面是一个完整的求解过程:
with(LinearAlgebra): A := Matrix([[4, 3], [6, 3]]); b := <1, 2>; x := LinearSolve(A, b); # 用 A 和 b 直接解 P, L, U := LUDecomposition(A); # 返回置换矩阵、下三角、上三角 x2 := LinearSolve(U, LinearSolve(L, P . b)); # 手动回代 Q, R := QRDecomposition(A); x3 := LinearSolve(R, Q^+ . b); # Q^+ 是 Q 的共轭转置P . b是先做置换,再对下三角矩阵做前代,最后对上三角做回代。这个手动流程能帮你理解LinearSolve内部发生了什么。Q^+使用了^+运算符表示共轭转置,这是 Maple 里的特殊写法。对于实数矩阵,它退化为转置。注意LUDecomposition的返回顺序在不同版本可能受选项影响,最好用output选项固定。
实际计算中还有一个容易忽略的点:LinearSolve对奇异矩阵会报错,但LeastSquares会返回一个最小范数解。比如A := Matrix([[1,2],[2,4]])和b := <1,2>时,LinearSolve会提示系统不一致,而LeastSquares会给出一个近似解。这在实际拟合问题里很实用。
4. 大规模矩阵:面板操作、浮点精度与 Modular 子包
实际工程中的矩阵很少是 3x3。Maple 对 10x10 或更小的矩阵会在工作表里完整显示,更大的矩阵则显示为占位符。你可以在文档中双击占位符打开一个独立的矩阵浏览器,也可以右键选择“浏览矩阵”。这是 Maple 交互式环境下非常实用的功能,但我自己更习惯用命令来控制输出。
4.1 大矩阵的显示限制与面板插入
当矩阵超过 10 行或 10 列,普通输出变成占位符。你可以用Matrix(50, 50, (i,j)->i*j)试试,工作表里只会出现一个带尺寸提示的方框。双击它会打开窗口查看矩阵元素,还能通过对话框下方按钮把数据输出到 Excel。
面板插入矩阵的操作在标准工作表中很直接:从左侧“矩阵”面板选择行数和列数,点击“插入矩阵”。插入后用鼠标框选整个矩阵,复制到其他行,再执行乘法。这些交互操作背后生成的其实是同一套LinearAlgebra命令。对于脚本自动化,面板操作没有意义,但如果你在给客户做演示,面板交互比命令更直观。
对于代码生成,我一般会在工作表中用Maplet或者任务模板来辅助输入,但最终都会把生成的命令粘贴到.mpl文件里做版本管理。这样可以保证演示和自动化代码一致,避免“我在面板里点能跑,写脚本就报错”的尴尬。
4.2 数据类型与浮点计算陷阱
LinearAlgebra 的数值核心来自 NAG 和 LAPACK,这意味着一旦矩阵元素带有小数,Maple 会自动落入浮点路径。浮点矩阵的datatype默认是float,但也可以是complex(float)。你可以通过Matrix的datatype选项强制指定,例如Matrix(3,3,datatype=float)。
区分符号计算和数值计算非常重要。看下面的对比:
with(LinearAlgebra): A := Matrix([[1, 1], [1, 1 + 1/10000000000]]); B := Matrix([[1.0, 1.0], [1.0, 1.0000000001]]); ConditionNumber(B); # 结果很大,表明矩阵接近奇异 # Rank(B) 在浮点容差下可能与 Rank(A) 不一致A的元素是有理数,B的元素中有一个小数,整个矩阵就会被解释为浮点矩阵。ConditionNumber可以提前预警:如果条件数接近1/eps,结果基本不可信。eps是机器精度,约 2.22e-16。遇到这类问题,先检查矩阵里有没有无意输入的小数点。
如果要强行保持精确算术,可以把Digits调高后再用Matrix构造,但这对 LAPACK 数值例程无效。更常见的做法是先用符号模式确认结构,再用浮点模式跑大规模数值,最后对比两者的秩和特征值。
下面是常用数据类型的适用场景:
| datatype | 适用场景 | 备注 |
|---|---|---|
anything | 符号矩阵、混合表达 | 默认,最慢 |
float | 数值计算 | 双精度,兼容 LAPACK |
complex(float) | 复数矩阵 | 特征值、FFT 相关 |
integer | 整数精确运算 | 模运算可用 |
当矩阵元素是整数且有界,integer类型配合精确算术可以避免舍入误差。但如果数值很大,精确计算可能慢得不可接受,这时可以考虑下一节的 Modular 子包。
4.3 Modular 子包:模 m 下的整数矩阵计算
LinearAlgebra[Modular] 专门处理 Z/mZ 上的稠密线性代数。所谓 Z/m,就是每个元素都取模 m,比如 m=7 时,元素范围是 0 到 6。这种计算在密码学、编码理论和某些数论算法里非常常见。
Modular 子包的函数名称也以大写字母开头,使用前需要先指定模数。下面是一个在模 7 下求秩和行列式的例子:
with(LinearAlgebra): with(LinearAlgebra[Modular]): # 创建一个模 7 下的矩阵 M := Matrix(2, 2, [[3, 1], [2, 2]]); # 在模 p 下求秩 r := Mod(Rank, 7, M); # 模 p 下的行列式 d := Mod(Determinant, 7, M);Mod(f, p, A)的f是 LinearAlgebra 中的函数名,但必须能在模 p 下工作。Rank和Determinant是常用的,MatrixInverse也可以直接通过Mod(MatrixInverse, p, A)调用,前提是矩阵在模 p 下可逆。注意,Mod要求矩阵元素是整数,且所有中间计算都会对 p 取余,所以结果永远是 0 到 p-1 之间的整数。
Modular 子包的价值在于,当矩阵规模较大且模数为小素数时,计算速度远快于浮点路径,因为所有运算都是整数加减乘和取模。我曾在有限域上的线性码译码项目里用它验证生成矩阵的秩,比手写 C++ 模块快得多。如果你需要反复测试不同模数下的性质,可以把p作为变量传入循环,避免每次重新构造矩阵。
5. 用 Student[LinearAlgebra] 做分步演示与结果导出
如果你在做课程设计或者给团队讲线性代数,Maple 的 Student[LinearAlgebra] 包比直接调用 LinearAlgebra 更合适。它提供LinearSolveTutor、GaussianEliminationTutor等带界面的演示工具,可以把每一步消元过程展开。但要注意,这些 Tutor 函数是在标准工作表环境里使用的,纯命令行下无法弹出窗口。
5.1 分步演示
我比较常用的做法是先用Student[LinearAlgebra][LinearSolveTutor]跑一遍小矩阵,让学生看到加减乘除的中间结果,然后用LinearAlgebra命令验证最终答案。比如:
with(Student[LinearAlgebra]): LinearSolveTutor(Matrix([[1,2],[3,4]]), <5,6>);这个命令会打开一个 Maplet 窗口,左边是原始矩阵,右边是逐步操作面板,用户手动选择行变换,每一步都会输出对应的初等矩阵。如果只是想知道最终答案,直接LinearSolve就够了。Tutor 的价值在于理解过程而不是结果。
5.2 把矩阵结果导出到 Excel
在工作表中双击大矩阵占位符,打开的矩阵浏览器对话框里有一个输出按钮,可以把整个矩阵导出为 Excel 文件。命令行方式也支持:用ExportMatrix("data.xls", A)就能把矩阵写到表格文件。ExportMatrix来自 ExcelTools 包,常见做法是:
with(ExcelTools): A := Matrix([[1,2],[3,4]]); ExportMatrix("matrix.xls", A);这里文件扩展名.xls决定格式,如果改成.xlsx也可以。注意需要机器上装有 Excel 或兼容组件,Maple 通过 COM/ODBC 写文件。在 Linux 服务器上,我一般自己用fprintf循环输出 CSV,这样不依赖外部软件。
本文还有配套的精品资源,点击获取