sampledoc's Scientific Python Tools

Table Of Contents

Previous topic

IPython tips

Next topic

Some frequent errors

This Page

Examples

Here we put a few complete examples that should be relevant for the numerics lectures.

First example

Define .

We want to plot the error made by using the trapezoidal rule when approximating and .

As exact value we take the value of the integral as produced by the function quad from the sub-package integrate of scipy. This function is just a wrapper to the Fortran library QUADPACK. Please, use IPython facility to consult the documentation of it.

The aim of the plots is to put in evidence the exponential convergence of the trapezoidal rule when the smoothness of the function extends above its periodical domain. The plots should be done for several possible parameters .

from numpy import *
from matplotlib.pyplot import *
from scipy import integrate

def trapr(func, a, b, N):
    x = linspace(a,b, N+1)
    h = x[1] - x[0]
    res = sum(func(x[1:-1])) + 0.5*(func(x[0])+func(x[-1]))
    res = res * h
    return res

# number of quadrature points used
N = 25

# integration limits
left = 0.0
right = 1.0

# alocate space for results
res = zeros(N)

lista = [0.5, 0.9, 0.95, 0.99]

for a in lista:
    myf = lambda x: 1./sqrt(1.0 - a*sin(2*pi*x-1))
    for n in xrange(N):
        res[n] = trapr(myf, left, right, n+1)

    exact, aerr = integrate.quad(myf, left, right)

    print("a: "+str(a))
    print("quad: "+str(exact))
    print("aerr: "+str(aerr))

    err = abs(res-exact)
    semilogy(arange(1,N+1), err, label="a = "+str(a))

grid(True)
legend(loc="lower left")
show()

(Source code, png, hires.png, pdf)

_images/traprule.png

At lines 1-3 we import the libraries we are using. At lines 5-10 we define our quadrature rule function. Note that there are several possibilities to prepare the array of sampling points. The integrand is evaluated once at all points (vectorial) and the function sum of numpy is used in order to add the necessary values in most efficient way possible.

After preparing the data, we run the loop over the interesting values of the parameter a.

At line 25 we define the function to be integrated as a lambda function. Note that if we define it as a function of two parameters, we’d have difficulties in the later call of the trapr function.

We would like to have a program that computes both integrals and makes both plots at one. Here’s a possibility:

from numpy import *
from matplotlib.pyplot import *
from scipy import integrate

def trapr(func, a, b, N):
    """
    Compute the integral from a to b of func via trap. rule with N points
    """
    x = linspace(a,b, N+1)
    h = x[1] - x[0]
    res = sum(func(x[1:-1])) + 0.5*(func(x[0])+func(x[-1]))
    res = res * h
    return res

def ploterr(left, right, N, lista, pf):
    # allocate space for results
    res = zeros(N)

    for a in lista:
        myf = lambda x: 1.0/sqrt(1.0- a*sin(2*pi*x-1))

        for n in xrange(N):
            res[n] = trapr(myf, left, right, n+1)

        exact, aerr = integrate.quad(myf, left, right)

        print("a: "+str(a))
        print("quad: "+str(exact))
        print("aerr: "+str(aerr))

        err = abs(res-exact)
        pf(arange(1,N+1), err, label="a = "+str(a))

    grid(True)
    legend(loc="lower left")
    savefig("err"+str(right)+".png")
    close()


# not really necessary here, but you see how to do modules and test them
if __name__ == "__main__":
    lista = [0.5, 0.9, 0.95, 0.99]

    ploterr(0., 1., 25, lista, pf=semilogy)
    ploterr(0., 0.5, 100, lista, pf=loglog)
_images/err1_0.png _images/err0_5.png

In last code, we incorporated the loop in a function that gets the integration range, the list of wished parameters and the preferred plot function (semilogy is better for the identification of the exponential convergence). The type of the file is decided by the extension of the name of the file. Note also the string concatenation used in the construction of the file name.

