-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcoursework.py
More file actions
executable file
·154 lines (114 loc) · 4.35 KB
/
Copy pathcoursework.py
File metadata and controls
executable file
·154 lines (114 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/python
# -----------------------------------------------------------
# IMPORTS.
# Foreword: I imported numpy and linalg libraries,
# only to use functions that I do not deem to useful
# to rewrite. Its not worth reinventing the wheel for
# certain functions such as vdot (dot product of two vectors)
# and norm. These can be easily be rewritten if necessary
# but I did not do so since I did not want to waste time and
# instead focused on the core part of the exercise.
# -----------------------------------------------------------
from numpy import linalg as LA
import numpy as np
# -----------------------------------------------------------
# PRECISION THRESHOLD CONSTANT EPSILON
# The threshold is set to 0.0001 but can be set to a
# smaller value if desired.
# -----------------------------------------------------------
EPSILON = 1e-4
# -----------------------------------------------------------
# HELPER FUNCTIONS
# -----------------------------------------------------------
# Returns the given vector, normalized.
def normalize(v):
norm = LA.norm(v)
if norm == 0:
return v
return v / norm
# Computes the projection of u onto w.
def proj(u, w):
return (np.vdot(u, w) / (LA.norm(w)) ** 2) * w
# -----------------------------------------------------------
# QR DECOMPOSITION ALGORITHM USING GRAM SCHMIDT METHOD.
# The algorithm performs a gram schmidt decomposition on
# the matrix and concurrently calculates R.
# -----------------------------------------------------------
def qr_decomp(A):
# Get dimension of matrix.
n = len(A)
# Create a copy of the matrix.
cp = A.copy()
# Initialize 2 matrices Q and R.
Q = np.zeros(shape=(n, n))
R = np.zeros(shape=(n, n))
for i in range(n):
u = A[:, i]
w = u
# Apply GS method.
for k in range(i):
u -= proj(w, Q[:, k])
Q[:, i] = normalize(u)
# Fill R at correct position.
for j in range(i + 1):
R[j, i] = np.vdot(Q[:, j], cp[:, i])
# Return results.
return Q, R
# -----------------------------------------------------------
# THE QR ITERATION ALGORITHM
# Performs iterative QR decomposition, while concurrently
# changing q to obtain the eigenvectors. The function
# uses a helper which determines whether the computation
# is precise enough.
# -----------------------------------------------------------
def accurate_computation(r_0, r_1):
subtraction = np.matrix(r_1) - np.matrix(r_0)
return LA.norm(subtraction) < EPSILON
def qr_iterator(A):
q_0, r_0 = qr_decomp(A)
# Do initial computation.
a = np.array(np.matrix(r_0) * np.matrix(q_0))
# Iterate until the computation is accurate enough.
while True:
q, r = qr_decomp(a)
if accurate_computation(r_0, r):
return a, q_0
else:
q_0 = np.matrix(q_0) * np.matrix(q)
m = np.array(np.matrix(r) * np.matrix(q))
r_0 = r
a = m
# -----------------------------------------------------------
# THE MAIN METHOD.
# -----------------------------------------------------------
def main():
# Get input from the user.
n = int(input('Please enter the size of the matrix you would like to generate.\n'))
# Generate random matrix of correct dimensions
# Here N is chosen to be 100, but it can be any value
# the user sees fit.
# The user can reset this if necessary.
N = 100
rand_m = np.random.uniform(-N, N, size=(n, n))
# Make a symmetric matrix out of the generated matrix.
A = (rand_m + rand_m.T) / 2
# Effectuate QR iteration on A.
q, r = qr_iterator(A.copy())
# Open result file.
fout = open('results.txt', 'wb')
# Write the generated matrix.
fout.write('The generated matrix was:\n\n'.encode('utf-8'))
for line in np.matrix(A):
np.savetxt(fout, line, delimiter=' ', fmt='%8.3f')
# Write the eigenvalues.
fout.write('\nThe resulting eigenvalues are:\n\n'.encode('utf-8'))
eigenvalues = np.array(np.diagonal(q))
np.savetxt(fout, eigenvalues.reshape(1, eigenvalues.shape[0]), delimiter=', ', fmt='%.3f')
# Write the eigenvectors.
fout.write('\nThe resulting eigenvectors are:\n\n'.encode('utf-8'))
for line in r:
np.savetxt(fout, line, delimiter=' ', fmt='%8.3f')
# Finish and close the file.
fout.close()
if __name__ == "__main__":
main()