
Functionality to dynamically define R functions and S4 methods with in-lined C, C++ or Fortran code supporting .C and .Call calling conventions.
cfunction(sig=character(), body=character(), includes=character(),
otherdefs=character(),
language=c("C++", "C", "Fortran", "F95", "ObjectiveC", "ObjectiveC++"),
verbose=FALSE,
convention=c(".Call", ".C", ".Fortran"),
Rcpp=FALSE,
cppargs=character(), cxxargs=character(), libargs=character(),
dim=NULL, implicit=NULL, module=NULL, name=NULL) ## S4 methods for signatures
# f='character', sig='list', body='list'
# f='character', sig='character', body='character'
setCMethod(f, sig, body, ...)
## Further arguments:
# setCMethod(f, sig, body, includes="", otherdefs="", cpp=TRUE,
# verbose=FALSE, where=topenv(.GlobalEnv), ...)
If sig
is a single character vector, cfunction
returns a single
function
; if it is a list, it returns a list of functions.
setCMethod
declares new methods with given names and signatures and
returns invisible NULL
.
A single character value if sig
and body
are character vectors
or a character vector of the same length and the length of sig
or
body
with the name(s) of methods to create.
A match of formal argument names for the function with the
character-string names of corresponding classes. Alternatively,
a named list of such character vectors. The names of the list elements will
be used as function names (see example). If sig
is not a list,
the function name used in the code can be specified by the name
argument.
A character vector with C, C++ or Fortran code omitting function
declaration (only the body, i.e. in case of C starting after the function
opening curly bracket and ending before the closing curly bracket,
brackets excluded). In case of setCMethod
with signature
list
-- a list of such character vectors.
A character vector of additional includes and preprocessor statements etc that will be put between the R includes and the user function(s).
A characted vector with the code for any further definitions of
functions, classes, types, forward declarations, namespace usage clauses etc
which is inserted between the includes and the declarations of the functions
defined in sig
.
A character value that specifies the source language of the
inline code. The possible values for language
include all those
supported by R CMD SHLIB
on any platform, which are currently C,
C++, Fortran, F95, ObjectiveC and ObjectiveC++; they may not all be supported
on your platform. One can specify the language either in full as above, or
using any of the following case insensitive shortened forms: c, cpp,
c++, f, f95, objc, objcpp, objc++
. Defaults to C++
.
If TRUE
prints the compilation output, the source
code of the resulting program and the definitions of all declared
methods. If FALSE
, the function is silent, but it prints compiler
warning and error messages and the source code if compilation fails.
Which calling convention to use? See the Details section.
If TRUE
adds inclusion of Rcpp.h
to
includes
, also queries the Rcpp
package about
the location of header and library files and sets environment
variables PKG_CXXFLAGS
and PKG_LIBS
accordingly so that
the R / C++ interface provided by the Rcpp
package can be
used. Default value is FALSE
.
Optional character vector of tokens to be passed to
the compiler via the PKG_CPPFLAGS
environment
variable. Elements should be fully formed as for example
c("-I/usr/local/lib/foo", "-DDEBUG")
and are passed along verbatim.
Optional character vector of tokens to be passed to
the compiler via the PKG_CXXFLAGS
environment
variable. Elements should be fully formed as for example
c("-I/usr/local/lib/foo", "-DDEBUG")
and are passed along verbatim.
Optional character vector of tokens to be passed to the
compiler via the PKG_LIBS
environment variable. Elements should
be fully formed as for example c("-L/usr/local/lib/foo -lfoo",
"--lpthread")
and are passed along verbatim.
Optional character vector defining the dimensionality of the
function arguments. Of same length as sig
. Fortran or F95 only.
A character vector defining the implicit declaration in
Fortran or F95; the default is to use the implicit typing rules for Fortran,
which is integer
for names starting with the letters I
through
N
, and real
for names beginning with any other letter.
As R
passes double precision, this is not the best choice.
Safest is to choose implicit = "none"
which will require all names
in the subroutine to be explicitly declared.
Name(s) of any modules to be used in the Fortran
or
F95
subroutine.
Function name to be used in the code. Only used if sig
is
not a list. This is useful if the DLL created is to be used in conjunction
with the ode
function of the deSolve
package.
Reserved.
Oleg Sklyar, Duncan Murdoch, Mike Smith, Dirk Eddelbuettel
To declare multiple functions in the same library one can use setCMethod
supplying lists of signatures and implementations. In this case, provide as
many method names in f
as you define methods. Avoid clashes when selecting
names of the methods to declare, i.e. if you provide the same name several times
you must ensure that signatures are different but can share the same generic!
The source code in the body
should not include the header or
"front-matter" of the function or the close, e.g. in C or C++ it
must start after the C-function opening curly bracket and end before
the C-function closing curly bracket, brackets should not be
included. The header will be automatically generated from the R-signature
argument. Arguments will will carry the same name as used in the signature,
so avoid variable names that are not legal in the target language
(e.g. names with dots).
C/C++: If convention == ".Call"
(the default), the .Call
mechanism
is used and its result is returned directly as the result of the call of the
generated function. As the last line of the generated C/C++ code a
return R_NilValue;
is added in this case and a warning is generated
in case the user has forgotten to provide a return value. To suppress the
warning and still return NULL, add return R_NilValue;
explicitly.
Special care is needed with types, memory allocation and protection
-- exactly the same as if the code was not inline: see the
Writing R Extension manual for information on .Call
.
If convention == ".C"
or convention == ".Fortran"
, the
.C
or .Fortran
mechanism respectively is
used, and the return value is a list containing all arguments.
Attached R includes include R.h
for ".C"
, and
additionally Rdefines.h
and R_ext\Error.h
for
".Call"
.
Foreign Function Interface
x <- as.numeric(1:10)
n <- as.integer(10)
if (FALSE) {
## A simple Fortran example - n and x: assumed-size vector
code <- "
integer i
do 1 i=1, n(1)
1 x(i) = x(i)**3
"
cubefn <- cfunction(signature(n="integer", x="numeric"), code, convention=".Fortran")
print(cubefn)
cubefn(n, x)$x
## Same Fortran example - now n is one number
code2 <- "
integer i
do 1 i=1, n
1 x(i) = x(i)**3
"
cubefn2 <- cfunction(signature(n="integer", x="numeric"), implicit = "none",
dim = c("", "(*)"), code2, convention=".Fortran")
cubefn2(n, x)$x
## Same in F95, now x is fixed-size vector (length = n)
code3 <- "x = x*x*x"
cubefn3 <- cfunction(sig = signature(n="integer", x="numeric"), implicit = "none",
dim = c("", "(n)"), code3, language="F95")
cubefn3(20, 1:20)
print(cubefn3)
## Same example in C
code4 <- "
int i;
for (i = 0; i < *n; i++)
x[i] = x[i]*x[i]*x[i];
"
cubefn4 <- cfunction(signature(n="integer", x="numeric"), code4, language = "C", convention = ".C")
cubefn4(20, 1:20)
## Give the function in the source code a name
cubefn5 <- cfunction(signature(n="integer", x="numeric"), code4, language = "C", convention = ".C",
name = "cubefn")
code(cubefn5)
}
## use of a module in F95
modct <- "module modcts
double precision, parameter :: pi = 3.14159265358979
double precision, parameter :: e = 2.71828182845905
end"
getconstants <- "x(1) = pi
x(2) = e"
cgetcts <- cfunction(getconstants, module = "modcts", implicit = "none",
includes = modct, sig = c(x = "double"), dim = c("(2)"), language = "F95")
cgetcts(x = 1:2)
print(cgetcts)
## Use of .C convention with C code
## Defining two functions, one of which calls the other
sigSq <- signature(n="integer", x="numeric")
codeSq <- "
for (int i=0; i < *n; i++) {
x[i] = x[i]*x[i];
}"
sigQd <- signature(n="integer", x="numeric")
codeQd <- "
squarefn(n, x);
squarefn(n, x);
"
fns <- cfunction( list(squarefn=sigSq, quadfn=sigQd),
list(codeSq, codeQd),
convention=".C")
squarefn <- fns[["squarefn"]]
quadfn <- fns[["quadfn"]]
squarefn(n, x)$x
quadfn(n, x)$x
## Alternative declaration using 'setCMethod'
setCMethod(c("squarefn", "quadfn"), list(sigSq, sigQd),
list(codeSq, codeQd), convention=".C")
squarefn(n, x)$x
quadfn(n, x)$x
## Use of .Call convention with C code
## Multyplying each image in a stack with a 2D Gaussian at a given position
code <- "
SEXP res;
int nprotect = 0, nx, ny, nz, x, y;
PROTECT(res = Rf_duplicate(a)); nprotect++;
nx = INTEGER(GET_DIM(a))[0];
ny = INTEGER(GET_DIM(a))[1];
nz = INTEGER(GET_DIM(a))[2];
double sigma2 = REAL(s)[0] * REAL(s)[0], d2 ;
double cx = REAL(centre)[0], cy = REAL(centre)[1], *data, *rdata;
for (int im = 0; im < nz; im++) {
data = &(REAL(a)[im*nx*ny]); rdata = &(REAL(res)[im*nx*ny]);
for (x = 0; x < nx; x++)
for (y = 0; y < ny; y++) {
d2 = (x-cx)*(x-cx) + (y-cy)*(y-cy);
rdata[x + y*nx] = data[x + y*nx] * exp(-d2/sigma2);
}
}
UNPROTECT(nprotect);
return res;
"
funx <- cfunction(signature(a="array", s="numeric", centre="numeric"), code)
x <- array(runif(50*50), c(50,50,1))
res <- funx(a=x, s=10, centre=c(25,15))
if (interactive()) image(res[,,1])
## Same but done by registering an S4 method
setCMethod("funy", signature(a="array", s="numeric", centre="numeric"), code, verbose=TRUE)
res <- funy(x, 10, c(35,35))
if (interactive()) { x11(); image(res[,,1]) }
Run the code above in your browser using DataLab