Katia Oleinik koleinikbuedu Scientific Computing and Visualization Boston University httpwwwbuedutechresearchtrainingtutorialslist RCC programming 2 Goal performance enhancement ID: 141952
Download Presentation The PPT/PDF document "R – C/C++ programming" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
R – C/C++ programmingKatia Oleinikkoleinik@bu.eduScientific Computing and VisualizationBoston University
http://www.bu.edu/tech/research/training/tutorials/list
/Slide2
R-C/C++ programming2
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
Slide3
R-C/C++ programming3
.C()
interface
/* 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.Slide4
R-C/C++ programming4
.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.okatana:~ %
Important:
In
linux
(and
R
) environment commands are case sensitive! Slide5
R-C/C++ programming5
.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
")
>Slide6
R-C/C++ programming6
.C()
interface
>
#
load C function to R workspace
>
dyn.load
("
exC1.so
")
>
# create a vector
>
iv <- 1:3Slide7
R-C/C++ programming7
.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))Slide8
R-C/C++ programming8
.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
3Slide9
R-C/C++ programming9
.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.Slide10
R-C/C++ programming10
.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.Slide11
R-C/C++ programming11
/* exC2.c – example C function to be called from R */
/*
normalize the vector */
i
nclude
<
math.h
>
include <
string.h
>
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.cSlide12
R-C/C++ programming12
.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 Slide13
R-C/C++ programming13
.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(
"
"
)Slide14
R-C/C++ programming14
.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
))Slide15
R-C/C++ programming15
.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]
0Slide16
R-C/C++ programming16
.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
))Slide17
R-C/C++ programming17
.C()
interface
>
out
$
C_out
[1]
"
error
"
$
A_out
[1]
0 0 0
$
B_out
[1]
0 0 0
$
ierr_out
[1]
-1Slide18
R-C/C++ programming18
.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.soSlide19
R-C/C++ programming19
.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’ attributesSlide20
R-C/C++ programming20
.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 */
i
nclude
<
R
.h
>
/* 2 standard includes for .Call interface) */
include
<
Rdefines.h
> 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 – S
imple
EXP
ression
.
2 standard includes needed for
.Call
interface
If function is void it should return
R_NilValue
object.Slide21
R-C/C++ programming21
.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 */
i
nclude
<
R
.h
>
include
<
Rdefines.h
>
SEXP exampleC3 ( SEXP
iValue
){
int
local_iValue
;
/* convert R object to c-accessible variable
*/
local_iValue
=
INTEGER_VALUE
(
iValue
);
return (
R_NilValue
);
}
exC3.cSlide22
R-C/C++ programming22
.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 */
i
nclude
<
R
.h
>
include
<
Rdefines.h
>
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.cSlide23
R-C/C++ programming23
.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
NULLSlide24
R-C/C++ programming24
.Call()
interface
–
passing a
vector
/*
exC4.c - example C function to be called from R */
/*
normalize
the vector and return its length
*/
i
nclude
<
R
.h
>
include <Rdefines.h>
include
<
Rmath.h
>
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
!Slide25
R-C/C++ programming25
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.cSlide26
R-C/C++ programming26
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 Slide27
R-C/C++ programming27
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 !Slide28
R-C/C++ programming28
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
!Slide29
R-C/C++ programming29
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.cSlide30
R-C/C++ programming30
.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] 7Slide31
31
This tutorial has been made possible by
Scientific
Computing and Visualization
group
at
Boston University
.
Katia Oleinik
koleinik@bu.edu