Returns f with RTMB's tape-safe replacements for c(), [<- and
diag<- bound at the top of its body. Call it on any function a user
supplies that frmtmb will later put on an AD tape, so that the user
does not have to carry the binding boilerplate. frmtmb applies it to
the tape-side slots and to those only: frmtmb_family()'s lpdf
and lcdf, and frmtmb_structure()'s loglik. valid_y, sim,
post$mean_fn and the rest run on doubles, off the tape, where the
bindings would buy nothing. A package that takes tape-side functions
of its own applies this to those. It is safe to call on any object:
a non-function and a primitive come back unchanged.
Value
f, with the three bindings prepended to its body when it is
a function that needs them, and unchanged otherwise.
Details
RTMB's replacements are LEXICAL. frmtmb's own objective code binds
them where it needs them ("c" <- RTMB::ADoverload("c")), but a
function the USER wrote inherits nothing from those bindings, and
base c() silently strips the advector class when a plain numeric
comes first. The result is a wrong gradient with no error.
A body rewrite, not an environment injection, on purpose: the
byte-code compiler may inline base builtins unless the shadowing is
visible in the body it compiles, so an environment binding is not
reliably honored while these assignments always are. ADoverload()
resolves at CALL time - base versions off the tape, AD versions on
it - so the wrapped function stays correct in both worlds, and the
cost is three lookups per call of a function that is taped once.
A function that already names ADoverload manages its own scope and
is returned untouched, so a hand-placed binding is respected and a
double wrap never stacks. Helpers the wrapped function CALLS still
use their own environments - lexical scope cannot be injected
transitively - so a helper that builds advectors needs the explicit
spelling of its own.
See also
frmtmb_family() and frmtmb_structure(), whose tape-side
slots frmtmb wraps with this