2013-06-17 31 views
9

Ich habe mich durch Rcpp Dirk Eddelbuettel Tutorial hier gearbeitet:Ausführen kompiliert C++ Code mit RCPP

http://www.rinfinance.com/agenda/

ich gelernt habe, wie eine C++ Datei in einem Verzeichnis zu speichern und nennen es und führen Sie es aus innerhalb R. Die C++ Datei heißt ich bin mit ‚logabs2.ccp‘ und ihr Inhalt sind direkt die von einem von Dirk Dias:

#include <Rcpp.h> 

using namespace Rcpp; 

inline double f(double x) { return ::log(::fabs(x)); } 

// [[Rcpp::export]] 
std::vector<double> logabs2(std::vector<double> x) { 
    std::transform(x.begin(), x.end(), x.begin(), f); 
    return x; 
} 

ich betreibe es mit diesem R-Code:

library(Rcpp) 
sourceCpp("c:/users/mmiller21/simple r programs/logabs2.cpp") 
logabs2(seq(-5, 5, by=2)) 
# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438 

Ich führe den Code auf einem Windows 7-Rechner aus der R GUI, die standardmäßig zu installieren scheint. Ich habe auch die neueste Version von Rtools installiert. Der obige R-Code scheint relativ lange zu benötigen. Ich vermute, dass die meiste Zeit dem Kompilieren des C++ - Codes gewidmet ist und dass, sobald der C++ - Code kompiliert wurde, er sehr schnell läuft. Microbenchmark schlägt sicherlich vor, dass Rcpp Rechenzeit reduziert.

Ich habe noch nie C++ verwendet, aber ich weiß, dass ich beim Kompilieren von C-Code eine * .exe-Datei bekomme. Ich habe meine Festplatte aus einer Datei namens logabs2.exe gesucht, kann aber keine finden. Ich frage mich, ob der obige C++ - Code noch schneller ausgeführt werden könnte, wenn eine logabs2.exe Datei erstellt wurde. Ist es möglich, eine logabs2.exe Datei zu erstellen und sie irgendwo in einem Ordner zu speichern und dann Rcpp diese Datei aufrufen zu lassen, wann immer ich sie benutzen wollte? Ich weiß nicht, ob das Sinn macht. Wenn ich eine C++ - Funktion in einer * .exe-Datei speichern könnte, müsste ich die Funktion vielleicht nicht jedes Mal kompilieren, wenn ich sie mit Rcpp verwenden wollte, und dann wäre der Rcpp-Code vielleicht noch schneller.

Entschuldigung, wenn diese Frage keinen Sinn ergibt oder ein Duplikat ist. Wenn es möglich ist, die C++ - Funktion als eine * .exe-Datei zu speichern, hoffe ich, dass jemand mir zeigt, wie ich meinen obigen R-Code modifiziere, um ihn auszuführen. Vielen Dank für Ihre Hilfe oder dafür, dass Sie mir klar gemacht haben, warum das, was ich Ihnen vorschlage, nicht möglich oder empfehlenswert ist.

Ich freue mich darauf, Dirks neues Buch zu sehen.

+2

Haben Sie sich den Befehl 'R CMD SHLIB' angesehen? Damit können Sie einfach Ihre C++ - Funktion in eine DLL-Datei kompilieren und dann die kompilierte Datei mit 'dyn.load()' laden. Schauen Sie sich '' SHLIB'' und '' dyn.load'' für Details an! – user1981275

+0

@ user1981275 Vielen Dank für den Kommentar. Bisher bin ich an diesen Punkt gekommen: C: \ Programme \ R \ R-3.0.1 \ bin \ x64> rcmd SHLIB -oc: \ Benutzer \ mmiller21 \ Dokumente \ r \ Win-Bibliothek \ 3.0 \ rcpp \ include \ logabs2.dll c: \ Benutzer \ mmiller21 \ Dokumente \ r \ Win-Bibliothek \ 3.0 \ rcpp \ include \ logabs2.cpp Ich erhalte die folgende Nachricht: make: *** Keine Regel, um das Ziel c: \ users \ zu machen mmiller21 \ Dokumente \ r \ Win-Bibliothek \ 3.0 \ rcpp \ include \ logabs2.o ', benötigt von' c: \ Benutzer \ mmiller21 \ Dokumente \ r \ Win-Bibliothek \ 3.0 \ rcpp \ include \ logabs2.dll '. Halt. Die Nachricht scheint zu sagen, dass ich eine Objektdatei vermisse, die mir aus meiner Arbeit mit C. vertraut ist. –

+0

Ich benutze das DOS-Befehlsfenster. Wenn das Problem wirklich eine fehlende Objektdatei ist, können Sie vorschlagen, wie ich eine Objektdatei erstellen kann? Vielleicht würde es, sobald es erstellt wurde, in einer Liste zusammen mit logabs2.cpp am Ende des Befehls im vorherigen Kommentar erscheinen? Danke trotzdem. –

Antwort

4

Sie sagen

Ich habe noch nie C++ verwendet, bis jetzt, aber ich weiß, dass, wenn ich C-Code kompilieren Ich erhalte eine * .exe-Datei

und das ist wahr, wenn und nur Sie erstellen eine ausführbare Datei. Hier bauen wir dynamisch ladbare Bibliotheken und diejenigen thend zu verschiedenen extensionos haben auf dem Betriebssystem abhängig: .dll für Windoof, .so für Linux, .dynlib für OS X.

Also nichts falsch hier, Sie hatten einfach die falsche Annahme.

1

Wenn Sie eine Entität erhalten möchten, die Sie behalten können, was Sie suchen, ist ein R Paket. Es gibt viele Ressourcen online, um zu lernen, wie man sie macht (z.B. Hadley's slides).

Wir haben Rcpp.package.skeleton Sie könnten nützlich finden.

Also, die Funktion wird einmal kompiliert, wenn das Paket installiert ist, und dann verwenden Sie es einfach.

6

Vielen Dank an user1981275, Dirk Eddelbuettel und Romain Francois für ihre Antworten. Unten ist, wie ich eine C++ - Datei kompiliert und eine * .dll erstellt, dann aufgerufen und diese * .dll-Datei innerhalb R verwendet.

Schritt 1. Ich habe einen neuen Ordner mit dem Namen 'c: \ users \ mmiller21 \ myrpackages' erstellt und die Datei 'logabs2.cpp' in diesen neuen Ordner eingefügt. Die Datei 'logabs2.cpp' wurde wie in meinem ursprünglichen Beitrag beschrieben erstellt.

Schritt 2. Innerhalb des neuen Ordners habe ich ein neues R Paket mit dem Namen 'logabs2' unter Verwendung einer R Datei erstellt, die ich namens 'new package creation.r' geschrieben habe. Der Inhalt von ‚neuen Paket creation.r‘ sind:

setwd('c:/users/mmiller21/myrpackages/') 

library(Rcpp) 

Rcpp.package.skeleton("logabs2", example_code = FALSE, cpp_files = c("logabs2.cpp")) 

fand ich die obige Syntax für Rcpp.package.skeleton auf einer von Hadley Wickham Webseiten: https://github.com/hadley/devtools/wiki/Rcpp

Schritt 3. ich das neue R Paket „logabs2“ installiert in R mit der folgenden Zeile in dem DOS-Eingabefenster:

C:\Program Files\R\R-3.0.1\bin\x64>R CMD INSTALL -l c:\users\mmiller21\documents\r\win-library\3.0\ c:\users\mmiller21\myrpackages\logabs2 

wo:

die Lage der Rcmd.exe Datei ist:

C:\Program Files\R\R-3.0.1\bin\x64> 

die Lage der installierten R Pakete auf meinem Computer:

c:\users\mmiller21\documents\r\win-library\3.0\ 

und die Lage meines neuen R Paket vor installiert ist:

Die im DOS-Befehlsfenster verwendete Syntax wurde durch Versuch und Irrtum gefunden und ist möglicherweise nicht ideal. Irgendwann habe ich eine Kopie von 'logabs2.cpp' in 'C: \ Programme \ R \ R-3.0.1 \ bin \ x64>' eingefügt, aber das war nicht wichtig.

Schritt 4. Nach dem neuen R Paket Installation lief ich es eine R Datei mit I ‚neuem Paket usage.r‘ im Namen ‚c:/users/mmiller21/myrpackages /‘ Ordner (obwohl ich glaube, die nicht Ordner war wichtig). Der Inhalt von 'neuem Paket usage.r' ist:

library(logabs2) 
logabs2(seq(-5, 5, by=2)) 

Der Ausgang war:

# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438 

Diese Datei das Paket geladen Rcpp ohne mich zu fragen.

In diesem Fall wurde die Basis R schneller angenommen, dass ich das richtig gemacht habe.

#> microbenchmark(logabs2(seq(-5, 5, by=2)), times = 100) 
#Unit: microseconds 
#      expr min  lq median  uq  max neval 
# logabs2(seq(-5, 5, by = 2)) 43.086 44.453 50.6075 69.756 190.803 100 

#> microbenchmark(log(abs(seq(-5, 5, by=2))), times=100) 
#Unit: microseconds 
#       expr min  lq median uq  max neval 
# log(abs(seq(-5, 5, by = 2))) 38.298 38.982 39.666 40.35 173.023 100 

Allerdings war die DLL-Datei schneller als die externe CPP-Datei aufrufen:

system.time(

cppFunction(" 
NumericVector logabs(NumericVector x) { 
    return log(abs(x)); 
} 
") 

) 

# user system elapsed 
# 0.06 0.08 5.85 

Obwohl Basis R schneller scheint oder so schnell wie die * DLL-Datei in diesem Fall, ich habe keine bezweifle, dass die Verwendung der * .dll-Datei mit Rcpp in den meisten Fällen schneller ist als die Basis R.

Dies war mein erster Versuch, ein R-Paket zu erstellen oder Rcpp zu verwenden, und ich habe zweifellos nicht die effizientesten Methoden verwendet. Außerdem entschuldige ich mich für typografische Fehler in diesem Beitrag.

EDIT

In einem Kommentar unten denke ich Romain Francois schlug ich den Anschluss an die * CPP-Datei ändern:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 

NumericVector logabs(NumericVector x) { 
return log(abs(x)); 
} 

und neu erstellen mein R Paket, das ich jetzt getan haben. Ich habe dann im Vergleich Basis R gegen mein neues Paket mit dem folgenden Code:

library(logabs) 

logabs(seq(-5, 5, by=2)) 
log(abs(seq(-5, 5, by=2))) 

library(microbenchmark) 

microbenchmark(logabs(seq(-5, 5, by=2)), log(abs(seq(-5, 5, by=2))), times = 100000) 

Basis R noch schneller ein klein wenig ist oder nicht anders:

Unit: microseconds 
         expr min  lq median  uq  max neval 
    logabs(seq(-5, 5, by = 2)) 42.401 45.137 46.505 69.073 39754.598 1e+05 
log(abs(seq(-5, 5, by = 2))) 37.614 40.350 41.718 62.234 3422.133 1e+05 

Vielleicht ist dies, da die Basis R bereits vektorisiert ist. Ich vermute mit komplexeren Funktionen Basis R wird viel langsamer sein. Oder ich benutze immer noch nicht den effizientesten Ansatz oder vielleicht habe ich irgendwo einen Fehler gemacht.

+0

Die Verwendung von 'std :: vector ' oder ein 'NumericVector' ist nicht dasselbe. 'lobabs2' muss zuerst das R-Objekt in einen' std :: vector 'konvertieren, das ist teuer, da Sie die Daten kopieren müssen. Am Ende geben Sie dann einen 'std :: vector ' zurück, also muss 'Rcpp' dies in ein R-Objekt umwandeln, wiederum bedeutet dies Datenkopie. –

+0

In Ihrem letzten Codeblock messen Sie die Zeit, die benötigt wird, um den Code zu kompilieren. Das ist kein fairer Vergleich. –

+0

@Romain Francois Vielen Dank für Ihre Kommentare. Ich versuche nicht unfair zu sein. Ich habe einfach noch nicht genug gelernt, um eine effizientere Antwort zu geben. Ich war noch nicht in der Lage, dyn.load und .Call zum Laufen zu bringen, zum Beispiel nach dem Erstellen der * .dll-Datei mit Rcpp.package.skeleton und/oder dem Installieren des neuen Pakets. Noch konnte ich die * .dll Datei mit SHLIB nicht erstellen. Wenn ich zu einer effizienteren Lösung komme, werde ich sie veröffentlichen. Mein Ziel ist es zu lernen, wie man den Nutzen von Rcpp maximieren kann. –