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

nimbleExternalCall {nimble} | R 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`.

### 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 `nimbleFunction`s.

### 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)

[Package nimble version 0.9.1 Index]