Switch BLAS/LAPACK without leaving your R session

BLAS and LAPACK comprise all the low-level linear algebra subroutines that handle your matrix operations in R and other software. Fedora ships the reference implementation from Netlib, which is accurate and stable, but slow, as well as several optimized backends, such as ATLASBLIS (serial, OpenMP and threaded versions) and OpenBLAS (serial, OpenMP and threaded flavours as well). However, up to version 32, Fedora lacked a proper mechanism to switch between them.

We are excited to announce that this situation changes with the upcoming release, which is already in beta status. Starting with Fedora 33, R (as well as Numpy, Octave and all the other BLAS/LAPACK consumers) is linked against the outstanding FlexiBLAS library, a BLAS/LAPACK wrapper that enables runtime switching of the optimized backend, and the OpenMP version of OpenBLAS is set as the default system-wide backend.

Moreover, the accompanying flexiblas R package enables changing the BLAS/LAPACK provider, as well as setting the number of threads for parallel backends, without leaving the R session. Let’s give this a quick test using docker:

$ docker run --rm -it fedora:33
$ dnf install R-flexiblas # install R and the FlexiBLAS API interface for R
$ dnf install flexiblas-* # install all available optimized backends

Then, in an R session we see:

library(flexiblas)

# check whether FlexiBLAS is available
flexiblas_avail()
#> [1] TRUE

# get the current backend
flexiblas_current_backend()
#> [1] "OPENBLAS-OPENMP"

# list all available backends
flexiblas_list()
#> [1] "NETLIB"           "__FALLBACK__"     "BLIS-THREADS"     "OPENBLAS-OPENMP"
#> [5] "BLIS-SERIAL"      "ATLAS"            "OPENBLAS-SERIAL"  "OPENBLAS-THREADS"
#> [9] "BLIS-OPENMP"

# get/set the number of threads
flexiblas_set_num_threads(12)
flexiblas_get_num_threads()
#> [1] 12

This is an example of GEMM benchmark for all the backends available:

library(flexiblas)

n <- 2000
runs <- 10
ignore <- "__FALLBACK__"

A <- matrix(runif(n*n), nrow=n)
B <- matrix(runif(n*n), nrow=n)

# load backends
backends <- setdiff(flexiblas_list(), ignore)
idx <- flexiblas_load_backend(backends)

# benchmark
timings <- sapply(idx, function(i) {
  flexiblas_switch(i)

  # warm-up
  C <- A[1:100, 1:100] %*% B[1:100, 1:100]

  unname(system.time({
    for (j in seq_len(runs))
      C <- A %*% B
  })[3])
})

results <- data.frame(
  backend = backends,
  `timing [s]` = timings,
  `performance [GFlops]` = (2 * (n / 1000)^3) / timings,
  check.names = FALSE)

results[order(results$performance),]
#>            backend timing [s] performance [GFlops]
#> 1           NETLIB     56.776            0.2818092
#> 5            ATLAS      5.988            2.6720107
#> 2     BLIS-THREADS      3.442            4.6484602
#> 8      BLIS-OPENMP      3.408            4.6948357
#> 4      BLIS-SERIAL      3.395            4.7128130
#> 6  OPENBLAS-SERIAL      3.206            4.9906425
#> 7 OPENBLAS-THREADS      0.773           20.6985770
#> 3  OPENBLAS-OPENMP      0.761           21.0249671

For questions, suggestions or issues related to this R interface, please use its issue tracker or the R-SIG-Fedora mailing list. For more general issues, please use Red Hat Bugzilla or the upstream issue tracker. There are a couple of posters by the authors of FlexiBLAS (1, 2) with a similar demo for Octave.

cran2copr: RPM repos with 15k binary R packages

Bringing R packages to Fedora (in fact, to any distro) is an Herculean task, especially considering the rate at which CRAN grows nowadays. So I am happy to announce the cran2copr project, which is an attempt to maintain binary RPM repos for most of CRAN (~15k packages as of Feb. 2020) in an automated way using Fedora Copr.

Are you a Fedora user? Enable the CRAN Copr repo for your system:

$ sudo dnf copr enable iucar/cran

and you are ready to go. Packages are prefixed with R-CRAN-, e.g.:

$ sudo dnf install R-CRAN-rstanarm

Currently, only x86_64 chroots for supported (non-EOL) versions of Fedora, including rawhide, are enabled. If you are interested in other chroots (from the supported architectures and distros), please open an issue on GitHub expressing so, but it is unlikely that it will be enabled in the short to medium term due to current storage limitations in the Copr infrastructure.

