Timings of midpoint quadrature

Jonathan Gillett


In [6]:
def midpt_for(f, interval, N_pts):
    a, b = interval
    h = (b - a) / float(N_pts)
    est = 0.0
    for k in range(1, N_pts+1):
        x_k = a + (k-0.5)*h
        est += f(x_k)
    return h * est

In [7]:
def midpt_np(f, interval, N_pts):
    a, b = interval
    h = (b - a) / float(N_pts)
    # Numpy array of all x_k values
    x_k = np.arange(1, N_pts+1)
    # Apply universal functions to numpy array
    x_k = a + (x_k-0.5)*h
    x_k = f(x_k)
    return h * np.sum(x_k)

In [12]:
import numpy as np

# Evaluate the performance of the midpoint quadrature technique
# using a for loop vs. a numpy ndarray with universal functions
print "Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 100"
print "Using a for loop..."
%timeit midpt_for(lambda x: 4/(1 + x**2), (0, 1), 100)
print "Using a numpy ndarray..."
%timeit midpt_np(lambda x: 4/(1 + x**2), (0, 1), 100)


Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 100
Using a for loop...
10000 loops, best of 3: 63.3 µs per loop
Using a numpy ndarray...
10000 loops, best of 3: 33.5 µs per loop

In [14]:
print "Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 10,000"
print "Using a for loop..."
%timeit midpt_for(lambda x: 4/(1 + x**2), (0, 1), 10000)
print "Using a numpy ndarray..."
%timeit midpt_np(lambda x: 4/(1 + x**2), (0, 1), 10000)


Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 100,000
Using a for loop...
100 loops, best of 3: 6.32 ms per loop
Using a numpy ndarray...
10000 loops, best of 3: 136 µs per loop

In [16]:
print "Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 100,000"
print "Using a for loop..."
%timeit midpt_for(lambda x: 4/(1 + x**2), (0, 1), 100000)
print "Using a numpy ndarray..."
%timeit midpt_np(lambda x: 4/(1 + x**2), (0, 1), 100000)


Midpoint evaluation of f(x)=4/(1+x**2) using N_pts = 100,000
Using a for loop...
10 loops, best of 3: 63.1 ms per loop
Using a numpy ndarray...
1000 loops, best of 3: 1 ms per loop

Observations

It is interesting to note that the performance improvement of the implementation using ndarray in comparison to a naiive approach using a for loop is significantly faster for each size of N_pts used, with the difference in performance becoming more significant in each of the tests performed with N_pts of 100; 10,000; and 100,000.

It's interesting to note that for a small value of N_pts of 100 the difference is negligible, however when a much higher amount of precision is needed in the case of a N_pts being 100,000 the numpy ndarray implementation is approximated 63 times faster than the naiive approach using a for loop.

Part of the performance difference is due to the fact that for loops in Python, which allows a list of any type are inherently slow due to memory access whereas in numpy the universal function operation is much faster as it is easy for the underlying libraries in numpy to calculate the exact memory address for each cell and apply the operation to it.

The performance improvements of numpy are significant due to the underlying libraries used (which have been fine-tuned over mnay years) and the homoegeneity of the ndarrays.


In [ ]: