Search code examples
pythonscipy

Scipy Quad integration, The integral is probably divergent or slowly convergent


I am trying to use scipy's integrate.quad and it isn't working for my function.

import numpy as np
from scipy.integrate import quad

def cos_func (x):
    return np.cos(np.power(x, 3) + 1)

result_quad = quad(cos_func, 0, 10)[0]
print(result_quad)

I have tried with just x and x^2 in the cos function and both work fine, it's only with x^3, I have also tried using x**3 instead of np.power(x, 3) and that didn't change anything. Any help in fixing and explaining why it doesn't work would be appreciated.


Solution

  • The x3 in cos(x3+1) will cause the cosine function to oscillate very fast near x=10. You would need a lot of nodes to capture all those oscillations. One way of circumventing that would be to split the integral range for x into [0,1] and [1,10] and make the substitution x=u1/3 to do the second one. (The substitution would be ill-behaved at x=0).

    import numpy as np
    from scipy.integrate import quad
    
    def cos_func (x):
        return np.cos(np.power(x, 3) + 1)
    
    def ucos_func (u):
        return np.cos(u + 1) / ( 3 * u ** ( 2.0 / 3.0 ) )
    
    result_quad = quad(cos_func, 0, 1)[0] + quad( ucos_func, 1, 1000.0 )[0]
    print(result_quad)
    

    Output (I hope it's right!):

    0.0451983043279886
    

    Trying a home-grown version for the original integral (sorry, in c++!):

    #include <iostream> 
    #include <cmath>
    #include <iomanip>
    using namespace std;
    
    double integrate( double a, double b, int n, double f( double ) );
    
    int main()
    {
       auto f = []( double x ){ return cos( x * x * x + 1 ); };
       double a = 0, b = 10;
       
       #define SP << setw( 15 ) <<
       cout SP "intervals" SP "estimate" << '\n';
       for ( int n = 10; n <= 1000000; n *= 10 )
       {
          double I = integrate( a, b, n, f );
          cout SP n SP I << '\n';
       }
    }
    
    double integrate( double a, double b, int n, double f( double ) )
    {
       double dx = ( b - a ) / n;
       double sum = 0.5 * ( f( a ) + f( b ) );
       for ( int k = 1; k < n; k++ ) sum += f( a + k * dx );
       return sum * dx;
    }
    

    Output with number of intervals:

      intervals       estimate
             10       -3.00969
            100       0.559173
           1000      0.0424572
          10000      0.0451753
         100000      0.0451981
        1000000      0.0451983