Labs

Labs for October 7th, 2015
Exercise 0.1. Implement all the methods presented in the lecture, i.e.:
numpy import dot, array, zeros_like, allclose, max, abs
numpy.linalg import norm
copy import deepcopy
scipy.linalg import lu, inv
1
from
from
from
from
6
def noPivot(A, row):
return row + 1
def partialPivot(A, row):
return abs(A[row:,row]).argmax() + row
11
def scaledPivot(A, row):
scales = max(abs(A), 1)
return abs(A[row:,row]/scales[row:]).argmax() + row
16
21
26
31
def GaussJordan(A, b, pivoting = noPivot):
(rows, cols) = A.shape
for row in range(0, rows-1):
pivot = pivoting(A, row)
if abs(A[pivot, row]) < 1e-8: raise ValueError()
if pivot != row:
A[[row, pivot],:] = A[[pivot, row],:]
b[[row, pivot]] = b[[pivot, row]]
for i in range(row+1, rows):
if abs(A[row, row]) < 1e-8: raise ValueError()
factor = A[i, row] / A[row, row]
A[i, row+1:rows] = A[i, row+1:rows] - factor*A[row, row+1:rows]
b[i] = b[i] - factor*b[row]
for k in range(rows-1,-1,-1):
b[k] = (b[k] - dot(A[k, k+1:rows], b[k+1:rows])) / A[k, k]
return b
def GaussJordanPartial(A, b):
return GaussJordan(A, b, pivoting = partialPivot)
36
def GaussJordanScaled(A, b):
return GaussJordan(A, b, pivoting = scaledPivot)
def LU(A, b):
L, U = lu(A, permute_l=True)
1
41
46
51
56
61
66
71
76
81
# Solve Ly = B for y ("forward")
y = zeros_like(b)
for m, b in enumerate(b.flatten()):
y[m] = b
if m:
for n in xrange(m):
y[m] -= y[n] * L[m, n]
y[m] /= L[m, m]
# Solve y = Ux for x ("backward")
x = zeros_like(b)
for midx in xrange(B.size):
m = b.size - 1 - midx # backwards index
x[m] = y[m]
if midx:
for nidx in xrange(midx):
n = b.size - 1 - nidx
x[m] -= x[n] * U[m, n]
x[m] /= U[m, m]
return x
def Jacobi(A, b, tol = 1e-10, limit = 100):
x = zeros_like(b)
for iteration in range(limit):
next = zeros_like(x)
for i in range(A.shape[0]):
s1 = dot(A[i, :i], x[:i])
s2 = dot(A[i, i + 1:], x[i + 1:])
next[i] = (b[i] - s1 - s2) / A[i, i]
if allclose(x, next, atol=tol): break
x = next
return x
def GaussSeidel(A, b, tol = 1e-10, limit = 100):
x = zeros_like(b)
for iteration in range(limit):
next = zeros_like(x)
for i in range(A.shape[0]):
s1 = dot(A[i, :i], next[:i])
s2 = dot(A[i, i + 1:], x[i + 1:])
next[i] = (b[i] - s1 - s2) / A[i, i]
if allclose(x, next, rtol=tol): break
x = next
return x
.
2
Test the methods on some well-known systems, trace the computation step by step, and try to explain
the results, as much as you can:
2
7
# An example from https://en.wikipedia.org/wiki/Gauss-Seidel_method
# with solution [-38 29]
A1 = array([[2.0, 3.0], [5.0, 7.0]])
b1 = array([11.0, 13.0])
A2 = array([[0.0, 1.0], [1.0, 1.0]])
b2 = array([1.0, 1.0])
# An example of Trefethen and Bau, with solution [-1, 1]
A3 = array([[1e-20, 1.0], [-1.0, 0.0]])
b3 = array([1.0, 1.0])
12
17
22
27
# Another example of Trefethen and Bau, with loss of n-bits of precision
# in n x n system. Try the same structure for larger n.
A4 = array([[ 1.0, 0.0, 0.0, 0.0, 1.0],
[-1.0, 1.0, 0.0, 0.0, 1.0],
[-1.0, -1.0, 1.0, 0.0, 1.0],
[-1.0, -1.0, -1.0, 1.0, 1.0],
[-1.0, -1.0, -1.0, -1.0, 1.0]])
b4 = array([0.0, 0.0, 0.0, 0.0, 0.0])
# An example from Faddeev and Faddeeva
A5 = array([
[5.0,
7.0,
6.0,
5.0],
[7.0,
10.0,
8.0,
7.0],
[6.0,
8.0,
10.0,
9.0],
[5.0,
7.0,
9.0,
10.0]])
b5 = array([23.0, 32.0, 33.0, 31.0])
.
Exercise 0.2. Consider the following routine for generating systems with an arbitrary condition number
c and prescribed solution (all ones):
2
7
import random
from numpy.linalg import svd
def randomIllConditioned(n = 10, c = 10000):
A = random.rand(n,n)
U, s, V = svd(A)
ss = zeros((n,n))
for j in range(n):
ss[j, j] = s[0] - j * (s[0] - s[0] / c) / (n - 1)
next = dot(dot(U, ss), V.T)
b = dot(next, ones(n))
return (next, b)
.
Plot the error of each method presented in class as a function of the condition number.
3
Exercise 0.3. Extend your experiments above with the conjugate gradient:
4
9
def CG(A, b, x0, tol = 1.0e-10, limit = 100):
x = x0
r0 = b - dot(A, x)
p = r0
for i in xrange(limit):
a = float(dot(r0.T, r0)/dot(dot(p.T, A), p))
if allclose(x, x + p*a, rtol=tol): break
x = x + p*a
r = r0 - dot(A*a, p)
b = float(dot(ri.T, ri)/dot(r0.T, r0))
p = ri + b * p
r0 = ri
return x
.
Additionally, plot the number of iterations and time needed to solve a random system for the three
iterative methods.
Hint: use module random, function random.rand(n,n).
4