I have a very basic question about C++ integration in R via Rcpp. Suppose I want to implement a simple function like this one in C++:
inte = function(x, y, a, b){
model = approxfun(x, y)
return(integrate(model, a, b)$value)
}
So a very basic approach would be to call R's function 'integrate' as much as needed:
// [[Rcpp::export]]
double intecxx(Function inte, NumericVector x, NumericVector y,
double a, double b) {
NumericVector res;
res = inte(x, y, a, b);
return res[0];
}
However, I need to use this 'intecxx' in many other parts of my C++ code, so calling it from somewhere else results in 'inte' not being available in the scope. Any help is appreciated.
If you are willing to modify intecxx by hardcoding the call to inte inside the body, rather than trying to pass it as a parameter, you could use this approach:
#include <Rcpp.h>
/*** R
inte = function(x, y, a, b){
model = approxfun(x, y)
return(integrate(model, a, b)$value)
}
.x <- 1:10
set.seed(123)
.y <- rnorm(10)
*/
// [[Rcpp::export]]
double intecxx(Rcpp::NumericVector x, Rcpp::NumericVector y, double a, double b) {
Rcpp::NumericVector res;
Rcpp::Environment G = Rcpp::Environment::global_env();
Rcpp::Function inte = G["inte"];
res = inte(x, y, a, b);
return res[0];
}
I defined inte in the same source file as intecxx to ensure that it is available in the global environment, and therefore callable from within intecxx through G.
R> inte(.x, .y, 1, 10)
[1] 1.249325
R> intecxx(.x, .y, 1, 10)
[1] 1.249325
R> all.equal(inte(.x, .y, 1, 10),intecxx(.x, .y, 1, 10))
[1] TRUE
Related
Is there any way to efficiently translate the outer() function for multiplication of two vectors from R base to RcppArmadillo? I attempted to do so but it is not efficient at all.
Take the following example:
library(Rcpp)
library(RcppArmadillo)
library(microbenchmark)
#Outer attempt
cppFunction(depends = "RcppArmadillo",
'
arma::mat outer_rcpp(arma::vec x, arma::vec y) {
int x_length = x.n_elem;
int y_length = y.n_elem;
arma::mat final(x_length, y_length);
// And use loops instead of outer
for(int i = 0; i < x_length; i++) {
final.col(i) = x[i] * y;
}
return(final);
}
'
)
#Test for equal results
a <- rnorm(5)
base <- base::outer(a, a)
rcpp <- outer_rcpp(a, a)
all.equal(base, rcpp)
#Test for speed
b <- rnorm(5000)
microbenchmark(base = base::outer(b, b),
rcpp = outer_rcpp(b, b), times = 10)
The results are 2 times slower using R base. I am sure that this can be done though matrix multiplication, any idea how?
As #thelatemail pointed out in the comments, the outer routine is already using a heavily optimized C routine.
src/library/base/R/outer.R: tcrossprod usage.
src/main/array.c: underlying C routine powering the tcrossprod computation.
Armadillo itself has its own optimization for addressing matrix multiplication using the dgemm and dgemv routines from LAPACK:
armadillo_bits/mul_gemm.hpp: C := alpha*op( A )op( B ) + betaC,
armadillo_bits/mul_gemv.hpp: y := alphaAx + betay, or y := alphaA**Tx + betay,
Playing around with the outerproduct calculations leads to a few optimizations. Mainly, we're opting to move the outer product into armadillo actions instead of loops:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat outer_rcpp(const arma::vec& x, const arma::vec& y) {
int x_length = x.n_elem;
int y_length = y.n_elem;
arma::mat final(x_length, y_length);
// And use loops instead of outer
for(int i = 0; i < x_length; i++) {
final.col(i) = x[i] * y;
}
return final;
}
// [[Rcpp::export]]
arma::mat outer_with_armadillo(const arma::vec& x, const arma::vec& y) {
arma::mat final = x*y.t();
return final;
}
// [[Rcpp::export]]
arma::mat outer_with_armadillo_transposed(const arma::vec& x, const arma::rowvec& y) {
arma::mat final = x*y;
return final;
}
Revisiting the benchmarking code, we have:
b = rnorm(5000)
b_tranposed = t(b)
bench_results = microbenchmark::microbenchmark(base = base::outer(b, b),
outer_armadillo_loop = outer_rcpp(b, b),
outer_armadillo_optimized = outer_with_armadillo(b, b),
outer_armadillo_optimized_transposed = outer_with_armadillo_transposed(b, b_tranposed), times = 10)
bench_results
expr
min
lq
mean
median
uq
max
neval
base
132.8601
141.3532
156.9979
146.7993
154.8954
234.2619
10
outer_armadillo_loop
278.4115
279.9204
317.7907
288.4212
329.0769
451.6872
10
outer_armadillo_optimized
272.4348
283.3380
347.7913
304.1181
339.3282
728.2264
10
outer_armadillo_optimized_transposed
269.7855
270.7108
297.9580
279.8099
312.3488
386.4270
10
From the results, the lowest I could achieve is having a pre-transposed b vector from column vector form into row-vector form: (n x 1) * (1 x m)
I am trying to convert my R function to C++ using Rcpp, but I came around errors that I don't understand quite well.
The following code gives my R function, my (poor) attempt to translate it and some examples of uses at the end (testing that the two function return the same thing...)
My R Code function:
intersect_rectangles <- function(x_min, x_max, y_min, y_max) {
rez <- list()
rez$min <- pmax(x_min, y_min)
rez$max <- pmin(x_max, y_max)
if (any(rez$min > rez$max)) {
return(list(NULL))
}
return(rez)
}
My attempt to create the same function with Rcpp.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List Cpp_intersect_rectangles(NumericVector x_min,NumericVector
x_max,NumericVector y_min,NumericVector y_max) {
// Create a list :
NumericVector min = pmax(x_min,y_min);
NumericVector max = pmin(x_max,y_max);
List L = List::create(R_NilValue);
if (! any(min > max)) {
L = List::create(Named("min") = min , _["max"] = max);
}
return(L);
}
I receive the following error messages:
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/sugar/logical/SingleLogicalResult.h:36:2: error: implicit instantiation of undefined template 'Rcpp::sugar::forbidden_conversion<false>'
forbidden_conversion<x>{
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/sugar/logical/SingleLogicalResult.h:74:40: note: in instantiation of template class 'Rcpp::sugar::conversion_to_bool_is_forbidden<false>' requested here
conversion_to_bool_is_forbidden<!NA> x ;
^
file637e53281965.cpp:13:9: note: in instantiation of member function 'Rcpp::sugar::SingleLogicalResult<true, Rcpp::sugar::Negate_SingleLogicalResult<true, Rcpp::sugar::Any<true, Rcpp::sugar::Comparator<14, Rcpp::sugar::greater<14>, true, Rcpp::Vector<14, PreserveStorage>, true, Rcpp::Vector<14, PreserveStorage> > > > >::operator bool' requested here
if (! any(min > max))
If the Rcpp function is implemented correctly, then the following should work:
u = rep(0,4)
v = rep(1,4)
w = rep(0.3,4)
x = c(0.8,0.8,3,3)
all.equal(intersect_rectangles(u,v,w,x), Cpp_intersect_rectangles(u,v,w,x))
all.equal(intersect_rectangles(u,v,w,w), Cpp_intersect_rectangles(u,v,w,w))
What's wrong with my cpp code?
The reason the code isn't translating correctly is due to how the any() Rcpp sugar implementation was created. In particular, we have that:
The actual return type of any(X) is an instance of the
SingleLogicalResult template class, but the functions is_true
and is_false may be used to convert the return value to bool.
Per https://thecoatlessprofessor.com/programming/unofficial-rcpp-api-documentation/#any
Therefore, the solution is to add .is_true() to the any() function call, e.g. !any(condition).is_true().
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List Cpp_intersect_rectangles(NumericVector x_min, NumericVector x_max,
NumericVector y_min, NumericVector y_max) {
// Create a list :
NumericVector min = pmax(x_min, y_min);
NumericVector max = pmin(x_max, y_max);
List L = List::create(R_NilValue);
if (! any(min > max).is_true()) {
// ^^^^^^^^^ Added
L = List::create(Named("min") = min , _["max"] = max);
}
return(L);
}
Then, through testing we get:
u = rep(0,4)
v = rep(1,4)
w = rep(0.3,4)
x = c(0.8,0.8,3,3)
all.equal(intersect_rectangles(u,v,w,x), Cpp_intersect_rectangles(u,v,w,x))
# [1] TRUE
all.equal(intersect_rectangles(u,v,w,w), Cpp_intersect_rectangles(u,v,w,w))
# [1] TRUE
I am trying to call R function optim() in Rcpp. I saw an example in Calling R's optim function from within C++ using Rcpp, but I am unable to modify it correctly for my use case. Basically, the objective function depends on the x and y but I want to optimize it with respect to b.
Here is the R code that does what I want:
example_r = function(b, x, y) {
phi = rnorm(length(x))
tar_val = (x ^ 2 + y ^ 2) * b * phi
objftn_r = function(beta, x, y) {
obj_val = (x ^ 2 + y ^ 2) * beta
return(obj_val)
}
b1 = optim(b, function(beta) {
sum((objftn_r(beta, x, y) - tar_val) ^ 2)
}, method = "BFGS")$par
result = (x ^ 2 + y ^ 2) * b1
return(b1)
}
Here's is my attempt to translate it to _RcppArmadillo:
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]
arma::vec example_rcpp(arma::vec b, arma::vec x, arma::vec y){
arma::vec tar_val = pow(x,2)%b-pow(y,2);
return tar_val;
}
// [[Rcpp::export]]
arma::vec optim_rcpp(const arma::vec& init_val, arma::vec& x, arma::vec& y){
Rcpp::Environment stats("package:stats");
Rcpp::Function optim = stats["optim"];
Rcpp::List opt_results = optim(Rcpp::_["par"] = init_val,
Rcpp::_["fn"] = Rcpp::InternalFunction(&example_rcpp),
Rcpp::_["method"] = "BFGS");
arma::vec out = Rcpp::as<arma::vec>(opt_results[0]);
return out;
}
However, this code is returning:
> optim_rcpp(1:3,2:4,3:5)
Error in optim_rcpp(1:3, 2:4, 3:5) : not compatible with requested type
I'm not sure what the error is here.
Before we begin, I have a few remarks:
Please show all of your attempt.
In particular, make sure your example is a minimal reproducible example
Do not delete or shorten code unless asked.
Keep the scope of your question narrow.
Using optim from R in C++ is very different than using in C++ the underlying C++ code for opt() from nlopt.
Avoid spamming questions.
If you find yourself asking more than 3 questions in rapid succession, please read the documentation or talk in person with someone familiar with the content.
I've cleaned up your question as a result... But, in the future, this likely will not happen.
Data Generation Process
The data generation process seems to be done in 2 steps: First, outside of the example_r function, and, then inside the function.
This should be simplified so that it is done outside of the optimization function. For example:
generate_data = function(n, x_mu = 0, y_mu = 1, beta = 1.5) {
x = rnorm(n, x_mu)
y = rnorm(n, y_mu)
phi = rnorm(length(x))
tar_val = (x ^ 2 + y ^ 2) * beta * phi
simulated_data = list(x = x, y = y, beta = beta, tar_val = tar_val)
return(simulated_data)
}
Objective Functions and R's optim
Objective functions must return a single value, e.g. a scalar, in R. Under the posted R code, there was effectively two functions designed to act as an objective function in sequence, e.g.
objftn_r = function(beta, x, y) {
obj_val = (x ^ 2 + y ^ 2) * beta
return(obj_val)
}
b1 = optim(b, function(beta) {
sum((objftn_r(beta, x, y) - tar_val) ^ 2)
}, method = "BFGS")$par
This objective function should therefore be re-written as:
objftn_r = function(beta_hat, x, y, tar_val) {
# The predictions generate will be a vector
est_val = (x ^ 2 + y ^ 2) * beta_hat
# Here we apply sum of squares which changes it
# from a vector into a single "objective" value
# that optim can work with.
obj_val = sum( ( est_val - tar_val) ^ 2)
return(obj_val)
}
From there, the calls should align as:
sim_data = generate_data(10, 1, 2, .3)
b1 = optim(sim_data$beta, fn = objftn_r, method = "BFGS",
x = sim_data$x, y = sim_data$y, tar_val = sim_data$tar_val)$par
RcppArmadillo Objective Functions
Having fixed the scope and behavior of the R code, let's focus on translating it into RcppArmadillo.
In particular, notice that the objection function defined after the translation returns a vector and not a scalar into optim, which is not a single value. Also of concern is the lack of a tar_val parameter in the objective function. With this in mind, the objective function will translate to:
// changed function return type and
// the return type of first parameter
double obj_fun_rcpp(double& beta_hat,
arma::vec& x, arma::vec& y, arma::vec& tar_val){
// Changed from % to * as it is only appropriate if
// `beta_hat` is the same length as x and y.
// This is because it performs element-wise multiplication
// instead of a scalar multiplication on a vector
arma::vec est_val = (pow(x, 2) - pow(y, 2)) * beta_hat;
// Compute objective value
double obj_val = sum( pow( est_val - tar_val, 2) );
// Return a single value
return obj_val;
}
Now, with the objective function set, let's address the Rcpp call into R for optim() from C++. In this function, the parameters of the
function must be explicitly supplied. So, x, y, and tar_val must be present in the optim call. Thus, we will end up with:
// [[Rcpp::export]]
arma::vec optim_rcpp(double& init_val,
arma::vec& x, arma::vec& y, arma::vec& tar_val){
// Extract R's optim function
Rcpp::Environment stats("package:stats");
Rcpp::Function optim = stats["optim"];
// Call the optim function from R in C++
Rcpp::List opt_results = optim(Rcpp::_["par"] = init_val,
// Make sure this function is not exported!
Rcpp::_["fn"] = Rcpp::InternalFunction(&obj_fun_rcpp),
Rcpp::_["method"] = "BFGS",
// Pass in the other parameters as everything
// is scoped environmentally
Rcpp::_["x"] = x,
Rcpp::_["y"] = y,
Rcpp::_["tar_val"] = tar_val);
// Extract out the estimated parameter values
arma::vec out = Rcpp::as<arma::vec>(opt_results[0]);
// Return estimated values
return out;
}
All together
The full functioning code can be written in test_optim.cpp and compiled via sourceCpp() as:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// changed function return type and
// the return type of first parameter
// DO NOT EXPORT THIS FUNCTION VIA RCPP ATTRIBUTES
double obj_fun_rcpp(double& beta_hat,
arma::vec& x, arma::vec& y, arma::vec& tar_val){
// Changed from % to * as it is only appropriate if
// `beta_hat` is the same length as x and y.
// This is because it performs element-wise multiplication
// instead of a scalar multiplication on a vector
arma::vec est_val = (pow(x, 2) - pow(y, 2)) * beta_hat;
// Compute objective value
double obj_val = sum( pow( est_val - tar_val, 2) );
// Return a single value
return obj_val;
}
// [[Rcpp::export]]
arma::vec optim_rcpp(double& init_val,
arma::vec& x, arma::vec& y, arma::vec& tar_val){
// Extract R's optim function
Rcpp::Environment stats("package:stats");
Rcpp::Function optim = stats["optim"];
// Call the optim function from R in C++
Rcpp::List opt_results = optim(Rcpp::_["par"] = init_val,
// Make sure this function is not exported!
Rcpp::_["fn"] = Rcpp::InternalFunction(&obj_fun_rcpp),
Rcpp::_["method"] = "BFGS",
// Pass in the other parameters as everything
// is scoped environmentally
Rcpp::_["x"] = x,
Rcpp::_["y"] = y,
Rcpp::_["tar_val"] = tar_val);
// Extract out the estimated parameter values
arma::vec out = Rcpp::as<arma::vec>(opt_results[0]);
// Return estimated values
return out;
}
Test Case
# Setup some values
beta = 2
x = 2:4
y = 3:5
# Set a seed for reproducibility
set.seed(111)
phi = rnorm(length(x))
tar_val = (x ^ 2 + y ^ 2) * beta * phi
optim_rcpp(beta, x, y, tar_val)
# [,1]
# [1,] 2.033273
Note: If you would like to avoid a matrix of size 1 x1 from being returned please use double as the return parameter of optim_rcpp and switch Rcpp::as<arma::vec> to Rcpp::as<double>
Suppose I have the following list:
x <- list(a = c(1, 2), b = c("a", "c"), c = 1:10)
In R, I can remove the first element using the following two methods:
x[-1]
x[1] <- NULL
I'm trying to do same thing in Rcpp, but I can't figure it out. Following code just assigns NULL to the first element.
// [[Rcpp::export]]
Rcpp::List removeElement(Rcpp::List x)
{
x[0] = R_NilValue;
return(x);
}
Any ideas?
What about
// [[Rcpp::export]]
Rcpp::List removeElement(Rcpp::List x, int j)
{
IntegerVector idx = seq_len(x.length());
return(x[idx != j]);
}
Or if you want the indices to start from 0 use
IntegerVector idx = seq_len(x.length()) - 1;
Consider the following R code,
## ----------- R version -----------
caller <- function(x=1:3, fun = "identity", ...){
## do some other stuff
## ...
## then call the function
eval(call(fun, x))
}
fun1 <- function(x, ...){
x + x
}
fun2 <- function(x, a = 10) a * x
caller(fun = "fun1")
caller(fun = "fun2")
The user can pass a function name "fun", that is used by caller. I wish to perform the same task with RcppArmadillo objects (as part of a more complex task, obviously). The function would be defined in C++, and the user selects it at the R level by referring to its name:
caller_cpp(1:3, "fun1_cpp")
or
caller_cpp(1:3, "fun2_cpp")
etc.
Here's my naive attempt for the caller function, that even fails to compile:
## ----------- C++ version -----------
library(Rcpp)
require( RcppArmadillo )
sourceCpp( code = '
// [[Rcpp::depends("RcppArmadillo")]]
#include <RcppArmadillo.h>
using namespace arma ;
using namespace Rcpp ;
colvec fun1_cpp(const colvec x)
{
colvec y ;
y = x + x;
return (y);
}
colvec fun2_cpp(const colvec x)
{
colvec y ;
y = 10*x;
return (y);
}
// mysterious pointer business in an attempt
// to select a compiled function by its name
typedef double (*funcPtr)(SEXP);
SEXP putFunPtrInXPtr(SEXP funname) {
std::string fstr = Rcpp::as<std::string>(funname);
if (fstr == "fun1")
return(Rcpp::XPtr<funcPtr>(new funcPtr(&fun1_cpp)));
else if (fstr == "fun2")
return(Rcpp::XPtr<funcPtr>(new funcPtr(&fun2_cpp)));
}
// [[Rcpp::export]]
colvec caller_cpp(const colvec x, character funname)
{
Rcpp::XPtr fun = putFunPtrInXPtr(funname);
colvec y ;
y = fun(x);
return (y);
}
')
Edit: adapted the example after following Dirk's suggestion to look at RcppDE.
(Sometime you need to use svn log ... on files to see how dated they are...)
I think a better use case is in my "port" of the C-based DEoptim to Rcpp / RcppArmadillo: RcppDE. In it, I allow the optimization routine to use either an R function (as DEoptim does) or a user-supplied compiled function -- which is what you want here as I understand it.
There is a tiny bit of C++ scaffolding, but you should have no problem following that.
Edit on 2013-01-21 Below is a complete solution which I have also justed posted as this new post at the Rcpp Gallery -- including some comments and sample usage.
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace arma;
using namespace Rcpp;
vec fun1_cpp(const vec& x) { // a first function
vec y = x + x;
return (y);
}
vec fun2_cpp(const vec& x) { // and a second function
vec y = 10*x;
return (y);
}
typedef vec (*funcPtr)(const vec& x);
// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr(std::string fstr) {
if (fstr == "fun1")
return(XPtr<funcPtr>(new funcPtr(&fun1_cpp)));
else if (fstr == "fun2")
return(XPtr<funcPtr>(new funcPtr(&fun2_cpp)));
else
return XPtr<funcPtr>(R_NilValue); // runtime error as NULL no XPtr
}
// [[Rcpp::export]]
vec callViaString(const vec x, std::string funname) {
XPtr<funcPtr> xpfun = putFunPtrInXPtr(funname);
funcPtr fun = *xpfun;
vec y = fun(x);
return (y);
}
// [[Rcpp::export]]
vec callViaXPtr(const vec x, SEXP xpsexp) {
XPtr<funcPtr> xpfun(xpsexp);
funcPtr fun = *xpfun;
vec y = fun(x);
return (y);
}