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. :(
----------------------------------------
Eileen Meyer
Physics& Astronomy MS-108
Rice University
6100 Main St. Houston, TX 77005
www.interfolio.com/portfolio/eileenmeyer
| 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