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) 77.097 79.875 84.7426 80.764 81.8005 426.226
## 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) 205.117 212.147 1752.606 216.463
## optR(A, b, method = "gauss") 126487.087 129042.099 153720.770 135657.781
## uq max neval
## 266.959 15352.81 10
## 141199.090 261307.09 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) 23.84495 24.78473 30.24274
## lsolve.bicgstab(A, b, verbose = FALSE) 24.97148 25.80768 31.73318
## median uq max neval
## 26.11515 27.40209 69.77136 10
## 26.55203 28.52512 73.96657 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) 226.311 264.939 285.5058
## optR(Pdense, b, method = "gauss") 57101.033 58165.199 61133.6082
## pcg(Pdense, b) 748.079 789.130 851.2275
## median uq max neval
## 272.2215 314.235 349.444 10
## 60154.8845 61938.211 70940.536 10
## 799.9620 847.336 1228.328 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) 17.59523 18.26187 22.77363
## lsolve.cgs(Psparse, b, verbose = FALSE) 12.88290 13.39831 19.55777
## lsolve.gs(Psparse, b, verbose = FALSE) 19.58531 19.85953 32.53004
## lsolve.sor(Psparse, b, verbose = FALSE) 15.54219 24.76857 26.00506
## median uq max neval
## 18.93487 19.85735 56.93639 10
## 13.89513 14.50053 56.41323 10
## 26.69694 29.37179 70.60771 10
## 27.28669 27.86600 30.37206 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.