Rlinsolve is a collection of iterative solvers for (sparse) linear system of equations. It heavily relies on two popular packages, RcppArmadillo for speeding up computation and Matrix for sparse matrix support.
Introducing RcppArmadillo simply added computational boost. Let’s check by comparing with some basic approaches by simulating 10000 x 500 system matrix for normal equation form.
library(microbenchmark)
library(pcg)
library(optR)
library(Rlinsolve)
A = matrix(rnorm(10000*50),nrow=10000)
x = matrix(rnorm(50))
b = A%*%x
First example is to use a default solve
function from R base.
# for SOLVE in R base, it needs to be transformed into normal equation form.
Anormal = t(A)%*%A
bnormal = t(A)%*%b
microbenchmark(solve(Anormal,bnormal))
## Unit: microseconds
## expr min lq mean median uq max
## solve(Anormal, bnormal) 78.325 81.8975 87.49633 82.531 83.527 499.605
## neval
## 100
Let’s compare other available packages(pcg
and optR
) and their computation time,
microbenchmark(pcg(Anormal,bnormal),
optR(A,b,method="gauss"),
times=10)
## Unit: microseconds
## expr min lq mean median
## pcg(Anormal, bnormal) 176.942 180.905 1699.8 204.992
## optR(A, b, method = "gauss") 124439.352 125070.702 148178.9 127928.057
## uq max neval
## 212.599 15077.92 10
## 131852.394 260476.41 10
Finally, let’s test two functions in our package, lsolve.bicgstab and lsolve.sor,
microbenchmark(lsolve.sor(A,b,verbose=FALSE),
lsolve.bicgstab(A,b,verbose=FALSE),
times=10)
## Unit: milliseconds
## expr min lq mean
## lsolve.sor(A, b, verbose = FALSE) 21.19073 21.93595 27.70857
## lsolve.bicgstab(A, b, verbose = FALSE) 22.27486 22.49040 26.41073
## median uq max neval
## 22.74821 24.72226 66.97025 10
## 23.15536 23.68600 56.83389 10
where we can witness that our codes are definitely faster by at least several folds.
We have an auxiliary function to generate sparse system matrix, aux.fisch
, and let’s make a 100 x 100 sparse matrix, and corresponding system.
Psparse = aux.fisch(10,sparse=TRUE) # sparse matrix
Pdense = aux.fisch(10,sparse=FALSE) # dense matrix
x = matrix(rnorm(100))
b = Pdense %*% x
Again, we perform the test from previously used functions from other packages as well as functions in Rdimtools package,
microbenchmark(solve(Pdense,b),
optR(Pdense,b,method="gauss"),
pcg(Pdense,b),
times=10)
## Unit: microseconds
## expr min lq mean
## solve(Pdense, b) 238.379 244.152 264.7912
## optR(Pdense, b, method = "gauss") 56443.788 56734.605 58115.9259
## pcg(Pdense, b) 733.741 758.646 825.7333
## median uq max neval
## 257.6550 264.911 347.933 10
## 56915.9395 57821.605 66459.789 10
## 785.2585 788.458 1249.490 10
microbenchmark(lsolve.bicg(Psparse,b,verbose=FALSE),
lsolve.cgs(Psparse,b,verbose=FALSE),
lsolve.gs(Psparse,b,verbose=FALSE),
lsolve.sor(Psparse,b,verbose=FALSE),
times=10)
## Unit: milliseconds
## expr min lq mean
## lsolve.bicg(Psparse, b, verbose = FALSE) 16.11628 17.44843 21.20758
## lsolve.cgs(Psparse, b, verbose = FALSE) 13.06897 13.20903 23.71067
## lsolve.gs(Psparse, b, verbose = FALSE) 12.16514 19.67327 26.33566
## lsolve.sor(Psparse, b, verbose = FALSE) 14.24851 18.29322 23.58357
## median uq max neval
## 17.66852 18.25845 51.71854 10
## 14.07305 17.32506 68.83595 10
## 21.32276 27.33819 71.31194 10
## 23.34910 24.53429 43.74753 10
where in our case, supporting sparse matrices have shown much superior results. Note that the size has been set to be small since dense solvers are too slow to be manageably visible.