Presentation is loading. Please wait.

Presentation is loading. Please wait.

R – C/C++ programming Katia Oleinik Scientific Computing and Visualization Boston University

Similar presentations


Presentation on theme: "R – C/C++ programming Katia Oleinik Scientific Computing and Visualization Boston University"— Presentation transcript:

1 R – C/C++ programming Katia Oleinik koleinik@bu.edu Scientific Computing and Visualization Boston University http://www.bu.edu/tech/research/training/tutorials/list/

2 R-C/C++ programming 2 Goal – performance enhancement. Benefits – use of existing C/C++ libraries and memory management Base R package provides 3 types of interfaces between R and C/C++.C().Call().External() – used to create R packages There are other R packages that provide interface between R and C/C++ (and other languages such as FORTRAN and Python): Rcpp

3 R-C/C++ programming 3.C() interface /* exC1.c – example C function to be called from R */ void exampleC1(int *iVec){ iVec[0] = 7; return; } /* exC1.c – example C function to be called from R */ void exampleC1(int *iVec){ iVec[0] = 7; return; } exC1.c Important: Function returns no values – it is VOID All the values that need to be changed/returned by a function must be passed through its arguments.

4 R-C/C++ programming 4.C() interface katana:~ % R CMD SHLIB exC1.c gcc -std=gnu99 -I/usr/local/IT/R-2.13.2/lib64/R/include - I/usr/local/include -fpic -g -O2 -c exC1.c -o exC1.o gcc -std=gnu99 -shared -L/usr/local/lib64 -o exC1.so exC1.o katana:~ % katana:~ % R CMD SHLIB exC1.c gcc -std=gnu99 -I/usr/local/IT/R-2.13.2/lib64/R/include - I/usr/local/include -fpic -g -O2 -c exC1.c -o exC1.o gcc -std=gnu99 -shared -L/usr/local/lib64 -o exC1.so exC1.o katana:~ % Important: In linux (and R) environment commands are case sensitive!

5 R-C/C++ programming 5.C() interface Note: In windows after the function is compiled it will be named exC1.dll > # load C function to R workspace > dyn.load("exC1.so") > > # load C function to R workspace > dyn.load("exC1.so") >

6 R-C/C++ programming 6.C() interface > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3 > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3

7 R-C/C++ programming 7.C() interface > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3 > # call c-function > out <-.C("exampleC1", newVec = as.integer(iv)) > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3 > # call c-function > out <-.C("exampleC1", newVec = as.integer(iv))

8 R-C/C++ programming 8.C() interface > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3 > # call c-function > out <-.C("exampleC1", newVec = as.integer(iv)) > out $newVec [1] 7 2 3 > # load C function to R workspace > dyn.load("exC1.so") > # create a vector > iv <- 1:3 > # call c-function > out <-.C("exampleC1", newVec = as.integer(iv)) > out $newVec [1] 7 2 3

9 R-C/C++ programming 9.C() interface Note: Allocate memory to the vectors passed to.C in R by creating vectors of the right length The first argument to.C is a character string of the C function name The rest of the arguments are R objects to be passed to the C function. All arguments should be coerced to the correct R storage mode to prevent mismatching of types that can lead to errors C returns a list object The second argument in this example is given a name newVec. This name is used to access the component in the returned list object.

10 R-C/C++ programming 10.C() interface Note: R has to allocate memory for the arrays passed to and from C. R has to pass objects of correct type R copies its arguments prior to passing them to C and then creates a copy of the values passed back from C.

