Call R Functions in Rcpp

Calling R function from Rcpp

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

Rcpp: calling c++ function in R without exporting c++ function

I think you're probably mixing up the concept of exporting C++ code to be used in R (via // [[Rcpp::export]]), which is entirely different to exporting R functions from your package, i.e. making those functions available to end-users of your package.

To make your Rcpp functions callable from within R at all, you need to // [[Rcpp::export]] them. If you don't do this, none of your C++ code will be available from within your R package.

It sounds like what you would like to do is to use the Rcpp-exported functions within your package but to hide them from end-users. This is a common use case for Rcpp, as it allows you to have an R function that acts as an end-user interface to your C++ code, while leaving you free to alter the C++ implementation in future developments without the risk of breaking existing users' code.

Any function you have created within your package, be it an R function or an Rcpp-exported function, has to actively be exported from your package to make it available to end-users. This is a different concept from // [[Rcpp::export]], which is needed to access C++ functions from within your package's R code.

Any R functions will only be exported from your R package if you specify them in the NAMESPACE file in your project's root directory. Thus to export myfunction() you need to have a line that says export(myfunction) in the NAMESPACE file. You are using roxygen2, which will generate this line automatically as long as you write @export in the roxygen skeleton. An alternative to using roxygen's exporting system is to specify an exportPattern in the NAMESPACE file that uses regex to export only functions whose names match a certain pattern.

My usual workflow is to prefix any Rcpp-exported functions with a period by writing my C++ functions like this:

// [[Rcpp::export(.MyCppFunction)]]
int BoringFunction() { return 0; }

I can now call the C++ function from R like this:

MyRFunction <- function()
{
result <- .MyCppFunction()
return(result)
}

The first line in my NAMESPACE file looks like this:

exportPattern("^[[:alpha:]]+")

Which means that any R function in my package starting with a letter will be exported. Since all the functions I Rcpp::export start with a period, I can use them internally within the R package but they won't be exported to end-users.

In other words, end-users of the package can call MyRFunction() but would get an error if they tried to call .MyCppFunction

How to call R function (which should not be exported) from Rcpp?

You have to get a bit meta here. It is possible to get an environment containing all the unexported functions in a package using the base R function asNamespace. This function itself can be used inside Rcpp. You then create a new Environment from the output of that function, from which you can harvest the unexported function.

As an example, let's get the unexported function ggplot2:::as_lower_ascii to do some work on a string we pass to an Rcpp function:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
CharacterVector fun(CharacterVector input){
Function asNamespace("asNamespace");
Environment ggplot_env = asNamespace("ggplot2");
Function to_lower_ascii = ggplot_env["to_lower_ascii"];
return to_lower_ascii(input);
}

So if we source this, then back in R we can do:

fun("HELLO WORLD")
#> [1] "hello world"

calling a user-defined R function from C++ using Rcpp

You declare that the function should return an int, but use wrap which indicates the object returned should be a SEXP. Moreover, calling an R function from Rcpp (through Function) also returns a SEXP.

You want something like:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
SEXP mySuminC(){
Environment myEnv = Environment::global_env();
Function mySum = myEnv["mySum"];
int x = myEnv["x"];
int y = myEnv["y"];
return mySum(Rcpp::Named("x", x), Rcpp::Named("y", y));
}

(or, leave function return as int and use as<int> in place of wrap).

That said, this is kind of non-idiomatic Rcpp code. Remember that calling R functions from C++ is still going to be slow.

how to call a function created in Rcpp from another Rccp function

A slight rewrite of your file to avoid calling a C++ via an intermediate R function which is (generally) a bad idea and almost always an uncalled-for and heavy tax on performance.

As you defined a valid C++ function in the same file and before its use (so that you don't need a signature to declare it as e.g. a header file would do for you) can simply call it.

I also changed the loop index variable to get rid of one warning during compilation, and, while I was at it, removed using namespace Rcpp; and switched to explicit calls with namespace which is more explicit and a little 'safer' from surprises in larger code bases.

Edit: And as your loops are in fact invariant to the loop index,
we can rewrite the code as vectorized calls whicg is shorter, simpler, faster, and easier to reason with. (And could, of course, be done from R too...)

Code

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector esat(Rcpp::NumericVector Tk) {
Rcpp::NumericVector esat_out(Tk.size(), NAN);
for (R_xlen_t i=0; i<Tk.size(); i++) {
esat_out[i] = 6.1121 * Tk[i];
}
return esat_out;
}

// [[Rcpp::export]]
Rcpp::NumericVector h_evap(Rcpp::NumericVector Tk) {
Rcpp::NumericVector h_evap_out(Tk.size(), NAN);
Rcpp::NumericVector f_out = esat(Tk);
for (R_xlen_t i=0; i<Tk.size(); i++) {
h_evap_out[i] = (313.15 - Tk[i]);
h_evap_out[i] = h_evap_out[i] + f_out[i];
}
return h_evap_out;
}

// [[Rcpp::export]]
Rcpp::NumericVector esatV(Rcpp::NumericVector Tk) {
Rcpp::NumericVector esat_out = 6.1121 * Tk;
return esat_out;
}

// [[Rcpp::export]]
Rcpp::NumericVector h_evapV(Rcpp::NumericVector Tk) {
Rcpp::NumericVector f_out = esatV(Tk);
Rcpp::NumericVector h_evap_out = 313.15 - Tk + f_out;
return h_evap_out;
}

/*** R
esat(42)
h_evap(42)
esatV(42)
h_evapV(42)
*/

Usage

> Rcpp::sourceCpp("~/git/stackoverflow/68605528/answer.cpp")

> esat(42)
[1] 256.708

> h_evap(42)
[1] 527.858

> esatV(42)
[1] 256.708

> h_evapV(42)
[1] 527.858
>


Related Topics



Leave a reply



Submit