开发者

Lemon Graph Library on R using Rcpp

开发者 https://www.devze.com 2023-02-08 17:58 出处:网络
I think that this answer is a bit complex because it involves several things. I want to do high performance computations with R particularly with graphs (networks). As a 开发者_StackOverflowR package

I think that this answer is a bit complex because it involves several things.

I want to do high performance computations with R particularly with graphs (networks). As a 开发者_StackOverflowR package igraph is very nice. But R is slow, so I want to code the computationally expensive routines in C++ (maybe in C). I take a look at the igraph C library and I found it a little messy to work with. I also look at the Boost Graph Library and I read about it that it is difficult to learn. So I eventually found Lemon Graph Library. It is in C++ and seems very nice to work with.

So I installed the Lemon Graph Library as recommended in the official page. Then using the Rcpp and inline packages I manage myself to run Lemon Graph C++ code from R. Here I write in detail what I had made. But basically I put this:

   inc <- '
           #include <lemon/list_graph.h>
           using namespace lemon ;
           '


   src <- '
          int xx = Rcpp::as<int>(x);

          int res = xx + 1;

          ListDigraph g;

          ListDigraph::Node u = g.addNode();
          ListDigraph::Node v = g.addNode();
          ListDigraph::Arc  a = g.addArc(u, v);

          int i = countNodes(g);
          int j = countArcs(g);

          Rprintf("num nodes is %d , and num edges is %d \\n",i,j);

          return Rcpp::wrap(res);
          '

       fun <- cxxfunction( signature(x="numeric"), body=src,include=inc, plugin="Rcpp")

in a myexample_inline.R file and then run a R console and write:

> library("inline")
> library("Rcpp")
> source("myexample_inline.R")
> fun(1)
num nodes is 2 , and num edges is 1 
[1] 2

So it works !!! But now I have the following problem. If I make a C++ function (say double func1(g)) that for example calculates some property to some Lemon graph object. How I call that function from the inlined code? I must made func1() as a template function and put it in the include field of cxxfunction()?

Basically: I can't figure out how to call a C++ function inlined in R from another C++ function also inlined in R. Is it possible? Is there another way that do not uses inline code?

Maybe I can do it using Rcpp modules but I couldn't (still) figure out how to do this. I'm having problems with making modules work. I will keep trying with this, but maybe I can get some kind of hint from here.

I also thought about the possibility to develop (my first) a package. But I had the problem that the Lemon Graph C++ code call the headers in this way (for example):

#include <iostream>
#include <lemon/list_graph.h>

So it means (at least I believe this) that I can not avoid the installation of the Lemon Graph Library. If I want to make a R package of the Lemon Graph Library I have to "rewrite" all the code again !!! So this is not my main option.

Best Regards


I have managed to success to this problem. Here you can find a detailed explanation about what I have done. Maybe, it is trivial to most of the people here, but it may be a good starting point for someone that is in the same position that I was. I will post a resume here of what I done.

First I installed the Lemon Graph (C++) Library (LGL). I just downloaded the LGL from its home page (from here). Then I proceed:

$ tar xvzf lemon-1.2.tar.gz
$ cd lemon-1.2
$ ./configure
$ make
$ make check    # This is optional, but recommended. It runs a bunch of tests.
$ sudo make install

Then check if it works. So in a file named mycode.cc I put:

#include <iostream>
#include <lemon/list_graph.h>

using namespace lemon;
using namespace std;

int main()
{
  ListDigraph g;

  ListDigraph::Node u = g.addNode();
  ListDigraph::Node v = g.addNode();
  ListDigraph::Arc  a = g.addArc(u, v);

  cout << "Hello World! This is LEMON library here." << endl;
  cout << "We have a directed graph with " << countNodes(g) << " nodes "
       << "and " << countArcs(g) << " arc." << endl;

  return 0;
}

Then I compile and run it:

$ g++ -O2 mycode.cc -lemon
... BLA BLA BLA ... 
$./a.out
Hello World! This is LEMON library here.
We have a directed graph with 2 nodes and 1 arc.

So it works. Now, the idea is to integrate that code into R via Rcpp. So in some directory I open a R console and I do:

> require("Rcpp")
Loading required package: Rcpp
> Rcpp.package.skeleton("pkgwithlgl")
Creating directories ...
Creating DESCRIPTION ...
Creating NAMESPACE ...
Creating Read-and-delete-me ...
Saving functions and data ...
Making help files ...
Done.
Further steps are described in './pkgwithlgl/Read-and-delete-me'.

