Created
May 5, 2014 21:07
-
-
Save addisoneee/6817f8886b9a791c40c0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#------------------------------------------------------------------------------- | |
# Name: Numerical Project Assignment #2, Subject #3 | |
# Purpose: To determine the eigenvalues of a matrix using QR decomposition | |
# | |
# Author: Addison Euhus | |
# | |
# Created: 04/30/2014 | |
# Copyright: (c) Addison Euhus 2014 | |
#------------------------------------------------------------------------------- | |
from numpy import * | |
from numpy import random as rd | |
from pylab import * | |
#******************************************************** | |
#Real Valued 4x4 Matrix | |
A = matrix('1 2 3 7; 4 5 6 7; 7 7 8 9; 1 7 -1 9') | |
#Complex Valued 4x4 Matrix | |
#A = matrix('-4 2 0 0; -2 -4 0 0; 0 0 2 3; 0 0 -3 2') | |
#Random Valued Matrix | |
#A = rd.random((100,100)) | |
#Diagonal Matrix | |
#A = eye(7,7) | |
#******************************************************* | |
#Constant that is used to check for near-zero matrix values | |
#Smaller epsilon -> more accurate results for small-valued matrices | |
epsilon = 10**(-12) | |
#Iterations done before the program checks that the solution is | |
#a block matrix and thus calls a function to compute complex eigenvalues | |
iterate = 100 | |
#Transforms parameter matrix A into matrix with Hessenberg form | |
def Hessenberg(A): | |
#Checks that it is nxn, assigns the value to n | |
if(A.shape[0] != A.shape[1]): | |
return | |
else: | |
n = A.shape[0] | |
#The following for loop iterates on the parameter matrix A | |
#and constructs a matrix with Hessenberg form and equivalent | |
#eigenvalues of A. Computes x1, u1, p1, P1, and eventually the new A | |
for z in range(0,n-2): | |
x1 = A[z+1:,z] | |
vect = zeros(shape=(1,n-1-z)) | |
vect[0,0] = 1 | |
u1 = x1 - linalg.norm(x1)*vect.T | |
if(linalg.norm(u1) == 0): | |
continue | |
p1 = eye(n-1-z) - 2*(u1*u1.T)/linalg.norm(u1)**2 | |
P1 = zeros(shape=(n,n)) | |
for x in range(0,z+1): | |
P1[x,x] = 1 | |
for x in range(0,n-z-1): | |
P1[x+z+1,z+1:] = p1[x] | |
A = P1*A*P1 | |
return clean(A) | |
#Cleans A of approximately zero values using epsilon as the criteria | |
def clean(A): | |
#Checks that it is nxn, assigns the value to n | |
if(A.shape[0] != A.shape[1]): | |
return | |
else: | |
n = A.shape[0] | |
#Checks near-zero values in the matrix | |
for x in range(0,n): | |
for y in range(0,n): | |
if(abs(A[x,y]) < epsilon): | |
A[x,y] = 0 | |
return A | |
#Checks below the diagonal of A to determine if it is upper triangular | |
#Returns true if there are non-zero values below the diagonal | |
def scanLowerTriangle(A): | |
#Checks that it is nxn, assigns the value to n | |
if(A.shape[0] != A.shape[1]): | |
return | |
else: | |
n = A.shape[0] | |
#Checks below the diagonal for non-zero values | |
for x in range(1,n): | |
for y in range(0,x): | |
if(abs(A[x,y]) > epsilon): | |
return True | |
return False | |
#Checks whether the parameter matrix A is a block matrix | |
#Returns true if it is a block matrix | |
def isBlockMatrix(A): | |
#Checks that it is nxn and even, assigns the value to n | |
if(A.shape[0] != A.shape[1] or A.shape[0] % 2 != 0): | |
return | |
else: | |
n = A.shape[0] | |
#Automatically returns true if 2x2 | |
if(n == 2): | |
return True | |
#Checks each block on the diagonal for non-zero values | |
for x in range(2,n,2): | |
if(abs(A[x,x-2]) > epsilon): | |
return False | |
if(abs(A[x,x-1]) > epsilon): | |
return False | |
if(abs(A[x+1,x-2]) > epsilon): | |
return False | |
if(abs(A[x+1,x-1]) > epsilon): | |
return False | |
return True | |
#Computes the eigenvalues of a block matrix , returns eigenvalues | |
def complexCompute(A): | |
#Checks that it is nxn and even, assigns the value to n | |
if(A.shape[0] != A.shape[1] or A.shape[0] % 2 != 0): | |
return | |
else: | |
n = A.shape[0] | |
#Evaluates the eigenvalues of each 2x2 block on the diagonal | |
twoBytwos = [] | |
for x in range(0,n,2): | |
ai = zeros(shape=(2,2)) | |
ai[0] = A[x,x:x+2] | |
ai[1] = A[x+1,x:x+2] | |
twoBytwos.append(ai) | |
eigenvals = [] | |
for ai in twoBytwos: | |
eigenvals.append(linalg.eig(ai)[0]) | |
return eigenvals | |
#Iterates on A using the QR-Algorithm in order to compute the eigenvalues | |
def eigenSearch(A): | |
#Checks that it is nxn, assigns the value to n | |
if(A.shape[0] != A.shape[1]): | |
return | |
else: | |
n = A.shape[0] | |
#Values used to check for complex eigenvalues/block matrices | |
block = False | |
q = 0 | |
#Iterative loop that using QR-Algorithm where A will converge to | |
#either a diagonal or block matrix | |
while(scanLowerTriangle(A) == True and block == False): | |
Q = qr(A)[0] | |
R = qr(A)[1] | |
A = R*Q | |
q = q+1 | |
if(q >= iterate): | |
if(isBlockMatrix(A) == True and scanLowerTriangle(A) == True): | |
block = True | |
else: | |
q = 0 | |
#Cleans A and then computes the eigenvalues of A by either checking | |
#that it is a block matrix, and calling the complexCompute function, | |
#or by pulling the eigenvalues directly off of the diagonal of the | |
#triangular matrix | |
A = clean(A) | |
eigenvals = [] | |
if(block): | |
eigenvals = complexCompute(A) | |
else: | |
for x in range(0,n): | |
eigenvals.append(A[x,x]) | |
return eigenvals, A | |
#Runs the algorithm, prints the eigenvectors | |
print eigenSearch(Hessenberg(A))[0] | |
#Runs the algorithm, prints the decomposed matrix | |
#print eigenSearch(Hessenberg(A))[1] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment