Reformat pieces of expressions in SymPy to prevent distribution of constant coefficient

為{幸葍}努か 提交于 2021-02-08 08:16:27

问题


Suppose I define the following expression:

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

which prints out:

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

I have two questions regarding this expression. Firstly, is there a way to keep the expression in the format in which I entered it? In particular, is there something that I could do in order to leave the denominator of the first term as 25*(x + 3)?

Secondly, if I have the expression in its printed form, what is the best way to break apart the expression, reformat the denominator of the first term, and then put it back together? Ideally I would be able to just dig into the expression using a series of args calls to get to the denominator of the first term, and then use the factor function to factor it properly, as in poly1.args[0].args[1].args[0].factor(). The problem is that, since the Tuples making up the expression are immutable, I can't just replace a piece of poly1 with the expression computed above. Is there a better way to substitute in the factored polynomial than just rebuilding the whole expression from scratch?

Note: I'd rather not use the subs() method, because that searches the entire expression, and it seems like there might be cases where you would want to be very specific about the different pieces you modify.


回答1:


Automatic distribution of constants is a touchy subject. There is an option to disable it as follows:

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)

Or you can wrap 25 in UnevaluatedExpr to prevent its interaction with other terms.

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

Or use the un-evaluated product (Mul) in the denominator:

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

Or wrap the denominator in factor_terms -- a gentler form of factor which does the job of extracting the coefficient without messing too much with the expression.

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

Or cheat by introducing a symbol that looks like a number:

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

Suggested reading: Prevent expression evaluation

The second question, about targeted replacement, is hard to answer in this generality. One has to recurse through the expression tree, rebuilding expr as expr.func(*args) where args are expr.args, possibly modified. The main issue is how you will know that this instance of 25*x + 75 is the one that should be replaced.



来源:https://stackoverflow.com/questions/53243409/reformat-pieces-of-expressions-in-sympy-to-prevent-distribution-of-constant-coef

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!