Faster matrix math in R on macOS

Update (October 2021): macOS 10.14 “Big Sur” and later do not ship with Accelerate BLAS dynamic libraries in the filesystem, so this trick only works up to macOS 10.13 “High Sierra”

If you want faster matrix operations in R on your Mac, you can use Apple’s BLAS (Basic Linear Algebra Subprograms) library from their Accelerate framework instead of the library which comes with the R binary that you get from CRAN. (Unless you built R from source yourself.) CRAN recommends against this, saying:

Although fast, it is not under our control and may possibly deliver inaccurate results. [Source: R for Mac OS X FAQ]

So proceed at your own discretion, I suppose? To switch Apple’s BLAS:

cd /Library/Frameworks/R.framework/Resources/lib
ln -sf /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/Versions/Current/libBLAS.dylib libRblas.dylib

You can verify by running sessionInfo() in R. You should see:

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

P.S. Use ln -sf libRblas.0.dylib libRblas.dylib to revert back to default.

Benchmarks

Benchmark 1

library(microbenchmark)
d <- 1e3
x <- matrix(rnorm(d^2), d, d)
microbenchmark(tcrossprod(x), solve(x), svd(x), times = 10L)

With R’s default (libRblas.0.dylib):

Unit: milliseconds
          expr       min        lq      mean    median        uq       max
 tcrossprod(x)  276.9307  278.8472  283.9451  282.5854  288.7777  299.6700
      solve(x)  681.5183  696.7888  703.4895  703.6030  712.5728  724.7195
        svd(x) 2672.3574 2692.6614 2701.0442 2698.4279 2722.2180 2730.9727

With Apple’s vecLib (libBLAS.dylib):

Unit: milliseconds
          expr        min        lq      mean    median        uq       max
 tcrossprod(x)   8.642364  10.59531  10.60989  10.80781  11.35995  11.62067
      solve(x)  37.205422  41.38051  43.77767  42.34975  42.92999  54.71387
        svd(x) 278.528673 290.26926 304.74482 307.49666 317.56819 325.29980

Benchmark 2

library(microbenchmark)
set.seed(20190604)
n <- 1e3
p <- 1e2
b <- rnorm(p + 1, 0, 10)
x <- matrix(runif(n * p, -10, 10), ncol = p, nrow = n)
y <- cbind(1, x) %*% b + rnorm(n, 0, 2)
microbenchmark(lm(y ~ x))

With R’s default (libRblas.0.dylib):

Unit: milliseconds
           expr     min       lq     mean   median       uq      max neval
      lm(y ~ x) 17.0145 20.27288 22.58367 22.16553 24.49879 37.37704   100

With Apple’s vecLib (libBLAS.dylib):

Unit: milliseconds
           expr      min       lq    mean   median       uq      max neval
      lm(y ~ x) 5.478486 7.888307 9.210001 8.84202 10.30503 15.80064   100
Posted on:
June 4, 2019
Length:
2 minute read, 328 words
Tags:
computing R
See Also:
Wikipedia Preview for R Markdown documents
Even faster matrix math in R on macOS with M1
Making Of: Session Tick visualization