Skip to content

[Rcpp-devel] using RInside calls in a subroutine?

3 messages · Eileen Meyer, Dirk Eddelbuettel

#
I need to call R functions through a C++ subroutine.  The problem is 
that, as many have pointed out, you can't call the RInside environment 
more than once.  So how do I get my subroutine to "know" about R? Can I 
pass something along?  I am not really a C++ programmer, so I apologize 
for my ignorance.  (and THANKS for developing some pretty amazing tools)

Here is an example of what doesn't work.

First, the subroutine:

#include "r_funcs.h"
std::vector< double > ks_test(std::vector< double >x, std::vector< 
double >y, int argc, char *argv[]) {

   SEXP ans;

   R.RInside::assign(x,"x");
   R.RInside::assign(y, "y");

   std::string evalstr = " \
     cat('Running ls()\n'); print(ls());    \
     ks <- ks.test(x,y);            \
     ks$p";

   R.RInside::parseEval(evalstr, ans);
   RcppVector<double> vec(ans);
   std::vector<double> v = vec.stlVector();

   return(v);
}

header file:

#ifndef R_FUNCS_H
#define R_FUNCS_H


#include <RInside.h>
//#include <Rcpp.h>

std::vector< double > ks_test(std::vector< double >x, std::vector< 
double >y, int argc, char *argv[]);

#endif //R_FUNCS_H


the main file:

#include <stdio.h>
#include "r_funcs.h"

int main(int argc, char *argv[]) {

   RInside::RInside R(argc,argv);
   // testing stuff
   std::vector< double > x(5);
   std::vector< double > y(5);
   int i;
   double var[5] = {1,2.2,3.4,4.33,42.4};
   for(i=0; i<5; i++) {
     x[i] = var[i];
     std::cout << x[i] << std::endl;
   }

   double var2[5] = {3.224,4.1,4.22,4,4.4};
   for(i=0; i<5; i++) {
     y[i] = var2[i];
   }

   // correct function call
   std::vector< double > v = ks_test(x,y,argc,argv);

   // output
   std::cout << "In main_stat_compare, ks p-value is " << v[0] << std::endl;

   exit(0);
}


