1. Geometric Transformation of Shapes Using Matrix Multiplication

# triangle vertices
triangle <- matrix(c(0,0,
                     1,0,
                     .5,1),
                   ncol = 2, byrow = TRUE)




plot(triangle, type= "n", xlim= c(-2,2), xlab = "X", ylab= "Y", asp=1)
polygon(triangle, col="red", border = "black")
points(triangle, pch = 19)
text(triangle, labels = c("A", "B", "C"), pos = 3)

Scaling

triangle <- matrix(c(0, 0,  
                     2, 0,  
                     1, 2), 
                   ncol = 2, byrow = TRUE)


plot(NULL, xlim = c(-3, 3), ylim = c(-3, 3), 
     xlab = "X-axis", ylab = "Y-axis", main = "Incrementally Scaled Triangle")  

# Loop through specified scale values
scale_values <- c(1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0, 0.75, 0.5, 0.75)


for (val in scale_values) {
 
  trans_matrix <- matrix(c(val, 0, 
                            0, val), nrow = 2, ncol = 2)
  

  scaled_triangle <- triangle %*% t(trans_matrix)
  
 
  polygon(scaled_triangle, col = rgb(0.5, 0.5, 1, alpha = 0.5), border = "black")
}

Rotate

triangle <- matrix(c(0, 0,  
                     2, 0,  
                     1, 2), 
                   ncol = 2, byrow = TRUE)


plot(NULL, xlim = c(-3, 3), ylim = c(-3, 3), 
     xlab = "X-axis", ylab = "Y-axis", main = "Incrementally Rotated Triangle") 


rotation_angles <- seq(0, 2 * pi, length.out = 12)  


for (theta in rotation_angles) {

  rotation_matrix <- matrix(c(cos(theta), -sin(theta),
                              sin(theta), cos(theta)), ncol = 2)
  
 
  rotated_triangle <- triangle %*% t(rotation_matrix)
  
 
  polygon(rotated_triangle, col = rgb(0.5, 0.5, 1, alpha = 0.5), border = "black")
}

Reflection

triangle <- matrix(c(0, 0,  
                     2, 0,  
                     1, 2), 
                   ncol = 2, byrow = TRUE)


plot(NULL, xlim = c(-3, 3), ylim = c(-3, 3), 
     xlab = "X-axis", ylab = "Y-axis", main = "Incrementally Reflected Triangle")  


reflection_matrices <- list(
  matrix(c(1, 0,  # Reflection across X-axis
            0, -1), ncol = 2),
  matrix(c(-1, 0,  # Reflection across Y-axis
            0, 1), ncol = 2),
  matrix(c(0, 1,  # Reflection across Y = X
            1, 0), ncol = 2),
  matrix(c(0, -1,  # Reflection across Y = -X
            -1, 0), ncol = 2)
)


for (reflection_matrix in reflection_matrices) {
  
  reflected_triangle <- triangle %*% t(reflection_matrix)
  
 
  polygon(reflected_triangle, col = rgb(1, 0.5, 0.5, alpha = 0.5), border = "black")
}

2. Matrix Properties and Decomposition

Prove AB =/ BA

## [1] "Matrix A:"
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    4
## [1] "Matrix B:"
##      [,1] [,2]
## [1,]    0    1
## [2,]    1    0
## [1] "AB (A * B):"
##      [,1] [,2]
## [1,]    2    1
## [2,]    4    3
## [1] "BA (B * A):"
##      [,1] [,2]
## [1,]    3    4
## [2,]    1    2
## [1] "Are AB and BA identical?  FALSE"

Prove that A^TA is symmetric

## 
## A^T * A:
##      [,1] [,2]
## [1,]   10   14
## [2,]   14   20
## 
## Is A^T * A symmetric?  TRUE

Prove that A^T A is non-negative

## 
## Determinant of A^T * A:  4
## Is the determinant non-negative?  TRUE

Singular Value Decomposition (SVD) and image compression

3. Matrix Rank, Properties, and eigenspace

Determine the Rank of Matrix A

A <- matrix(c(2, 4, 1, 3, 
              -2, -3, 4, 1, 
              5, 6, 2, 8, 
              -1, -2, 3, 7), nrow = 4, byrow = TRUE)

# Find the rank of matrix A
rank_A <- qr(A)$rank


cat("Rank of matrix A: ", rank_A, "\n")
## Rank of matrix A:  4

Determine the Rank of Matrix B Using Row Reduction

## Rank of matrix B:  1

Compute the Eigenvalues and Eigenvectors of Matrix A

A_eigen <- matrix(c(3, 1, 2, 
                    0, 5, 4, 
                    0, 0, 2), nrow = 3, byrow = TRUE)

# Compute eigenvalues and eigenvectors
eigen_A <- eigen(A_eigen)

