You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何关闭SymPy中Add构造函数的项重排序功能?

SymPy中如何禁止表达式自动重排?

问题背景

在SymPy中构造符号表达式时,希望完全匹配源材料的格式,但Add构造函数会自动重排项,示例如下:

>>> a, b = symbols("a b")
>>> b+a
a + b
>>> srepr(b+a)
Add(Symbol('a'), Symbol('b'))

虽然这种重排通常合理,但需要在修改前保持表达式完全匹配源材料。

根据Add的文档说明:

Add()会对参数求值,除非传入evaluate=False。求值逻辑包括:

  1. 扁平化处理...
  2. 移除单位元...
  3. 合并系数...
  4. 项排序
    Add(y, x, 2) -> Add(2, x, y)

但传入evaluate=False似乎无效:

>>> srepr(Add(b, a, evaluate=False))
Add(Symbol('a'), Symbol('b'))

实际需求是生成如下格式的表达式:

⎛        1        ⎞
      ⎜─────────────────⎟
      ⎜   1         1   ⎟
      ⎜─────── + ───────⎟
      ⎜R⋅N + S        1 ⎟
      ⎜          E + ───⎟
      ⎝              s⋅C⎠
─────────────────────────────
⎛                  1        ⎞
⎜D + L⋅s + ─────────────────⎟
⎜             1         1   ⎟
⎜          ─────── + ───────⎟
⎜          R⋅N + S        1 ⎟
⎜                    E + ───⎟
⎝                        s⋅C⎠

但SymPy自动重排后变成:

1                        
─────────────────────────────────────────────────
⎛   1         1   ⎞ ⎛                  1        ⎞
⎜─────── + ───────⎟⋅⎜D + L⋅s + ─────────────────⎟
⎜N⋅R + S        1 ⎟ ⎜             1         1   ⎟
⎜          E + ───⎟ ⎜          ─────── + ───────⎟
⎝              C⋅s⎠ ⎜          N⋅R + S        1 ⎟
                    ⎜                    E + ───⎟
                    ⎝                        C⋅s⎠

环境信息:

  • SymPy 1.14.0
  • Python 3.10.12
  • Ubuntu 22.04.4 LTS

可行方案:使用UnevaluatedExpr包装表达式

要阻止SymPy自动重排或化简表达式,可以用UnevaluatedExpr包装需要保留原始顺序的部分,它会让表达式保持未求值状态,直到显式调用.doit()方法才会触发化简。

示例:保留Add的原始顺序

from sympy import symbols, Add, UnevaluatedExpr

a, b = symbols("a b")
expr = Add(UnevaluatedExpr(b), UnevaluatedExpr(a), evaluate=False)
print(expr)  # 输出 b + a
print(srepr(expr))
# 输出 Add(UnevaluatedExpr(Symbol('b')), UnevaluatedExpr(Symbol('a')))

针对复杂分式的处理

对于需求中的分式结构,需要将分子、分母里需要保留顺序的加法部分逐层用UnevaluatedExpr包装:

from sympy import symbols, UnevaluatedExpr, Add

R, N, S, E, s, C, D, L = symbols("R N S E s C D L")

# 定义分子内的加法项(保留原始顺序)
inner_add = Add(UnevaluatedExpr(1/(R*N + S)), UnevaluatedExpr(1/(E + 1/(s*C))), evaluate=False)
numerator = 1 / inner_add

# 定义分母内的加法项(保留原始顺序)
outer_add = Add(UnevaluatedExpr(D), UnevaluatedExpr(L*s), UnevaluatedExpr(1/inner_add), evaluate=False)
expr = numerator / outer_add

print(expr)

执行后输出的表达式会完全匹配源材料的格式,不会自动重排乘法项或调整加法顺序。


注意事项

  • UnevaluatedExpr会完全阻止SymPy对包装部分的化简操作(包括合并同类项、移除单位元等),若后续需要化简,可调用expr.doit()触发求值。
  • 对于嵌套表达式,需要逐层包装需要保留顺序的子表达式,确保每一层的Add/Mul都不会触发自动重排。

内容的提问来源于stack exchange,提问作者jonathanjo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:13:23