问题
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