在SymPy中重新格式化表达式,以防止常数系数的分布

时间:2018-11-10 21:07:23

标签: python sympy

假设我定义以下表达式:

poly1 = 6/(25*(x + 3)) + 1/(5*(x + 3)**2)

打印出来的

6/(25*x + 75) + 1/(5*(x + 3)**2)

关于这个表达,我有两个问题。首先,有没有一种方法可以使表达式保持输入时的格式?尤其是,我可以做些什么以使第一项的分母保持为25*(x + 3)吗?

第二,如果我有印刷形式的表达式,那么拆分表达式,重新格式化第一项的分母,然后重新组合在一起的最佳方法是什么?理想情况下,我可以使用一系列args调用来深入研究表达式以得出第一项的分母,然后像poly1.args[0].args[1].args[0].factor()一样使用factor函数对其进行适当的分解。问题在于,由于组成表达式的元组是不可变的,所以我不能仅用上面计算的表达式替换poly1的一部分。有没有比从头开始重建整个表达式更好的替代因式多项式的方法?

注意:我不希望使用subs()方法,因为它会搜索整个表达式,并且似乎在某些情况下,您可能希望对修改的不同部分非常具体。 / p>

1 个答案:

答案 0 :(得分:1)

常量的自动分布是touchy subject。有一个禁用它的选项,如下所示:

from sympy.core.evaluate import distribute
with distribute(False):
    poly1 = 6/(25*(x+3)) + 1/(5*(x + 3)**2)
    print(poly1)  #  6/(25*(x + 3)) + 1/(5*(x + 3)**2)

或者您可以将25包裹在UnevaluatedExpr中,以防止其与其他术语进行交互。

poly1 = 6/(UnevaluatedExpr(25)*(x+3)) + 1/(5*(x + 3)**2)
print(poly1)  #  6*25**(-1)/(x + 3) + 1/(5*(x + 3)**2)

或在分母中使用未评估的产品(Mul):

poly1 = 6/Mul(25, x+3, evaluate=False) + 1/(5*(x + 3)**2)
print(poly1)  #  6/(25*(x + 3)) + 1/(5*(x + 3)**2)

或者将分母包装在factor_terms中,这是factor的一种较柔和的形式,它的作用是提取系数,而又不会对表达式造成太多干扰。

poly1 = 6/factor_terms(25*(x+3)) + 1/(5*(x + 3)**2)
print(poly1)  #  6/(25*(x + 3)) + 1/(5*(x + 3)**2)

或者通过引入看起来像数字的符号来作弊:

c25 = symbols('25')
poly1 = 6/(c25*(x+3)) + 1/(5*(x + 3)**2)
print(poly1)  #  1/(5*(x + 3)**2) + 6/(25*(x + 3))

建议阅读:Prevent expression evaluation

关于目标替换的第二个问题通常很难回答。必须recurse through the expression tree,将expr重建为expr.func(*args),其中argsexpr.args,可能会被修改。主要问题是您将如何知道25*x + 75 this 实例是应替换的实例。