This commit is contained in:
jakubknczny 2021-05-31 18:06:14 +02:00
parent b37d1af801
commit 6ed8b516e3

98
main.py
View File

@ -1,23 +1,30 @@
from typing import Tuple
import numpy as np
from copy import deepcopy from copy import deepcopy
from matplotlib import pyplot as plt
from typing import Tuple
import numpy as np
from scipy.linalg import solve
""" """
Class that performs qr decomposition. Use methods: Class that performs qr decomposition. Use methods:
perform_householder_QR, perform_householder_QR,
perform_givens_QR perform_givens_QR
both accept np.nadarry that fulfils m >= n condtion is 2d, and contains real numbers. both accept np.ndarray that fulfils m >= n condition is 2d, and contains real numbers.
""" """
class QR: class QR:
def __init__(self) -> None: def __init__(self) -> None:
pass pass
""" """
Checks if caulcuated matricies fulfill QR decomposition conditions, that is: Checks if calculated matrices fulfill QR decomposition conditions, that is:
A = QR , where Q -> Q * Qt = I and R is a upper triangular matrix A = QR , where Q -> Q * Qt = I and R is a upper triangular matrix
""" """
def __check_condition(self, Q: np.matrix, R: np.matrix) -> bool: def __check_condition(self, Q: np.matrix, R: np.matrix) -> bool:
if not np.allclose(R, np.triu(R)): if not np.allclose(R, np.triu(R)):
print("R matrix is not upper traingle.") print("R matrix is not upper triangle.")
return False return False
I = np.identity(Q.shape[1]) I = np.identity(Q.shape[1])
comparison = np.equal(np.matmul(np.transpose(Q), Q), I) comparison = np.equal(np.matmul(np.transpose(Q), Q), I)
@ -25,9 +32,11 @@ class QR:
print("Q matrix is not orthogonal.") print("Q matrix is not orthogonal.")
return False return False
return True return True
""" """
Checks if given matrix is 2d, m >= n and filled with real numbers Checks if given matrix is 2d, m >= n and filled with real numbers
""" """
def __check_pre_conditions(self, matrix: np.ndarray) -> bool: def __check_pre_conditions(self, matrix: np.ndarray) -> bool:
if not matrix.shape[0] >= matrix.shape[1]: if not matrix.shape[0] >= matrix.shape[1]:
print("Matrix is m is lesser than n.") print("Matrix is m is lesser than n.")
@ -36,16 +45,17 @@ class QR:
print("Matrix is not 2D.") print("Matrix is not 2D.")
return False return False
if not np.isreal(matrix).all(): if not np.isreal(matrix).all():
print("Matrix doesn't containt all real numbers.") print("Matrix doesn't contain all real numbers.")
return False return False
return True return True
""" """
Method that performs Householder Transformation QR, acceptcs 2D, real numbers matrix, that Method that performs Householder Transformation QR, accepts 2D, real numbers matrix, that
fulfills m >= n condition. Return Q and R matrices. fulfills m >= n condition. Return Q and R matrices.
""" """
def perform_householder_QR(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: def perform_householder_QR(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
if(self.__check_pre_conditions(matrix)): if self.__check_pre_conditions(matrix):
return self.__householder_qr(matrix) return self.__householder_qr(matrix)
else: else:
print("Incorrect type.") print("Incorrect type.")
@ -55,10 +65,10 @@ class QR:
v = matrix / (matrix[0] + np.copysign(np.linalg.norm(matrix), matrix[0])) v = matrix / (matrix[0] + np.copysign(np.linalg.norm(matrix), matrix[0]))
v[0] = 1 v[0] = 1
tau = 2 / (v.T @ v) tau = 2 / (v.T @ v)
return v,tau return v, tau
def __householder_qr(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: def __householder_qr(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
m,n = matrix.shape m, n = matrix.shape
R = matrix.copy() R = matrix.copy()
Q = np.identity(m) Q = np.identity(m)
@ -76,27 +86,40 @@ class QR:
m, n = matrix.shape m, n = matrix.shape
R = matrix R = matrix
Q = np.eye(m) Q = np.eye(m)
G = np.zeros((2,2)) G = np.zeros((2, 2))
for j in range(n): for j in range(n):
for i in reversed(range(j+1, m)): for i in reversed(range(j + 1, m)):
a, b = R[i-1, j], R[i, j] a, b = R[i - 1, j], R[i, j]
G = np.asarray([[a, b], [-b, a]]) / np.sqrt(a**2 + b**2) G = np.asarray([[a, b], [-b, a]]) / np.sqrt(a ** 2 + b ** 2)
R[i-1:i+1, j] = G @ R[i-1:i+1, j] R[i - 1:i + 1, j] = G @ R[i - 1:i + 1, j]
Q[i-1:i+1, :] = G @ Q[i-1:i+1, :] Q[i - 1:i + 1, :] = G @ Q[i - 1:i + 1, :]
return Q.T, R return Q.T, R
""" """
Method that performs Givens Rotation QR, acceptcs 2D, real numbers matrix, that Method that performs Givens Rotation QR, accepts 2D, real numbers matrix, that
fulfills m >= n condition. Return Q and R matrices. fulfills m >= n condition. Return Q and R matrices.
""" """
def perform_givens_QR(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
if(self.__check_pre_conditions(matrix)): def perform_givens_QR(self, matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
if self.__check_pre_conditions(matrix):
return self.__givens_qr(matrix) return self.__givens_qr(matrix)
else: else:
print("Incorrect type.") print("Incorrect type.")
raise Exception raise Exception
def solve_least_squares(self, A: np.ndarray, b: np.array):
Q, R = self.perform_householder_QR(A)
x = solve(R, np.dot(Q.T, b))
return x
def __design_matrix(self, A: np.ndarray):
return np.hstack((np.ones(A.shape[0]).reshape(-1, 1), A[:, :-1]))
def fit_poly(self, A: np.ndarray):
return self.solve_least_squares(
np.dot(self.__design_matrix(A), self.__design_matrix(A).T),
A[:, -1:].reshape(-1, 1))
""" """
@ -104,7 +127,7 @@ Usage example
""" """
if __name__ == "__main__": if __name__ == "__main__":
qr = QR() qr = QR()
matrix = np.matrix('1 2 4; 5 6 7; 8 9 10') matrix = np.matrix('0 0 0; 1 1 2; 1 2 4; 3 3 5; 5 6 7; 8 9 10')
matrix = np.asarray(matrix) matrix = np.asarray(matrix)
print(matrix) print(matrix)
a = deepcopy(matrix) a = deepcopy(matrix)
@ -123,4 +146,39 @@ if __name__ == "__main__":
Q, R = np.linalg.qr(c) Q, R = np.linalg.qr(c)
print(Q) print(Q)
print(R) print(R)
print('solve least squares')
b_v = np.asarray([1, 1, ])
print(matrix)
print(b_v)
def PolyCoefficients(x, coeffs):
""" Returns a polynomial for ``x`` values for the ``coeffs`` provided.
The coefficients must be in ascending order (``x**0`` to ``x**o``).
"""
o = len(coeffs)
y = 0
for i in range(o):
y += coeffs[i] * x ** i
return y
def f(a, b):
return a + 2 * b
x1 = np.asarray(range(0, 6))
x2 = np.asarray(range(0, 6))
y = f(x1, x2)
mat = np.asmatrix([x1, x2, y])
plt3d = plt.figure().gca(projection='3d')
xx, yy = np.meshgrid(range(10), range(10))
plt3d.plot_surface(xx, yy, f(xx, yy), alpha=0.2)
print(mat.T)
print(matrix)
print(matrix.shape, mat.T.shape)
# plt3d.plot_surface(xx, yy, PolyCoefficients(xx, qr.fit_poly(matrix)), alpha=0.2)
plt3d.plot_surface(xx, yy, PolyCoefficients(xx, qr.fit_poly(mat.T)), alpha=0.2)
plt.show()