Introduction to .Call interface Hao Chai Department of Statistics and Actuarial Science The University of Iowa Productive Seminar March 6, 2012 Hao Chai (U of Iowa) Introduction to .Call interface 1 / 41
May 10, 2015
Introduction to .Call interface
Hao Chai
Department of Statistics and Actuarial ScienceThe University of Iowa
Productive SeminarMarch 6, 2012
Hao Chai (U of Iowa) Introduction to .Call interface 1 / 41
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 2 / 41
Introduction
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 3 / 41
Introduction
.C and .Call are two interfaces in R to call C routines. Similar foreignlanguage interface functions are .Fortran and .External.
Hao Chai (U of Iowa) Introduction to .Call interface 4 / 41
Introduction
Advantages of R
Straight forward syntax.Easy to learn, to use, to track the results and to debug.Over 3,000 packages available to carry out many kinds of statisticalanalysis and produce professional graphics.Vectorized language....
Disadvantage of R
Loops.
Hao Chai (U of Iowa) Introduction to .Call interface 5 / 41
Introduction
Advantages of R
Straight forward syntax.Easy to learn, to use, to track the results and to debug.Over 3,000 packages available to carry out many kinds of statisticalanalysis and produce professional graphics.Vectorized language....
Disadvantage of R
Loops.
Hao Chai (U of Iowa) Introduction to .Call interface 5 / 41
Introduction
Toy example
Our goal is to generate a variance-covariance matrix Σ = (σij), where
σij =
{a · b|i−j |, if i 6= j ;1, if i = j .
We have at least three methods:
A simple R function matgen R:
matgen_R = function(P, a, b)
{
Covmatrix = matrix(rep(1, P * P), nrow = P)
for (i in 1 : P)
for (j in 1 : P)
if (i != j)
Covmatrix[i, j] = exp(log(a) + log(b)
* abs(i - j))
Covmatrix
}
Hao Chai (U of Iowa) Introduction to .Call interface 6 / 41
Introduction
Toy example
An R function using matrix indexing matgen Rind:
matgen_Rind = function(P, a, b)
{
Covmatrix = matrix(rep(1, P * P), nrow = P)
for (i in 1 : (P - 1))
{Covmatrix[cbind((1 + i) : P, 1 : (P - i))] =
exp(log(a) + log(b) * abs(i))
Covmatrix[cbind(1 : (P - i), (1 + i) : P)] =
exp(log(a) + log(b) * abs(i))}
Covmatrix
}
Hao Chai (U of Iowa) Introduction to .Call interface 7 / 41
Introduction
An R function calling C routines matgen RC:
matgen_RC = function(P, a, b)
{
.Call("matrix_gen", as.integer(P), as.double(a),
as.double(b))
}
Also we can use R compiler to compile the first two pure R functions andget matgen Rcmp and matgen Rindcmp.
Hao Chai (U of Iowa) Introduction to .Call interface 8 / 41
Introduction
Toy example
Result
> P = 1000
test elapsed user.self relative
5 matgen Rindcmp(P, 0.5, 0.9) 0.80 0.75 1.004 matgen Rind(P, 0.5, 0.9) 0.97 0.86 1.211 matgen RC(P, 0.5, 0.9) 1.04 1.01 1.302 matgen Rcmp(P, 0.5, 0.9) 19.98 19.51 24.983 matgen R(P, 0.5, 0.9) 65.44 64.45 81.80
Hao Chai (U of Iowa) Introduction to .Call interface 9 / 41
C part
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 10 / 41
C part
Header files
To enable the communication between R and C, the following header filesare needed in the C code.
#include <R.h>
#include <Rinternals.h> /% For .C or .Call %/
#include <Rdefines.h> /% For .External %/
#include <R_ext/Rdynload.h>
Hao Chai (U of Iowa) Introduction to .Call interface 11 / 41
C part .C interface
To use .C interface, main() function in C code needs to be replaced by
static void CFuncName(arg1, arg2, ...)
Arguments above have to be of pointer type. Therefore, we need tocoerce the scalar arguments to scalars in C.
C function can only return values to R through its arguments. Inother words, there are two kinds of arguments: arguments that passvalues from R to C and arguments that return values from C to R.
The C code using .C interface in the toy example is
Hao Chai (U of Iowa) Introduction to .Call interface 12 / 41
C part .C interface
.C interface in toy example
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
#include <math.h>
static void matrix_gen(double *Rp, double *Ra, double *Rb,
double *Rmatrix)
{
R_len_t i, j, p = Rp[0];
double a = Ra[0], b = Rb[0];
for (i = 0; i < p; i++)
for (j = 0; j < p; j++)
if (i == j) Rmatrix[i * p + j] = 1;
else Rmatrix[i * p + j] = exp(log(a) + abs(i - j)
* log(b));
}
Hao Chai (U of Iowa) Introduction to .Call interface 13 / 41
C part .C interface
Mapping types between R and C
Table: Comparison of R and C data types.1
R storage mode C types
logical int *integer int *double double *
character char **complex Rcomplex *
1Cited from “Writing R Extensions”Hao Chai (U of Iowa) Introduction to .Call interface 14 / 41
C part .Call interface
What can we expect from .Call?2
Pass R objects to C
Create R objects in C
Manipulate R objects in C
Return R objects from C
Call R functions from C
2See Brian CaffoHao Chai (U of Iowa) Introduction to .Call interface 15 / 41
C part .Call interface
To use .Call interface, main() function in C code needs to be replaced by
SEXP CFuncName(SEXP arg1, SEXP arg2, ...)
SEXP is a structure in C standing for S expression.
The returned value from C will also be SEXP type.
If new SEXP objects are defined within the C function, usePROTECT to protect them in the memory so that it will not becleaned by R as garbage.
Hao Chai (U of Iowa) Introduction to .Call interface 16 / 41
C part .Call interface
Basic structure of C functions
SEXP CFuncName(SEXP arg1, arg2, ...)
{
[arg1 = coerceVector(arg1, INTSXP)]
# Coerce the vector to the right type.
SEXP Robj, return_val; # Define new R objects.
PROTECT(return_val = allocMatrix(REALSXP, arg1, arg2))
# Protect return_val.
[body of function]
UNPROTECT(1)
return(return_val) # Return the values to R.
}
Hao Chai (U of Iowa) Introduction to .Call interface 17 / 41
C part .Call interface
Useful data types in Rinternals.h
Table: SEXPTYPE and R equivalent 3
SEXPTYPE R equivalent
REALSXP numeric with storage mode doubleINTSXP integerLGLSXP logicalSTRSXP characterVECSXP list (generic vector)DOTSXP a ‘...’ objectENVSXP environment
3Cited from “Writing R Extensions”Hao Chai (U of Iowa) Introduction to .Call interface 18 / 41
C part .Call interface
Useful macros in Rinternals.h
There are plenty of useful functions defined in Rinternals.h. Usefulfunctions can be found in “Writing R Extensions” or “R Internals”.
Table: List of useful functions in Rinternals.h4
Name Usage Example
coerceVector Coerce R object to SEXPTYPE arg1=..(arg1,INTSXP)allocVector Allocate memory for R vector Robj=..(STRSXP,2)allocMatrix Allocate memory for R matrix Robj=..(STRSXP,2,2)
nrows Get the No. of rows of a matrix ..nrow(Rmatrix)ncols Get the No. of cols of a matrix ..ncol(Rmatrix)
PROTECT Protect an R object See examples.UNPROTECT UNPROTECT some R objects See examples.
4.. represents the function name in the same row.Hao Chai (U of Iowa) Introduction to .Call interface 19 / 41
C part .Call interface
Useful functions in Rinternals.h
Table: List of useful functions in Rinternals.h Cont.5
Name Usage Example
STRING ELT Returns the memo. add. of R string ..(Rstr, 0)VECTOR ELT Returns the memo. add. of R list ..(Rlist, 1)
INTEGER Return the memo. add. of R int ..(Rint)REAL Return the memo. add. of R real ..(Rdoub)CHAR Convert a Rchar to characters ..(Rchar)
SET VECTOR ELT Assign value to an element of R list See example
5.. represents the function name in the same row.Hao Chai (U of Iowa) Introduction to .Call interface 20 / 41
C part .Call interface
Special Values
There are some constants for special values in R
R NaN
R PosInf
R NegInf
R NaReal
R NilValue
There are also some macros for error checking in C ISNA, ISNAN,R FINITE, NA INTEGER, NA LOGICAL, NA STRING, NA REAL
Hao Chai (U of Iowa) Introduction to .Call interface 21 / 41
C part .Call interface
.Call interface in toy example
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
#include "math.h"
SEXP matrix_gen(SEXP RP, SEXP Ra, SEXP Rb)
{
R_len_t i, j, p = INTEGER(RP)[0];
SEXP Rmatrix;
RP = coerceVector(RP, INTSXP);
Ra = coerceVector(Ra, REALSXP);
Rb = coerceVector(Rb, REALSXP);
PROTECT(Rmatrix = allocMatrix(REALSXP, p, p));
Hao Chai (U of Iowa) Introduction to .Call interface 22 / 41
C part .Call interface
.Call interface in toy example
double *mat, a = REAL(Ra)[0], b = REAL(Rb)[0];
mat = REAL(Rmatrix);
for (i = 0; i < p; i++)
for (j = 0; j < p; j++)
if (i == j) mat[i * p + j] = 1;
else mat[i * p + j] = exp(log(a) +
abs(i - j) * log(b));
UNPROTECT(1);
return(Rmatrix);
}
Hao Chai (U of Iowa) Introduction to .Call interface 23 / 41
R part
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 24 / 41
R part
Interfaces in R
To create a dynamic library, run the following code in the command line:
R CMD SHLIB CFileName.c
CFileName.dll or CFileName.so will be generated in the same directory.Then load the dynamic library which is generated by C code using
> dyn.load("CFileName.so")
in Linux/MacOS, or
> dyn.load("CFileName.dll")
in Windows, or a universal solution
> dyn.load(paste("CFileName", .Platform$dynlib.ext,
+ sep = ""))
Hao Chai (U of Iowa) Introduction to .Call interface 25 / 41
R part
There are three interfaces in R to load the dynamic library generated by C.
1 .C(”CFuncName”, arg1, arg2, ...)
2 .Call(”CFuncName”, arg1, arg2, ...)
3 .External(”CFuncName”, arg1, arg2, ...)
There are some options when using .C, such as NAOK andPACKAGE. For detailed information, refer to “Writing R Extensions”.
Hao Chai (U of Iowa) Introduction to .Call interface 26 / 41
Examples
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 27 / 41
Examples
Pass numeric values to C
func1 is a function with two arguments Rn and Rvec. It returns the largestelement of the first Rn elements of vector Rvec.
SEXP func1(SEXP Rvec, SEXP Rn)
{
Rvec = coerceVector(Rvec, REALSXP);
R_len_t i = 0, n = INTEGER(Rn)[0];
double *vec, max = REAL(Rvec)[0];
SEXP return_val;
PROTECT(return_val = allocVector(REALSXP, 1));
vec = REAL(Rvec);
for (i = 1; i < n; i++)
if (vec[i] >= max) max = vec[i];
REAL(return_val)[0] = max;
UNPROTECT(1);
return(return_val);
}Hao Chai (U of Iowa) Introduction to .Call interface 28 / 41
Examples
Pass numeric values to C
In R, we do the following
a = c(7, 4, 8, 9, 2, 5)
n = 4
dyn.load("f:/presentation/intro2dotCall/illust.dll")
.Call("func1", as.double(a), as.integer(n))
Hao Chai (U of Iowa) Introduction to .Call interface 29 / 41
Examples
Pass strings, return a list
func2 is able to calculate the quadratic form or the linear product of amatrix and a vector. It has three arguments: Rstr, Ry and RM. Ry is avector, RM is a matrix. If Rstr is ”quadratic”, then t(Ry) %*% RM %*%Ry is returned. If Rstr is ”linear”, then RM %*% Ry is returned. If Rstr is”both”, then both of the above will be returned as an R list.
Hao Chai (U of Iowa) Introduction to .Call interface 30 / 41
Examples
Pass strings, return a list
SEXP func2(SEXP RM, SEXP Ry, SEXP Rstr)
{
Rstr = coerceVector(Rstr, STRSXP);
RM = coerceVector(RM, REALSXP);
Ry = coerceVector(Ry, REALSXP);
SEXP return_lst, vec, num;
double *M = REAL(RM), *y = REAL(Ry);
double result1 = 0, *result2;
R_len_t i, j, nr, nc, l;
const char *method;
method = CHAR(STRING_ELT(Rstr, 0));
nr = nrows(RM);
nc = ncols(RM);
l = length(Ry);
Hao Chai (U of Iowa) Introduction to .Call interface 31 / 41
Examples
if (((strcmp(method, "both") == 0) ||
(strcmp(method,"linear") == 0)) && (nc != l))
error("The matrix and the vector need to be conformable!");
if (((strcmp(method, "both") == 0) ||
(strcmp(method, "quadratic") == 0)) &&
((nc != l) || (nr != l)))
error("The matrix and the vector need to be conformable!");
if (strcmp(method, "both") == 0)
{
PROTECT(return_lst = allocVector(VECSXP, 2));
PROTECT(vec = allocVector(REALSXP, nr));
PROTECT(num = allocVector(REALSXP, 1));
result2 = REAL(vec);
result1 = REAL(num)[0];
}
else PROTECT(return_lst = allocVector(VECSXP, 1));
Hao Chai (U of Iowa) Introduction to .Call interface 32 / 41
Examples
if (strcmp(method, "linear") == 0)
{
PROTECT(vec = allocVector(REALSXP, nr));
result2 = REAL(vec);
}
if (strcmp(method, "quadratic") == 0)
{
PROTECT(num = allocVector(REALSXP, 1));
result1 = REAL(num)[0];
}
if ((strcmp(method, "quadratic") == 0) ||
(strcmp(method, "both") == 0))
for (i = 0; i < nr; i++)
for (j = 0; j < nc; j++)
result1 = result1 + M[i + j * nr] * y[i] * y[j];
Hao Chai (U of Iowa) Introduction to .Call interface 33 / 41
Examples
if ((strcmp(method, "linear") == 0) ||
(strcmp(method, "both") == 0))
for (i = 0; i < nr; i++)
{
result2[i] = 0;
for (j = 0; j < nc; j++)
result2[i] = result2[i] + M[i + j * nr] * y[j];
}
Hao Chai (U of Iowa) Introduction to .Call interface 34 / 41
Examples
if (strcmp(method, "quadratic") == 0)
SET_VECTOR_ELT(return_lst, 0, num);
if (strcmp(method, "linear") == 0)
SET_VECTOR_ELT(return_lst, 0, vec);
if (strcmp(method, "both") == 0)
{
SET_VECTOR_ELT(return_lst, 0, num);
SET_VECTOR_ELT(return_lst, 1, vec);
}
UNPROTECT(2);
if (strcmp(method, "both") == 0)
UNPROTECT(1);
return(return_lst);
}
Hao Chai (U of Iowa) Introduction to .Call interface 35 / 41
Examples
Pass strings, return a list
The R code to call the function func2 is
dyn.load("f:/presentation/intro2dotCall/illust.dll")
M <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3)
y <- c(1, 0, -1)
.Call("func2", M, as.double(y), "both")
Hao Chai (U of Iowa) Introduction to .Call interface 36 / 41
Other
Outline
1 Introduction
2 C part.C interface.Call interface
3 R part
4 Examples
5 Other
Hao Chai (U of Iowa) Introduction to .Call interface 37 / 41
Other
Evaluating R expressions in C
It is also possible to evaluate R expressions in C code. The followingfunctions/macros are useful in this case. More details can be found in“Writing R extensions”.
defineVar
findVar
findFun
install
Hao Chai (U of Iowa) Introduction to .Call interface 38 / 41
Other
Some misc.
The “Writing R Extensions” manual is the main source for this talk.
More functions and macros can be found in Rinternals.h, oralternatively Rdefines.h. Choose one and stick to it.
Several times, when ran .Call in R, R crashed. Very likely, it wascaused by the difference between number of arguments in .Call andnumber of arguments in the original C functions.
Related C and R files are available at Related files.
Hao Chai (U of Iowa) Introduction to .Call interface 39 / 41
Other
Refrences
Writing R ExtensionsR InternalsUsing .Call in R by Brian Caffo.dot Call Interface by Gopi Goswami.Rinternals.h
Hao Chai (U of Iowa) Introduction to .Call interface 40 / 41
Other
Thank you!
Hao Chai (U of Iowa) Introduction to .Call interface 41 / 41