c++ - 如何(轻松)将 C++ 函数包装到易于安装的 R 'package'

标签 c++ r eigen

假设我有一个 C++ 代码(请参阅下面的简单示例)。 我想让期刊审稿人轻松安装/运行

所以我认为最简单的方法是将其变形为简化的 类 R 包的 tar.gz 文件,以便裁判可以安装它 通过简单地调用 install.packages 到本地 .tar.gz 文件。

原因是不知道是什么机器 裁判正在使用,但我很确定裁判会 知道如何安装 R 包,这样更容易 我将我的代码变形为 R“包”——或者无论如何, 与它足够相似的东西,它可能是 通过简单调用 install.package() 安装。

对先前 question 的回答似乎暗示这个 确实有可能。我遵循了其中的建议并且 用我的 cpp 代码创建了一个/src 目录(显示的那个 下面)和一个包含以下内容的 Makevars.win 文件:

## This assume that we can call Rscript to ask Rcpp about its locations
## Use the R_HOME indirection to support installations of multiple R version
#PKG_LIBS = $(shell $(R_HOME)/bin/Rscript.exe -e "Rcpp:::LdFlags()")
PKG_CPPFLAGS = -I../inst/include -I.
PKG_CXXFLAGS = -DEIGEN_DONT_PARALLELIZE $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = $(shell $(R_HOME)/bin/Rscript.exe -e "Rcpp:::LdFlags()") $(SHLIB_OPENMP_CXXFLAGS)

和一个包含以下内容的 Makevars 文件:

## Use the R_HOME indirection to support installations of multiple R version
#PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` 
# This was created by RcppEigen.package.skeleton, but the R script that is 
# called creates error message:
# PKG_CPPFLAGS = `$(R_HOME)/bin/Rscript -e "RcppEigen:::RcppEigenCxxFlags()"`
PKG_CPPFLAGS = -I../inst/include
PKG_CXXFLAGS = -DEIGEN_DONT_PARALLELIZE $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` $(SHLIB_OPENMP_CXXFLAGS)

例如我只是按照 SO 帖子中的答案四处看看如何 这是在其他包中完成的(我还将 RcppEigen 添加到依赖项列表中,因为 这保证了 Eigen 安装在目标机器上)。我还创建了一个包含文件 MSE.R 的/R 目录,其中包含:

fx01<-function(x){
    x<-as.matrix(x)
    Dp<-rep(0,ncol(x))
    fit<-.C("mse",as.integer(nrow(x)),as.integer(ncol(x)),as.single(x),as.single(Dp))
    as.numeric(fit[[4]])
}

和一个空的/inst/include 和一个包含最小(但有效).Rd 文件的/man 目录。 我添加了一个 NAMESPACE 文件,其中包含:

import(Rcpp)
import(RcppEigen)
useDynLib(MySmallExample)

问题是:

  • C++ 函数可以正常编译/运行。有没有办法将其转换为 R 包,以便第三方轻松安装/运行。

这是用于此示例的 C++ 代码。

#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <fstream>
#include <iostream>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <vector>

#include <Eigen/Dense>
#include <Eigen/LU>
#include <Eigen/SVD>

using namespace std;
using namespace Eigen;
using Eigen::MatrixXf;
using Eigen::VectorXf;


float median(VectorXf& x) {
    int n=x.rows();
    int half=(n+1)/2;   
    half--;                 
    float med;
    nth_element(x.data(),x.data()+half,x.data()+x.size());  
    if((n%2)==1){
        med=x(half);
    } else {
        float tmp0=x(half);
        float tmp1=x.segment(half+1,half-1).minCoeff(); 
        med=0.5*(tmp0+tmp1);
    }
    return med;
}
VectorXf fx01(MatrixXf& x){
    int p=x.cols();
    int n=x.rows();
    VectorXf Recept(n);
    VectorXf Result(p);
    for(int i=0;i<p;i++){
        Recept=x.col(i);
        Result(i)=median(Recept);
    }
    return Result;
}
extern "C"{
    void mse(int* n,int* p,float* x,float* medsout){
        MatrixXf x_cen=Map<MatrixXf>(x,*n,*p);  
        VectorXf MedsOut=fx01(x_cen);
        Map<VectorXf>(medsout,*p)=MedsOut.array();
    }
}

最佳答案

您是否阅读过关于如何与 R 交互的“Writing R Extensions”手册?

在没有 Rcpp 的情况下,您当然可以自由地执行此操作,但我们编写 Rcpp 供我们使用,因为我们发现它使这些交换变得更加容易。 CRAN 上使用 Rcpp 的 94 个包似乎同意...

您正在使用 Eigen,并且您希望将其打包供第三方(“裁判”)使用。现在,如果你要使用 RcppEigen 你会确保 Eigen 存在于 RcppEigen 中。通过你所做的,你不是...

另外,.C() 是一个比 .Call() 限制更多的接口(interface)。

关于c++ - 如何(轻松)将 C++ 函数包装到易于安装的 R 'package',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14034868/

相关文章:

c++ - 为 iOS 构建 ICU

c++ - STL 中是否有进行字符串转换但带有长度参数的函数?

c++ - 无法将参数 1 从 'char' 转换为 'const std::basic_string<_Elem,_Traits,_Ax> &'

c++ - Eigen:基类模板特化中的类型推导

c++ - DenseBase、auto 和二进制操作表示数组具有不同的形状

C++ Noobie - 我无法在我的家庭作业中解决这个问题。我被困住了。请帮忙!

r - ggplot2 -- 自动放大 geom_smooth(使用 coord_cartesian)

r - 应用于 3 个变量的数据框转换

r - 使用 R 查找数据框中的列/字段中的连续重复项

c++ - Eigen + gmp 寻找 gmp_expr 而不是 mpq_class