nimbleExternalCall: Create a nimbleFunction that wraps a call to external...

View source: R/externalCalls.R

nimbleExternalCallR Documentation

Create a nimbleFunction that wraps a call to external compiled code

Description

Given C header information, a function that takes scalars or pointers can be called from a compiled nimbleFunction. If non-scalar return values are needed, an argument can be selected to behave as the return value in nimble.

Usage

nimbleExternalCall(
  prototype,
  returnType,
  Cfun,
  headerFile,
  oFile,
  where = getNimbleFunctionEnvironment()
)

Arguments

prototype

Argument type information. This can be provided as an R function using nimbleFunction type declarations or as a list of nimbleType objects.

returnType

Return object type information. This can be provided similarly to prototype as either a nimbleFunction type declaration or as a nimbleType object. In the latter case, the name will be ignored. If there is no return value, this should be void().

Cfun

Name of the external function (character).

headerFile

Name (possibly including file path) of the header file where Cfun is declared.

oFile

Name (possibly including path) of the .o file where Cfun has been compiled. Spaces in the path may cause problems.

where

An optional where argument passed to setRefClass for where the reference class definition generated for this nimbleFunction will be stored. This is needed due to R package namespace issues but should never need to be provided by a user.

Details

The only argument types allowed in Cfun are double, int, and bool, corresponding to nimbleFunction types double, integer, and logical, respectively.

If the dimensionality is greater than zero, the arguments in Cfun should be pointers. This means it will typically be necessary to pass additional integer arguments telling Cfun the size(s) of non-scalar arguments.

The return argument can only be a scalar or void. Since non-scalar arguments are passed by pointer, you can use an argument to return results from Cfun. If you wish to have a nimbleFunction that uses one argument of Cfun as a return object, you can wrap the result of nimbleExternalCall in another nimbleFunction that allocates the return object. This is useful for using Cfun in a nimbleModel. See example below.

Note that a nimbleExternalCall can only be executed in a compiled nimbleFunction, not an uncompiled one.

If you have problems with spaces in file paths (e.g. for oFile), try compiling everything locally by including dirName = "." as an argument to compileNimble.

Note that if you use Rcpp to generate object files, NIMBLE's use of the --preclean option to R CMD SHLIB can cause failures, so you may need to run nimbleOptions(precleanCompilation=FALSE) to prevent removal of needed object files.

Value

A nimbleFunction that takes the indicated input arguments, calls Cfun, and returns the result.

Author(s)

Perry de Valpine

See Also

nimbleRcall for calling arbitrary R code from compiled nimbleFunctions.

Examples

## Not run: 
sink('add1.h')
cat('
 extern "C" {
 void my_internal_function(double *p, double*ans, int n);
 }
')
sink()
sink('add1.cpp') 
cat('
 #include <cstdio>
 #include "add1.h"
 void my_internal_function(double *p, double *ans, int n) {
   printf("In my_internal_function\\n");
     /* cat reduces the double slash to single slash */ 
   for(int i = 0; i < n; i++) 
     ans[i] = p[i] + 1.0;
 }
')
sink()
system('g++ add1.cpp -c -o add1.o')
Radd1 <- nimbleExternalCall(function(x = double(1), ans = double(1),
n = integer()){}, Cfun =  'my_internal_function',
headerFile = file.path(getwd(), 'add1.h'), returnType = void(),
oFile = file.path(getwd(), 'add1.o'))
## If you need to use a function with non-scalar return object in model code,
## you can wrap it  in another nimbleFunction like this:
model_add1 <- nimbleFunction(
     run = function(x = double(1)) {
         ans <- numeric(length(x))
         Radd1(x, ans, length(x))
         return(ans)
         returnType(double(1))
     })
demoCode <- nimbleCode({
     for(i in 1:4) {x[i] ~ dnorm(0,1)} ## just to get a vector
     y[1:4] <- model_add1(x[1:4])
})
demoModel <- nimbleModel(demoCode, inits = list(x = rnorm(4)),
check = FALSE, calculate = FALSE)
CdemoModel <- compileNimble(demoModel, showCompilerOutput = TRUE)

## End(Not run)

nimble documentation built on Sept. 11, 2024, 7:10 p.m.