Generate tapes of unnormalised log-densities.
Use tape_ult()
to specify a custom unnormalised log-density using C++
code much like TMB::compile()
.
Use tape_uld_inbuilt()
for tapes of inbuilt unnormalised log-densities implemented in this package.
tape_uld_inbuilt(name, x, theta)tape_uld(fileORcode = "", x, theta, Cppopt = NULL)
A list of three objects
fun
a function that evaluates the function directly
tape
a tape of the function
file
the temporary file storing the final source code passed to Rcpp::sourceCpp()
Name of an inbuilt function. See details.
Value of independent variables for taping.
Value of the dynamic parameter vector for taping.
A character string giving the path name of a file containing the unnormalised log-density definition OR code. fileORcode
will be treated as a file name if fileORcode
contains no new line characters ('\n' or '\r\n') and has a file extension detected by tools::file_ext()
.
List of named options passed to Rcpp::sourceCpp()
The code (possibly in the file pointed to by fileORcode
) must be C++
that uses only CppAD
and Eigen
, which makes it very similar to the requirements of the input to TMB::compile()
(which also uses CppAD
and Eigen
).
The start of code
should always be "a1type fname(const veca1 &x, const veca1 &theta){
" where fname
is your chosen name of the log-density function, x
represents a point in the data space and theta
is a vector of parameters for the log-density. This specifies that the function will have two vector arguments (of type veca1
) and will return a single numeric value (a1type
).
The type a1type
is a double with special ability for being taped by CppAD
. The veca1
type is a vector of a1type
elements, with the vector wrapping supplied by the Eigen
C++ package (that is an Eigen
matrix with 1 column and dynamic number of rows).
In place operations like +=
on a1type
, veca1
and similar have not worked for me (compile errors); fortunately the efficiency of in place operations is irrelevant for taping operations.
The body of the function must use operations from Eigen and/or CppAD, prefixed by Eigen::
and CppAD::
respectively.
There are no easy instructions for writing these as it is genuine C++
code, which can be very opaque to those unfamiliar with C++
.
However, recently ChatGPT and claude.ai have been able to very quickly translating R
functions to C++
functions (KLH has been telling these A.I. to use Eigen and CppAD, and giving the definitions of a1type
and veca1
).
I've found the quick reference pages for Eigen
useful. Limited unary and binary operations are available directly from CppAD
without Eigen
.
For the purposes of score matching the operations should all be smooth to create a smooth log-density and the normalising constant may be omitted.
For tape_uld_inbuilt()
, currently available unnormalised log-density functions are:
dirichlet
ppi
vMF
Bingham
FB
The function tape_uld()
uses Rcpp::sourceCpp()
to generate a tape of a function defined in C++.
(An alternative design, where the function is compiled interactively and then taped using a function internal to scorematchingad
, was not compatible with Windows OS).
The result result is NOT safe to save or pass to other CPUs in a parallel operation.
Other tape builders:
avgrange()
,
fixdynamic()
,
fixindependent()
,
keeprange()
,
tape_Hessian()
,
tape_Jacobian()
,
tape_bdryw()
,
tape_gradoffset()
,
tape_logJacdet()
,
tape_smd()
,
tape_swap()
if (FALSE) {
out <- tape_uld(system.file("demo_custom_uld.cpp", package = "scorematchingad"),
rep(0.2, 5), rep(-0.1, 5))
out$fun(c(0.1, 0.2, 0.2, 0.2, 0.2), c(-0.5, -0.5, -0.1, -0.1, 0))
out$tape$eval(c(0.1, 0.2, 0.2, 0.2, 0.2), c(-0.5, -0.5, -0.1, -0.1, 0))
out$tape$Jac(c(0.1, 0.2, 0.2, 0.2, 0.2), c(-0.5, -0.5, -0.1, -0.1, 0))
out$tape$name
}
Run the code above in your browser using DataLab