Bernardo Costa
Bernardo Costa

Reputation: 509

Sympy - Simplify expression within domain

Can Sympy automatically simplify an expression that includes terms like this one:

cos(x)/(cos(x)**2)**(1/2)

which can be simplified to 1 in the domain that I am interested in 0 <= x <= pi/2 ?

(Examples of other terms that could be simplified in that domain: acos(cos(x)); sqrt(sin(x)**2); sqrt(cos(2*x) + 1); etc.)

Upvotes: 0

Views: 726

Answers (2)

Chris du Plessis
Chris du Plessis

Reputation: 1370

If you know the functions that are in your expression (such as sin, cos and tan), you can do the following according to this stack overflow question:

from sympy import *

x = symbols("x", positive=True)
ex = cos(x)/(cos(x)**2)**(S(1)/2)
ex = refine(ex, Q.positive(sin(x)))
ex = refine(ex, Q.positive(cos(x)))
ex = refine(ex, Q.positive(tan(x)))
print(ex)

Note that Q.positive(x*(pi/2-x)) did not help in the process of simplification for trig functions even though this is exactly what you want in general.

But what if you might have crazy functions like polygamma? The following works for some arbitrary choices for ex according to my understanding.

It wouldn't be a problem if the expression was already generated before by SymPy, but if you are inputting the expression manually, I suggest using S(1)/2 or Rational(1, 2) to describe one half.

from sympy import *

# define everything as it would have come from previous code
# also define another variable y to be positive
x, y = symbols("x y", positive=True)
ex = cos(x)/(cos(x)**2)**(S(1)/2)

# If you can, always try to use S(1) or Rational(1, 2)
# if you are defining fractions.
# If it's already a pre-calculated variable in sympy, 
# it will already understand it as a half, and you 
# wouldn't have any problems.
# ex = cos(x)/(cos(x)**2)**(S(1)/2)

# if x = arctan(y) and both are positive,
# then we have implicitly that 0 < x < pi/2
ex = simplify(ex.replace(x, atan(y)))
# revert back to old variable x if x is still present
ex = simplify(ex.replace(y, tan(x)))
print(ex)

This trick can also be used to define other ranges. For example, if you wanted 1 < x, then you could have x = exp(y) where y = Symbol("y", positive=True).

I think subs() will also work instead of replace() but I just like to be forceful with substitutions, since SymPy can sometimes ignore the subs() command for some variable types like lists and stuff.

Upvotes: 1

Oscar Benjamin
Oscar Benjamin

Reputation: 14480

You can substitute for a symbol that has the assumptions you want:

In [27]: e = cos(x)/(cos(x)**2)**(S(1)/2) + cos(x)                                                                     

In [28]: e                                                                                                             
Out[28]: 
            cos(x)   
cos(x) + ────────────
            _________
           ╱    2    
         ╲╱  cos (x) 

In [29]: cosx = Dummy('cosx', positive=True)                                                                           

In [30]: e.subs(cos(x), cosx).subs(cosx, cos(x))                                                                       
Out[30]: cos(x) + 1

Upvotes: 1

Related Questions