<- function(A, k) {
approx_inverse # Compute eigenvalues and eigenvectors
<- eigen(A)
eig
# Sort eigenvalues and eigenvectors
<- order(eig$values, decreasing = TRUE)
idx <- eig$values[idx]
eigenvalues <- eig$vectors[, idx]
eigenvectors
# Select top k eigenvalues and eigenvectors
<- eigenvalues[1:k]
eigenvalues_k <- eigenvectors[, 1:k]
eigenvectors_k
# Compute approximate inverse
<- 1 / eigenvalues_k
inv_eigenvalues_k <- eigenvectors_k %*% diag(inv_eigenvalues_k) %*% t(eigenvectors_k)
approx_inv
return(approx_inv)
}
Background
Improve matrix inversion speed by approximating using eigendecomposition
def approx_inverse(A, k):
# Compute eigenvalues and eigenvectors
= np.linalg.eig(A)
eigenvalues, eigenvectors
# Sort eigenvalues and eigenvectors
= eigenvalues.argsort()[::-1]
idx = eigenvalues[idx]
eigenvalues = eigenvectors[:, idx]
eigenvectors
# Select top k eigenvalues and eigenvectors
= eigenvalues[:k]
eigenvalues_k = eigenvectors[:, :k]
eigenvectors_k
# Compute approximate inverse
= 1 / eigenvalues_k
inv_eigenvalues_k = eigenvectors_k @ np.diag(inv_eigenvalues_k) @ eigenvectors_k.T
approx_inv
return approx_inv
<- function(n) {
sim_mat <- qr.Q(qr(matrix(rnorm(n^2), n)))
p <- crossprod(p, p*(n:1))
Sigma return(Sigma)
}sim_mat(100)[1:10,1:10]
<- sim_mat(2000)
Sigma <- solve(Sigma)
Sigma.inv <- approx_inverse(Sigma, 10)
Sigma.inv.approx <- eigen(Sigma)
a cor(c(Sigma.inv), c(Sigma.inv.approx))
plot(c(Sigma.inv), c(Sigma.inv.approx))
install.packages("microbenchmark")
library(microbenchmark)
library(dplyr)
<- function(n, approx) {
fn1 <- sim_mat(n)
Sigma <- Sys.time()
t1 <- solve(Sigma)
Sigma.inv <- Sys.time() - t1
t1 <- Sys.time()
t2 <- approx_inverse(Sigma, approx)
Sigma.inv.approx <- Sys.time() - t2
t2 <- cor(c(Sigma.inv), c(Sigma.inv.approx))
a tibble(cor=a, k=approx, time1=t1, time2=t2)
}
fn1(1000, 10)
microbenchmark()
<- expand.grid(
param n =
)
Eigendecomposition is the slow part. What about if we do eigendecomposition once and
<- sim_mat(2000)
A
<- eigen(A)
eig
<- solve(A)
Ainv <- eig$vectors %*% diag(1/eig$values) %*% t(eig$vectors)
Ainv2
cor(c(Ainv), c(Ainv2))
<- sample(1:2000, 400)
i
<- solve(A[i, i])
Ainvs <- eig$vectors[i,] %*% diag(1/eig$values) %*% t(eig$vectors[i,])
Ainv2s
cor(c(Ainvs), c(Ainv2s))
plot(c(Ainvs), c(Ainv2s))
plot(c(Ainv), c(Ainv2))
# Sort eigenvalues and eigenvectors
<- order(eig$values, decreasing = TRUE)
idx <- eig$values[idx]
eigenvalues <- eig$vectors[, idx]
eigenvectors
# Select top k eigenvalues and eigenvectors
<- eigenvalues[1:k]
eigenvalues_k <- eigenvectors[, 1:k]
eigenvectors_k
# Compute approximate inverse
<- 1 / eigenvalues_k
inv_eigenvalues_k <- eigenvectors_k %*% diag(inv_eigenvalues_k) %*% t(eigenvectors_k)
approx_inv
return(approx_inv)
sessionInfo()