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)
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)
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)
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 [ ]: