Библиотека графов лимонов на R с использованием Rcpp
Я думаю, что этот ответ немного сложен, потому что он включает в себя несколько вещей.
Я хочу делать высокопроизводительные вычисления с R, особенно с графиками (сетями). В качестве пакета R игра очень хороша. Но R медленный, поэтому я хочу кодировать вычислительно дорогие процедуры на C++ (возможно, на C). Я взглянул на библиотеку igraph C, и мне было немного грязно с ней работать. Я также смотрю на библиотеку графов ускорения и читаю, что ее трудно освоить. Так что в итоге я нашел библиотеку лимонных графов. Это на C++ и, кажется, очень приятно работать.
Поэтому я установил Lemon Graph Library, как рекомендовано на официальной странице. Затем, используя пакеты Rcpp и inline, я могу запустить код Lemon Graph C++ из R. Здесь я подробно напишу, что я сделал. Но в основном я поставил это:
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")
в файле myexample_inline.R, затем запустите консоль R и напишите:
> library("inline")
> library("Rcpp")
> source("myexample_inline.R")
> fun(1)
num nodes is 2 , and num edges is 1
[1] 2
Так что это работает!!! Но теперь у меня есть следующая проблема. Если я создаю функцию C++ (скажем, double func1(g)), которая, например, вычисляет некоторое свойство для некоторого объекта графа Лимона. Как я вызываю эту функцию из встроенного кода? Я должен сделать func1() как функцию шаблона и поместить ее в поле включения cxxfunction()?
По сути: я не могу понять, как вызвать функцию C++, встроенную в R, из другой функции C++, также встроенной в R. Возможно ли это? Есть ли другой способ, который не использует встроенный код?
Может быть, я могу сделать это с помощью модулей Rcpp, но я не мог (до сих пор) понять, как это сделать. У меня проблемы с работой модулей. Я буду продолжать пытаться с этим, но, возможно, я могу получить какой-то намек отсюда.
Я также подумал о возможности разработать (мой первый) пакет. Но у меня была проблема с тем, что код Lemon Graph C++ вызывает заголовки следующим образом (например):
#include <iostream>
#include <lemon/list_graph.h>
Так что это означает (по крайней мере, я в это верю), что я не могу избежать установки библиотеки графов лимонов. Если я хочу сделать пакет R библиотеки Lemon Graph Library, я должен снова "переписать" весь код!!! Так что это не мой основной вариант.
С уважением
2 ответа
Мне удалось успешно решить эту проблему. Здесь вы можете найти подробное объяснение того, что я сделал. Может быть, это тривиально для большинства людей здесь, но это может быть хорошей отправной точкой для кого-то, кто находится в том же положении, что и я. Я выложу здесь резюме того, что я сделал.
Сначала я установил библиотеку Lemon Graph (C++) (LGL). Я только что скачал LGL с его домашней страницы ( отсюда). Тогда я продолжаю:
$ 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
Затем проверьте, работает ли это. Итак, в файл с именем mycode.cc я положил:
#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;
}
Затем я компилирую и запускаю его:
$ 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.
Так что это работает. Теперь идея состоит в том, чтобы интегрировать этот код в R через Rcpp. Итак, в каком-то каталоге я открываю консоль R и делаю:
> 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
Таким образом, я только что создал новый исходный пакет на основе Rcpp с именем pkgwithlgl. Теперь внутри каталога pkgwithlgl (который является источником пакета, который я хочу изменить и установить) находится каталог с именем src. Внутри находятся файлы с кодом C++ пакета. В частности, есть файл с именем * rcpp_hello_world.cpp *, который содержит:
#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 ;
}
Теперь я изменяю его так, чтобы он стал:
#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) ;
}
Затем из консоли linux в каталоге контейнера исходного пакета я пишу:
$ R CMD INSTALL pkgwithlgl
который возвращает:
* 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)
Таким образом, пакет установлен (предупреждения связаны с тем, что я неправильно заполнил файл.Rd, т. Е. Файлы, содержащие подсказки о пакете). Я открываю консоль R и пишу:
> require("pkgwithlgl")
Loading required package: pkgwithlgl
Loading required package: Rcpp
> rcpp_hello_world()
num nodes is 2 , and num edges is 1
[1] 1
так работает!!! Это все.
Но эй!!! Что произойдет, если я соберу этот пакет и загрузлю его (например, в CRAN) (я не буду этого делать). Если кто-нибудь установит этот пакет из CRAN, будет ли он работать на него? Даже если он не устанавливает пакет LGL?
С уважением
Привет, и спасибо за ваш интерес к Rcpp.
Чтобы связать вызовы между различными библиотечными функциями, вы можете посмотреть на создание пакета. Теперь есть двадцать пакетов, использующих Rcpp, как указано на странице Rcpp в CRAN, поэтому у вас есть примеры для копирования. При первом одобрении. это ничем не отличается от написания обычной программы, и Rcpp просто поможет вам получить его в R.
Если у вас есть дополнительные вопросы, пожалуйста, не стесняйтесь задавать их rcpp-devel
список.