Here is a trick similar in spirit to the accepted answer, but which retains the original symbol in the expression.
Consider:
from sympy import symbols, sqrt, conjugate, Q
x = symbols('x', real=True, nonnegative=True)
expr = sqrt(1-x) * conjugate( sqrt(1-x) )
Assuming 0 <= x <= 1
, we know that expr
would simplify to 1-x
but we cannot directly make use of this assumptiom in sympy:
expr.simplify()
>>> sqrt(1 - x)*conjugate(sqrt(1 - x))
expr.refine(Q.positive(1-x))
>>> sqrt(1 - x)*conjugate(sqrt(1 - x))
We wish to communicate to sympy that 1-x
is always positive or zero. If we could replace 1-x
with a symbol y
declared as nonnegative=True
, then simplify()
could recognise sqrt(1-x) = sqrt(y)
is real and simplify away the conjugate and product.
We can do just that, and we don't even need to use a new symbol! We substitute x -> 1-x
so that sub-expressions f(1-x)
become f(x)
which can now be simplified, leveraging that their parameter is positive. Then, we restore 1-x -> x
by again substituting x -> 1-x
.
expr = expr.subs(x, 1-x).simplify().subs(x, 1-x)
>>> 1 - x
This seems safe; our substitution is mathematically equivalent to asserting that x <= 1
, which coupled with our explicit sympy assumption x >= 0
, achieves the intended bound.
We can easily extend this to simplify expressions assuming 0 <= x <= b
for a positive bound b
:
expr = expr.subs(x, b-x).simplify().subs(x, b-x)
t
rather thanx
, which is not desirable. And awkwardly,simplify
usingx=exp(-t)
will expand into an expression from which it cannot thereafter recognise0<x<1
– Embosom