Finally, we would like to rewrite the code such that we avoid the trick based on inlining and locality of the variable a. We have now the occasion to see a very powerful trait of python: class function.

from numpy import *
from matplotlib.pyplot import *
from scipy import integrate

def trapr(func, a, b, N):
    """
    Compute the integral from a to b of func via trap. rule with N points
    """
    x = linspace(a,b, N+1)
    h = x[1] - x[0]
    y = func(x)
    res = sum(y[1:-1]) + 0.5*(y[0]+y[-1])
    res = res * h
    return res

class Myf(object):
    """
    models a parametric function suited for evidencing
    exponential convergence of trap. rule
    """
    def __init__(self, ina):
        self.a = ina

    def __str__(self):
        return str(self.a)

    def __call__(self, x):
        return 1.0/sqrt(1.0- self.a*sin(2*pi*x-1))

def ploterr(f, left, right, N, lista, pf):
    # allocate space for results
    res = zeros(N)

    for a in lista:
        f.a = a
        print(f)

        for n in xrange(N):
            res[n] = trapr(f, left, right, n+1)

        exact, aerr = integrate.quad(f, left, right)

        print("a: "+str(a))
        print("quad: "+str(exact))
        print("aerr: "+str(aerr))

        err = abs(res-exact)
        pf(arange(1,N+1), err, label="a="+str(a))

    grid(True)
    legend(loc="lower left")
    savefig("err"+str(right)+".png")
    close()


# not really necessary here, but you see how to do modules and test them
if __name__ == "__main__":
    lista = [0.5, 0.9, 0.95, 0.99]

    # initialize the function
    myf = Myf(0.5)

    ploterr(myf, 0., 1., 25, lista, pf=semilogy)
    ploterr(myf, 0., 0.5, 100, lista, pf=loglog)
_images/err1_0.png _images/err0_5.png

The class Myf creates a callable objects. On line 61 we create one such object that models our parameter function, having the parameter set by the first element of the list of interesting parameters. During the loop at line 34, we modify the parameter of the object, which we use as a function to be integrated by our quadrature routines at lines 39 and 41.

This is a very simple example, but imagine the power at your hands given by the class function when you have to optimize a very complicated function (e.g. given only implicitly as the result of complicated algorithms) depending on several parameters.

Second example

"""
Calculates eigenvalues through direct power method

Originaly, there were the input parameters d and maxit,
but in the skript, d = [1:10] and maxit = 30 are used.
"""

import numpy as np
from matplotlib import pyplot as plt

def pm(A, z, sgn, ev, ew, maxit=30):
    """Performs 'maxit' iterations of the power method
    for the matrix 'A' and the initial vector 'z'
    and computes the error for the largest eigenvalue 'ew'
    having the sign 'sgn' and the corresponding eigenvector 'ev'
    """
    res = np.zeros((maxit,5))
    s = 1;
    for k in xrange(maxit):
        w = np.dot(A,z)
        no = np.linalg.norm(w)
        rq = np.real(np.vdot(w,z))
        z = w/no
        err_aew = abs(no-abs(ew))
        err_ew = abs(sgn*rq-ew)
        err_ev = np.linalg.norm(s*z-ev)
        res[k] = np.array([k, no, err_ev, err_aew, err_ew])
        s = s*sgn
    return res

def runpm(d, fname):
    """Performs the analysis of the power iteration starting from
    the array of eigenvalues d; the picture with the results goes
    to the file indicate by fname
    """
    n = len(d) # size of the matrix
    S = np.triu(np.diag(np.r_[n:0:-1]) + np.ones((n,n)))
    A = np.dot(S, np.dot(np.diag(d), np.linalg.inv(S)))

    # need exact ew and ew for error calculation
    w, V = np.linalg.eig(A)
    t = np.where(w == abs(w).max())
    k = t[0]
    if len(k) > 1:
        raise ValueError("Error: no single larges EV")
    ev = V[:,k[0]]
    ev /= np.linalg.norm(ev)
    ew = w[k[0]]

    sgn = 1
    if ew < 0:
        sgn = -1

    print("ew:")
    print(ew)
    print("sgn:")
    print(sgn)
    print("ev =")
    print(ev)

    z = np.random.rand(n)
    z /= np.linalg.norm(z)
    res = pm(A,z,sgn,ev,ew)

    plt.semilogy(res[:,0], res[:,2])
    plt.semilogy(res[:,0], res[:,3])
    plt.semilogy(res[:,0], res[:,4])
    plt.grid(True)
    plt.xlabel("iteration step k")
    plt.ylabel("errors")
    plt.savefig(fname)
    plt.show()


