# Integrals

Pylians provide routines to carry out numerical integrals in a more efficient way than scipy integrate. The philosophy is that to compute the integral $$\int_a^b f(x)dx$$ the user passes the integrator two arrays, one with some values of $$x$$ between a and b and another with the values of $$f(x)$$ at those positions. The integrator will interpolate internally the input data to evaluate the function at an arbitrary position $$x$$. Pylians implements in c the fortran odeint function and wrap in python through cython.

For instance, to compute $$\int_0^5 (3x^3+2x+5) dx$$ one would do

import numpy as np
import integration_library as IL

# integral value, its limits and precision parameters
yinit = np.zeros(1, dtype=np.float64)
x1    = 0.0
x2    = 5.0
eps   = 1e-8
h1    = 1e-10
hmin  = 0.0

# integral method and integrand function
function = 'linear'
bins     = 1000
x        = np.linspace(x1, x2, bins)
y        = 3*x**2 + 2*x + 5

I = IL.odeint(yinit, x1, x2, eps, h1, hmin, x, y, function, verbose=True)[0]

The value of integral is stored in I. The odeint routine needs the following ingredients:

• yinit. The value of the integral is stored in this variable. Should be a 1D double numpy array with one single element equal to 0. If several integrals are being computed sequentially this variable need to be declared for each integral.

• x1. Lower limit of the integral.

• x2. Upper limit of the integral.

• eps. Maximum local relative error tolerated. Typically set its value to be 1e8-1e10 lower than the value of the integral. Verify the convergence of the results by studying the dependence of the integral on this number.

• h1. Initial guess for the first time step (cannot be 0).

• hmin. Minimum allowerd time step (can be 0).

• verbose. Set it to True to print some information on the integral computation.

There are two main methods to carry out the integral, depending on how the interpolation is performed.

• function = 'linear'. The function is evaluated by interpolating linearly the input values of $$x$$ and $$y=f(x)$$.
• x. 1D double numpy array containing the input, equally spaced, values of $$x$$.

• y. 1D double numpy array containing the values of $$y=f(x)$$ at the x array positions.

• function = 'log'. The function is evaluated by interpolating logaritmically the input values of $$x$$ and $$y=f(x)$$.
• x. 1D double numpy array containing the input, equally spaced in log, values of $$\log_{10}(x)$$.

• y. 1D double numpy array containing the values of $$y=f(x)$$ at the x array positions.

An example of using the log-interpolation to compute the integral $$\int_1^2 e^x dx$$ is this

import numpy as np
import integration_library as IL

# integral value, its limits and precision parameters
yinit = np.zeros(1, dtype=np.float64)
x1    = 1.0
x2    = 2.0
eps   = 1e-10
h1    = 1e-12
hmin  = 0.0

# integral method and integrand function
function = 'log'
bins     = 1000
x        = np.logspace(np.log10(x1), np.log10(x2), bins)
y        = np.exp(x)

I = IL.odeint(yinit, x1, x2, eps, h1, hmin, np.log10(x), y,
function, verbose=True)[0]

Warning

Be careful when using the log-interpolation, since the code will crash if a zero or negative value is encounter.

The user can create its own function to avoid evaluating the integrand via interpolations. This function has to be placed in the file library/integration_library/integration_library.pyx (see linear and sigma functions as examples). After that, a new function call has to be created in the function odeint of that file (see linear and log as examples).