Reputation: 2703
I have an upper triangular matrix and I'd like to compute its inverse in a fast way. I tried qr.solve()
but I have the feeling that it's equivalent to solve()
, and that it does not exploit the triangular nature of the input matrix. What is the best way to do it?
Upvotes: 3
Views: 4025
Reputation: 11
I have, of late, confronted the same problem. My solution has been to load the Matrix package, and then define the following two R functions serving as wrappers for that task:
my.backsolve <- function(A, ...) solve(triu(A), ...)
my.forwardsolve <- function(A, ...) solve(tril(A), ...)
These need the Matrix package because triu
and tril
are defined in it. Then my.backsolve(A)
(resp. my.forwardsolve(A)
) computes the inverse of A
for the upper (resp. lower) triangular case.
A minor issue, though, might be that the result of each of the above two R functions is of class Matrix
. If one has issues with that, then apply as.vector
or as.matrix
to the result according to whether the r.h.s. is a vector or a matrix (in the algebraic sense).
Upvotes: 1
Reputation: 1
The R base function chol2inv
might be doing the trick for inverting triangular matrix. Inverts a symmetric, positive definite square matrix from its Choleski decomposition
. Equivalently, compute (X'X)^(-1)
from the (R part) of the QR decomposition of X
.
Even more generally, given an upper triangular matrix R, compute (R'R)^(-1)
.
See https://stat.ethz.ch/R-manual/R-devel/library/base/html/chol2inv.html
I tested its speed by microbenchmark method: qr.solve is slowest, solve ranks 3rd in speed, backsolve ranks 2nd in speed, chol2inv is the fastest.
cma <- chol(ma <- cbind(1, 1:3, c(1,3,7)))
microbenchmark(qr.solve(ma), solve(ma), cma<-chol(ma), chol2inv(cma), invcma<-backsolve(cma, diag(nrow(cma))), backinvma<-tcrossprod(invcma))
Upvotes: -1
Reputation: 5314
If you want to get the inverse of your matrix M
, you can simply use backsolve(M, diag(dim(M)[1]))
. For example:
M <- matrix(rnorm(100), 10, 10) # random matrix
M[lower.tri(M)] <- 0 # make it triangular
Minv <- backsolve(M, diag(dim(M)[1]))
M%*%Minv
When running this code you may see M%*%Minv
with very low coefficient (~10^-15) due to numerical approximation.
Upvotes: 2
Reputation: 2194
Try backsolve()
and use the identity matrix with appropriate dimension as the right-hand value.
library(microbenchmark)
n <- 2000
n.cov <- 1000
X <- matrix(sample(c(0L, 1L), size = n * n.cov, replace = TRUE),
nrow = n, ncol = n.cov)
R <- chol(crossprod(X))
rm(X)
microbenchmark(
backsolve = backsolve(r = R, x = diag(ncol(R))),
solve = solve(R),
times = 10)
Unit: milliseconds
expr min lq mean median uq max neval
backsolve 467.2802 467.5142 469.4457 468.1578 468.6501 482.2431 10
solve 748.2351 748.8318 750.0764 750.3319 750.9583 751.5005 10
Upvotes: 4
Reputation: 3561
It seems solve
performs somewhat faster than qr.solve
but qr.solve
is more robust.
n <- 50
mymatrix <- matrix(0, nrow=n, ncol=n)
fun1 <- function() {
for (i in 1:n) {
mymatrix[i, i:n] <- rnorm(n-i+1)+3
}
solve(mymatrix)
}
fun2 <- function() {
for (i in 1:n) {
mymatrix[i, i:n] <- rnorm(n-i+1)+3
}
qr.solve(mymatrix)
}
> system.time(for (i in 1:1000) fun1())
user system elapsed
1.92 0.03 1.95
> system.time(for (i in 1:1000) fun2())
user system elapsed
2.92 0.00 2.92
Note that if we remove the +3
when editing the matrix cells, solve
will almost always fail and qr.solve
will still usually give an answer.
> set.seed(0)
> fun1()
Error in solve.default(mymatrix) :
system is computationally singular: reciprocal condition number = 3.3223e-22
> set.seed(0)
> fun2()
[returns the inverted matrix]
Upvotes: 0