利用RcppArmadillo建立支持openmp并行的R程序包(整合C++函数)

准备工作(安装程序包并配置环境变量):

R软件:https://www.r-project.org/

对应的Rtools:https://cran.r-project.org/bin/windows/Rtools/

Miktex:https://miktex.org/

R需要安装 Rcpp 和 RcppArmadillo程序包:

https://cran.r-project.org/web/packages/Rcpp/index.html

https://cran.r-project.org/web/packages/RcppArmadillo/index.html

(也可通过install.packages('Rcpp') 和 install.packages('RcppArmadillo')安装)

建立骨架包

在R中运行如下命令生成基于Rcpp的R包骨架(不支持并行)

library(Rcpp)

Rcpp.package.skeleton( "Test" )

getwd()

Test保存在getwd()所示的文件夹下, 有 man, R, src三个文件夹, 以及DESCRIPTION以及 NAMESPACE 以及 Read-and-delete-me 三个文本文件,这个三个文件没有任何扩展名。

man下面, 保存的是所有R函数以及R程序包的帮助文件文件, 遵循是Latex格式。需要逐项填写

R下面, 保存的是R函数的文件, 每个R函数单独一个文件

src下面, 放的是cpp文件, 即c++的源文件

默认的情况下,

man文件夹下, 会有 rcpp_hello_world.Rd 文件,

R文件夹下, 会有RcppExports.R文件

src 文件夹下, 会有 rcpp_hello_world.cpp 和 RcppExports.cpp两个C++源文件

这些文件在本例中均可以删除。

或者在R中运行如下命令生成基于RcppArmadillo的R包骨架(支持并行)

library(RcppArmadillo)

RcppArmadillo.package.skeleton("Test")

getwd()

默认情况下,与Rcpp相比,RcppArmadillo会在src文件夹下多生成Makevars和Makevars.win,这两个文件不需要修改,其他操作与Rcpp相同。

改写C++代码

源代码:实现从1到n的加法

#include <iostream>
#include <omp.h>

using namespace std;

int get_sum(int n) {

    int sum = 0;

    #pragma omp parallel for
    for(int i = 0; i < n; i++) {

        sum += i;

    }

    return sum;

}

改写代码(getsum.cpp,放于src文件夹下):

#include <Rcpparmadillo.h>
#include <omp.h>

// [[Rcpp::depends(RcppArmadillo)]] 

using namespace Rcpp;

using namespace std;

// [[Rcpp::export]]
RcppExport SEXP get_sum(SEXP n_s) {
    
    int n = Rcpp::as<int> (n_s);

    int sum = 0;

    #pragma omp parallel for
    for(int i = 0; i < n; i++) {

        sum += i;

    }    
    
    return (wrap(sum));
}

注:1)在返回类型前要加上RcppExport,返回值则用wrap函数(记得加括号),可直接返回SEXP数据类型。

2)同时返回多个值的情况:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
Rcpp::List fastLm(const arma::mat& X, const arma::colvec& y) {

    int n = X.n_rows, k = X.n_cols;
        
    arma::colvec coef = arma::solve(X, y);    // fit model y ~ X

    arma::colvec res  = y - X*coef;           // residuals

    // std.errors of coefficients
    double s2 = std::inner_product(res.begin(), res.end(), res.begin(), 0.0)/(n - k);
                                                        
    arma::colvec std_err = arma::sqrt(s2 * arma::diagvec(arma::pinv(arma::trans(X)*X)));  

    return Rcpp::List::create(Rcpp::Named("coefficients") = coef,
                              Rcpp::Named("stderr")       = std_err,
                              Rcpp::Named("df.residual")  = n - k);
}

则可以返回result.coefficients, result.stderr, result.df.residual三个结果。

写调用函数

为了能够在R中调用编译后的C++函数,可以使用R中的.Call()函数(get_sum.R,置于R文件夹下)。

get_sum_R <- function(n_s) {

    .Call('get_sum', n_s, PACKAGE = 'Test')

}

#其中get_sum_R是R包中的方法名
#get_sum是C++中的函数名
#n_s是函数要接收参数
#PACKAGE是R包的名字

为了生成该get_sum_R函数的帮助文件, 需要将该函数粘贴到R console中,之后运行R命令 prompt(get_sum_R),所形成的get_sum_R.Rd 文件需要进一步根据参数的意义填写和编辑,之后放到man文件夹下。

建议为R包提供的每一个方法单独创建一个.Rd文件,其格式如下:

% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/get_sum.R
\name{get_sum_R}
\alias{get_sum_R}
\title{get the sum of 0 to (n_s - 1)}
\usage{
get_sum_R(n_s)
}
\arguments{
\item{n}{numeric variable}
}
\value{
the sum of 0 to (n_s - 1)
}
\description{
get sum
}
\examples{
get_sum_R(10)
}

编辑和填写 DESCRIPTION以及NAMESPACE 两个文本文件。删除 Read-and-delete-me文件。这样,程序包的源文件就做好了。

DESCRIPTION文件格式如下,修改Package名,Title和Version等信息。

Package: Test
Type: Package
Title: Test how to change the C++ code to R package
Version: 1.0
Date: 2020-11-18
Author: Zhang Yf
Maintainer: qdu-bioinfo <qdu_bioinfo@163.com>
Description: XXX.
License: GPL-2
Imports: Rcpp (>= 1.0.4.6)
LinkingTo: Rcpp, RcppArmadillo, RcppEigen
Depends: 
	R (>= 2.10)
RoxygenNote: 7.1.1

编译或安装R程序包的命令

package='Test'

#check skycalc package
R CMD check ${package}

#build skycalc package Windows Binary.bat
#INSTALL --build ${package}

#build skycalc package Linux Source Code.bat
R CMD build ${package}

#install skycalc package.bat
R CMD INSTALL ${package}

编写.bat文件,将其置于Test文件夹所在目录,并添加可执行权限,直接执行该文件, 即可完成程序包的检查、编译和安装。

准备数据文件

一般来说,为了复用性与测试,需要包中包含一些测试文件。 
添加数据文件的方法如下,在R console中按如下方式生成数据文件,然后通过use_data函数添加到Test库中,这样当加载库的时候,相应的数据文件也被加载进来了,可以直接使用。

library(devtools)

test_num = 10

use_data(test_num, Test)

调用函数

library(Test)

get_sum_R(10)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值