Files
math6601_projects/project1/Project1_Q1.py
2025-09-26 22:16:05 -04:00

108 lines
3.4 KiB
Python

import numpy as np
def proj(A:np.ndarray, b:np.ndarray) -> np.ndarray:
"""
Project vector b onto the column space of matrix A using the formula:
proj_A(b) = A(A^* A)^(-1) A^* b
Parameters:
A (np.ndarray): The matrix whose column space we are projecting onto.
b (np.ndarray): The vector to be projected.
Returns:
np.ndarray: The projection of b onto the column space of A.
"""
# Check if A is full rank
if np.linalg.matrix_rank(A) < min(A.shape):
raise ValueError("Matrix A must be full rank.")
# Compute the projection
AhA_inv = np.linalg.inv(A.conj().T @ A)
projection = A @ AhA_inv @ A.conj().T @ b
return projection
def proj_SVD(A:np.ndarray, b:np.ndarray) -> np.ndarray:
"""
Project vector b onto the column space of matrix A using SVD.
Parameters:
A (np.ndarray): The matrix whose column space we are projecting onto.
b (np.ndarray): The vector to be projected.
Returns:
np.ndarray: The projection of b onto the column space of A.
"""
# A = U S V^*
U, S, Vh = np.linalg.svd(A, full_matrices=False)
"""
proj_A(b) = A(A^* A)^(-1) A^* b
= U S V^* (V S^2 V^*)^(-1) V S U^* b
= U S V^* V S^(-2) V^* V S U^* b
= U U^* b
"""
# Compute the projection using the SVD components
projection = U @ U.conj().T @ b
return projection
def build_A(eps: float) -> np.ndarray:
"""
Build the matrix A(ε) as specified in the problem statement.
"""
A = np.array([
[1.0, 1.0, 0.0, (1.0 - eps)],
[1.0, 0.0, 1.0, (eps + (1.0 - eps))],
[0.0, 1.0, 0.0, eps],
[1.0, 0.0, 0.0, (1.0 - eps)],
[1.0, 0.0, 0.0, (eps + (1.0 - eps))]
], dtype=float)
return A
def build_b() -> np.ndarray:
"""
Build the vector b as specified in the problem statement.
"""
b = np.array([2.0, 1.0, 3.0, 1.0, 4.0])
return b
def question_1a(A: np.ndarray, b: np.ndarray):
# Question 1(a)
print("Question 1(a):")
projection = proj(A, b)
print("Projection of b onto the column space of A(1): (Using proj function)")
print(projection)
projection_svd = proj_SVD(A, b)
print("Projection of b onto the column space of A(1): (Using proj_SVD function)")
print(projection_svd)
print("Difference between the two methods:")
print(projection - projection_svd)
def question_1b(A: np.ndarray, b: np.ndarray):
# Question 1(b)
print("\nQuestion 1(b):")
for eps in [1.0, 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32]:
print(f"\nFor ε = {eps}:")
A_eps = build_A(eps)
try:
projection_eps = proj(A_eps, b)
print(f"Projection of b onto the column space of A({eps}):")
print(projection_eps)
except np.linalg.LinAlgError as e:
print(f"LinAlgError for eps={eps}: {e}")
except ValueError as ve:
print(f"ValueError for eps={eps}: {ve}")
projection_svd_eps = proj_SVD(A_eps, b)
print(f"Projection of b onto the column space of A({eps}) using SVD:")
print(projection_svd_eps)
print("Difference between the two methods:")
try:
print(projection_eps - projection_svd_eps)
except:
print("Could not compute difference due to previous error.")
projection_eps = None # Reset for next iteration
if __name__ == "__main__":
A = build_A(eps=1.0)
b = build_b()
question_1a(A, b)
question_1b(A, b)