首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Rcpp电源集实现:尝试在SET_VECTOR_ELT中设置索引8/8

Rcpp电源集实现:尝试在SET_VECTOR_ELT中设置索引8/8
EN

Stack Overflow用户
提问于 2015-04-25 07:52:28
回答 1查看 1.3K关注 0票数 1

考虑以一组元素作为输入向量并返回列表中的幂集:的函数。

代码语言:javascript
运行
复制
> pwr_set(letters[1:3])

[[1]]
character(0)

[[2]]
[1] "a"

[[3]]
[1] "b"

[[4]]
[1] "a" "b"

[[5]]
[1] "c"

[[6]]
[1] "a" "c"

[[7]]
[1] "b" "c"

[[8]]
[1] "a" "b" "c"

R定义:

代码语言:javascript
运行
复制
pwr_set <- function(els){
  n_els <- length(els)
  out <- vector(mode="list",length = 2 ^ n_els)
  out[[1]] <- character()     # first element in power set is the empty set

  listIdx <- 1L       # start a listIdx

  for(i in 1L:n_els){
    for(j in 1L:listIdx){
      listIdx <- listIdx + 1L
      out[[listIdx]] <- c(out[[j]], els[i])
    }
  }
  out
}

我提出了以下在Rcpp中实现的翻译:

代码语言:javascript
运行
复制
#include <Rcpp.h>
#include <Math.h>
using namespace Rcpp;


// [[Rcpp::export]]
List pwr_set_cpp(CharacterVector els) {

  int n_els = els.size();         // size of set
  int pwrset_card = pow(2,n_els); // number of subsets to make power set is 2^n_elements
  List out(pwrset_card);          // list for output
  int listidx = 0;                // to count through list indeces
  out[0] = CharacterVector::create(); // first element of list represents empty set
  CharacterVector tmp;            // to hold new extended vector

  for (int i=0; i < n_els; ++i) {
    for (int j=0; j <= listidx; ++j) {

      listidx++;
      tmp = out[j];
      tmp.push_back(els[i]);
      out[listidx] = tmp;

    }
  }
  return out;
}

但!

代码语言:javascript
运行
复制
> pwr_set_cpp(letters[1:3])

给出错误:attempt to set index 8/8 in SET_VECTOR_ELT

谷歌和查看源代码这里让我认为我试图索引超出了SET_VECTOR_ELT缓存?这一定意味着我误解了如何在Rcpp或类似的东西中执行输入/输出循环。

任何帮助我理解这里的指导都是很棒的。提前谢谢。

更新:修复。

根据@Romain和@nicola的回答/评论,关键的误解是在R中通过循环的方式是相当聪明的!(至少我现在比以前更欣赏它)。要在c++中实现同样的事情,我必须将listidx分解为一个counter变量(这是对j的条件检查)和一个临时cnt2,它实质上记录在当前计数器状态之上所采取的j步骤的数量。然后,counter在以cnt2的当前值传递每个出口后得到更新。

代码语言:javascript
运行
复制
#include <Rcpp.h>
#include <Math.h>
using namespace Rcpp;

// [[Rcpp::export]]
List pwr_set_cpp(CharacterVector els) {

  int n_els = els.size();         
  int pwrset_card = pow(2,n_els); 
  List out(pwrset_card);          
  out[0] = StringVector::create(); 
  CharacterVector tmp;            
  int counter = 0;
  for (int i=0; i < n_els; ++i) {
    int cnt2 = counter;            // capture counter state
      for (int j =0; j <= counter; ++j) {
        cnt2++;                   // capture counter + j steps
        tmp = as<StringVector>(out[j]);
        tmp.push_back(as<std::string>(els[i]));
        out[cnt2] = tmp;

    }
      counter = cnt2;             // update counter state
  }
  return out;
}

快速计时

只是为了好玩一个小小的基准。虽然我确信有更有效的方法来做到这一点(使用相同的算法结构),因为我做了很多复制STRSXP元素/向量的工作。

代码语言:javascript
运行
复制
x <- letters[1:18]
pwr_set_bitecompile <- compiler::cmpfun(pwr_set) # R 3.2.0 !
microbenchmark::microbenchmark(
    pwr_set(x),
    pwr_set_bitecompile(x),
    pwr_set_cpp(x))

Unit: milliseconds
                   expr      min       lq     mean   median       uq       max neval
             pwr_set(x) 748.6553 820.0667 841.2828 834.1229 856.2436 1023.1324   100
 pwr_set_bitecompile(x) 365.9969 480.9474 498.2100 503.5115 518.8562  596.8205   100
         pwr_set_cpp(x) 155.9447 283.8771 295.8411 300.4865 314.0826  342.0261   100
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-25 10:40:11

问题是,您正试图在out[8]中分配一些东西,这超出了列表中元素的数量。

请参见以下添加的行:

代码语言:javascript
运行
复制
  Rprintf( "out.size() = %d, listidx = %d\n", out.size(), listidx );
  out[listidx] = tmp;

你会得到:

代码语言:javascript
运行
复制
> pwr_set_cpp(letters[1:3])
out.size() = 8, listidx = 1
out.size() = 8, listidx = 2
out.size() = 8, listidx = 3
out.size() = 8, listidx = 4
out.size() = 8, listidx = 5
out.size() = 8, listidx = 6
out.size() = 8, listidx = 7
out.size() = 8, listidx = 8
Error in pwr_set_cpp(letters[1:3]) :
  tentative de modification de l'index 8/8 dans SET_VECTOR_ELT
Calls: sourceCpp ... withVisible -> eval -> eval -> pwr_set_cpp -> <Anonymous>
Exécution arrêtée      

另见@nicola的评论。你对listidxj做了些错事。如果溢出没有停止,您将得到一个无休止的循环。

可能令人困惑的是R代码:

代码语言:javascript
运行
复制
for(j in 1L:listIdx){
  listIdx <- listIdx + 1L
  out[[listIdx]] <- c(out[[j]], els[i])
}

计算1L:listIdx一次,以便在循环中,您可以使用listIdx来做其他事情。C++的情况并非如此。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29862539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档