Example from presentation “Byte Code Compiler Recent Work on R Runtime” by Tomas Kalibera with Luke Tierney Jan Vitek
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Vectorised solution
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
convv <- function(x, y) {
nx <- length(x)
ny <- length(y)
xy <- rbind(outer(x,y),
matrix(0, nx, ny))
nxy <- nx + ny - 1
length(xy) <- nxy * ny
dim(xy) <- c(nxy, ny)
rowSums(xy)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Nested for loops - initial version
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv0 <- function(x,y) {
nx <- length(x)
ny <- length(y)
z <- numeric(nx + ny - 1)
for(i in seq(length = nx)) {
xi <- x[[i]]
for(j in seq(length = ny)) {
ij <- i + j - 1
z[[ij]] <- z[[ij]] + xi * y[[j]]
}
}
z
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Base R: using 'replace()'
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv2 <- function(x,y) {
nx <- length(x)
ny <- length(y)
sy <- seq_along(y) - 1L
z <- numeric(nx + ny - 1)
for(i in seq(length = nx)) {
ij <- i + sy
z <- replace(z, ij, z[ij] + x[[i]] * y)
}
z
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# by-reference 3 - using 'br_copy()'
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv3 <- function(x,y) {
nx <- length(x)
ny <- length(y)
sy <- seq_along(y) - 1L
z <- numeric(nx + ny - 1)
for(i in seq(length = nx)) {
ij <- i + sy
br_copy(z, z[ij] + x[[i]] * y, n = ny, xi = i)
}
z
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# by-reference 4
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv4 <- function(x,y) {
nx <- length(x)
ny <- length(y)
sy <- seq_along(y) - 1L
z <- numeric(nx + ny - 1)
for(i in seq(length = nx)) {
ij <- i + sy
t <- duplicate(y)
br_fmadd(t, x[[i]], z[ij])
br_copy(z, t, xi = i)
}
z
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# by-reference 5
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv5 <- function(x,y) {
nx <- length(x)
ny <- length(y)
sy <- seq_along(y) - 1L
z <- numeric(nx + ny - 1)
t <- duplicate(y)
for(i in seq(length = nx)) {
br_copy(t, y)
br_fmadd(t, x[[i]], z[i + sy])
br_copy(z, t, xi = i)
}
z
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# by-reference 6
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
conv6 <- function(x,y) {
nx <- length(x)
ny <- length(y)
sy <- seq_along(y) - 1L
z <- numeric(nx + ny - 1)
ty <- duplicate(y)
tz <- duplicate(y)
for(i in seq(length = nx)) {
br_copy(ty, y)
br_copy(tz, z, n = ny, xi = 1, yi = i)
br_fmadd(ty, x[[i]], tz)
br_copy(z, ty, xi = i)
}
z
}
set.seed(1)
N <- 1000
x <- runif(N)
y <- runif(N)
if (FALSE) {
conv0(x, y)
conv1(x, y)
conv2(x, y)
conv3(x, y)
conv4(x, y)
convv(x, y)
convolve(x, rev(y), conj = TRUE, type = 'open')
}
conv0c <- compiler::cmpfun(conv0)
# conv1c <- compiler::cmpfun(conv1)
conv2c <- compiler::cmpfun(conv2)
conv3c <- compiler::cmpfun(conv3)
conv4c <- compiler::cmpfun(conv4)
conv5c <- compiler::cmpfun(conv5)
conv6c <- compiler::cmpfun(conv6)
convvc <- compiler::cmpfun(convv)
bench::mark(
conv0c(x, y),
# conv1c(x, y),
conv2c(x, y),
conv3c(x, y),
conv4c(x, y),
conv5c(x, y),
conv6c(x, y),
convvc(x, y),
convolve(x, rev(y), conj = TRUE, type = 'open')
)[, 1:5] |>
knitr::kable()
bench::mark(
conv0c(x, y),
conv6c(x, y),
convolve(x, rev(y), conj = TRUE, type = 'open')
)[, 1:5] |>
knitr::kable()