11 R-C/C++ programming 11 /* exC2.c – example C function to be called from R */ /* normalize the vector */ include void exampleC2(char **c, double *A, double *B, int *ierr){ double len = 0; /*local variable – vector length */ int i; for (i=0; i<3; i++) len += pow( A[i]), 2); /* check if the vector is degenerate */ if ( len < 0.000001){ ierr[0] = -1; /*error – null vector */ stncpy(c, “Error”, 5); return; } /* calculate output vector len = pow(len, 0.5); for (i=0; i<3; i++) B[i] = A[i] / len ; ierr[0] = 0; strncpy(c, “OK”, 2); return; } /* exC2.c – example C function to be called from R */ /* normalize the vector */ include void exampleC2(char **c, double *A, double *B, int *ierr){ double len = 0; /*local variable – vector length */ int i; for (i=0; i<3; i++) len += pow( A[i]), 2); /* check if the vector is degenerate */ if ( len < 0.000001){ ierr[0] = -1; /*error – null vector */ stncpy(c, “Error”, 5); return; } /* calculate output vector len = pow(len, 0.5); for (i=0; i<3; i++) B[i] = A[i] / len ; ierr[0] = 0; strncpy(c, “OK”, 2); return; } exC2.c

12 R-C/C++ programming 12.C() interface katana:~ % R CMD SHLIB exC2.c gcc -std=gnu99 -I/usr/local/IT/R-2.13.2/lib64/R/include - I/usr/local/include -fpic -g -O2 -c exC2.c -o exC2.o gcc -std=gnu99 -shared -L/usr/local/lib64 -o exC2.so exC2.o katana:~ % R CMD SHLIB exC2.c gcc -std=gnu99 -I/usr/local/IT/R-2.13.2/lib64/R/include - I/usr/local/include -fpic -g -O2 -c exC2.c -o exC2.o gcc -std=gnu99 -shared -L/usr/local/lib64 -o exC2.so exC2.o

13 R-C/C++ programming 13.C() interface > # load C function to R workspace > dyn.load("exC2.so") > # create error vector > ierr_in <- 0 > # create input vector > A_in <- c(2, 3, 6) > # create output vector > B_in <- c(0, 0, 0) > # create message vector (make sure it is long enough!) > C_in <- c(" ") > # load C function to R workspace > dyn.load("exC2.so") > # create error vector > ierr_in <- 0 > # create input vector > A_in <- c(2, 3, 6) > # create output vector > B_in <- c(0, 0, 0) > # create message vector (make sure it is long enough!) > C_in <- c(" ")

14 R-C/C++ programming 14.C() interface > # execute C function > out <-.C("exampleC2", + C_out = as.character(C_in), + A_out = as.numeric(A_in), + B_out = as.numeric(B_in), + ierr_out = as.integer(ierr_in)) > # execute C function > out <-.C("exampleC2", + C_out = as.character(C_in), + A_out = as.numeric(A_in), + B_out = as.numeric(B_in), + ierr_out = as.integer(ierr_in))

15 R-C/C++ programming 15.C() interface > out $C_out [1] "OK " $A_out [1] 2 3 6 $B_out [1] 0.2857143 0.4285714 0.8571429 $ierr_out [1] 0 > out $C_out [1] "OK " $A_out [1] 2 3 6 $B_out [1] 0.2857143 0.4285714 0.8571429 $ierr_out [1] 0

16 R-C/C++ programming 16.C() interface > # create input vector > A_in <- c(0, 0, 0) > # execute C function > out <-.C("exampleC2", "exampleC2", + C_out = as.character(C_in), + A_out = as.numeric(A_in), + B_out = as.numeric(B_in), + ierr_out = as.integer(ierr_in)) > # create input vector > A_in <- c(0, 0, 0) > # execute C function > out <-.C("exampleC2", "exampleC2", + C_out = as.character(C_in), + A_out = as.numeric(A_in), + B_out = as.numeric(B_in), + ierr_out = as.integer(ierr_in))

17 R-C/C++ programming 17.C() interface > out $C_out [1] "error " $A_out [1] 0 0 0 $B_out [1] 0 0 0 $ierr_out [1] -1 > out $C_out [1] "error " $A_out [1] 0 0 0 $B_out [1] 0 0 0 $ierr_out [1] -1

18 R-C/C++ programming 18.C() interface Note: To compile more than one C file: R CMD SHLIB file1.c file2.c file3.c The resulting file will be named file1.so

19 R-C/C++ programming 19.Call() interface does not copy arguments before and after calling c-function it is possible to find the length of the input vector inside c-function an easier access to wide-range of R – objects NA (missing values) handling Access to vectors’ attributes

20 R-C/C++ programming 20.Call() interface – passing a value /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include /* 2 standard includes for.Call interface) */ include SEXP exampleC3 ( SEXP iValue ){ return (R_NilValue); /* “void” function must return “NULL” value */ } /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include /* 2 standard includes for.Call interface) */ include SEXP exampleC3 ( SEXP iValue ){ return (R_NilValue); /* “void” function must return “NULL” value */ } exC3.c Note: All objects passed between R and C/C++ are of type SEXP – Simple EXPression. 2 standard includes needed for.Call interface If function is void it should return R_NilValue object.

21 R-C/C++ programming 21.Call() interface – passing a value /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include SEXP exampleC3 ( SEXP iValue ){ int local_iValue; /* convert R object to c-accessible variable */ local_iValue = INTEGER_VALUE(iValue); return (R_NilValue); } /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include SEXP exampleC3 ( SEXP iValue ){ int local_iValue; /* convert R object to c-accessible variable */ local_iValue = INTEGER_VALUE(iValue); return (R_NilValue); } exC3.c

22 R-C/C++ programming 22.Call() interface – passing a value /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include SEXP exampleC3 ( SEXP iValue ){ int local_iValue; /* convert R object to c-accessible variable */ local_iValue = INTEGER_VALUE(iValue); /* print value of the local variable*/ printf(" In exampleC3 iValue = %d\n", local_iValue); return (R_NilValue); } /* exC3.c – example C function to be called from R with.Call interface*/ /* access R object (scalar value) inside c-function */ include SEXP exampleC3 ( SEXP iValue ){ int local_iValue; /* convert R object to c-accessible variable */ local_iValue = INTEGER_VALUE(iValue); /* print value of the local variable*/ printf(" In exampleC3 iValue = %d\n", local_iValue); return (R_NilValue); } exC3.c

23 R-C/C++ programming 23.Call() interface – passing a value > # load C function to R workspace – same as before > dyn.load("exC3.so") > # call C function > out <-.Call("exampleC3", 7) In exampleC3 iValue = 7 > # explore output > out NULL > # load C function to R workspace – same as before > dyn.load("exC3.so") > # call C function > out <-.Call("exampleC3", 7) In exampleC3 iValue = 7 > # explore output > out NULL

