Skip to content

[Rcpp-devel] Create and access several instances of a C++ class from R

10 messages · soeren.vogel at uzh.ch, Dirk Eddelbuettel, Romain Francois +1 more

#
Hello

This posting continues the discussions from here:

https://stat.ethz.ch/pipermail/r-help/2011-April/276490.html

https://stat.ethz.ch/pipermail/r-devel/2011-May/060922.html

Following all recommendations, we have rewritten our class to use STL. However, I have been trying around with various changes, but I can't get it working with RCPP_MODULES. Also, the code snippets posted by Romain Francois did not help since we cannot use inline, rather we need raw C++ code that can be compiled using R CMD BUILD etc. Therefore, I kindly ask the experts here for an example adaption to the source below. I guess you experts instantly see what needs to be done next to make the code working. Could you please give tips for the next step?

Thank you

Regards
S?ren


/* FOO_mod.cpp */
#include <Rcpp.h>
#include <vector>
#include <valarray>
using namespace std;

// from FOO.h
class FOO
{
		double dtau;
		vector<double> D, ee, ff, S;

	public:
		int M;
		vector<double> C, t, s, par;
		vector<int> y;

		FOO();
		~FOO();

		double do_bar(vector<double> z);
};

// from FOO.cpp
double FOO::do_bar(vector<double> z)
{
	// whatever it does
}

RCPP_MODULE(mod_foo){
	using namespace Rcpp ;
	class_<FOO>( "FOO" )
		.constructor()
		.field( "M" , &FOO::M )
		.field( "C" , &FOO::C )
		.method( "do_bar", &FOO::do_bar )
	;
}
#
On 13 May 2011 at 16:11, soeren.vogel at uzh.ch wrote:
| Hello
| 
| This posting continues the discussions from here:
| 
| https://stat.ethz.ch/pipermail/r-help/2011-April/276490.html
| 
| https://stat.ethz.ch/pipermail/r-devel/2011-May/060922.html
| 
| Following all recommendations, we have rewritten our class to use STL. However, I have been trying around with various changes, but I can't get it working with RCPP_MODULES. Also, the code snippets posted by Romain Francois did not help since we cannot use inline, rather we need raw C++ code that can be compiled using R CMD BUILD etc. Therefore, I kindly ask the experts here for an example adaption to the source below. I guess you experts instantly see what needs to be done next to make the code working. Could you please give tips for the next step?

Could you detail what you mean by "can't get it working"?  Does it not
compile? If so, can you show how you tried to compile and the error you are
getting?

I'd like to help, but there is not enough information in this post.

Cheers, Dirk

| 
| Thank you
| 
| Regards
| S?ren
| 
| 
| /* FOO_mod.cpp */
| #include <Rcpp.h>
| #include <vector>
| #include <valarray>
| using namespace std;
| 
| // from FOO.h
| class FOO
| {
| 		double dtau;
| 		vector<double> D, ee, ff, S;
| 
| 	public:
| 		int M;
| 		vector<double> C, t, s, par;
| 		vector<int> y;
| 
| 		FOO();
| 		~FOO();
| 
| 		double do_bar(vector<double> z);
| };
| 
| // from FOO.cpp
| double FOO::do_bar(vector<double> z)
| {
| 	// whatever it does
| }
| 
| RCPP_MODULE(mod_foo){
| 	using namespace Rcpp ;
| 	class_<FOO>( "FOO" )
| 		.constructor()
| 		.field( "M" , &FOO::M )
| 		.field( "C" , &FOO::C )
| 		.method( "do_bar", &FOO::do_bar )
| 	;
| }
|
#
On 13.05.2011, at 18:55, Dirk Eddelbuettel wrote:

            
Hello Dirk

Compilation with R CMD CHECK FOO fails with the following error in 00install.out:

Error in dyn.load(file, DLLpath = DLLpath, ...) : 
  unable to load shared object '/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so':
  dlopen(/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so, 6): Symbol not found: __ZN3FOOC1Ev
  Referenced from: /Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so
  Expected in: flat namespace

The (original) class and its functions compile fine with R CMD SHLIB. So we guess that this error has something to do with the Rcpp modules implementation.

Currently, FOO_mod.cpp is embedded in a package "FOO" created with Rcpp.pack...("FOO", module=TRUE), DESCRIPTION and NAMESPACE were adjusted accordingly, all other C sources were removed. Recapture that the package compiled and installed with our previous FOO version, however, since we wanted to use pointers, rewriting was necessary. After that, even exposing a blank class (FOO without anything, except the constructor, but that again without parameters) fails with the error above. I guess that we still do not manage to expose the variables and the one method used in the class to R -- but we have no idea how to accomplish. If I know how to do it with one, say, int, one vector and the one method, perhaps I could understand how to do for the (many more) other variables in the complete class (indeed, FOO is only a reduced example).