if __name__=="__main__":
    # size of the matrix
    n = 10

    d = 1.0 + np.arange(n) # eigenvalues
    print("d:")
    print(d)
    print("d[-2]/d[-1]:")
    print(d[-2]/d[-1])
    runpm(d, "pm1.png")

    d = np.ones(n)
    d[-1] = 2.0 # eigenvalues
    print("d:")
    print(d)
    print("d[-2]/d[-1]:")
    print(d[-2]/d[-1])
    runpm(d, "pm2.png")

    d = 1.0 - 0.5**np.linspace(1,5,9) # eigenvalues
    print("d:")
    print(d)
    print("d[-2]/d[-1]:")
    print(d[-2]/d[-1])
    runpm(d, "pm3.png")
_images/pm1.png _images/pm2.png _images/pm3.png

Third example

Serial Monte-Carlo integration via IPython. Serial code:

"""
 Computes integral
 I0(1) = (1/pi) int(z=0..pi)  exp(-cos(z)) dz by raw MC.
 Abramowitz and Stegun give I0(1) = 1.266066
"""

import numpy as np
import time

t1 = time.time()

# number of times we run our MC inetgration
M = 100
asval = 1.266065878

ex = np.zeros(M)

print("A and S tables:  I0(1) = "+str(asval))
print("sample       variance        MC I0 val")
print("------       --------        ---------")

# how many experiments
k = 5
N = 10**np.arange(1,k+1)
v = []
e = []

for n in N:
    for m in xrange(M):
        x = np.random.rand(n)
        x = np.exp(np.cos(-np.pi*x))
        ex[m] = sum(x)/n

    ev = sum(ex)/M
    vex = np.dot(ex,ex)/M
    vex -=  ev**2
    v += [vex]
    e += [ev]
    print((n, vex, ev))

t2 = time.time()
t = t2 - t1

print("Serial calculation completed, time = "+str(t)+" s")

Output:

A and S tables:  I0(1) = 1.266065878
sample       variance        MC I0 val
------       --------        ---------
(10, 0.069908462650839942, 1.2525905567351583)
(100, 0.0055876950073416864, 1.2709643005937217)
(1000, 0.0006511488699125767, 1.262876852977836)
(10000, 5.7940507106613026e-05, 1.2664260011112918)
(100000, 6.7123607208063873e-06, 1.265782558306026)
Serial calculation completed, time = 5.22518420219 s

Fourth example

A nice plot showing the fixed-point iteration in action finding the golden ration.

from numpy import *
from matplotlib.pyplot import *

phi = lambda x: (1.0 + 1.0/(1.0*x))
#phi = lambda x: sqrt(x+1.0)

x0 = 1.2

x = [x0]
y = [0]

for i in xrange(10):
    x1 = phi(x0)

    x.append(x0)
    y.append(x1)

    x.append(x1)
    y.append(x1)

    x0 = x1

x = array(x)
y = array(y)

xmin = x.min() - 0.2
xmax = x.max() + 0.2

t = linspace(xmin, xmax, 50)

figure()
plot([xmin, xmax], [xmin, xmax], "g")
plot(t, phi(t), "b")

plot(x, zeros_like(x), "bo")
plot(xmin*ones_like(y), y, "bo")

plot(x, y, "r--")
plot(x, y, "r.")

xlim(xmin, xmax)
savefig("spiral1.png")

print(x)
print(y)
_images/spiral1.png