# Print eigenvalues and eigenvectors
cat("Eigenvalues of A:\n")
## Eigenvalues of A:
print(eigen_A$values)
## [1] 5 3 2
cat("\nEigenvectors of A:\n")
## 
## Eigenvectors of A:
print(eigen_A$vectors)
##           [,1] [,2]       [,3]
## [1,] 0.4472136    1 -0.3713907
## [2,] 0.8944272    0 -0.7427814
## [3,] 0.0000000    0  0.5570860

Check Linear Independence:

eigenvectors <- eigen_A$vectors


det_eigenvectors <- det(eigenvectors)

cat("\nDeterminant of the matrix of eigenvectors: ", det_eigenvectors, "\n")
## 
## Determinant of the matrix of eigenvectors:  -0.4982729
# If determinant is non-zero, the eigenvectors are linearly independent
cat("Are the eigenvectors linearly independent? ", det_eigenvectors != 0, "\n")
## Are the eigenvectors linearly independent?  TRUE

Diagonalization of Matrix A

D <- diag(eigen_A$values)

# Matrix of eigenvectors
P <- eigen_A$vectors


A_diag <- P %*% D %*% solve(P)

cat("\nDiagonalized matrix A:\n")
## 
## Diagonalized matrix A:
print(A_diag)
##      [,1] [,2] [,3]
## [1,]    3    1    2
## [2,]    0    5    4
## [3,]    0    0    2
equality_check <- all.equal(A_diag, A)
if (isTRUE(equality_check)) {
  cat("\nA_diag is approximately equal to A.\n")
} else {
  cat("\nA_diag is not equal to A: ", equality_check, "\n")
}
## 
## A_diag is not equal to A:  Attributes: < Component "dim": Mean relative difference: 0.3333333 > Numeric: lengths (9, 16) differ

4. Project: Eigenfaces from the LFW (Labeled Faces in the Wild) Dataset

Download the LFW Datase, Preprocess the Images:

resize <- function(img, width, height) {

  img_resized <- imager::resize(img, size_x = width, size_y = height)
  return(as.matrix(img_resized))
}


preprocess_images <- function(directory, target_size = c(64, 64), max_images = 100) {
 
  image_files <- list.files(directory, pattern = "\\.jpg$", full.names = TRUE, recursive = TRUE)
  
  
  image_files <- head(image_files, max_images)
  
  images <- list()
  
  for (file in image_files) {
    img <- readJPEG(file)

   
    if (length(dim(img)) == 3 && dim(img)[3] == 3) {
      
      gray_img <- 0.2989 * img[,,1] + 0.5870 * img[,,2] + 0.1140 * img[,,3]
    } else if (length(dim(img)) == 2) {
      
      gray_img <- img
    } else {
      stop(paste("Image format not supported for file:", file))
    }
    
    
    resized_img <- resize(as.cimg(gray_img), target_size[1], target_size[2])
    
    
    images[[file]] <- as.vector(resized_img)
  }
  
  return(do.call(rbind, images))  
}


image_matrix <- preprocess_images("C:/Users/angel/OneDrive/Desktop/lfw")

Apply PCA:

# Perform PCA
if (is.null(image_matrix) || nrow(image_matrix) == 0) {
    stop("image_matrix is NULL or empty. Please check your preprocessing step.")
}


pca_result <- prcomp(image_matrix, center = TRUE, scale. = TRUE)

# Determine the variance explained by each principal component
explained_variance <- pca_result$sdev^2 / sum(pca_result$sdev^2)
cumulative_variance <- cumsum(explained_variance)

# Find the number of components that explain 80% of the variance
num_components <- which(cumulative_variance >= 0.80)[1]
cat("Number of components for 80% variance:", num_components, "\n")
## Number of components for 80% variance: 26

visualize Eigenfaces

plot_eigenfaces <- function(pca_result, num_faces = 10) {
  par(mfrow = c(2, num_faces / 2))
  for (i in 1:num_faces) {
    eigenface <- matrix(pca_result$rotation[, i], nrow = 64)  
    image(eigenface, axes = FALSE, col = gray.colors(256))
  }
}


plot_eigenfaces(pca_result, num_faces = 10)

Reconstruct Images Using Eigenfaces

reconstructed_images <- pca_result$x[, 1:num_components] %*% t(pca_result$rotation[, 1:num_components])


plot_reconstructed_images <- function(reconstructed_images, num_faces = 10, image_size = 64) {
  par(mfrow = c(2, num_faces / 2), mar = c(1, 1, 1, 1))  
  for (i in 1:num_faces) {
    reconstructed_image <- matrix(reconstructed_images[i, ], nrow = image_size)  # Reshape to 64x64
    image(reconstructed_image, axes = FALSE, col = gray.colors(256))
    title(main = paste("Reconstructed Image", i)) 
  }
}


plot_reconstructed_images(reconstructed_images, num_faces = 10, image_size = 64)