资讯详情

SymPy N 维数组表达式(N-dim Array Expressions)完全指南:张量网络、收缩与轴置换的符号化操作

📅 2026/9/15 14:05:40 | 华诺云谱 👁 阅读
SymPy N 维数组表达式(N-dim Array Expressions)完全指南:张量网络、收缩与轴置换的符号化操作
SymPy N 维数组表达式N-dim Array Expressions完全指南张量网络、收缩与轴置换的符号化操作【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympySymPy 的sympy.tensor.array.expressions模块为 N 维数组提供了一组索引无关index-implicit的符号化表达式把张量积、张量收缩、取对角线和轴置换等运算表示为抽象语法树节点从而在不展开具体元素的前提下完成推导、化简与矩阵互转。本文基于该模块的官方文档与源码实现系统讲解四大核心运算类ArrayTensorProduct、ArrayContraction、ArrayDiagonal、PermuteDims的语义、构造方式、化简规则以及与索引显式形式、矩阵表达式之间的双向转换帮助你用符号方式建模矩阵乘法、迹、转置乃至张量导数。一、什么是数组表达式核心思想与设计动机传统上SymPy 处理 N 维数组有两条路线索引显式index-explicit形式如A[i, j]需要显式书写下标与求和号Sum和显式数值数组如ImmutableDenseNDimArray。数组表达式则提供了第三条路线索引无关的符号表达式。从源码看所有数组表达式对象都继承自 array_expressions.py 中的基类_CodegenArrayAbstract(Expr)而init.py 的模块文档字符串给出了两者的一一对应关系表数组运算显式执行数组表达式符号化表示tensorproductArrayTensorProducttensorcontractionArrayContractiontensordiagonalArrayDiagonalpermutedimsPermuteDims也就是说每个 N 维数组算子都有一个对应的数组表达式对象它们以某种方式表示作用于 N 维数组上的运算的抽象语法树。这种设计的价值在于表达式本身不立即求值可先做符号化简如合并嵌套收缩、整理置换便于推导数组运算的恒等式与求导法则可自由地在索引形式、数组表达式、矩阵表达式之间切换取各形式之长。ArraySymbolN 维数组的符号占位符ArraySymbol是 N 维版本的MatrixSymbol仅声明形状而不绑定具体数据 from sympy.tensor.array.expressions import ArraySymbol from sympy.abc import i, j, k A ArraySymbol(A, (3, 2, 4)) A.shape (3, 2, 4) A[i, j, k] A[i, j, k]调用as_explicit()可展开为逐元素列出的ImmutableDenseNDimArray A.as_explicit() [[[A[0, 0, 0], A[0, 0, 1], A[0, 0, 2], A[0, 0, 3]], [A[0, 1, 0], A[0, 1, 1], A[0, 1, 2], A[0, 1, 3]]], ...]从源码看ArraySymbol.__new__会把形状Tuple化并对每个维度_sympifyarray_expressions.py 第 62-68 行as_explicit()在形状含有符号时抛出ValueError(cannot express explicit array with symbolic shape)并要求各维度为整数第 78-82 行。与之配套的还有ArrayElement单个元素_diff_wrt True可作为求导变量、ZeroArray零数组等价于矩阵模块的ZeroMatrix、OneArray等基础构件。组件显式数组也可以进入表达式数组表达式不仅接受符号占位符也接受带具体元素的显式数组从而得到混合表达式 from sympy import Array from sympy import tensorproduct from sympy.tensor.array.expressions import ArrayTensorProduct a Array([1, 2, 3]) b Array([i, j, k]) expr ArrayTensorProduct(a, b, b) expr ArrayTensorProduct([1, 2, 3], [i, j, k], [i, j, k]) expr.as_explicit() tensorproduct(a, b, b) True二、四大核心运算类语义与源码级实现1. ArrayTensorProduct —— 张量积ArrayTensorProduct表示多个数组对象的张量积。其结果形状为各因子形状的拼接即若因子形状分别为(a1, a2)、(b1, b2)则结果的形状是(a1, a2, b1, b2)。源码第 308-346 行中__new__会先对每个参数_sympify收集各因子的ndim存入_sub_ndim_list并拼接get_shape得到_shape。构造时传入canonicalizeTrue会立即执行_canonicalize()第 348-480 行其化简规则包括展平嵌套ArrayTensorProduct(ArrayTensorProduct(A, B), C)展平为ArrayTensorProduct(A, B, C)合并标量系数把可交换的 rank-0 因子合并为单个前导系数如ArrayTensorProduct(x, A, y, B)化简为ArrayTensorProduct(x*y, A, B)把零因子归结为ZeroArray任一元是ZeroArray/ZeroMatrix时整体返回ZeroArray上提内部收缩与对角若张量积因子中含有ArrayContraction或ArrayDiagonal则把对应收缩/对角索引做全局平移后提到张量积外层形成ArrayContraction(ArrayTensorProduct(...), ...)或PermuteDims(ArrayDiagonal(...), ...)的标准形态上提置换因子中的PermuteDims会以复合置换的形式合并到外层。as_explicit()第 487-488 行则等价于调用tensorproduct(*args)展开为具体数组。2. ArrayContraction —— 轴收缩求和ArrayContraction(expr, (i, j), ...)对指定轴组执行收缩本质是对下标求和。二维情形下即求迹A_{ij} \Longrightarrow \sum_i A_{ii}其__new__第 1245-1266 行会调用_sort_contraction_indices对收缩索引组排序并通过_get_mapping_from_sub_ndim_list建立全局轴位置到子数组的映射结果形状为剔除被收缩轴后的剩余形状。源码_validate会校验收缩索引在有效范围内。_canonicalize()第 1268-1316 行的化简策略包括无收缩组时直接返回被作用表达式嵌套收缩合并denestArrayContraction(ArrayContraction(expr, ...), ...)合并为一组收缩收缩内穿 PermuteDimsArrayContraction(PermuteDims(...), ...)把置换吸收进收缩索引收缩下沉到张量积ArrayContraction(ArrayTensorProduct(A, B), (1, 2))是矩阵乘积的数组表达式形态对角与收缩的交互通过_ArrayContraction_denest_ArrayDiagonal等处理嵌套结构尺寸为 1 的轴上单索引收缩可被平凡消除必要时用Reshape修正形状。一个直观例子——ArrayContraction(M, (0, 1))表示矩阵M的迹而ArrayContraction(ArrayTensorProduct(M, N), (1, 2))表示M的第二轴与N的第一轴收缩即矩阵乘法见下文矩阵互转小节。3. ArrayDiagonal —— 取对角线ArrayDiagonal(expr, (i, j))让指定轴共享同一指标对角线化但不求和。二维矩阵情形A_{ij} \Longrightarrow A_{ii}源码文档字符串给出了一个高阶示例对A ⊗ B即A_{ab} B_{cd}的轴 1、2 取对角\Big[ A_{ab} B_{cd} \Big]_{abcd} \Longrightarrow \Big[ A_{ai} B_{id} \Big]_{adi}注意这个操作把 4 维数组降为 3 维新的对角线指标i只出现一次没有发生收缩求和收缩会把维度降到 2。关键实现细节第 929-953 行被对角化掉的轴会作为新维度追加到索引末尾这一点在推导形状时务必留意。4. PermuteDims —— 轴置换PermuteDims(expr, permutation)表示对数组轴的重排。矩阵转置就是最简单的置换 from sympy import MatrixSymbol from sympy.tensor.array.expressions import PermuteDims M MatrixSymbol(M, 3, 3) perm PermuteDims(M, (0 1)) # 轴 0 与轴 1 互换 perm.shape (3, 3)PermuteDims的__new__第 729-750 行要求置换大小必须等于表达式的维数否则抛出ValueError(Permutation size must be the length of the shape of expr)。除了显式传入Permutation对象还支持用指标顺序字符串间接描述置换第 683-691 行示例 M ArraySymbol(M, (1, 2, 3, 4, 5)) expr PermuteDims(M, index_order_oldijklm, index_order_newkijml) expr PermuteDims(M, (0 2 1)(3 4)) expr.shape (3, 1, 2, 5, 4)源码_get_permutation_from_index_orders第 917-926 行会校验新旧指标集合的一致性数量必须等于维数、两套指标必须相同否则报错permutation参数与index_order_new/index_order_old不能同时给出第 910-914 行。_canonicalize()第 752-769 行实现了一系列置换下沉化简复合嵌套置换PermuteDims(PermuteDims(expr, p1), p2)合并为单层PermuteDims(expr, p2*p1)穿过张量积_PermuteDims_denestarg_ArrayTensorProduct依据目标位置排序张量积因子把置换压到张量积内部得到排序后的因子与简化的残余置换文档示例中permutedims(tp, [2, 3, 1, 0])会把(M, N)排序为(N, M)置换从[2, 3, 1, 0]化简为[0, 1, 3, 2]穿过收缩_PermuteDims_denestarg_ArrayContraction将置换分摊到自由指标块并相应改写收缩索引置换为单位置换时直接返回被作用表达式。三、从索引显式形式构造数组表达式数组表达式是索引无关的但很多场景下我们习惯用下标形式书写。convert_indexed_to_array(expr, first_indices)接收索引显式表达式与指标顺序把它转换回数组表达式 from sympy.tensor.array.expressions import convert_indexed_to_array from sympy import Sum A ArraySymbol(A, (3, 3)) B ArraySymbol(B, (3, 3)) convert_indexed_to_array(A[i, j], [i, j]) A convert_indexed_to_array(A[i, j], [j, i]) PermuteDims(A, (0 1)) convert_indexed_to_array(A[i, j] B[j, i], [i, j]) ArrayAdd(A, PermuteDims(B, (0 1)))该函数实现在 from_indexed_to_array.py实现要点是把重复出现的自由指标视为对角ArrayDiagonal把被Sum求和的指标视为收缩ArrayContraction。下面两个例子非常直观矩阵对角线相同指标i出现两次、无求和 convert_indexed_to_array(A[i, i], [i]) ArrayDiagonal(A, (0, 1))矩阵迹相同指标被Sum求和 convert_indexed_to_array(Sum(A[i, i], (i, 0, 2)), [i]) ArrayContraction(A, (0, 1))矩阵乘法j为求和哑指标出现在两个因子中 convert_indexed_to_array(Sum(A[i, j]*B[j, k], (j, 0, 2)), [i, k]) ArrayContraction(ArrayTensorProduct(A, B), (1, 2))反过来convert_array_to_indexed实现在 from_array_to_indexed.py可以把数组表达式转换回索引显式形式。四、与矩阵模块的双向互操作数组表达式可以与矩阵模块的对象混用这在推导矩阵恒等式时非常有用。入口是convert_matrix_to_arrayfrom_matrix_to_array.py与convert_array_to_matrixfrom_array_to_matrix.py。矩阵乘法 ↔ 张量积 收缩 from sympy import MatrixSymbol from sympy.tensor.array.expressions import ArrayContraction, convert_matrix_to_array, convert_array_to_matrix M MatrixSymbol(M, 3, 3) N MatrixSymbol(N, 3, 3) expr convert_matrix_to_array(M*N) expr ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) convert_array_to_matrix(expr) M*N迹Trace↔ 收缩 from sympy import Trace convert_matrix_to_array(Trace(M)) ArrayContraction(M, (0, 1)) convert_matrix_to_array(Trace(M*N)) ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))转置 ↔ 轴置换 convert_matrix_to_array(M.T) PermuteDims(M, (0 1))多层收缩的化简doit()在上面的expr表示M*N上再对剩余两轴收缩即可得到Tr(M·N) expr_tr ArrayContraction(expr, (0, 1)) expr_tr ArrayContraction(ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), (0, 1))调用.doit()会执行_canonicalize()的嵌套合并逻辑array_expressions.py 第 267-272 行doit先深展开子表达式再统一 canonicalize把嵌套的两层收缩展平成单层四组索引的整体收缩 expr_tr.doit() ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))展开为显式数组as_explicit()任何数组表达式都可以调用as_explicit()展开为元素级表达式用于验证符号推导的正确性 expr.as_explicit() [[M[0, 0]*N[0, 0] M[0, 1]*N[1, 0] M[0, 2]*N[2, 0], ...], [M[1, 0]*N[0, 0] M[1, 1]*N[1, 0] M[1, 2]*N[2, 0], ...], [M[2, 0]*N[0, 0] M[2, 1]*N[1, 0] M[2, 2]*N[2, 0], ...]]这正是3×3矩阵乘积的逐元素展开式可作为与手算结果对照的标准答案。五、数组表达式的求导array_derivearray_derive实现在 arrayexpr_derivatives.py可以对数组表达式求导结果依然是数组表达式。矩阵对其自身的导数是最典型的例子 from sympy.tensor.array.expressions import array_derive d array_derive(M, M) d PermuteDims(ArrayTensorProduct(I, I), (3)(1 2))这里I是单位矩阵d表示一个四阶张量。展开验证其逐元素结果与显式矩阵求导完全一致 d.as_explicit() [[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], ...], ...] Me M.as_explicit() Me.diff(Me) [[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], ...], ...]两者逐元素相等说明数组表达式求导框架给出的结果是正确的。此外ArrayElement类实现了_eval_derivative第 125-135 行对不同数组元素求导返回 0对自身求导返回 1对同名不同下标返回 KroneckerDelta 的乘积——这是张量微积分自动化的底层基础。六、模块导出与辅助工具一览init.py 的__all__完整导出了以下 API表达式节点ArraySymbol、ArrayElement、ZeroArray、OneArray、ArrayTensorProduct、ArrayContraction、ArrayDiagonal、PermuteDims、ArrayAdd、ArrayElementwiseApplyFunc、Reshape转换函数convert_array_to_matrix、convert_matrix_to_array、convert_array_to_indexed、convert_indexed_to_array推导与化简array_derive、collect_tensor_products。其中collect_tensor_products来自 simplification.py用于在更复杂的表达式中聚集张量积因子ArrayAdd表示数组加法Reshape表示形状重塑ArrayElementwiseApplyFunc表示逐元素施加函数。这些节点与四大运算类一起构成了一个完整的 N 维数组符号表达式语言。七、深入阅读指引如果你希望进一步探索这个子系统建议按以下顺序阅读仓库源码sympy/tensor/array/expressions/init.py模块总入口包含运算符对应关系表与全部示例本文大量示例即源于此sympy/tensor/array/expressions/array_expressions.py全部表达式节点类的实现重点是_canonicalize系列化简方法sympy/tensor/array/expressions/from_indexed_to_array.py 与 from_array_to_indexed.py索引形式与数组表达式的双向转换sympy/tensor/array/expressions/from_matrix_to_array.py 与 from_array_to_matrix.py矩阵表达式与数组表达式的双向转换sympy/tensor/array/expressions/arrayexpr_derivatives.pyarray_derive求导实现sympy/tensor/array/expressions/utils.py收缩索引排序、映射构建、置换变换等内部工具sympy/tensor/array/expressions/tests 目录下的测试用例提供了大量运算结果应等于何种标准形式的回归验证样例与之配套的显式数组运算位于 sympy/tensor/array/arrayop.pytensorproduct、tensorcontraction、tensordiagonal、permutedims。总而言之sympy.tensor.array.expressions为 N 维数组提供了一套符号优先的操作语言先用四大节点搭建运算树再用_canonicalize/doit化简最后通过as_explicit、convert_*系列转换到需要的表示。无论你是想验证矩阵恒等式、推导张量微积分还是为自动微分或代码生成构建中间表示这套模块都是 SymPy 中值得优先使用的工具。【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。