RcppAramadillo Cube :: operator():索引越界

时间:2017-12-31 22:55:10

标签: rcpp

我一直在摆弄以下C ++代码,以便与我编写的R代码集成(这里包含的内容太多),但是继续收到Cube :: operator()索引超出范围的错误,我是不确定为什么会这样。我怀疑是3D阵列没有正确填充,如

中所述

making 3d array with arma::cube in Rcpp shows cube error

但我不确定如何妥善解决问题。

以下是我的完整C ++代码:

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


int sample_one(int n) {
  return n * unif_rand();
} 

int sample_n_distinct(const IntegerVector& x, 
                  int k,
                  const int * pop_ptr) {

  IntegerVector ind_index = RcppArmadillo::sample(x, k, false); 
  std::set<int> distinct_container;

  for (int i = 0; i < k; i++) {
     distinct_container.insert(pop_ptr[ind_index[i]]);
  }

  return distinct_container.size();
}

// [[Rcpp::export]]
arma::Cube<int> fillCube(const arma::Cube<int>& pop,
                     const IntegerVector& specs,
                     int perms,
                     int K) {

int num_specs = specs.size();
arma::Cube<int> res(perms, num_specs, K);

IntegerVector specs_C = specs - 1;
const int * pop_ptr;
int i, j, k;

for (i = 0; i < K; i++) {
    for (k = 0; k < num_specs; k++) { 
        for (j = 0; j < perms; j++) {
            pop_ptr = &(pop(0, sample_one(perms), sample_one(K)));
            res(j, k, i) = sample_n_distinct(specs_C, k + 1, pop_ptr);
        }
    }
}

return res;
}

有人知道可能产生上述错误的原因吗?

下面是调用C ++函数的R代码(包括C ++代码重现的一个注释掉的三重嵌套'for'循环)。

## Set up container(s) to hold the identity of each individual from each permutation ##

num.specs <- ceiling(N / K)

## Create an ID for each haplotype ##

haps <- 1:Hstar

## Assign individuals (N) to each subpopulation (K) ##

specs <- 1:num.specs

## Generate permutations, assume each permutation has N individuals, and sample those individuals' haplotypes from the probabilities ##

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())
}

## Make a matrix to hold individuals from each permutation ##

# HAC.mat <- array(dim = c(perms, num.specs, K))

## Perform haplotype accumulation ##

# for (k in specs) {
    # for (j in 1:perms) {
        # for (i in 1:K) {
            # select.perm <- sample(1:nrow(pop), size = 1, replace = TRUE) # randomly sample a permutation
            # ind.index <- sample(specs, size = k, replace = FALSE) # randomly sample individuals
            # select.subpop <- sample(i, size = 1, replace = TRUE) # randomly sample a subpopulation
            # hap.plot <- pop[select.perm, ind.index, select.subpop] # extract data
            # HAC.mat[j, k, i] <- length(unique(hap.plot)) # how many haplotypes are recovered
        # }
    # }
# }

HAC.mat <- fillCube(pop, specs, perms, K)

1 个答案:

答案 0 :(得分:1)

这是一个越界错误。问题的要点是呼叫

pop_ptr = &(pop(0, sample_one(perms), sample_one(K)));

因为

sample_one(perms)

被放置为最大长度为num_specs的访问索引。这可以通过res的定义来看出:

arma::Cube<int> res(perms, num_specs, K);

因此,从perms位置移出num_specs可以解决问题。

// [[Rcpp::export]]
arma::Cube<int> fillCube(const arma::Cube<int>& pop,
                         const IntegerVector& specs,
                         int perms,
                         int K) {

  int num_specs = specs.size();
  arma::Cube<int> res(perms, num_specs, K);

  IntegerVector specs_C = specs - 1;
  const int * pop_ptr;
  int i, j, k;

  for (i = 0; i < K; i++) {
    for (k = 0; k < num_specs; k++) { 
      for (j = 0; j < perms; j++) {

        // swapped location
        pop_ptr = &(pop(sample_one(perms), 0, sample_one(K)));
        // should the middle index be 0?
        res(j, k, i) = sample_n_distinct(specs_C, k + 1, pop_ptr);
      }
    }
  }

  return res;
}