ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SymPy SparseMatrix 完全指南:纯 Python 符号稀疏矩阵的创建、运算与分解

SymPy SparseMatrix 完全指南:纯 Python 符号稀疏矩阵的创建、运算与分解 SymPy SparseMatrix 完全指南纯 Python 符号稀疏矩阵的创建、运算与分解【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympySymPy 是一个纯 Python 编写的计算机代数系统其中的SparseMatrix稀疏矩阵专门用于存储和分析含有大量零元素的矩阵在有限元、图论、差分方程、大规模线性系统等场景下比稠密矩阵Matrix节省大量内存。本文以 SymPy 仓库中的 稀疏矩阵类参考文档 为核心骨架结合 sparse.py 的源码实现与 test_sparse.py 的测试用例系统讲解SparseMatrix/MutableSparseMatrix/ImmutableSparseMatrix的创建方式、读写语义、稀疏专有操作以及 Cholesky、LDL、LU 等分解与求解 API帮助你写出既节省内存又可直接用于符号运算的稀疏矩阵代码。SparseMatrix 类族总览sympy.matrices.sparse模块通过 Sphinx 的autoclass指令对外暴露三个类见 sparse.rstSparseMatrix最常用的入口源码中它是MutableSparseMatrix的别名见 sparse.py 的SparseMatrix MutableSparseMatrixMutableSparseMatrix可修改的稀疏矩阵支持m[i, j] value原地赋值ImmutableSparseMatrix不可变稀疏矩阵定义于 immutable.py可用于需要哈希的场景如作为字典键、放入集合。三者共享底层的SparseRepMatrix继承自RepMatrix见 sparse.py因此绝大多数运算逻辑是同一套实现区别只在于可变性与哈希性。在类文档的 See Also 中官方将DenseMatrix稠密矩阵列为对照当矩阵中零元素占绝大多数时使用SparseMatrix否则使用稠密矩阵更合适。创建 SparseMatrix六种构造形式SparseMatrix的构造函数经过_handle_creation_inputs见 sparse.py统一处理支持以下输入形式。1. 从另一个矩阵转换传入任意MatrixBase实例即可底层通过todok()提取非零元素 from sympy import SparseMatrix, Matrix SparseMatrix(Matrix([[1, 0], [0, 1]])) Matrix([ [1, 0], [0, 1]])2. 指定行列 扁平列表 / range SparseMatrix(2, 2, range(4)) Matrix([ [0, 1], [2, 3]])扁平列表的长度必须严格等于rows * cols否则抛出ValueError SparseMatrix(2, 2, [1, 2]) Traceback (most recent call last): ... ValueError: List length (2) ! rows*columns (4)3. 指定行列 字典DOK 格式字典的键是(row, col)元组值是对应的非零元素 SparseMatrix(2, 2, {(1, 1): 2}) Matrix([ [0, 0], [0, 2]])这是最贴合稀疏存储本质的构造方式——只指定非零项。若字典中某个位置越界会抛出ValueError SparseMatrix(1, 1, {(1, 1): 1}) ValueError: The location (1, 1) is out of the designated range[0, 0]x[0, 0]4. 自动确定尺寸autosizing将第一个参数设为None矩阵会自动按字典中最大下标扩展 SparseMatrix(None, {(1, 1): 1, (3, 3): 3}) Matrix([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 3]])None必须同时用于行列SparseMatrix(None, None, {...})也合法只给一个None会报错。若字典中所有值都为 0则形状为(0, 0)见 test_sparse.py 的测试。5. 嵌套列表允许锯齿状直接传入不齐整的嵌套列表缺失位置自动补零 SparseMatrix([[1, 2, 3], [1, 2], [1]]) Matrix([ [1, 2, 3], [1, 2, 0], [1, 0, 0]])注意安全校验规则扁平列表严格校验长度而嵌套列表只校验坐标是否越界。因此下面这个例子不报错元素都在 2×2 范围内 SparseMatrix(2, 2, [[1, 2]]) Matrix([ [1, 2], [0, 0]])但一旦元素超出声明范围就会抛错 SparseMatrix(2, 2, [[1, 2, 3]]) ValueError: The location (0, 2) is out of designated range: (1, 1)6. 按位置函数生成传入lambda i, j: ...函数会被应用于每个下标结果为 0 的项不存储 SparseMatrix(2, 2, lambda i, j: i*2j) Matrix([ [0, 1], [2, 3]])进阶值本身是矩阵时自动展开字典的值可以是矩阵、列表等构造时会自动展开填充到指定位置见 sparse.py 的update逻辑 from sympy import ones SparseMatrix(4, 4, {(1, 1): ones(2)}) Matrix([ [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]])若展开后与已有元素发生冲突会抛出ValueError: collision at (1, 1)对应 test_sparse.py 中的raises断言。元素访问、赋值与切片SparseMatrix支持标准的m[i, j]读取与赋值。把元素赋值为 0 时该位置会从内部字典中删除从而保持稀疏性测试见 test_sparse.py a SparseMatrix(((1, 0), (0, 1))) a[1, 1] 0 # 赋零即删除存储项 a.todok() {(0, 0): 1}切片操作与稠密矩阵一致返回的仍是SparseMatrix m0 SparseMatrix.eye(4) m0[:3, :3] Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])子矩阵块赋值同样支持例如m[2:4, 2:4] sparse_eye(2)。行/列级别的操作row_del、col_del、row_swap、col_swap、row_join、col_join在 test_sparse.py 中均有验证。稀疏专有查询nnz、row_list、col_listSparseMatrix提供三个判断存储效率与结构的关键方法nnz()返回非零元素个数即内部 DOK 字典的长度见 sparse.pyrow_list()别名属性RL按行主序返回(row, col, value)三元组列表col_list()别名属性CL按列主序返回(row, col, value)三元组列表。 a SparseMatrix(((1, 2), (3, 4))) a.nnz() 4 a.RL # 等价于 a.row_list() [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] a.CL # 等价于 a.col_list() [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)]RL/CL在类中被定义为 property见 sparse.py官方文档称其为 Alternate faster representation适合需要遍历所有非零项做图算法、装配刚度矩阵等场景。与 DOK 字典的互转todok / from_dok稀疏矩阵的底层存储就是 DOKDictionary of Keys字典两个通用 API 定义在 matrixbase.py from sympy import Matrix M Matrix.eye(3) M.todok() {(0, 0): 1, (1, 1): 1, (2, 2): 1} d {(0, 0): 1, (1, 2): 3, (2, 1): 4} Matrix.from_dok(3, 3, d) Matrix([ [1, 0, 0], [0, 0, 3], [0, 4, 0]])todok()返回的字典只有非零项且所有值都会经过_sympify转为 SymPy 表达式from_dok的实现见 matrixbase.py。从源码结构可以推断稀疏矩阵的几乎所有运算乘法、分解、求解都以这份 DOK 字典为数据源因此它是理解SparseMatrix内部机制的关键接口。注意私有的_smat属性自 SymPy 1.9 起已被弃用官方建议一律使用todok()见 sparse.py 中的弃用警告。逐元素变换applyfuncapplyfunc(f)将函数f应用到每个非零元素上结果仍为 0 的项不保留见 sparse.py m SparseMatrix(2, 2, lambda i, j: i*2j) m.applyfunc(lambda i: 2*i) Matrix([ [0, 2], [4, 6]])源码注释提醒这种只处理非零元素的语义与DenseMatrix.applyfunc作用于包括零在内的每个元素并不完全一致例如zeros(2, 2).applyfunc(lambda x: x 1)在稀疏版本中结果仍是零矩阵这是使用applyfunc时需要留意的行为差异。可变与不可变SparseMatrix 与 ImmutableSparseMatrixMutableSparseMatrix即SparseMatrix允许m[i, j] ...原地修改ImmutableSparseMatrix任何赋值都会抛出TypeError: Cannot set values of ImmutableSparseMatrix但支持hash可以放入集合或作为字典键见 immutable.py 的示例。两者可通过as_mutable()/as_immutable()互转定义于 sparse.py from sympy import SparseMatrix M SparseMatrix([[1, 2], [3, 4]]) I M.as_immutable() # 转为不可变 M2 I.as_mutable() # 再转回可变在内部实现上ImmutableSparseMatrix继承ImmutableRepMatrix其_fromrep会把 DOK 数据打包进Basic表达式节点见 immutable.py这正是它可哈希、可参与符号表达式结构的原因。线性方程求解solve 与 solve_least_squaresSparseMatrix提供两个求解入口见 sparse.pysolve(rhs, methodLDL)求解self * soln rhs。若矩阵非方阵行数小于列数时报ValueError(Under-determined system.)行数大于列数时提示改用solve_least_squaressolve_least_squares(rhs, methodLDL)超定系统的最小二乘解实现为(t*self).inv(methodmethod)*t*rhs其中t self.T见 sparse.py。官方文档中的最小二乘示例 from sympy import SparseMatrix, Matrix, ones S SparseMatrix(Matrix([1, 2, 3]).row_join(Matrix([2, 3, 4]))) r S*Matrix([2, 3]) xy S.solve_least_squares(Matrix([8, 14, 18])) xy Matrix([ [ 5/3], [10/3]]) (S*xy - r).norm().n(2) 0.58两个方法默认都使用LDL分解求逆solve_least_squares的文档字符串中提到可用methodCHCholesky等其他求逆方法具体选项可查看.inv()的文档。稀疏专用分解与三角求解SparseMatrix通过 decompositions.py 中的稀疏实现提供四个专门针对稀疏结构设计的分解/求解例程见 sparse.pycholeskyhermitianTrue返回满足L * L.T A的下三角矩阵L要求A为方阵、对称、正定、非奇异 A SparseMatrix(((25,15,-5),(15,18,0),(-5,0,11))) A.cholesky() Matrix([ [ 5, 0, 0], [ 3, 3, 0], [-1, 1, 3]]) A.cholesky() * A.cholesky().T A TruehermitianFalse时进行非埃尔米特 Cholesky 型分解适用于非正定矩阵 A SparseMatrix([[1, 2], [2, 1]]) L A.cholesky(hermitianFalse) L*L.T A True示例与说明见 decompositions.py。LDLdecompositionhermitianTrue返回 LDL 分解即A L * D * L.T形式是默认的求逆/求解基础。lower_triangular_solve / upper_triangular_solve分别求解下三角与上三角方程组实现位于 solvers.py 中的_lower_triangular_solve_sparse/_upper_triangular_solve_sparse。liupc 与 row_structure_symbolic_choleskyliupc()调用_liupc计算稀疏 Cholesky 分解的符号填充fill-in结构row_structure_symbolic_cholesky()返回符号 Cholesky 的行结构。这两者属于符号层面的结构分析工具用于在真正做数值/符号分解前预判非零元填充模式是理解稀疏分解效率的关键。此外通用的LUdecomposition()同样可用测试中验证了(L*U).permute_rows(p, backward) - testmat sparse_zeros(4)见 test_sparse.py。与其他矩阵类型的互操作row_join/col_join稀疏与稠密矩阵可互相拼接结果的类型保持为发起方类型test_sparse.pytolist()转为嵌套 Python 列表标量乘法5 * b、符号乘法b * Symbol(x)均返回SparseMatrix矩阵幂A**5也得到验证行列式det()支持稀疏矩阵的行列式计算test_sparse.py 覆盖了多组含符号与数值的用例reshape(rows, cols)调整形状并保持稀疏存储。源码导读与延伸阅读关注点参考位置类文档骨架本文主题doc/src/modules/matrices/sparse.rstSparseRepMatrix/MutableSparseMatrix实现sympy/matrices/sparse.pyImmutableSparseMatrix实现sympy/matrices/immutable.py稀疏 Cholesky / LDL / liupc 分解sympy/matrices/decompositions.pytodok/from_dok通用接口sympy/matrices/matrixbase.py稀疏矩阵测试用例sympy/matrices/tests/test_sparse.py小结SymPy 的SparseMatrix在继承通用矩阵 API 的基础上围绕 DOK 字典实现了高效的稀疏存储、逐元素变换、最小二乘与线性求解并提供符号级的 Cholesky/LDL 分解与填充结构分析工具。实战中你可以用SparseMatrix(rows, cols, {(i, j): value})直接构造大规模稀疏系统用nnz()/RL/CL检查存储结构再通过cholesky()/LDLdecomposition()与solve()完成符号求解需要哈希或不可变语义时改用ImmutableSparseMatrix即可。理解其仅存储非零项的核心机制是在符号计算中发挥稀疏矩阵价值的前提。【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表