Basics of Rlinsolve

Kisung You

2017-12-06

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) 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.

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)   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.