📜 ⬆️ ⬇️

How to use the features of R in C ++

R is a programming language for statistical data processing and working with graphics, as well as a free open-source computing environment within the GNU © Wikipedia project.

R contains a huge number of statistical algorithms for all occasions and they can be used not only from the native software environment: it is supported by such well-known mathematical packages like SPSS, Statistica, SAS, Wolfram Mathematica and some others. How can you integrate R into your applications?
At habrahabr, there was already an article about using R in C ++, however, she highlighted only one of the ways that can only be used if your code is distributed under a GPL-compatible license. But otherwise there is a way out - using the Rserve package.

Rserve


Rserve is a TCP / IP / unix socket server that allows you to use the capabilities of R without having to link to its libraries. Clients are implemented under various popular languages, such as C / C ++, Java, PHP. Client code is distributed under the LGPL.

Install R and Rserve:
# sudo apt-get instal r-base # sudo R > install.packages("Rserve"); 

Now it remains to run Rserve:
 # R CMD Rserve 

There is also a debug mode
 # R CMD Rserve.dbg 

When started without parameters, Rserve operates in TCP / IP mode of the server on the default port (6311). To use unix sockets, run Rserve with the --RS-socket flag.
 # R CMD Rserve --RS-socket "/home/zoberg/mysocket" 

The list of available flags can be viewed by typing
 # R CMD Rserve --help 

C ++ client


The C ++ client consists of 4 header files: Rconnection.h (there are all the announcements that may be needed in the work), Rsrv.h , config.h (only needed on Windows), sisocks.h (cross-platform sockets) and one Rconnection.cc . You can take them all from the official repository on guthub .
')
So, now let's analyze the demo , covering most of the basic operations.

 /// main.cpp #include <iostream> using std::cout; #define MAIN // c  sisocks.h #define SOCK_ERRORS // verbose socket errors #include "sisocks.h" #include "Rconnection.h" //     C++ API int main(int argc, char **argv) { initsocks(); //    Win32 -     unix //     Rserve. //     - "127.0.0.1", 6311. //    unix sockets,     : // Rconnection *rc = new Rconnection("/home/zoberg/mysocket", -1); Rconnection *rc = new Rconnection(); int i=rc->connect(); if (i) { char msg[128]; sockerrorchecks(msg, 128, -1); printf("unable to connect (result=%d, socket:%s).\n", i, msg); return i; } double d[6] = { 1.5, 2.4, 5.6, -1.2, 0.6, 1.7 }; //      "a"  R Rdouble *rd = new Rdouble(d, 6); rc->assign("a", rd); delete rd; //   "b"  2 x 3     b * t(b) Rdouble *x = (Rdouble*) rc->eval("b<-matrix(a,2); b%*%t(b)"); if (x) { //    ,    cout << x << "\n"; //       Rinteger *dim = (Rinteger*) x->attribute("dim"); if (dim) cout << dim->intAt(0) << " by " << dim->intAt(1) << " matrix\n"; //    ( ) double *d = x->doubleArray(); int i=0, ct = x->length(); while (i < ct) { cout << d[i++] << " "; } cout << "\n"; //   delete x; } //      i  R int ia[6] = { 1, 4, 6, 3, 5 , 2 }; Rinteger *ri = new Rinteger(ia, 6); rc->assign("i", ri); delete ri; //   —      , //       1936   //      . //      R,   Rvector *iris = (Rvector*) rc->eval("data(iris); iris"); if (!iris) { cout << "oops! couldn't get iris data\n"; delete rc; return 0; } //         (sepal width) - //      Rserve,         Rdouble *sw = (Rdouble*) iris->byName("Sepal.Width"); double *swd = sw->doubleArray(); // and print it ... { int i=0, ct=sw->length(); while (i<ct) { cout << swd[i++] << " "; } cout << "\n"; } //    ,   iris, //  sw  . delete iris; //   .   . delete rc; } 

A note about memory management: all the necessary memory is allocated by the Rmessage object, which is implicitly created when calling "eval". The owner of this object is Rexp, returned by eval (we call it the main one). You can not release any other Rexp, except the main thing! Any other Rexp associated with the principal becomes invalid after the release of the main Rexp. Also, after the release of the main Rexp, all pointers become invalid (for example, returned by the doubleArray () method).

Compile
 # g++ -c Rconnection.cc # g++ Rconnection.o main.cpp -o RExample -lcrypt 

and run
 # ./RExample Rdouble[4] 2 by 2 matrix 33.97 -2.1 -2.1 10.09 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 3.7 3.4 3 3 4 4.4 3.9 3.5 3.8 3.8 3.4 3.7 3.6 3.3 3.4 3 3.4 3.5 3.4 3.2 3.1 3.4 4.1 4.2 3.1 3.2 3.5 3.6 3 3.4 3.5 2.3 3.2 3.5 3.8 3 3.8 3.2 3.7 3.3 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 2 3 2.2 2.9 2.9 3.1 3 2.7 2.2 2.5 3.2 2.8 2.5 2.8 2.9 3 2.8 3 2.9 2.6 2.4 2.4 2.7 2.7 3 3.4 3.1 2.3 3 2.5 2.6 3 2.6 2.3 2.7 3 2.9 2.9 2.5 2.8 3.3 2.7 3 2.9 3 3 2.5 2.9 2.5 3.6 3.2 2.7 3 2.5 2.8 3.2 3 3.8 2.6 2.2 3.2 2.8 2.8 2.7 3.3 3.2 2.8 3 2.8 3 2.8 3.8 2.8 2.8 2.6 3 3.4 3.1 3 3.1 3.1 3.1 2.7 3.2 3.3 3 2.5 3 3.4 3 

Done! More information about the interface with R can be obtained by examining Rconnection.h.

Rserv.conf


I will say a few words about the configuration file Rserv.conf. It provides an interesting opportunity to execute some code on R immediately upon starting Rserve. The default configuration file is searched for in /etc/Rserv.conf, but you can also set another path using the --RS-conf flag when Rserve is started. Rserv.conf can contain the following options:

workdir [/tmp/Rserv]

pwdfile [none=disabled]

remote enable|disable [disable]

auth required|disable [disable]
plaintext enable|disable [disable]
fileio enable|disable [enable]
interactive yes|no [yes] (since 0.6-2)

( 0.1-9):
socket [none=disabled]
port [6311]
maxinbuf [262144]

( 0.3):
maxsendbuf [0=unlimited]
uid [none]
gid [none]
su now|server|client [none] (since 0.6-1)


( 0.3-16):
source
eval

( 0.5 unix):
chroot [none]
sockmod [0=default]
umask [0]

( 0.5-3):
encoding native|utf8|latin1 [native]


Rserve C++ , . , - .

PS load-balancer Rserve: RSproxy .

UPDATE: Windows Ws2_32.lib.

Source: https://habr.com/ru/post/198012/


All Articles