0

Suppose I have an c++ code (see below for a simple example). I want to make it easy for a journal referee to install/run it.

So i figured the easiest way is to warp it unto a simplified R package-like tar.gz file so the referee could install it by simply invoking install.packages to a local .tar.gz file.

The reason for this is that i do not know what machine the referee is using, but i'm pretty sure the referee would know how to install a R packages so it's much easier for me to warp my code as a R 'package' --or at any rate, something sufficiently similar to it that it could be installed by a simple call to install.package().

An answer to a earlier question seems to suggest this is indeed possible. I followed the suggestions therein and created a /src directory with my cpp code (the one shown below) and a Makevars.win file containing:

## 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)

and a Makevars file containing:

## 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)

e.g. I simply followed the answer in the SO post to look around for how this is done in other packages (I also add RcppEigen to the list of dependencies because this guarantees that Eigen is installed on the target machine). I also created a /R directory containing the file MSE.R which contains:

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

and an empty /inst/include and a /man directory containing a minimal (but valid) .Rd file. I've added a NAMESPACE file containing:

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

Here is the question:

  • the c++ function otherwise compiles/runs fine. Is there a way to warp it unto a R package so as to make it easy to install/run by a third person.

Here is the c++ code used for this example.

#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();
    }
}
4

2 に答える 2

4

Rとのインターフェース方法については、「R拡張機能の作成」マニュアルを読んだことがありますか?

もちろん、Rcppなしでこれを行うことは自由ですが、これらの交換が非常に簡単になることがわかったため、Rcppを使用するために作成しました。Rcppを使用するCRAN上の94個のパッケージは同意しているようです...

Eigenを使用していて、これをサードパーティ(「レフリー」)用にパッケージ化する必要があります。これで、RcppEigenを使用する場合、EigenがRcppEigen内にあるので確実に存在することになります。あなたがしていることで、あなたはそうではありません...

さらに、.C()それははるかに制限的なインターフェースです.Call()

于 2012-12-26T01:04:25.533 に答える
2

適切なDESCRIPTIONファイルを用意することは非常に重要です。私はこれを使用しました:

Package: MySmallExample
Type: Package
Title: MysmallExample
Version: 0.0.0
Date: 2012-12-24
Depends: Rcpp (>= 0.9.10)
Imports: RcppEigen (>= 0.2.0)
Suggests: mvtnorm
LinkingTo: Rcpp, RcppEigen
Description: A small minimal Package.
License: GPL (>= 2)
LazyLoad: yes
Authors@R: person("joe", "programer", email =
        "joe.programer@joe_inc.com", role = c("aut", "cre"))
Collate: 'MSE.R'
Packaged: 2012-12-24 12:34:56 UTC; andi
Author: joe programer [aut, cre]
Maintainer: joe programer <joe.programer@joe_inc.com>
Repository: CRAN
Date/Publication: 2012-12-24 12:34:56

最も重要なことは「Collat​​e:」フィールドのようです。/Rディレクトリ内のすべての.Rファイルを適切にリストする必要があります。Depends&ImportsフィールドもNAMESPACEファイルと一致している必要があります。

ファイルNAMESPACEに行が含まれていることも非常に重要です

export("fx01","fx02")

ここで、「fx01」、「fx02」は、/ R / *。Rファイル(この場合はfx01のみ)内のすべてのR関数の名前です。

次に、すべてを.tar.gzにラップしました。と走った

install.packages("MySmallExample.tar.gz",repos=NULL,type="source")


> install.packages("/MySmallExample.tar.gz",repos=NULL,type="source")
Installing package(s) into ‘/R/x86_64-pc-linux-gnu-library/2.15’
(as ‘lib’ is unspecified)
* installing *source* package ‘MySmallExample’ ...
** libs
g++ -I/usr/share/R/include -DNDEBUG -I../inst/include  -I"/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/include" -I"/R/x86_64-pc-linux-gnu-library/2.15/RcppEigen/include"  -DEIGEN_DONT_PARALLELIZE -fopenmp -fpic  -O3 -pipe  -g  -c MSE.cpp -o MSE.o
g++ -shared -o MySmallExample.so MSE.o -L/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/lib -lRcpp -Wl,-rpath,/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/lib -fopenmp -L/usr/lib/R/lib -lR
installing to /R/x86_64-pc-linux-gnu-library/2.15/MySmallExample/libs
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded

* DONE (MySmallExample)
于 2012-12-26T02:05:21.190 に答える