
SymPy 量纲与量纲系统完全指南理解 Dimension 与 DimensionSystem 的底层原理【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympySymPy 的sympy.physics.units模块在纯 Python 中构建了一套完整的单位系统框架而**量纲Dimension与量纲系统DimensionSystem**正是这套框架的地基。本文以官方 API 文档 dimensions.rst 为核心结合 dimensions.py 的完整实现与 test_dimensions.py 的测试用例深入讲解量纲的创建、代数运算规则、量纲系统的构建方法以及它在 SI、MKSA、自然单位制等真实系统中的实际应用。读完本文你将能熟练使用Dimension进行量纲推导、利用DimensionSystem解析量纲依赖并理解 SymPy 单位换算背后的量纲机制。一、为什么需要量纲物理量的类型系统在经典力学中时间与温度是截然不同的物理概念量纲dimension正是用来在符号层面区分它们的工具。与数值度量不同量纲不提供任何数值大小信息它只回答这个物理量是什么这一类型问题——可以把它理解为物理量的类型系统就像编程语言禁止把字符串与整数相加一样量纲系统禁止把长度与时间直接相加。在 SymPy 中Dimension是一个继承自Expr的表达式子类见 dimensions.py其类定义中标注了is_commutative True、is_number False、is_positive True、is_real True这保证了量纲对象能像普通符号表达式一样参与 SymPy 的代数运算同时始终被当作正实数处理例如使sqrt(M**2)能化简为M。量纲模块的 docstring 中有一个重要设计说明同一物理量在不同单位制中可能拥有不同的量纲地位。例如在 MKS 中长度与时间不可相加但在自然单位制natural system中由于c 1长度与时间在量纲上等价计算机的维度基中甚至不存在时间这一维而只有速度维——因此把时间加到长度上这个问题在自然单位制中根本没有意义。这一点是理解后续DimensionSystem多样性的关键。二、Dimension 的创建与基本属性Dimension的构造函数接受两个参数name量纲名称必填与symbol符号表示可选。名称既可以是字符串也可以是 SymPy 表达式 from sympy.physics.units import Dimension length Dimension(length) length Dimension(length) time Dimension(time) time Dimension(time)在底层实现中dimensions.py字符串名称会被自动转换为Symbol构造时会校验名称必须是合法的数学表达式Expr否则抛出TypeError。symbol参数必须为字符串或Symbol测试用例 test_dimensions.py 验证了传入其他类型会触发AssertionError。内置的常用量纲定义在 dimension_definitions.py 中可以看到它们如何携带符号length Dimension(namelength, symbolL) mass Dimension(namemass, symbolM) time Dimension(nametime, symbolT) force Dimension(nameforce, symbolF) energy Dimension(nameenergy, symbolE) angle Dimension(nameangle)其中L、M、T是 MKS 基础量纲current电流符号I是 MKSA 新增的基础量纲temperature、amount_of_substance、luminous_intensity是 SI 追加的基础量纲。其余如velocity、acceleration、momentum、power、pressure、frequency、action、voltage、charge等则属于导出量纲derived dimensions。每个Dimension对象都有两个只读属性name返回其名称表达式symbol返回其符号可能为None。字符串表示str(Dimension(length, L))输出为Dimension(length, L)。三、Dimension 的代数运算规则量纲可以像普通表达式一样通过乘法、除法与乘方组合出新的量纲这是量纲分析的核心能力 velocity length / time velocity Dimension(length/time) l2 length**2 l2 Dimension(length**2)3.1 乘、除、幂运算从 dimensions.py 的实现可以看到__pow__/_eval_power指数会被sympify化新量纲表示为Dimension(self.name**other)因此支持分数次幂与符号次幂如sqrt(length)即length**S.Half__mul__两个Dimension相乘得到Dimension(self.name * other.name)若乘以无量纲数值other.free_symbols为空则返回自身因为量纲乘以纯数不变__truediv__定义为self * Pow(other, -1)与普通 SymPy 表达式行为一致。测试 test_dimensions.py 验证了这些规则2*length length*2 length/2 length纯数缩放不改变量纲、length**2与length*length等价、length/length的量纲依赖为空字典{}即无量纲、length**-1对应{length: -1}。3.2 加法与减法只有同量纲才合法加法与减法的规则更为严格只有两个完全相同的量纲才能相加/相减结果为原量纲不同量纲相加则报错。由于量纲之间不存在大小或顺序的概念减法的实现直接复用加法dimensions.py length length Dimension(length)有趣的是Dimension的__add__实现dimensions.py区分了两种场景若另一个操作数是同量纲的Dimension返回自身若操作数是普通符号或数值如length x、length 1则允许通过并保持为一个Add表达式因为这种情况下符号x可以被解释为以 length 为单位的数。这对应 GitHub issue 14547 的处理逻辑。但若操作数包含Quantity单位对象则抛出TypeError(cannot sum dimension and quantity)。测试用例 test_dimensions.py 完整覆盖了这些行为raises(TypeError, lambda: length foot) # 量纲对象与单位对象不可相加 raises(TypeError, lambda: length - foot) x Symbol(x) e length x # 与普通符号相加被允许 assert e.is_Add and set(e.args) {length, x}3.3 负号量纲没有方向__neg__直接返回自身dimensions.py即-length length。这与减法语义一致量纲只描述维度构成不携带方向或大小。四、DimensionSystem一组自洽的量纲单个量纲只能描述是什么而一组量纲及其相互依赖关系则构成量纲系统。DimensionSystem类dimensions.py同时继承Basic与_QuantityMapper其构造函数接受三个参数base_dims基础量纲basis如 MKS 中的length、mass、timederived_dims导出量纲它们由基础量纲组合定义如velocity由length / time定义可选dimensional_dependencies维度依赖字典说明每个导出量纲如何依赖基础量纲可选。构造函数内部会做一系列规范化dimensions.py字符串与Symbol会被统一转换为Dimension基础量纲若未在依赖字典中会自动登记为{dim: 1}幂为 1 的自依赖出现在依赖字典键中但既非基础也非导出的量纲会被自动追加到derived_dims同时校验同一量纲不能同时是基础与导出抛出ValueError、基础量纲重复定义抛出IndexError。最终三个参数被存入args元组分别由只读属性base_dims、derived_dims、dimensional_dependencies暴露。4.1 核心方法get_dimensional_dependencies这是量纲系统最常用的方法返回给定量纲在基础量纲基下的幂指数字典。以 SI 量纲系统为例其维度系统为dimsys_SI定义于 si.py from sympy.physics.units.systems.si import dimsys_SI dimsys_SI.get_dimensional_dependencies(velocity) {Dimension(length, L): 1, Dimension(time, T): -1} dimsys_SI.get_dimensional_dependencies(l2) {Dimension(length, L): 2}从实现看dimensions.py该方法会对量纲名称表达式做递归分解名称是单个Symbol时直接在依赖字典中查表未登记的量纲视为基础量纲返回{dim: 1}名称是数字或数值常量如pi时返回空字典{}无量纲名称是Mul时对每个因子递归求依赖并按幂指数相加名称是Add时要求所有加数的依赖字典完全一致否则抛出TypeError(Only equivalent dimensions can be added or subtracted.)——这正是同量纲才能相加在系统层面的强制校验名称是Pow时底数的依赖指数乘以幂指数若指数本身不是符号或无量纲表达式则报错名称是函数如三角函数、log、sqrt、Abs时对参数做特殊处理详见第六节。它还提供mark_dimensionless参数当量纲依赖为空时可返回{Dimension(1): 1}以显式标记无量纲。4.2 其他实用方法equivalent_dims(dim1, dim2)比较两个量纲的依赖字典是否完全相等用于判断量纲是否等价。例如sqrt(a**2 b**2)其中a、b均为长度量纲与length等价对应 issue 18738 的修复。is_dimensionless(dimension)当量纲名称为 1或依赖字典为空时返回True。注意测试验证了Dimension(undefined)未登记量纲返回False——因为未登记量纲会被当作基础量纲处理。extend(new_base_dims, new_derived_dims(), new_dim_depsNone)在现有系统基础上追加新的基础量纲、导出量纲与依赖关系返回新的DimensionSystem同时继承原系统的量纲映射与比例因子映射。SI 量纲系统正是这样从 MKSA 逐级扩展而来的见 si.pydimsys_SI dimsys_MKSA.extend([temperature, amount_of_substance, luminous_intensity])dimsys_default dimsys_SI.extend([information])。has_integer_powers(dim_sys)检查量纲的所有幂指数是否都是整数。中间计算可能出现分数次幂如sqrt(length)的依赖为{length: 1/2}该方法用于确认最终结果良定义。测试 test_dimensions.py 验证了length**1.5返回False。print_dim_base(dim)以基础量纲符号的幂乘积形式输出量纲的字符串表达式如L**1*M**1*T**-2形式的符号表达式。此外该类还保留了list_can_dims、inv_can_transf_matrix、can_transf_matrix、dim_can_vector、dim_vector、dim、is_consistent等属性它们在源码 docstring 中均被明确标注为 Useless method, kept for compatibility with previous versions. DO NOT USE.——即仅为兼容旧版本而保留不建议在新代码中使用。五、内置量纲系统从 MKS 到 SI 与自然单位制5.1 MKS / MKSA / SI 的逐级扩展SymPy 的内置单位系统展示了量纲系统的层次化扩展思想详见 systems/mksa.py 与 systems/si.pyMKS基础量纲为length、mass、time即米-千克-秒MKSA在 MKS 基础上追加current安培作为基础量纲并通过new_dim_deps给出电磁学导出量纲的显式依赖例如voltage: {mass: 1, length: 2, current: -1, time: -3}, charge: {current: 1, time: 1}, impedance: {mass: 1, length: 2, current: -2, time: -3},SI在 MKSA 基础上再追加temperature、amount_of_substance、luminous_intensity三个基础量纲见 si.py形成完整的七个基础量纲体系。这种扩展是理解单位换算的关键convert_to的结果依赖所选单位系统的量纲结构。例如在 SI 中电流是基础量纲convert_to(ampere, [meter, gram, second], SI)无法换算而原样返回但在cgs_gauss单位制中电流不是基础量纲可以表示为长度、质量、时间的组合换算结果变为149896229*sqrt(gram)*meter**(3/2)/(50*second**2)示例见 index.rst。5.2 自然单位制更换基底的范例自然单位制systems/natural.py展示了量纲系统更激进的用法——令 c 1, hbar 1意味着用速度与作用量替代长度与时间作为基底用能量替代质量_natural_dim DimensionSystem( base_dims(action, energy, velocity), derived_dims(length, mass, time, momentum, force, power, frequency) )在这个量纲系统中长度与时间不再独立而是由action、energy、velocity组合导出。这印证了文档开篇的说明同一个物理量在不同量纲系统中可以拥有完全不同的维度身份而 SymPy 通过DimensionSystem的基底可更换性优雅地支持了这种多样性这也是该实现相对于其他库不预先假定 SI 关系的核心优势见 index.rst。六、量纲与函数的交互无量纲参数校验量纲系统不仅能处理代数表达式还能对函数调用做量纲校验这是防止物理公式书写错误的重要机制。从_get_dimensional_dependencies_for_name的函数分支dimensions.py可以看到三角函数TrigonometricFunction子类参数必须无量纲或具有angle量纲。因此cos(1)、cos(angle)合法依赖为空{}而cos(length)抛出TypeError指数/对数等普通函数所有参数必须无量纲log(length)、log(100, length)均报错Abs、sqrt等函数透传参数的量纲依赖因此Abs(length)的依赖为{length: 1}sqrt(length/length)无量纲。测试 test_dimensions.py 对上述规则有完整覆盖包括atan2(length, length)合法、atan2(length, time)报错、dimsys_SI.get_dimensional_dependencies(pi) {}等边界情况。七、Dimension 在单位系统中的角色与 Quantity 的关联量纲是单位系统的构建材料但它本身不包含任何数值。在 SymPy 中Quantity单位与物理常数通过_QuantityMapperdimensions.py与量纲建立映射set_quantity_dimension(quantity, dimension)为某个单位/常数设置量纲仅对特定单位系统有效若该关系在所有单位系统中成立应使用quantity.set_global_dimension(dimension)set_quantity_scale_factor(quantity, scale_factor)设置该量相对于另一同量纲量的比例因子同样区分局部与全局set_global_relative_scale_factor设置时前缀Prefix与其他Quantity会自动替换为其与基准单位的比例get_quantity_dimension(unit)与get_quantity_scale_factor(unit)查询映射查找顺序为局部映射 → 全局映射 → 量纲等价映射未登记的单位默认无量纲、比例因子为 1。以 SI 系统为例si.py可以看到量纲与比例因子的配对注册方式SI.set_quantity_dimension(elementary_charge, charge) SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb) SI.set_quantity_dimension(katal, amount_of_substance / time) SI.set_quantity_scale_factor(katal, mol/second) SI.set_quantity_dimension(gray, energy / mass) # 吸收剂量 SI.set_quantity_scale_factor(gray, meter**2/second**2) SI.set_quantity_dimension(becquerel, 1 / time) # 放射性活度 SI.set_quantity_scale_factor(becquerel, 1/second)值得注意的是 si.py 在模块加载末尾会执行一致性自检遍历所有比例因子用equivalent_dims校验比例的维度表达式与已登记量纲是否等价若失配则抛出ValueError(quantity value and dimension mismatch)——这保证了内置单位定义的内在一致性。SI 中弧度被显式设为无量纲SI.set_quantity_dimension(radian, One)。八、综合实战从量纲到单位换算将上述知识串联起来可以完成一个完整的量纲分析工作流先用Dimension推导物理公式的量纲构成再用DimensionSystem验证公式是否量纲自洽最后通过UnitSystem与convert_to完成实际单位换算相关模块索引见 units/index.rst。 from sympy.physics.units import Dimension, speed_of_light, meter, second from sympy.physics.units import convert_to from sympy.physics.units.systems.si import dimsys_SI from sympy.physics.units.definitions.dimension_definitions import ( ... length, time, mass, force, pressure) # 1. 组合量纲速度、力、压强 velocity length / time force_dim mass * length / time**2 pressure_dim force_dim / length**2 # 2. 用 SI 量纲系统验证力与压强表达式的量纲依赖 dimsys_SI.get_dimensional_dependencies(force_dim) {mass: 1, length: 1, time: -2} dimsys_SI.get_dimensional_dependencies(pressure_dim) {mass: 1, length: -1, time: -2} # 3. 量纲一致性校验mass*length/time**2 force 合法 dimsys_SI.get_dimensional_dependencies(mass * length / time**2 force) {length: 1, mass: 1, time: -2} # 4. 单位换算光速用米与秒表达依赖 SI 系统的量纲结构 convert_to(speed_of_light, [meter, second]) 299792458*meter/second其中第 3 步背后正是DimensionSystem的_get_dimensional_dependencies_for_name对Add表达式的同量纲校验测试见 test_dimensions.pymass*length/time**2与force的依赖字典完全一致因而相加合法若错误地加上pressure依赖不同则会抛出TypeError。九、进一步探索量纲与量纲系统的核心实现dimensions.py内置量纲定义含所有基础与导出量纲dimension_definitions.py各内置单位系统的量纲结构si.py、mksa.py、natural.py行为级测试用例覆盖全部运算规则与报错分支test_dimensions.py单位系统模块总览与换算示例units/index.rst【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考