Adding Rcpp settings
 >> added Depends: Rcpp
 >> added LinkingTo: Rcpp
 >> added useDynLib directive to NAMESPACE
 >> added Makevars file with Rcpp settings
 >> added Makevars.win file with Rcpp settings
 >> added example header file using Rcpp classes
 >> added example src file using Rcpp classes
 >> added example R file calling the C++ example
 >> added Rd file for rcpp_hello_world

So, in this way I just created a new Rcpp based source package named pkgwithlgl. Now inside the pkgwithlgl directory (which is the source of the package that I want to modify and install) there is a directory named src. Inside it there are the files with the C++ code of the package. In particular there is one named *rcpp_hello_world.cpp* which contains:

#include "rcpp_hello_world.h"

SEXP rcpp_hello_world(){
   using namespace Rcpp ;

   CharacterVector x = CharacterVector::create( "foo", "bar" )  ;
   NumericVector y   = NumericVector::create( 0.0, 1.0 ) ;
   List z            = List::create( x, y ) ;

   return z ;
}

Now, I modify it so it becomes:

#include "rcpp_hello_world.h"
#include <lemon/list_graph.h>
using namespace lemon ;

SEXP rcpp_hello_world(){
    using namespace Rcpp ;

    int res = 1;

    ListDigraph g;

    ListDigraph::Node u = g.addNode();
    ListDigraph::Node v = g.addNode();
    ListDigraph::Arc  a = g.addArc(u, v);

    int i = countNodes(g);
    int j = countArcs(g);

    Rprintf("num nodes is %d , and num edges is %d \n",i,j);

    return wrap(res) ;
}

Then, from the linux console in the container directory of the source package I write:

$ R CMD INSTALL pkgwithlgl

which returns:

* installing to library ‘/home/juan/R/x86_64-pc-linux-gnu-library/2.12’
* installing *source* package ‘pkgwithlgl’ ...
** libs
g++ -I/usr/share/R/include   -I"/usr/local/lib/R/site-library/Rcpp/include"   -fpic  -O3     -pipe  -g -c rcpp_hello_world.cpp -o rcpp_hello_world.o
g++ -shared -o pkgwithlgl.so rcpp_hello_world.o -L/usr/local/lib/R/site-library/Rcpp/lib     -lRcpp -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib -L/usr/lib64/R/lib -lR
installing to /home/juan/R/x86_64-pc-linux-gnu-library/2.12/pkgwithlgl/libs
** R
** preparing package for lazy loading
** help
Warning:     /home/juan/Desktop/facu/investigacion_ensayos/Cosas_crudas/programming_coding/R-work-    space/integrating_R_with_cpp_via_Rcpp/using_packages/pkgwithlgl/man/pkgwithlgl-    package.Rd:32: All text must be in a section
Warning:     /home/juan/Desktop/facu/investigacion_ensayos/Cosas_crudas/programming_coding/R-work-    space/integrating_R_with_cpp_via_Rcpp/using_packages/pkgwithlgl/man/pkgwithlgl-   package.Rd:33: All text must be in a section
*** installing help indices
  converting help for package ‘pkgwithlgl’
    finding HTML links ... done
    pkgwithlgl-package                      html  
    rcpp_hello_world                        html  
** building package indices ...
** testing if installed package can be loaded

* DONE (pkgwithlgl)    

So the package is installed (the warnings has to do with the fact that I don't filled in the right way the .Rd file, ie, the files that contains the helps about the package). The I open a R console and write:

> require("pkgwithlgl")
Loading required package: pkgwithlgl
Loading required package: Rcpp
> rcpp_hello_world()
num nodes is 2 , and num edges is 1
[1] 1

so it works !!! That is all.

But hey !!! What happens if I build this package and upload it into (forexample) CRAN (I will not do it). If some one install this package from CRAN, will it work for him? Even if it does not install the LGL package?

Best Regards


Howdy, and thanks for your interest in Rcpp.

To bind calls between different library functions, you may want to look into building a package. There are now twenty packages using Rcpp as listed on the Rcpp page on CRAN so you have examples to copy from. At a first appromixation,. this is no different from writing a normal program and Rcpp simply helps you getting it to R.

If you have more questions, please feel free to bring them to the rcpp-devel list.

0

精彩评论

暂无评论...
验证码 换一张
取 消