简体   繁体   中英

How to speed up symbolic integration using SymPy?

I am trying to integrate the following expression symbolically (final expression will be in terms of x):

from sympy import *
x, y = symbols('x, y')
expr = 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))
int_expr = simplify(integrate(expr, x,(y,0,2*pi)))
print(int_expr)

Point to be noted, when I am integrating 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x) the program works a little faster. Joining the sqrt(cos(x)) to it makes it very slow and it takes like an eternity to implement the code. I have reached to this mathematical expression after doing much simplification and it has made the program 'start working' Is there any way to speed up this code? Any suggestion is very much appreciated.

Firstly I advise against using floats especially in the exponent (ie 2j ). You should use sympy's exact rationals and also I for sqrt(-1) .

That gives us this:

In [11]: expr = sqrt(15/(2*pi))/4 * exp(2*I*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))

In [12]: int_expr = Integral(expr, (x, 0, 2*pi))

In [13]: int_expr
Out[13]: 
2⋅π                                 
 ⌠                                  
 ⎮       2⋅ⅈ⋅y    3      ________   
 ⎮  √30⋅ℯ     ⋅sin (x)⋅╲╱ cos(x)    
 ⎮  ───────────────────────────── dx
 ⎮               8⋅√π               
 ⌡                                  
 0  

Now I notice that actually the extraneous factor can be pulled out of this integral. We can use factor_terms to do that:

In [14]: factor_terms(int_expr)
Out[14]: 
           2⋅π                      
            ⌠                       
     2⋅ⅈ⋅y  ⎮     3      ________   
√30⋅ℯ     ⋅ ⎮  sin (x)⋅╲╱ cos(x)  dx
            ⌡                       
            0                       
────────────────────────────────────
                8⋅√π                

Seeing the integral that remains it's worth knowing that when you have an integral with no free symbols in it (the only symbol in the integrand is the dummy integration symbol) then you can often get a faster approximate result by evaluating the integral numerically:

In [15]: Integral(sin(x)**3 * sqrt(cos(x)), (x, 0, 2*pi))
Out[15]: 
2⋅π                      
 ⌠                       
 ⎮     3      ________   
 ⎮  sin (x)⋅╲╱ cos(x)  dx
 ⌡                       
 0                       

In [16]: _.n()
Out[16]: -0.e-103 + 0.e-103⋅ⅈ

This is showing that the integral is basically zero.

The algorithms used for symbolic integration can be extremely slow for some cases. This is a general problem with many integration algorithms and they are often quite sensitive to the exact form of the input. You shouldn't be surprised that an additional factor of sqrt(cos(x)) changes things: it would make the integral significantly harder by hand as well as there is no "product rule" for integrals. In this example it is slow in the "heurisch" algorithm so you can set heurisch=False to disable that but then none of the other algorithms can evaluate the integral so you won't get a result.

Often a substitution will make the integral a lot easier and you can ask sympy to do the substitution explicitly. In this case we can use the substitution z = cos(x) but we need to split the integral into two parts from 0 to pi and from pi to 2*pi so that the substitution is monotonic in each part:

In [30]: Integral(expr, (x, 0, pi))
Out[30]: 
π                                 
⌠                                 
⎮      2⋅ⅈ⋅y    3      ________   
⎮ √30⋅ℯ     ⋅sin (x)⋅╲╱ cos(x)    
⎮ ───────────────────────────── dx
⎮              8⋅√π               
⌡                                 
0                                 

In [31]: Integral(expr, (x, 0, pi)).transform(cos(x), z)
Out[31]: 
1                           
⌠                           
⎮         ⎛     2⎞  2⋅ⅈ⋅y   
⎮  √30⋅√z⋅⎝1 - z ⎠⋅ℯ        
⎮  ────────────────────── dz
⎮           8⋅√π            
⌡                           
-1                          

In [32]: Integral(expr, (x, 0, pi)).transform(cos(x), z).doit()
Out[32]: 
     2⋅ⅈ⋅y          2⋅ⅈ⋅y
√30⋅ℯ        √30⋅ⅈ⋅ℯ     
────────── + ────────────
  21⋅√π         21⋅√π    

In [33]: _ + Integral(expr, (x, pi, 2*pi)).transform(cos(x), z).doit()
Out[33]: 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM