0

I am fairly new learner to Rcpp, primarily needing it to speed up slow R code that is not easily parallelized because of dependencies within for loop iterations.

I wish to convert the following R code to C++ code to be directly used via Rcpp.

migrate_r <- function(pop) {
    if (m != 0) {
        if (model == "Step") {
            for (i in 1:K) {
                for (j in 1:K) {
                    for (k in 2:(K - 1)) {
                        i <- sample(perms, size = ceiling(perms * m/2), replace = FALSE)
                        j <- sample(perms, size = ceiling(perms * m/2), replace = FALSE)
                        tmp <- pop[i,, sample(k)]
                        pop[i,, sample(k)] <- pop[j,, sample(k)]
                        pop[j,, sample(k)] <- tmp
                    }
                }
            }
        }
    }
    pop
}

My attempt is as follows:

// [[Rcpp::depends(RcppArmadillo)]]
#define ARMA_DONT_PRINT_OPENMP_WARNING
#include <RcppArmadillo.h>
#include <RcppArmadilloExtensions/sample.h>
#include <set>
using namespace Rcpp;

// [[Rcpp::export]]
arma::Cube<int> migrate_cpp(arma::Cube<int> pop) {
String model;
int i, j, k, K, perms, tmp;
double m;

if (m != 0) {
    if (model == "Step") {
        for (i = 0; i < K; i++) {
            for (j = 0; j < K; j++) {
                for(k = 1; k < (K - 1); k++) {
                    i = RcppArmadillo::sample(perms, ceil(perms * m / 2), false);
                    j = RcppArmadillo::sample(perms, ceil(perms * m / 2), false);
                    tmp = pop[i, RcppArmadillo::sample(k, K, true)];
                    pop[i, RcppArmadillo::sample(k, K, true)] = pop[j, RcppArmadillo::sample(k, K, true)];
                    pop[j, RcppArmadillo::sample(k, K, true)] = tmp;
                    }
                }
            }
        }
    }
return pop;
}

Essentially both functions swap random rows in an 3-dimensional array ('pop') via a temporary variable. The C++ code doesn't run.

I know I am close to getting the C++ code to work, which will result in massive speedup compared to the R for loop.

Is there something I am missing here? Any assistance is greatly appreciated and warmly welcomed.

A reproducible example

##### Load packages #####

library(Rcpp)
library(RcppArmadillo)

### Set parameters ###

K <- 2  
N <- 6 
Hstar <- 5 
probs <- rep(1/Hstar, Hstar)
m <- 0.20
perms <- 2 # number of permutations

num.specs <- ceiling(N / K)

haps <- 1:Hstar

specs <- 1:num.specs

gen.perms <- function() {
    sample(haps, size = num.specs, replace = TRUE, prob = probs)
}

pop <- array(dim = c(perms, num.specs, K))

for (i in 1:K) {
    pop[,, i] <- replicate(perms, gen.perms())
}

pop
, , 1

     [,1] [,2] [,3]
[1,]    3    5    1
[2,]    2    3    3

, , 2

     [,1] [,2] [,3]
[1,]    2    5    3
[2,]    3    5    3

migrate_r(pop) # notice rows have been swapped between subarrays

, , 1

     [,1] [,2] [,3]
[1,]    3    5    1
[2,]    2    5    3

, , 2

     [,1] [,2] [,3]
[1,]    3    5    3
[2,]    2    3    3 
compbiostats
  • 909
  • 7
  • 22
  • 2
    1. No global definitions. Move all variables inside the function. 2. Read up on [`arma::cube` accessors](http://arma.sourceforge.net/docs.html#submat), 3. note the type issue you have. Consider using [`arma::randi`](http://arma.sourceforge.net/docs.html#randi). Overall, this wasn't really translated. It was stopped halfway through. Consider reading the new [Rcpp introduction vignette](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf) – coatless Jan 22 '18 at 05:48
  • Thanks! I should have remembered about the deadly sin of declaring globals.... must've got past me. – compbiostats Jan 22 '18 at 06:10
  • Just noticed too that perms and tmp aren't declared. – compbiostats Jan 22 '18 at 07:22
  • I have updated the C++ code, which resulted in considerably fewer errors, but it's still buggy. Could you take a further look? – compbiostats Jan 22 '18 at 17:19
  • I have actually not been able to find any instances of using string characters within Rcpp if statements. Is it correct to presume then that if (model == "Step") has no effect? – compbiostats Jan 23 '18 at 05:16
  • @JarrettPhilips could you add a minimally reproducible example of the _R_ code? E.g. how is it called? – coatless Jan 23 '18 at 05:17
  • I have no clue what "Named might actually work" means. But, as of right now, we cannot really help you because the code isn't reproducible at all. First, write an _R_ function that works. Show us the inputs you are using. Then, translate it to _C++_. For help, see the new [Rcpp introduction vignette](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf) that emphasizes this process. – coatless Jan 23 '18 at 05:26
  • Named is used to assign named elements in a vector, according to one of @DirkEddelbuettel ' s presentations – compbiostats Jan 23 '18 at 05:30
  • This is not relevant in your case. Please focus on writing a minimally reproducible example of the code in _R_. Then work on the _C++_ translation. Ping me when the post is updated. I'll look at it tomorrow. – coatless Jan 23 '18 at 05:37
  • I have posted a reproducible example. I believe both the R loop and the C++ implementation are equivalent, but the latter doesn't run. Thanks for taking a look. – compbiostats Jan 23 '18 at 16:46
  • So, to be clear, the _R_ code being translated is from the parameters up to through the `for` loop? The `pop` is your attempt to translate this routine to _C++_ or was it left out? – coatless Jan 23 '18 at 16:48
  • Forgive me, but I don't follow what you're saying about 'pop' being left out. 'pop' is just a 3D array that is populated with labels 1:5 (i.e., the 'haps' in the R loop). – compbiostats Jan 23 '18 at 16:54
  • Okay... Can you write the _R_ code (e.g. what was shown initial) as a function called `migrate_r`. Change the name of the _Rcpp_ function to `migrate_cpp` and _show_ how it is called. E.g. I should be able to get results from the call of this code. **[This is what makes the example minimally reproducible.](https://stackoverflow.com/a/5963610/1345455)** – coatless Jan 23 '18 at 16:58
  • Ok I can do that – compbiostats Jan 23 '18 at 17:06
  • Alright, done. Hopefully it is clearer now. – compbiostats Jan 23 '18 at 17:23
  • I have shown output from migrate_r. The input to migrate_cpp should be 'pop' from the input to migrate_r ( i.e., same as 'pop' generated from replicate() ). Once I have a working migrate_cpp, there will be no need to keep migrate_r. – compbiostats Jan 23 '18 at 18:02
  • @JarrettPhillips I want to make sure I understand *exactly* what you are trying to do. Is it that you want to take one randomly selected row from one randomly selected slice of the array and exchange it from one randomly selected row in a second randomly selected slice of the array? – duckmayr Feb 01 '18 at 13:51
  • @duckmayr That's the gist of it. It took me a bit to get code up and running, but I believe I have managed to implement this successfully in C++. – compbiostats Feb 01 '18 at 15:21
  • @JarrettPhillips If you have a working solution to your problem, I would suggest posting the solution with an explanation for why it solved your problem, [which is encouraged by Stack Overflow](https://stackoverflow.com/help/self-answer), and accepting it after the mandatory 48 hour waiting period if a better answer doesn't come along. That way if anyone has a somewhat similar issue in the future, it might help them out. – duckmayr Feb 01 '18 at 15:45

0 Answers0