DDuri
DDuri

Reputation: 13

Improve performance of the R program using Rcpp

I'm trying to speed up my R code - I'm wondering if this is something that can be done in Rcpp. This is my code that I started to write.

library(Rcpp)

cppFunction('int cont.run_C(int reps=10000,int n=10000,int d=0.005,int l=10 ,int s=0.1) {
  r = rep(0, reps)
  theta = rep(0, n)
  for(int t = 0; t < reps; t++) {
    epsilon = rnorm(1, 0, d)
    Zt = sum(epsilon > theta ? 1 : epsilon < -theta ? -1: 0)
    r[t] = Zt / (l * n)
    theta = runif(n) < s ? abs(r[t]) : theta
  }
  return mean(r)
}')

system.time(cont.run_C())

Upvotes: 1

Views: 101

Answers (1)

Ralf Stubner
Ralf Stubner

Reputation: 26823

Before trying to translate your code to C++ it makes sense to look at the R code first, especially if you do not know C++. If you use a profiler on your code, you will see that much of the time is spent in the two lines with ifelse. However, both lines can be improved. The first line is equivalent to:

Zt <- sum(epsilon > theta) - sum(epsilon < -theta)

The second line can be written as

theta[runif(n) < s] <- abs(r[t])

These two changes reduce the runtime on my system from over 10s to under 5s. Looking at the profiler results again, we see that now most of the time is spent in runif. Here we can use a faster RNG from my dqrng package, reducing the runtime to under 2s. Final code:

library(dqrng)

cont.run <- function(reps=10000, n=10000, d=0.005, l=10 ,s=0.1) {
  r <- rep(0, reps)
  theta <- rep(0, n)
  for (t in 1:reps) {
    epsilon <- dqrnorm(1, 0, d)
    #Zt = sum(ifelse(epsilon > theta, 1, ifelse(epsilon < -theta, -1, 0)))
    Zt <- sum(epsilon > theta) - sum(epsilon < -theta)
    r[t] <- Zt / (l * n)
    theta[dqrunif(n) < s] <- abs(r[t])
  }
  return(mean(r))
}

system.time(cont.run())
#>        User      System verstrichen 
#>       1.804       0.244       2.049

Created on 2019-05-21 by the reprex package (v0.2.1)

Upvotes: 3

Related Questions