Of course if I move the RInside declaration into the subroutine, this 
example works, but I can only call the ks test once. :(
#
On 7 December 2010 at 12:00, Eileen Meyer wrote:
| I need to call R functions through a C++ subroutine.  The problem is 
| that, as many have pointed out, you can't call the RInside environment 
| more than once.  

News to me.

What you cannot do is _instantiante more than one RInside object_ because R
itself is single-threaded, non-reentrant and whatever evil thing else we can
imagine.

One R program, one RInside instance. Share it within your program. Not that hard.

| So how do I get my subroutine to "know" about R? 

A global variable?  A variable in passed as reference?  

| Can I pass something along?  I am not really a C++ programmer, so I apologize 
| for my ignorance.  (and THANKS for developing some pretty amazing tools)

We cannot make you a C++ programmer via an email or two.  You need to read up
and practice. 

Did you look at the existing examples in the RInside package?

 
| Here is an example of what doesn't work.
| 
| First, the subroutine:
| 
| #include "r_funcs.h"
| std::vector< double > ks_test(std::vector< double >x, std::vector< 
| double >y, int argc, char *argv[]) {

Why do you need to pass argc and argv into the work function?
| 
|    SEXP ans;
| 
|    R.RInside::assign(x,"x");
|    R.RInside::assign(y, "y");

What is R. -- where is it defined?
 
|    std::string evalstr = " \
|      cat('Running ls()\n'); print(ls());    \
|      ks <- ks.test(x,y);            \
|      ks$p";
| 
|    R.RInside::parseEval(evalstr, ans);
|    RcppVector<double> vec(ans);
|    std::vector<double> v = vec.stlVector();
| 
|    return(v);
| }



| 
| header file:
| 
| #ifndef R_FUNCS_H
| #define R_FUNCS_H
| 
| 
| #include <RInside.h>
| //#include <Rcpp.h>
| 
| std::vector< double > ks_test(std::vector< double >x, std::vector< 
| double >y, int argc, char *argv[]);
| 
| #endif //R_FUNCS_H
| 
| 
| the main file:
| 
| #include <stdio.h>
| #include "r_funcs.h"
| 
| int main(int argc, char *argv[]) {
| 
|    RInside::RInside R(argc,argv);
|    // testing stuff
|    std::vector< double > x(5);
|    std::vector< double > y(5);
|    int i;
|    double var[5] = {1,2.2,3.4,4.33,42.4};
|    for(i=0; i<5; i++) {
|      x[i] = var[i];
|      std::cout << x[i] << std::endl;
|    }
| 
|    double var2[5] = {3.224,4.1,4.22,4,4.4};
|    for(i=0; i<5; i++) {
|      y[i] = var2[i];
|    }
| 
|    // correct function call
|    std::vector< double > v = ks_test(x,y,argc,argv);
| 
|    // output
|    std::cout << "In main_stat_compare, ks p-value is " << v[0] << std::endl;
| 
|    exit(0);
| }
| 
| 
| Of course if I move the RInside declaration into the subroutine, this 
| example works, but I can only call the ks test once. :(


See my questions above.  Your example does not even built (and yes, I went
through the trouble of creating three files and adapting the Makefile from
RInside's own examples/standard/Makefile.

But if we can't even build it we can't comment on it.

Sorry, Dirk
 
 
| 
| 
| 
| 
| 
| 
| -- 
| ----------------------------------------
| Eileen Meyer
| 
| Physics&   Astronomy MS-108
| Rice University
| 6100 Main St. Houston, TX 77005
| www.interfolio.com/portfolio/eileenmeyer
| 
| _______________________________________________
| Rcpp-devel mailing list
| Rcpp-devel at lists.r-forge.r-project.org
| https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
#
Eileen,

To make this a little more instructive, please find a repaired single-file
version of your program below.  You can of course split off a header file and
a file for the function but there is no need.  Below it is a quick Makefile
based on the aforementioned Makefile from the RInside examples.

With that:

edd at max:/tmp/eileen$ make
g++ -I/usr/share/R/include -I/usr/local/lib/R/site-library/Rcpp/include -I"/usr/local/lib/R/site-library/RInside/include" -O3 -pipe -g -Wall   -c -o main.o main.cpp
cc   main.o  -L/usr/lib64/R/lib -lR  -lblas -llapack -L/usr/local/lib/R/site-library/Rcpp/lib -lRcpp -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib -L/usr/local/lib/R/site-library/RInside/lib -lRInside -Wl,-rpath,/usr/local/lib/R/site-library/RInside/lib -o main
edd at max:/tmp/eileen$ ./main
1
2.2
3.4
4.33
42.4
Running ls()
[1] "argv" "x"    "y"   
In main_stat_compare, ks p-value is 0.873016
Running ls()
[1] "argv" "ks"   "x"    "y"   
In main_stat_compare, ks p-value is 0.873016
edd at max:/tmp/eileen$ 

Cleanly calls twice, just as we suspected. 

Cheers, Dirk


#include <stdio.h>
#include <RInside.h>

std::vector< double > ks_test(std::vector< double >x, std::vector<double >y, RInside & R) {

   SEXP ans;

   R.assign(x,"x");
   R.assign(y, "y");

   std::string evalstr = " \
     cat('Running ls()\n'); print(ls());    \
     ks <- ks.test(x,y);            \
     ks$p";

   R.parseEval(evalstr, ans);
   Rcpp::NumericVector vec(ans); // new API 
   std::vector<double> v = Rcpp::as<std::vector<double> >(vec); // use as() to convert
   return(v);
}

int main(int argc, char *argv[]) {

   RInside::RInside R(argc,argv);
   // testing stuff
   std::vector< double > x(5);
   std::vector< double > y(5);
   int i;
   double var[5] = {1,2.2,3.4,4.33,42.4};
   for(i=0; i<5; i++) {
     x[i] = var[i];
     std::cout << x[i] << std::endl;
   }

   double var2[5] = {3.224,4.1,4.22,4,4.4};
   for(i=0; i<5; i++) {
     y[i] = var2[i];
   }

   // correct function call
   std::vector< double > v = ks_test(x,y,R);

   // output
   std::cout << "In main_stat_compare, ks p-value is " << v[0] << std::endl;

   // and call again
   v = ks_test(x,y,R);

   // output
   std::cout << "In main_stat_compare, ks p-value is " << v[0] << std::endl;

   exit(0);
}



// --------------- Makefile below


## -*- mode: make; tab-width: 8; -*-
##
## Simple Makefile
##
## TODO: 
##  proper configure for non-Debian file locations,   [ Done ]
##  allow RHOME to be set for non-default R etc

## comment this out if you need a different version of R, 
## and set set R_HOME accordingly as an environment variable
R_HOME := 		$(shell R RHOME)

sources := 		$(wildcard *.cpp)
#programs := 		$(sources:.cpp=)


## include headers and libraries for R 
RCPPFLAGS := 		$(shell $(R_HOME)/bin/R CMD config --cppflags)
RLDFLAGS := 		$(shell $(R_HOME)/bin/R CMD config --ldflags)
RBLAS := 		$(shell $(R_HOME)/bin/R CMD config BLAS_LIBS)
RLAPACK := 		$(shell $(R_HOME)/bin/R CMD config LAPACK_LIBS)

## if you need to set an rpath to R itself, also uncomment
#RRPATH :=		-Wl,-rpath,$(R_HOME)/lib

## include headers and libraries for Rcpp interface classes
RCPPINCL := 		$(shell echo 'Rcpp:::CxxFlags()' | $(R_HOME)/bin/R --vanilla --slave)
RCPPLIBS := 		$(shell echo 'Rcpp:::LdFlags()'  | $(R_HOME)/bin/R --vanilla --slave)


## include headers and libraries for RInside embedding classes
RINSIDEINCL := 		$(shell echo 'RInside:::CxxFlags()' | $(R_HOME)/bin/R --vanilla --slave)
RINSIDELIBS := 		$(shell echo 'RInside:::LdFlags()'  | $(R_HOME)/bin/R --vanilla --slave)

## compiler etc settings used in default make rules
CXX := 			$(shell $(R_HOME)/bin/R CMD config CXX)
CPPFLAGS := 		-Wall $(shell $(R_HOME)/bin/R CMD config CPPFLAGS)
CXXFLAGS := 		$(RCPPFLAGS) $(RCPPINCL) $(RINSIDEINCL) $(shell $(R_HOME)/bin/R CMD config CXXFLAGS)
LDLIBS := 		$(RLDFLAGS) $(RRPATH) $(RBLAS) $(RLAPACK) $(RCPPLIBS) $(RINSIDELIBS)

all: 			main

main:			main.o