What we want to prevent is to completely write the C-code for R use only. The best solution would be to change only some lines of code or even write a simple wrapper for the header file containing the class (there in C++). However, we thought it would be helpful to get it working in the first place, and then reengineer the code back to a more modular source.

Thank you for your help
S?ren
#
Soeren,
On 13 May 2011 at 20:07, soeren.vogel at uzh.ch wrote:
| Compilation with R CMD CHECK FOO fails with the following error in 00install.out:
| 
| Error in dyn.load(file, DLLpath = DLLpath, ...) : 
|   unable to load shared object '/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so':
|   dlopen(/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so, 6): Symbol not found: __ZN3FOOC1Ev
|   Referenced from: /Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so
|   Expected in: flat namespace
| 
| The (original) class and its functions compile fine with R CMD SHLIB. So we guess that this error has something to do with the Rcpp modules implementation.

It took me a few minutes with trial and error, but essentially the mistake
seems to have been this:

| > | 		FOO();
| > | 		~FOO();

You declared the constructor and deconstructor but there was no code
anywhere.  A pair of empty braces ' {}; '  is all it takes.  

In the process, I renamed things from 'foo' (just to be plain) to 'Baz'.  So
the file is now

-----------------------------------------------------------------------------
// baz_module.cpp 
#include <Rcpp.h>

// from Baz.h
class Baz
{
private:
  double dtau;
  std::vector<double> D, ee, ff, S;

public:
  int M;
  std::vector<double> C, t, s, par;
  std::vector<int> y;

  Baz() {};
  ~Baz() {};

  double do_bar(std::vector<double> z);
};

// from Baz.cpp
double Baz::do_bar(std::vector<double> z) {
  // whatever it does
  return 42.0;			// need to return something here
}

RCPP_MODULE(baz){
  using namespace Rcpp ;
  class_<Baz>( "Baz" )
    .constructor()
    .field( "M" , &Baz::M )
    .field( "C" , &Baz::C )
    .method( "do_bar", &Baz::do_bar )
    ;
}
-----------------------------------------------------------------------------

and with the line 

    RcppModules: yada, baz

we get this module loaded:


R> library(mypackage)
R> Baz
C++ class 'Baz' <0x1c37db0>
Constructors:
    Baz()

Fields: 
    std::vector<double, std::allocator<double> > C
    int M

Methods: 
     double do_bar(std::vector<double, std::allocator<double> >)  
           
R> 
R> bb <- new(Baz)
R> bb
C++ object <0x18c8f90> of class 'Baz' <0x1c37db0>
R> bb$M <- 12
R> print(bb$M)
[1] 12
R> print(bb$C)
numeric(0)
R> bb$C <- seq(1.1, 5.5, by=1.1)
R> bb$C
[1] 1.1 2.2 3.3 4.4 5.5
R> R> print(bb$do_bar(1:4))
[1] 42
R>


I hope you can take it from here. 

Cheers, Dirk
3 days later
#
Hello Dirk

That was exactly the trick! Thanks a lot! Our class and code work so far, but it may take more time to debug or find bad design. Perhaps we will be back with more detailed questions. Anyway, one question already emerged. When librarying the class, assigning an object, do some calculations, whatever -- everything goes fine. Yet, when using R CMD BATCH on a file listing the same commands as by hand, R produces some nice information at the end, however, here it produces an segmentation fault, which does -- according to my small knowledge -- say something bad:
user  system elapsed 
  0.702   0.017   0.714 
R(72992) malloc: *** error for object 0x2c9b604: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

 *** caught segfault ***
address 0x4909d58, cause 'memory not mapped'

Traceback:
 1: save(list = ls(envir = .GlobalEnv, all.names = TRUE), file = outfile,     version = version, ascii = ascii, compress = compress, envir = .GlobalEnv,     precheck = FALSE)
 2: save.image(name)
 3: sys.save.image(".RData")
aborting ...

Any idea what goes wrong there?

Regards
S?ren + Carlo
On 14.05.2011, at 18:17, Dirk Eddelbuettel wrote:
Soeren,
On 13 May 2011 at 20:07, soeren.vogel at uzh.ch wrote:
| Compilation with R CMD CHECK FOO fails with the following error in 00install.out:
| 
| Error in dyn.load(file, DLLpath = DLLpath, ...) : 
|   unable to load shared object '/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so':
|   dlopen(/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so, 6): Symbol not found: __ZN3FOOC1Ev
|   Referenced from: /Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so
|   Expected in: flat namespace
| 
| The (original) class and its functions compile fine with R CMD SHLIB. So we guess that this error has something to do with the Rcpp modules implementation.

It took me a few minutes with trial and error, but essentially the mistake
seems to have been this:

| > | 		FOO();
| > | 		~FOO();

