Dot Call interface

Post on 10-May-2015

695 views 0 download

Tags:

Transcript of Dot Call interface

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