Basics of Rlinsolve

Kisung You

2017-10-07

Rlinsolve

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.

Solving Ax=b

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.

Solving Ax=b with sparse A

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.