You declared the constructor and deconstructor but there was no code
anywhere.  A pair of empty braces ' {}; '  is all it takes.  

In the process, I renamed things from 'foo' (just to be plain) to 'Baz'.  So
the file is now

-----------------------------------------------------------------------------
// baz_module.cpp 
#include <Rcpp.h>

// from Baz.h
class Baz
{
private:
 double dtau;
 std::vector<double> D, ee, ff, S;

public:
 int M;
 std::vector<double> C, t, s, par;
 std::vector<int> y;

 Baz() {};
 ~Baz() {};

 double do_bar(std::vector<double> z);
};

// from Baz.cpp
double Baz::do_bar(std::vector<double> z) {
 // whatever it does
 return 42.0;			// need to return something here
}

RCPP_MODULE(baz){
 using namespace Rcpp ;
 class_<Baz>( "Baz" )
   .constructor()
   .field( "M" , &Baz::M )
   .field( "C" , &Baz::C )
   .method( "do_bar", &Baz::do_bar )
   ;
}
-----------------------------------------------------------------------------

and with the line 

   RcppModules: yada, baz

we get this module loaded:


R> library(mypackage)
R> Baz
C++ class 'Baz' <0x1c37db0>
Constructors:
   Baz()

Fields: 
   std::vector<double, std::allocator<double> > C
   int M

Methods: 
    double do_bar(std::vector<double, std::allocator<double> >)  

R> 
R> bb <- new(Baz)
R> bb
C++ object <0x18c8f90> of class 'Baz' <0x1c37db0>
R> bb$M <- 12
R> print(bb$M)
[1] 12
R> print(bb$C)
numeric(0)
R> bb$C <- seq(1.1, 5.5, by=1.1)
R> bb$C
[1] 1.1 2.2 3.3 4.4 5.5
R> R> print(bb$do_bar(1:4))
[1] 42
R>


I hope you can take it from here. 

Cheers, Dirk
#
On May 18, 2011 2:53 AM, <soeren.vogel at uzh.ch> wrote:
but it may take more time to debug or find bad design. Perhaps we will be
back with more detailed questions. Anyway, one question already emerged.
When librarying the class, assigning an object, do some calculations,
whatever -- everything goes fine. Yet, when using R CMD BATCH on a file
listing the same commands as by hand, R produces some nice information at
the end, however, here it produces an segmentation fault, which does --
according to my small knowledge -- say something bad:
freed object - object was probably modified after being freed.
version = version, ascii = ascii, compress = compress, envir =
.GlobalEnv,     precheck = FALSE)
As you can see, the problem occurs when R is saving the worksheet.  At
present an instance of a Rcpp module class cannot be saved. It is likely
that this will need to be addressed by the person designing each C++ class
that will be expressed in a module.  R can't serialize the contents of
memory that it doesn't "own".

The current fix is "don't do that".  Add the --no-save or --vanilla in your
call to R CMD BATCH to suppress saving the worksheet.
00install.out:
'/Users/sovo/GUTS/FOO.Rcheck/FOO/libs/i386/FOO.so':
not found: __ZN3FOOC1Ev
we guess that this error has something to do with the Rcpp modules
implementation.
So
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110518/ce8175bb/attachment.htm>
1 day later
#
On 18.05.2011, at 15:17, Douglas Bates wrote:

            
Hello Douglas

Ah, I see. Thanks for this tip.

However, I am wondering why removing objects and detaching the package (where the Rcpp module resides) do not resolve the issue in the same way:

x <- new(FOO)
do_something_with_x()
rm(x)
detach("package:GUTS")

Regards
*S*
#
Le 20 mai 2011 ? 12:01, soeren.vogel at uzh.ch a ?crit :
My guess is this is related to garbage collection. Removing an object makes it candidate for GC, but it does not necessarily occur right away. 

Maybe forcing it through gc() would do the trick ...
#
On Fri, May 20, 2011 at 5:01 AM, <soeren.vogel at uzh.ch> wrote:
You are counting on being able to clean out everything that the
modules have created in the .GlobalEnv and it is entirely possible
that there are still a few pieces left in various corners.  It is
simplest to avoid trying to save the worksheet.
1 day later
#
On 20.05.2011, at 17:26, Douglas Bates wrote:

        
On Fri, May 20, 2011 at 5:01 AM, <soeren.vogel at uzh.ch> wrote:

            
Hello

Just to get that clearly: Whatever I do with a C++ class in one session will be lost after quit? So, that would mean, to save my current work (done with an Rcpp module class) requires me to write a representation of the c++ object in R, which can be saved and which, after reload, rebuilds the last state of R affairs? Guessing that, my conclusion would be to not expose the Rcpp module class, rather to build an R class which rests upon the C++ stuff and holds the important information. That in turn would mean almost double use of memory? Or how would you recommend to work around?

Thanks
S?ren + Carlo