24 R-C/C++ programming 24.Call() interface – passing a vector /* exC4.c - example C function to be called from R */ /* normalize the vector and return its length */ include SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; return (rLen); /* return a value */ } /* exC4.c - example C function to be called from R */ /* normalize the vector and return its length */ include SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; return (rLen); /* return a value */ } exC4.c Note: Rmath.h include provides access to many R-functions include rnorm(),rgamma(), etc. Function should return SEXP object..Call() interface allows for changing the function arguments – be careful!

25 R-C/C++ programming 25 SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; /* output value – length of a vector */ double * pVector; /* local variable - pointer to the input vector */ double vLen = 0; /* local variable to calculate intermediate values */ int len; /* local variable – size of the input vector */ int i; /* local variable – loop index */ return (rLen); /* return a value */ } SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; /* output value – length of a vector */ double * pVector; /* local variable - pointer to the input vector */ double vLen = 0; /* local variable to calculate intermediate values */ int len; /* local variable – size of the input vector */ int i; /* local variable – loop index */ return (rLen); /* return a value */ } exC4.c

26 R-C/C++ programming 26 SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; /* get the pointer to the vector */ pVector = NUMERIC_POINTER(Vector); return (rLen); /* return a value */ } SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; /* get the pointer to the vector */ pVector = NUMERIC_POINTER(Vector); return (rLen); /* return a value */ } exC4.c Note: Use INTEGER_POINTER() and CHARACTER_POINTER() to get pointer to integer and character arrays respectfully

27 R-C/C++ programming 27 SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; /* get the pointer to the vector */ pVector = NUMERIC_POINTER(Vector); /* number of elements in the array */ len = length(Vector); return (rLen); /* return a value */ } SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; /* get the pointer to the vector */ pVector = NUMERIC_POINTER(Vector); /* number of elements in the array */ len = length(Vector); return (rLen); /* return a value */ } exC4.c Note: We can get the size of the input R-vector !

28 R-C/C++ programming 28 SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; pVector = NUMERIC_POINTER(Vector); len = length(Vector); /* allocate storage for integer variable (array works also!) */ PROTECT(rLen = NEW_NUMERIC(1)); UNPROTECT(1); return (rLen); /* return a value */ } SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; pVector = NUMERIC_POINTER(Vector); len = length(Vector); /* allocate storage for integer variable (array works also!) */ PROTECT(rLen = NEW_NUMERIC(1)); UNPROTECT(1); return (rLen); /* return a value */ } exC4.c Note: To allocate integer and character arrays use NEW_INTEGER(len) and NEW_CHARACTER(len) functions respectfully PROTECT() and UNPROTECT() command must be balanced!

29 R-C/C++ programming 29 SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; pVector = NUMERIC_POINTER(Vector); len = length(Vector); PROTECT(rLen = NEW_NUMERIC(1)); /* calculate the length */ for( i=0; i < len; i++)vLen += pow(pVector[i], 2); if ( vLen > 0.000001){ vLen = pow( vLen,0.5 ); /* Here we are working with a pointer - it WILL change R vector */ for( i=0; i < len; i++ )pVector[i] /= vLen; } /* copy the value of local variable into R-object */ REAL(rLen)[0] = vLen; UNPROTECT(1); return (rLen); /* return a value */ } SEXP exampleC4 ( SEXP Vector ){ SEXP rLen; double * pVector; double vLen = 0; int len; int i; pVector = NUMERIC_POINTER(Vector); len = length(Vector); PROTECT(rLen = NEW_NUMERIC(1)); /* calculate the length */ for( i=0; i < len; i++)vLen += pow(pVector[i], 2); if ( vLen > 0.000001){ vLen = pow( vLen,0.5 ); /* Here we are working with a pointer - it WILL change R vector */ for( i=0; i < len; i++ )pVector[i] /= vLen; } /* copy the value of local variable into R-object */ REAL(rLen)[0] = vLen; UNPROTECT(1); return (rLen); /* return a value */ } exC4.c

30 R-C/C++ programming 30.Call() interface – passing an array > # load C function to R workspace – same as before > dyn.load("exC4.so") > # define and input array > A_in <- c( 2, 3, 6) > # call C function > out <-.Call("exampleC4", A_in) > # input array changed !!! > A_in [1] 0.2857143 0.4285714 0.8571429 > out [1] 7 > # load C function to R workspace – same as before > dyn.load("exC4.so") > # define and input array > A_in <- c( 2, 3, 6) > # call C function > out <-.Call("exampleC4", A_in) > # input array changed !!! > A_in [1] 0.2857143 0.4285714 0.8571429 > out [1] 7

31 31 This tutorial has been made possible by Scientific Computing and Visualization group at Boston University. Katia Oleinik koleinik@bu.edu


Download ppt "R – C/C++ programming Katia Oleinik Scientific Computing and Visualization Boston University"

Similar presentations


Ads by Google