十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

SymPy 微分几何模块(sympy.diffgeom)完全指南:从流形与坐标变换到黎曼曲率计算

SymPy 微分几何模块(sympy.diffgeom)完全指南:从流形与坐标变换到黎曼曲率计算 SymPy 微分几何模块sympy.diffgeom完全指南从流形与坐标变换到黎曼曲率计算【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy本篇技术指南以 SymPy 官方参考文档 doc/src/modules/diffgeom.rst 为骨架系统讲解纯 Python 计算机代数系统 SymPy 中微分几何子模块sympy.diffgeom的完整 API 与用法。读者将掌握如何定义流形、图册与坐标系如何执行坐标变换与雅可比计算如何构造标量场、向量场与 1-形式场如何使用李括号、外微分、张量积、楔积、李导数、协变导数等算符以及如何从度量直接计算 Christoffel 符号、黎曼张量与 Ricci 张量分量并在积分曲线计算中得到实战级运用。模块定位与设计思想sympy.diffgeom是 SymPy 中面向微分几何符号计算的核心模块源码位于 sympy/diffgeom/diffgeom.py约 2270 行配套的预定义流形位于 sympy/diffgeom/rn.py公共 API 导出清单见 sympy/diffgeom/init.py。从源码结构看模块的设计围绕三条主线展开几何基底对象Manifold流形→Patch图册/坐标片→CoordSystem坐标系层层嵌套构成点与场的空间背景场对象BaseScalarField标量场/坐标函数、BaseVectorField向量场、由Differential生成的 1-形式场它们都实现为 SymPy 的Expr子类可以直接参与符号运算与复合算符与张量构造器Commutator、TensorProduct、WedgeProduct、LieDerivative、BaseCovarDerivativeOp、CovarDerivativeOp以及一组面向度量的工具函数metric_to_Christoffel_1st、metric_to_Riemann_components等和积分曲线工具intcurve_series、intcurve_diffequ。其中covariant_order与contravariant_order两个辅助函数负责判定表达式的协变/逆变阶数是整个模块类型检查的基石几乎所有算符在求值前都会用它们做参数合法性校验例如 diffgeom.py 的 BaseVectorField.call会拒绝非标量场输入。基础对象流形、图册与坐标系Manifold流形Manifold(name, dim)接受流形名称与维度两个参数。它在数学上代表局部同胚于欧氏空间的拓扑空间但按 Manifold 的类文档 的说明该类不提供研究流形拓扑性质的手段只作为几何对象的容器与维度来源from sympy.diffgeom import Manifold m Manifold(M, 2) m # M m.dim # 2 m.name # M注意从源码可以看到Manifold现在是不可变对象__new__中直接以(name, dim)构造其patches属性已被废弃_deprecated_list自 1.7 起官方建议改用独立的 Python 列表来维护图册清单。Patch图册坐标片Patch(name, manifold)定义流形上的一个单连通开集坐标片在其上可以建立坐标卡chart以便用实数元组参数化每一个点from sympy.diffgeom import Manifold, Patch m Manifold(M, 2) p Patch(P, m) p # P p.dim # 2Patch不提供研究其拓扑性质的接口见 Patch 类文档其coord_systems属性同样已废弃。参考文档中该类的参考文献指向 G. Sussman、J. Wisdom、W. Farr 的著作Functional Differential Geometry2013这也是本模块设计思路的重要来源。CoordSystem坐标系与坐标变换CoordSystem是使用频率最高的基础类。构造签名与参数含义如下见 CoordSystem 类文档参数类型含义namestr坐标系名称patchPatch坐标系所在的坐标片symbolslist of Symbol可选坐标符号的名称与假设不传时自动生成并默认假设为实数值Symbol(name_i, realTrue)relationsdict可选坐标变换关系键为(源系统名, 目标系统名)二元组值为(变换前符号, 变换后表达式)二元组relations是模块实现坐标变换的核心机制逆向变换与间接变换都可以由它自动推导源码注释明确说明 Inverse transformation and indirect transformation can be found automatically。经典的两维直角坐标与极坐标示例from sympy import symbols, pi, sqrt, atan2, cos, sin from sympy.diffgeom import Manifold, Patch, CoordSystem m Manifold(M, 2) p Patch(P, m) x, y symbols(x y, realTrue) r, theta symbols(r theta, nonnegativeTrue) relation_dict { (Car2D, Pol): [(x, y), (sqrt(x**2 y**2), atan2(y, x))], (Pol, Car2D): [(r, theta), (r*cos(theta), r*sin(theta))] } Car2D CoordSystem(Car2D, p, (x, y), relation_dict) Pol CoordSystem(Pol, p, (r, theta), relation_dict)构造完成后CoordSystem提供一组核心方法transformation(sys)返回从self到sys的变换函数sympy.LambdaCar2D.transformation(Pol) # Lambda((x, y), Matrix([ # [sqrt(x**2 y**2)], # [ atan2(y, x)]]))transform(sys, coordinatesNone)直接返回变换后的坐标矩阵不传坐标时使用自身坐标符号也可传入数值坐标Car2D.transform(Pol) # Matrix([[sqrt(x**2 y**2)], [atan2(y, x)]]) Car2D.transform(Pol, [1, 2]) # Matrix([[sqrt(5)], [atan(2)]])jacobian(sys, coordinatesNone)与jacobian_determinant(sys, coordinatesNone)返回变换的雅可比矩阵与雅可比行列式Pol.jacobian(Car2D) # Matrix([ # [cos(theta), -r*sin(theta)], # [sin(theta), r*cos(theta)]]) Pol.jacobian(Car2D, [1, pi/2]) # Matrix([[0, -1], [1, 0]]) Car2D.jacobian_determinant(Pol) # 1/sqrt(x**2 y**2)从源码实现看transformation()的求值顺序为同系统恒等变换 → 在relations中直接命中 → 通过_solve_inverse求逆借助sympy.solvers.solve解方程组无解抛NotImplementedError多解抛ValueError→ 通过_indirect_transformation借助Dijkstra 最短路径算法_dijkstra在关系图中寻找中转路径并逐段代入合成。这些行为均有 tests/test_diffgeom.py 的 test_coordsys_transform 覆盖包括不可逆变换抛 NotImplementedError多解抛 ValueErrorC1→C2→C3 间接变换等边界场景。CoordinateSymbol带上下文的坐标符号CoordSystem.symbols属性返回的不是构造时传入的普通Symbol而是一组CoordinateSymbol实例见 CoordinateSymbol 类文档。它包装了属于哪个坐标系、是第几个坐标的上下文信息x, y Car2D.symbols x.name # x x.coord_sys Car2D # True x.index # 0 x.is_real # True其亮点在于rewrite()方法可以把坐标符号乃至包含它的任意表达式改写为另一个坐标系下的表示x.rewrite(Pol) # r*cos(theta) sqrt(x**2 y**2).rewrite(Pol).simplify() # r预定义流形R2 与 R3sympy/diffgeom/rn.py 预置了二维与三维欧氏流形以及常见坐标系并内置了坐标变换关系与全部基础场对象开箱即用R2R2_rrectangular 直角坐标坐标x, y与R2_ppolar 极坐标坐标rho, theta源码中符号取非负假设nonnegativeTrue变换关系见relations_2dR3R3_r直角坐标x, y, z、R3_c柱坐标rho, psi, z、R3_s球坐标r, theta, phi六个方向的变换对全部定义在relations_3d中。为了使用方便rn.py 在流形、图册与坐标系三个层次上都挂载了快捷属性from sympy.diffgeom.rn import R2, R2_r, R2_p R2.x, R2.y # 直角坐标函数标量场 R2.r, R2.theta # 极坐标函数 R2.e_x, R2.e_y # 直角基向量场 R2.e_r, R2.e_theta # 极坐标基向量场 R2.dx, R2.dy # 直角基 1-形式 R2.dr, R2.dtheta # 极坐标基 1-形式因此可以直接写R2.x、R2.e_y、R2.dx这种高度贴近教材记号的表达式让示例代码极其简洁。点与三类基本场Point点数学上点属于流形、本身没有坐标坐标由坐标卡赋予由于实现上的限制Point(coord_sys, coords)必须同时给定坐标系与坐标见 Point 类文档from sympy import pi from sympy.diffgeom import Point from sympy.diffgeom.rn import R2, R2_r, R2_p rho, theta R2_p.symbols p Point(R2_p, [rho, 3*pi/4]) p.manifold R2 # True p.coords() # Matrix([[rho], [3*pi/4]]) p.coords(R2_r) # 自动变换到直角坐标 # Matrix([[-sqrt(2)*rho/2], # [ sqrt(2)*rho/2]])coords(sysNone)不传参数返回定义时的坐标传坐标系则自动执行变换。虽然点的用法与定义时坐标系无关但文档与源码都提醒若选用不合适的坐标系表达式可能因化简局限而变得复杂。BaseScalarField标量场坐标函数标量场将点映射为标量某坐标系的基础标量场则返回该点在该坐标系中的第index个坐标见 BaseScalarField 类文档。CoordSystem.base_scalar(index)/base_scalars()用于构造别名coord_function/coord_functionsfrom sympy import Function, pi from sympy.diffgeom import BaseScalarField from sympy.diffgeom.rn import R2_r, R2_p rho, _ R2_p.symbols point R2_p.point([rho, 0]) fx, fy R2_r.base_scalars() ftheta BaseScalarField(R2_r, 1) fx(point) # rho 点在极坐标下第一个坐标为 rho fy(point) # 0 (fx**2 fy**2).rcall(point) # rho**2 g Function(g) fg g(ftheta - pi) fg.rcall(point) # g(-pi)由于BaseScalarField是Expr子类任意 SymPy 表达式加法、乘法、复合函数都能自然地构成复合标量场。__call__中传入Point时才求值传入其他对象则原样返回自身以保证所有场对象可以递归复合调用。BaseVectorField向量场方向导数算符向量场是作用于标量场、返回方向导数的算符基向量场则专门针对某个坐标求偏导见 BaseVectorField 类文档from sympy import Function, pprint from sympy.diffgeom import BaseVectorField from sympy.diffgeom.rn import R2_p, R2_r x, y R2_r.symbols rho, theta R2_p.symbols fx, fy R2_r.base_scalars() point_p R2_p.point([rho, theta]) g Function(g) s_field g(fx, fy) v BaseVectorField(R2_r, 1) # 即 ∂/∂y pprint(v(s_field)) # / d \| # |---(g(x, xi))|| # \dxi /|xiy pprint(v(s_field).rcall(point_p)) # / d \| # |---(g(rho*cos(theta), xi))|| # \dxi /|xirho*sin(theta)从源码看__call__的实现分两步先把标量场中的所有BaseScalarField替换为占位函数并求导得到链式法则骨架再借助coord_sys.jacobian()把各基坐标对目标坐标的偏导代入完成任意两个坐标系之间基向量作用的换算。这也解释了为何结果中常出现 Jacobian 矩阵的分量。微分几何核心算符Commutator李括号两个向量场的李括号[v1, v2]定义为对任意标量场f满足v1(v2(f)) - v2(v1(f))的向量场见 Commutator 类文档from sympy import simplify from sympy.diffgeom import Commutator from sympy.diffgeom.rn import R2_p, R2_r fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() e_r R2_p.base_vector(0) Commutator(e_x, e_y) # 0 同一坐标系的基向量对合 c_xr Commutator(e_x, e_r) # Commutator(e_x, e_rho)跨坐标系保留为符号对象 simplify(c_xr(fy**2)) # -2*cos(theta)*y**2/(x**2 y**2)源码行为值得注意若两个向量场只涉及同一个坐标系且都是基向量场则直接返回S.Zero若跨坐标系且无法立即化简则保留为Commutator符号对象待施加到标量场时再通过v1(v2(f)) - v2(v1(f))展开求值。Differential外微分Differential表示形式的微分外微分。对 0-形式f其微分df满足df(v) v(f)见 Differential 类文档from sympy import Function from sympy.diffgeom import Differential from sympy.diffgeom.rn import R2_r fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() g Function(g) s_field g(fx, fy) dg Differential(s_field) dg # d(g(x, y)) dg(e_x) # dg 作用在 e_x 上 e_x(g)得到关于 x 的偏导 Differential(dg) # 0 外微分两次必为零dd 0源码在构造时就处理了两个关键情形传入向量场会直接抛ValueError对已是Differential的对象再取微分则返回S.Zero即庞加莱引理d²0的实现。对高阶形式__call__使用外微分的不变公式源码注释链接到维基百科 Exterior derivative#Invariant formula通过替换每对向量场为其李括号来完成求值。TensorProduct张量积张量积由低阶场构造多线性泛函高阶张量但它不具反对称性因此不是形式场见 TensorProduct 类文档from sympy.diffgeom import TensorProduct from sympy.diffgeom.rn import R2_r fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() dx, dy R2_r.base_oneforms() TensorProduct(dx, dy)(e_x, e_y) # 1 TensorProduct(dx, dy)(e_y, e_x) # 0 非反对称 TensorProduct(dx, fx*dy)(fx*e_x, e_y) # x**2 TensorProduct(e_x, e_y)(fx**2, fy**2) # 4*x*y TensorProduct(e_y, dx)(fy) # dx 部分收缩 # 张量积可嵌套 tp1 TensorProduct(dx, dy) TensorProduct(tp1, dx)(e_x, e_y, e_x) # 1张量积支持部分收缩partial contraction即提升指标操作在rcall的参数中放入None保留对应位置参数不足时还会自动补NoneTP TensorProduct metric TP(dx, dx) 3*TP(dy, dy) metric.rcall(e_y, None) # 3*dy metric.rcall(e_y) # 3*dy 自动补齐 None__new__会把纯标量因子提出作为系数只对真正的多线性场做乘积__call__则按内部各因子阶数把输入参数切分成子列表再逐段作用。这套机制正是后面构造度量张量TP(dx, dx) TP(dy, dy)的基础。WedgeProduct楔积积分语境下只有完全反对称的形式才有意义楔积正是构造这类形式的工具见 WedgeProduct 类文档from sympy.diffgeom import WedgeProduct from sympy.diffgeom.rn import R2_r fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() dx, dy R2_r.base_oneforms() WedgeProduct(dx, dy)(e_x, e_y) # 1 WedgeProduct(dx, dy)(e_y, e_x) # -1 反对称 WedgeProduct(dx, fx*dy)(fx*e_x, e_y) # x**2 WedgeProduct(e_x, e_y)(fy, None) # -e_x # 可嵌套 wp1 WedgeProduct(dx, dy) WedgeProduct(wp1, dx)(e_x, e_y, e_x) # 0从实现看WedgeProduct.__call__会把自身展开为所有参数排列的带符号由Permutation.signature()给出张量积之和再乘以各因子阶数阶乘倒数归一化——这就是反对称化的标准算法。源码注释也坦诚指出该计算涉及全排列速度偏慢。LieDerivative李导数李导数由向量场沿其积分曲线的推前pushforward定义见 LieDerivative 类文档from sympy.diffgeom import LieDerivative, TensorProduct from sympy.diffgeom.rn import R2_r, R2_p fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() e_rho, e_theta R2_p.base_vectors() dx, dy R2_r.base_oneforms() LieDerivative(e_x, fy) # 0 对常值标量场 LieDerivative(e_x, fx) # 1 LieDerivative(e_x, e_x) # 0 # 李导数作用于向量场退化为李括号 LieDerivative(e_x, e_rho) # Commutator(e_x, e_rho) LieDerivative(e_x e_y, fx) # 1 tp TensorProduct(dx, dy) LieDerivative(e_x, tp) # LieDerivative(e_x, TensorProduct(dx, dy))构造逻辑源码 LieDerivative.new非常清晰对含基向量场的表达式返回Commutator(v_field, expr)对纯标量场直接返回v_field.rcall(expr)方向导数对高阶形式则保留为符号对象求值时按v(expr(*args))减去各位置的李括号项展开。BaseCovarDerivativeOp 与 CovarDerivativeOp协变导数协变导数需要 Christoffel 符号数据因此这两个类的构造都要传入由metric_to_Christoffel_2nd生成的连接系数数组见 BaseCovarDerivativeOp 与 CovarDerivativeOp 类文档from sympy.diffgeom import BaseCovarDerivativeOp, CovarDerivativeOp from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct from sympy.diffgeom.rn import R2_r TP TensorProduct fx, fy R2_r.base_scalars() e_x, e_y R2_r.base_vectors() dx, dy R2_r.base_oneforms() # 平面直角度量 ds² dx² dy² 的 Christoffel 符号全零 ch metric_to_Christoffel_2nd(TP(dx, dx) TP(dy, dy)) ch # [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] # 沿基向量 e_x 的协变导数 cvd BaseCovarDerivativeOp(R2_r, 0, ch) cvd(fx) # 1 cvd(fx*e_x) # e_x # 沿任意向量场 f_x*e_x 的协变导数 cvd2 CovarDerivativeOp(fx*e_x, ch) cvd2(fx) # x cvd2(fx*e_x) # x*e_xBaseCovarDerivativeOp的求值分三步源码call先把字段中的向量替换为占位函数并沿目标基方向求导再把占位函数的导数替换为按 Christoffel 符号展开的Γᵏ_μν e_k线性组合最后换回原向量完成化简。CovarDerivativeOp则是把wrt向量场中的每个基向量替换为对应的BaseCovarDerivativeOp后递归调用。积分曲线工具intcurve_series积分曲线的级数展开intcurve_series(vector_field, param, start_point, n6, coord_sysNone, coeffsFalse)返回向量场积分曲线γ(t)的泰勒级数展开默认阶数n6满足方程V(f)(γ(t)) d/dt f(γ(t))见 intcurve_series 文档from sympy.abc import t, x, y from sympy.diffgeom.rn import R2_p, R2_r from sympy.diffgeom import intcurve_series start_point R2_r.point([x, y]) vector_field R2_r.e_x intcurve_series(vector_field, t, start_point, n3) # Matrix([[t x], [y]]) # coeffsTrue 时逐阶返回展开系数列表 series intcurve_series(vector_field, t, start_point, n3, coeffsTrue) series[0] # Matrix([[x], [y]]) series[1] # Matrix([[t], [0]]) series[2] # Matrix([[0], [0]]) # 在极坐标系中展开自动执行坐标变换 series intcurve_series(vector_field, t, start_point, n3, coord_sysR2_p, coeffsTrue) series[1] # Matrix([[t*x/sqrt(x**2 y**2)], [-t*y/(x**2 y**2)]])实现上每个坐标方向的泰勒项为t^i / i! · Vⁱ(f)(start_point)Vⁱ表示向量场反复作用i次完全对应泰勒定理的算子形式。这也是检验向量场几何性质的实用工具。intcurve_diffequ积分曲线的微分方程intcurve_diffequ(vector_field, param, start_point, coord_sysNone)返回积分曲线所满足的常微分方程组及其初值条件返回(equations, init_cond)二元组见 intcurve_diffequ 文档from sympy.abc import t from sympy.diffgeom.rn import R2, R2_p, R2_r from sympy.diffgeom import intcurve_diffequ start_point R2_r.point([0, 1]) vector_field -R2.y*R2.e_x R2.x*R2.e_y # 绕原点的旋转场 equations, init_cond intcurve_diffequ(vector_field, t, start_point) equations # [f_1(t) Derivative(f_0(t), t), -f_0(t) Derivative(f_1(t), t)] init_cond # [f_0(0), f_1(0) - 1] # 换到极坐标系方程立刻变成常数系数形式 equations, init_cond intcurve_diffequ(vector_field, t, start_point, R2_p) equations # [Derivative(f_0(t), t), Derivative(f_1(t), t) - 1] init_cond # [f_0(0) - 1, f_1(0) - pi/2]源码用Function(f_%d)生成曲线各坐标分量的待定函数方程为d/dt f_i(t) - V(f_i)(γ(t)) 0初值条件为f_i(0) - f_i(start_point) 0。这个例子直观展示了选对坐标系如何让同一几何对象从耦合方程组退化为平凡方程。面向度量的张量分量计算这组函数是模块的重头戏给定度量张量以 1-形式的张量积表示自动完成从 Christoffel 符号到黎曼、Ricci 张量的整条计算链。twoform_to_matrix二形式转矩阵twoform_to_matrix(expr)把二形式w表示为矩阵M[i,j] w(e_i, e_j)见 twoform_to_matrix 文档from sympy.diffgeom.rn import R2 from sympy.diffgeom import twoform_to_matrix, TensorProduct TP TensorProduct twoform_to_matrix(TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # 单位阵 twoform_to_matrix(R2.x*TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # Matrix([[x, 0], [0, 1]]) twoform_to_matrix(TP(R2.dx, R2.dx) TP(R2.dy, R2.dy) - TP(R2.dx, R2.dy)/2) # Matrix([[1, 0], [-1/2, 1]])源码会校验输入必须是纯协变二阶形式covariant_order 2且逆变阶为 0并要求表达式只涉及单一坐标系否则抛出ValueError。metric_to_Christoffel_1st 与 metric_to_Christoffel_2ndmetric_to_Christoffel_1st(expr)返回度量对应的 Levi-Civita 联络的第一类 Christoffel 符号Γ_{kij} ½(∂ₖgᵢⱼ ∂ⱼgᵢₖ − ∂ᵢgⱼₖ)。实现中先检查度量矩阵是否对称matrix.is_symmetric()非对称直接报错再对各基向量求导组合见 源码metric_to_Christoffel_1st(TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] metric_to_Christoffel_1st(R2.x*TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # [[[1/2, 0], [0, 0]], [[0, 0], [0, 0]]]metric_to_Christoffel_2nd(expr)返回第二类 Christoffel 符号Γᵢⱼₖ Σₗ gⁱˡ Γₗⱼₖ通过逆度量矩阵提升指标。源码注释透露一个工程细节由于逆矩阵运算对含非符号元素BaseScalarField的矩阵不直接支持实现采用把标量场替换成普通符号 → 求逆 → 再替换回来的 workaround见 源码metric_to_Christoffel_2nd(R2.x*TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # [[[1/(2*x), 0], [0, 0]], [[0, 0], [0, 0]]]metric_to_Riemann_components黎曼张量分量metric_to_Riemann_components(expr)在度量表达式所在坐标系的规范基下计算黎曼张量分量见 源码。标准示例是二维指数度规from sympy import exp from sympy.diffgeom.rn import R2 from sympy.diffgeom import metric_to_Riemann_components, TensorProduct TP TensorProduct # 平直度量 → 黎曼张量全零 metric_to_Riemann_components(TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # [[[[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]] # 非平凡度量ds² exp(2ρ) dρ² ρ² dθ² non_trivial_metric exp(2*R2.r)*TP(R2.dr, R2.dr) R2.r**2*TP(R2.dtheta, R2.dtheta) riemann metric_to_Riemann_components(non_trivial_metric) riemann[0, :, :, :] # [[[0, 0], [0, 0]], [[0, exp(-2*rho)*rho], [-exp(-2*rho)*rho, 0]]] riemann[1, :, :, :] # [[[0, -1/rho], [1/rho, 0]], [[0, 0], [0, 0]]]实现分为两部分对应黎曼张量的标准分解riemann_a为 Christoffel 符号偏导之差∂_μ Γ − ∂_ν Γriemann_b为 Christoffel 符号乘积之差ΓΓ − ΓΓ两者相加得到完整分量。metric_to_Ricci_componentsRicci 张量分量metric_to_Ricci_components(expr)通过对黎曼张量的第一个与第三个指标缩并得到 Ricci 张量R_ij Σ_k Rᵏ_ikj见 源码from sympy import exp from sympy.diffgeom.rn import R2 from sympy.diffgeom import metric_to_Ricci_components, TensorProduct TP TensorProduct metric_to_Ricci_components(TP(R2.dx, R2.dx) TP(R2.dy, R2.dy)) # [[0, 0], [0, 0]] non_trivial_metric exp(2*R2.r)*TP(R2.dr, R2.dr) R2.r**2*TP(R2.dtheta, R2.dtheta) metric_to_Ricci_components(non_trivial_metric) # [[1/rho, 0], [0, exp(-2*rho)*rho]]向量场换基vectors_in_basisvectors_in_basis(expr, to_sys)把表达式中的基向量全部改写成目标坐标系基向量的线性组合系数保留在原坐标系表达式中见 源码from sympy.diffgeom import vectors_in_basis from sympy.diffgeom.rn import R2_r, R2_p vectors_in_basis(R2_r.e_x, R2_p) # -y*e_theta/(x**2 y**2) x*e_rho/sqrt(x**2 y**2) vectors_in_basis(R2_p.e_r, R2_r) # sin(theta)*e_y cos(theta)*e_x实现利用cs.jacobian(to_sys, ...)的转置矩阵与目标坐标系基向量列向量做矩阵乘法(Jᵀ · [e₁, …, eₙ])ᵢ这正是基向量变换的经典公式。该函数是BaseCovarDerivativeOp内部把任意坐标系字段规整到同一基底的前提。场的类型判定covariant_order 与 contravariant_ordercovariant_order(expr)与contravariant_order(expr)返回表达式的协变/逆变阶数见 源码它们是所有算符参数校验的基础工具from sympy.diffgeom import contravariant_order, covariant_order from sympy.diffgeom.rn import R2 from sympy.abc import a contravariant_order(a) # 0 contravariant_order(a*R2.x 2) # 0 contravariant_order(a*R2.x*R2.e_y R2.e_x) # 1 covariant_order(a*R2.x*R2.dy R2.dx) # 1判定规则从源码可见Add要求各项阶数一致否则报错Mul最多允许一个非零阶因子Pow不允许底或指数含场BaseVectorField的逆变阶为 1Differential使协变阶 1TensorProduct的阶数为各因子阶数之和。正是靠这对函数Differential能拒绝向量场输入、Commutator能拒绝非向量场输入、twoform_to_matrix能识别必须是二形式。一个完整实战从度量到曲率标量的流水线把上面的工具串联起来只需几行代码即可完成给定度规 → Christoffel → 黎曼 → Ricci的完整曲率计算链这在广义相对论与微分几何的符号推导中非常实用from sympy import exp, simplify from sympy.diffgeom.rn import R2 from sympy.diffgeom import (TensorProduct, metric_to_Christoffel_1st, metric_to_Christoffel_2nd, metric_to_Riemann_components, metric_to_Ricci_components) TP TensorProduct g exp(2*R2.r)*TP(R2.dr, R2.dr) R2.r**2*TP(R2.dtheta, R2.dtheta) Gamma1 metric_to_Christoffel_1st(g) # 第一类 Christoffel 符号 Gamma2 metric_to_Christoffel_2nd(g) # 第二类 Christoffel 符号协变导数用 Riem metric_to_Riemann_components(g) # 黎曼张量分量 Ricci metric_to_Ricci_components(g) # Ricci 张量分量 Ricci # Matrix([[1/rho, 0], [0, exp(-2*rho)*rho]])版本兼容性说明从源码中的sympy_deprecation_warning调用可以确认diffgeom.py 等多处自SymPy 1.7起本模块有一批旧的可变接口被废弃写作本文时这些旧接口仍可用但会发出警告CoordSystem.connect_to()→ 改用构造时的relations关键字参数CoordSystem现在不可变CoordSystem.coord_tuple_transform_to()→ 改用transform()CoordSystem(..., names...)→ 改用symbols[Symbol(..., realTrue), ...]向symbols传字符串如[x, y]→ 改为传带假设的SymbolManifold.patches、Patch.coord_systems、CoordSystem.transforms等属性 → 用独立的普通 Python 容器自行维护。新代码应一律采用relations字典式构造官方文档 doc/src/modules/diffgeom.rst 所列的 14 个类Manifold、Patch、CoordSystem、CoordinateSymbol、Point、BaseScalarField、BaseVectorField、Commutator、Differential、TensorProduct、WedgeProduct、LieDerivative、BaseCovarDerivativeOp、CovarDerivativeOp与 8 个函数intcurve_series、intcurve_diffequ、vectors_in_basis、twoform_to_matrix、metric_to_Christoffel_1st、metric_to_Christoffel_2nd、metric_to_Riemann_components、metric_to_Ricci_components即构成该模块的完整公共 API全部通过 sympy/diffgeom/init.py 在from sympy.diffgeom import ...下直接可用。进一步阅读模块参考文档doc/src/modules/diffgeom.rst本文依据的官方文档骨架核心实现源码sympy/diffgeom/diffgeom.py预定义流形 R2/R3sympy/diffgeom/rn.py公共 API 导出sympy/diffgeom/init.py测试用例覆盖坐标变换、R2/R3 恒等式、曲率计算等sympy/diffgeom/tests/test_diffgeom.py、sympy/diffgeom/tests/test_class_structure.py、sympy/diffgeom/tests/test_function_diffgeom_book.py、sympy/diffgeom/tests/test_hyperbolic_space.py需要注意的是本文所有示例均来自源码内嵌 docstring 与测试断言可直接在from sympy.diffgeom import ...之后于交互式环境如 isympy.py中原样运行验证部分结果在文档中标记为doit()/simplify()之后的形式实际打印可能保留Subs或三角函数结构属正常现象。【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表