如何从C中调用R的顺序函数(通过R_orderVector())?

时间:2015-05-16 03:33:08

标签: c r

在一个在R包中调用的C函数中,我需要对它进行排序 数字。为了与R做的一致,我想称之为 R使用的排序算法/函数,所以R_orderVector()。我得到了 完全在R_orderVector()调用时出现分段错误。 下面是一个最小的工作示例('最小工作包'的文件) 它再现了分割错误。我做错了什么?

### DESCRIPTION ################################################################

Package: foo
Version: 0.0-1
Encoding: UTF-8
Title: Sorting from C via R's R_orderVector()
Description: See title
Authors@R: c(person(given = "Foo", family = "Bar", role = c("aut", "cre"), email = "foo@bar.com"))
Author: Foo Bar [aut, cre]
Maintainer: Foo Bar <foo@bar.com>
Depends: R (>= 3.0.0)
Imports:
Suggests:
Enhances:
License: GPL-2 | GPL-3
NeedsCompilation: yes
Repository: CRAN
Date/Publication: 2014-03-25 15:26:50


### NAMESPACE ##################################################################

useDynLib(foo, .registration = TRUE)
export("myRsort")


### ./R/mySort.R ###############################################################

myRsort <- function(x) {
    stopifnot(is.numeric(x), length(x) <= 64)
    myRsort_ <- NULL # to avoid "myRsort_: no visible binding for global variable 'myRsort_'"
    .Call("myRsort_", x)
}


### ./man/myRsort.Rd ###########################################################

\name{myRsort}
\alias{myRsort}
\title{Using R's Sorting Algorithm from C}
\description{
  R's sorting algorithm is called from C.
}
\usage{
myRsort(x)
}
\arguments{
  \item{x}{vector}
}
\value{
  vector
}
\author{Marius Hofert}
\examples{
set.seed(271)
x <- runif(10)
myRsort(x)
}
\keyword{utilities}


### ./src/init.c ###############################################################

#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>

#include "myRsort.h"


static const R_CallMethodDef callMethods[] = {
    {"myRsort_", (DL_FUNC) &myRsort_, 1},
    {NULL, NULL, 0}
};

void R_init_foo(DllInfo *dll)
{
    R_useDynamicSymbols(dll, FALSE);
    R_registerRoutines(dll, NULL, callMethods, NULL, NULL); /* s. WRE (2015, Section 5.4) */
}


### ./src/myRsort.c ############################################################

#include "myRsort.h"

void myRsort_aux(double *x, int n, double *res)
{
    int *ind; /* pointer to vector of indices as required for order (permutation of 0:(n-1)) */
    ind = (int *) R_alloc(n, sizeof(int));

    SEXP xsexp = PROTECT(allocVector(REALSXP, n)); /* turn x into SEXP */
    double *xsexp_ = REAL(xsexp); /* pointer */

    R_orderVector(ind, n, xsexp, TRUE, TRUE); /* nalast (use same default as order()); decreasing=TRUE */
    /* the last line generates a seg-fault */

    int i;
    for(i=0; i<n; i++) res[i] = x[ind[i]];
}

SEXP myRsort_(SEXP x)
{
    double *x_ = REAL(x); /* pointer to n-vector */
    int n = LENGTH(x); /* length n */
    int maxlen = 64; /* vector can be at most of length 64 here */

    SEXP res = PROTECT(allocVector(REALSXP, maxlen)); /* result */
    double *res_ = REAL(res); /* pointer to the (sorted) result */
    myRsort_aux(x_, n, res_);

    UNPROTECT(1);
    return res;
}


### ./src/myRsort.h ############################################################

#ifndef myRsort_H
#define myRsort_H

#include <R.h>
#include <Rinternals.h>
#include <Rmath.h>

void myRsort_aux(double *x, int n, double *res);
SEXP myRsort_(SEXP x);

#endif

1 个答案:

答案 0 :(得分:0)

似乎您:

  • 忘记了UNPROTECT
  • 未复制myRsort_aux中的值。
  • 没有正确使用R_orderVector函数。

这是一个可以Rcpp::sourceCpp编辑的工作示例:

#include <Rcpp.h>

void myRsort_aux(double *x, int n, double *res)
{
  int *ind = (int *) R_alloc(n, sizeof(int));
  
  SEXP xsexp = PROTECT(Rf_allocVector(REALSXP, n));
  // you forgot to copy the values?
  for(int i = 0; i < n; ++i)
    REAL(xsexp)[i] = x[i];
  // a call as in https://github.com/wch/r-source/blob/7dcdfc2d2d0ce3ce6fe84aa1cf0d27b5cbc833fc/src/main/sort.c#L1096
  R_orderVector(ind, n, Rf_lang1(xsexp), TRUE, TRUE);
  
  for(int i = 0; i < n; i++) 
    res[i] = x[ind[i]];
  
  UNPROTECT(1); // seems like you forgot this
}

// [[Rcpp::export(rng = false)]]
SEXP myRsort_(SEXP x)
{
  double *x_ = REAL(x);
  int n = LENGTH(x); 
  int maxlen = 64; 
  
  SEXP res = PROTECT(Rf_allocVector(REALSXP, maxlen)); 
  double *res_ = REAL(res); 
  myRsort_aux(x_, n, res_);
  
  UNPROTECT(1);
  return res;
}

/*** R
set.seed(1)
to_be_sorted <- rnorm(10)
head(myRsort_(to_be_sorted), 10)
#R> [1]  1.5952808  0.7383247  0.5757814  0.4874291  0.3295078  0.1836433 -0.3053884 -0.6264538 -0.8204684 -0.8356286
*/

您可能只使用R_rsort in this case.