These repos are automatically synchronized with CRAN every day at 00:00 UTC through a GitHub Action that removes archived packages and builds the most recent updates. If you find any issue with any of the supported packages (see details and limitations below), please open an issue on GitHub.

Acknowledgements

Thanks to the authors of cran2deb for the inspiration. Thanks to RedHat and, particularly, the Copr team for developing this tool and maintaining the Fedora Copr service for the Fedora community. And thanks to AWS too, because they provide a CDN for free.

simmer 4.4.0 on CRAN

The 4.4.0 release of simmer, the Discrete-Event Simulator for R, is on CRAN. This update stabilises a new pace of a couple of new releases per year, which is more appropriate given the maturity that the project has reached.

This release brings us a dozen bug fixes and improvements, including the unification of the leave/renege API, further enhancements of convenience function to set up generators, and performance improvements for the simulation environment definition thanks to the vectorisation of add_resource and add_generator. See below for a complete list of changes.

New features

  • Add out and keep_seized parameters to leave() with the same behaviour as in renege_in() and renege_if(). Code and documentation of these functions are now integrated under help(renege) (#208, #217).
  • Convenience functions fromto and from_to accept dynamic parameters for arguments start_timestop_time and every (#219).
  • Activities to interact with sources have been vectorised to modify multiple sources at once (#222).
  • Several generators or resources with the same parameters can be added with a single call to add_generator() and add_resource() respectively if a vector of names is provided (#221).

Minor changes and fixes:

  • Fix get_mon_*() dispatch for named lists (#210).
  • Get/put the RNG state when random numbers are required in the backend (#218).
  • Fix convenience functions fromto and from_to to preserve the environment of the supplied functions (as part of #219).
  • Documentation improvements (#212, #220).
  • Fix queueing in multiple resources after preemption (#224 addressing #206).

El laberinto del IRPF

Sobre el IRPF existen muchas leyendas urbanas: desde las que dicen que a los catalanes se les va la mitad del sueldo en impuestos, hasta aquello de que supuestamente puedes acabar ganando menos con una subida de sueldo. Todo esto no es cierto, pero el tema tampoco es tan simple como aplicar los tipos por tramos de la famosa tabla y ya está. No en vano, la Agencia Tributaria tiene unos bonitos «manuales prácticos» de nada menos que 1300 páginas. En serio.

El caso es que a @marga_tf y a mí nos han concedido un proyecto de investigación multidisciplinar en la UC3M (más sobre esto, quizás, en otro momento), y el mes que viene toca sacar una oferta de empleo para contratar a un técnico de apoyo para el proyecto. Queremos que tenga un sueldo digno, y por ello andaba yo echando cuentas entre la calculadora de Cinco Días y la de la Agencia Tributaria para verificar el sueldo neto, pero me salían resultados distintos. Total, que una cosa llevó a la otra y… acabé haciéndome mi propia calculadora, cuya salida tiene esta pinta:

Lo hice y lo entendí. Y por si a alguien más le puede servir, he publicado una app donde se puede juguetear con los diferentes parámetros (tramos, cotización, reducción, mínimo…) y las gráficas cambian en consecuencia. Obviamente, cubre el caso más sencillo, pero variando los parámetros probablemente se puedan añadir deducciones y cubrir casos más complejos. El código está en GitHub.

Actualización: He añadido el cálculo del tipo marginal (cuánto pagas por cada euro adicional). Lo que sucede en las rentas bajas es un auténtico disparate. Por ejemplo, al pasar de ganar 17 mil euros brutos anuales a 18 mil, se perciben únicamente unos 400 euros más, lo que supone un 56% de IRPF para esos mil euros de subida. Ya lo denunciaban hace más de un año en Nada es Gratis (me puso sobre la pista @gilbellosta).

A más datos, mejor servicio público

La digitalización es un aspecto imparable de nuestras sociedades modernas. Cada vez más datos personales acaban en manos de grandes empresas tecnológicas que, en contraprestación, nos ofrecen cada vez nuevos y mejores servicios. Esto, no obstante, conlleva unos riesgos para la privacidad y una preocupación creciente de la ciudadanía, que ya ha visto saltar a los medios diversos escándalos por una gestión poco ética, o directamente ilegal, de esos datos. Leyes como la nueva GDPR europea responden a esa preocupación, y tratan de asegurar que la explotación de nuestros datos se realice con las máximas garantías, aunque todavía queda mucho por hacer.

Sigue leyendo A más datos, mejor servicio público, mi última colaboración en el Cuaderno de Cultura Científica, que complementa este otro, publicado hace unos días, acerca de la polémica suscitada la semana pasada por determinados titulares en prensa.