【问题标题】:Sympy's subs limitationsSympy 的潜艇限制
【发布时间】:2016-09-05 15:18:07
【问题描述】:

我正在处理一些长方程,但不是很复杂,我想使用 sympy 来简化和“分解”它们。但是我遇到了一些问题。以下是一些最小示例的列表:

问题1:对称性

from sympy import *
from __future__ import division
a = symbols('a')
b = symbols('b')
expr = 1/12*b + 1
expr.subs(1/12*b, a)
expr.subs(b*1/12, a)

第一行给出了预期的结果(即a+1),而第二行没有替换。

问题 2:因式分解

表达式的某些部分被分解,当我扩展表达式时,它们会被简化,因此无法进行替换。例如

(((x+1)**2-x).expand()).subs(x**2+2*x, y+1)

会给x^2+x+1,我要找的是y+2-x

问题

有没有办法解决这些问题?或者也许我应该使用另一个符号数学工具?欢迎提出任何建议。

【问题讨论】:

标签: python sympy substitution symbolic-math


【解决方案1】:

SymPy 中有一个主要问题,那就是,由于 Python 的工作方式,number/number 给出了一个浮点数(或者如果您使用 Python 2 而不是 from __future__ import division,则进行整数除法)。

在第一种情况下,在您的原始表达式中,Python 从左到右计算 1/12*b1/12 由 Python 计算得到 0.08333333333333333,然后乘以 b。在第二种情况下,b*1 被评估为b。然后 b/12 由 SymPy 评估(因为 b 是一个 SymPy 对象),得到 Rational(1, 12)*b

由于浮点数的不精确性,SymPy 不认为浮点数 0.08333333333333333 等于有理数 1/12

关于这个问题的更多讨论here。作为一种解决方法,您应该避免直接使用 integer/integer 而不以某种方式包装它,以便 SymPy 可以创建一个理性的。以下都将创建一个理性:

b/12
Rational(1, 12)*b
S(1)/12*b

对于(((x+1)**2-x).expand()).subs(x**2+2*x, y+1),问题在于x**2 + 2*x 没有完全出现在表达式中,即x**2 + x + 1。 SymPy 通常只替换它准确看到的东西。

您似乎不介意添加和减去 x 来进行替换。所以我建议改为(((x+1)**2-x).expand()).subs(x**2, y+1 - 2*x)。通过仅替换单个术语 (x**2),替换将始终有效,并且 2*x 将取消以保留任何 x 术语剩余(在本例中为 -x)。

【讨论】:

    【解决方案2】:

    以下是解决问题的可能方法:

    from sympy import *
    
    a = symbols('a')
    b = symbols('b')
    expr = 1 / 12 * b + 1
    print(expr.subs((1 / 12) * b, a))
    print(expr.subs(b * (1 / 12), a))
    
    x = symbols('x')
    y = symbols('y')
    expr = ((x + 1)**2 - x).expand()
    print(expr.subs(x**2 + x, y - x + 1))
    

    【讨论】:

    • 对于第一个问题,我认为有一个from __future__ import division ,我尝试了这个添加并且它正在工作。但是,我不明白为什么。对于第二个问题,这真的不能解决我的问题。我在这里给出的只是最小的例子,但实际上方程式真的很长。我不能真正“欺骗”结果。而且我绝对无法更改要替换的值...感谢您的回答!
    • 对于第二个问题,也许我的问题是“是否可以在不简化的情况下进行扩展”?
    【解决方案3】:

    关于问题 1,请注意 1/12*bb*1/12 在 sympy 中不是相同的东西。第一个是一个浮点数乘以一个符号,而第二个是一个精确的符号表达式(你可以通过一个简单的 print 语句来检查它)。由于expr 包含1/12*b,因此第二个subs 不起作用也就不足为奇了。

    关于问题 2,您提供的 subs 规则不明确。特别是替换规则意味着方程x**2+2*x==y+1。然而,这个方程有很多解释,例如,

    x**2 == y + 1 - 2*x(这是你考虑的那个),

    x**2 + x == y + 1 - x,

    x == (y + 1 - x**2)/2,

    出于这个原因,我认为 sympy 拒绝执行替换实际上是一种正确的方法。

    如果是你想要的第一个解释,最好在subs规则中明确提供,即

    (((x+1)**2-x).expand()).subs(x**2, -2*x + y + 1)
    

    -x + y + 2

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      相关资源
      最近更新 更多