| Title: | Exact Derivatives via Automatic Differentiation |
|---|---|
| Description: | Exact automatic differentiation for R functions. Provides a composable derivative operator D that computes gradients, Hessians, Jacobians, and arbitrary-order derivative tensors at machine precision. D(D(f)) gives Hessians, D(D(D(f))) gives third-order tensors for skewness of maximum likelihood estimators, and so on to any order. Works through any R code including loops, branches, and control flow. |
| Authors: | Alexander Towell [aut, cre] (ORCID: <https://orcid.org/0000-0001-6443-9897>) |
| Maintainer: | Alexander Towell <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.7.1 |
| Built: | 2026-05-27 07:45:07 UTC |
| Source: | https://github.com/queelius/nabla |
Implements forward-mode automatic differentiation using dual numbers with S4 classes. Supports exact arbitrary-order derivatives through recursive nesting of duals, with high-level functions for computing gradients, Hessian matrices, and Jacobians of arbitrary functions.
dualConstructor for dual numbers.
dual_variableShorthand for dual(x, 1).
dual_constantShorthand for dual(x, 0).
dual_vectorContainer for indexable dual vectors.
dual_variable_nCreate a dual seeded for n-th order differentiation.
deriv_nExtract the k-th derivative from a nested dual result.
differentiate_nCompute f(x) and all derivatives up to order n.
DComposable total derivative operator. D(f)
returns the derivative function; apply k times for k-th order tensors.
gradientGradient of a scalar-valued function.
hessianHessian matrix of a scalar-valued function.
jacobianJacobian matrix of a vector-valued function.
Maintainer: Alexander Towell [email protected] (ORCID)
Baydin, A. G., Pearlmutter, B. A., Radul, A. A., & Siskind, J. M. (2018). Automatic differentiation in machine learning: a survey. Journal of Machine Learning Research, 18(153), 1–43.
Related CRAN packages: dual, numDeriv, madness
Computed as exp(lbeta(a, b)).
beta(a, b) ## S4 method for signature 'numeric,numeric' beta(a, b) ## S4 method for signature 'ANY,ANY' beta(a, b)beta(a, b) ## S4 method for signature 'numeric,numeric' beta(a, b) ## S4 method for signature 'ANY,ANY' beta(a, b)
a |
A numeric or dual value. |
b |
A numeric or dual value. |
beta(a, b) with derivative.
beta(2, 3) a <- dual_variable(2) value(beta(a, 3))beta(2, 3) a <- dual_variable(2) value(beta(a, 3))
D(f) returns the derivative of f as a new function.
D(f, x) evaluates the derivative at x.
D(D(f)) composes for second-order derivatives, and so on.
D(f, x = NULL, order = 1L)D(f, x = NULL, order = 1L)
f |
A function taking a parameter vector (via |
x |
Optional numeric vector. If provided, evaluates |
order |
Derivative order (default 1). |
Each application of D appends one n-dimension to the output
shape, where n = length(x):
For f: R^n -> R: D gives (n) gradient, D^2 gives
(n,n) Hessian, D^3 gives (n,n,n), etc.
For f: R^n -> R^m: D gives (m,n) Jacobian, D^2 gives
(m,n,n), etc.
The composability works because the S4 dispatch for dualr arithmetic
handles nested duals recursively. When D(f) is called with dual
inputs (from an outer D), derivative propagation is automatic.
gradient(), hessian(), and jacobian() are convenience
wrappers: gradient(f, x) is D(f, x), hessian(f, x) is
D(f, x, order = 2), and jacobian(f, x) is D(f, x).
If x is NULL, a function. Otherwise, a numeric
vector, matrix, or array of the appropriate tensor shape.
f <- function(x) x[1]^2 * x[2] D(f, c(3, 4)) D(f, c(3, 4), order = 2) g <- function(x) list(x[1] * x[2], x[1]^2) D(g, c(2, 3)) Df <- D(f) DDf <- D(Df) DDf(c(3, 4))f <- function(x) x[1]^2 * x[2] D(f, c(3, 4)) D(f, c(3, 4), order = 2) g <- function(x) list(x[1] * x[2], x[1]^2) D(g, c(2, 3)) Df <- D(f) DDf <- D(Df) DDf(c(3, 4))
Extract the derivative (tangent) part of a dual number
deriv(d) ## S4 method for signature 'dualr' deriv(d) ## S4 method for signature 'numeric' deriv(d)deriv(d) ## S4 method for signature 'dualr' deriv(d) ## S4 method for signature 'numeric' deriv(d)
d |
A |
The deriv slot.
deriv(dual(3, 1))deriv(dual(3, 1))
After evaluating a function on a dual created by
dual_variable_n, use deriv_n to extract any
derivative from 0 (the function value) up to the seeded order.
deriv_n(d, k)deriv_n(d, k)
d |
A (possibly nested) dual number, or a numeric. |
k |
A non-negative integer: 0 for the function value, 1 for the first derivative, etc. |
A numeric value.
x <- dual_variable_n(1, order = 3) r <- exp(x) deriv_n(r, 0) deriv_n(r, 1) deriv_n(r, 2) deriv_n(r, 3)x <- dual_variable_n(1, order = 3) r <- exp(x) deriv_n(r, 0) deriv_n(r, 1) deriv_n(r, 2) deriv_n(r, 3)
Evaluates f at a dual variable seeded for order n,
returning the function value and all derivatives from 1 to n.
differentiate_n(f, x, order)differentiate_n(f, x, order)
f |
A function of one numeric argument. |
x |
A numeric value at which to differentiate. |
order |
A positive integer: the maximum derivative order. |
A named list with components value, d1,
d2, ..., d<order>.
differentiate_n(sin, pi/4, order = 4)differentiate_n(sin, pi/4, order = 4)
Create a dual number
dual(value, deriv = 0)dual(value, deriv = 0)
value |
The primal value (numeric or dual for nesting). |
deriv |
The derivative component (numeric or dual for nesting). Defaults to 0. |
A dual object.
x <- dual(3, 1) value(x) deriv(x)x <- dual(3, 1) value(x) deriv(x)
Wraps a numeric value as a dual with zero derivative, representing a constant with respect to the differentiation variable.
dual_constant(x)dual_constant(x)
x |
A numeric value. |
A dual with value = x and deriv = 0.
k <- dual_constant(5) deriv(k)k <- dual_constant(5) deriv(k)
Wraps a numeric value as a nested dual with all derivative components
zero, representing a constant with respect to the differentiation
variable at nesting depth n.
dual_constant_n(x, order)dual_constant_n(x, order)
x |
A numeric value. |
order |
A non-negative integer specifying the nesting depth. |
A (possibly nested) dual number with zero derivatives.
k <- dual_constant_n(5, order = 3) deriv_n(k, 1) deriv_n(k, 2) deriv_n(k, 3)k <- dual_constant_n(5, order = 3) deriv_n(k, 1) deriv_n(k, 2) deriv_n(k, 3)
Convenience constructor for the independent variable when computing
derivatives. Sets deriv = 1 so that the output's derivative slot
contains .
dual_variable(x)dual_variable(x)
x |
A numeric value. |
A dual with value = x and deriv = 1.
x <- dual_variable(2) deriv(x^2)x <- dual_variable(2) deriv(x^2)
Recursively nests dual numbers to enable exact computation of
derivatives up to order n. The variable is seeded so that
after evaluating a function f, the k-th derivative can be
extracted with deriv_n(result, k).
dual_variable_n(x, order)dual_variable_n(x, order)
x |
A numeric value at which to differentiate. |
order |
A positive integer specifying the derivative order. |
A (possibly nested) dual number.
x <- dual_variable_n(2, order = 3) r <- x^4 deriv_n(r, 3)x <- dual_variable_n(2, order = 3) r <- x^4 deriv_n(r, 3)
Wraps a list of dual objects in a container that supports [] indexing
and length(), so that user functions can use natural
theta[1] notation.
dual_vector(...)dual_vector(...)
... |
Dual objects, or a single list of dual objects. |
A dual_vector.
dv <- dual_vector(dual(1, 0), dual(2, 1)) length(dv) value(dv[1])dv <- dual_vector(dual(1, 0), dual(2, 1)) length(dv) value(dv[1])
Indexing and length for dual_vector
## S4 method for signature 'dual_vector,numeric' x[i, j, ..., drop = TRUE] ## S4 method for signature 'dual_vector' length(x)## S4 method for signature 'dual_vector,numeric' x[i, j, ..., drop = TRUE] ## S4 method for signature 'dual_vector' length(x)
x |
A |
i |
Numeric index. |
j, drop, ...
|
Ignored (present for generic compatibility). |
A single dual for scalar index; a dual_vector for
vector index; an integer for length.
dv <- dual_vector(dual(10, 1), dual(20, 0), dual(30, 0)) value(dv[1]) length(dv)dv <- dual_vector(dual(10, 1), dual(20, 0), dual(30, 0)) value(dv[1]) length(dv)
A container for multiple dual numbers that supports indexing
with [ and [[, allowing log-likelihood functions to be
written with theta[1], theta[2] notation.
.DataList of dual objects.
Implements arithmetic (+, -, *, /, ^),
comparison (==, !=, <, >, <=, >=),
and logical (&, |) operators. Derivatives follow standard
calculus rules (sum, product, quotient, power, chain).
## S4 method for signature 'dualr,dualr' e1 + e2 ## S4 method for signature 'dualr,numeric' e1 + e2 ## S4 method for signature 'numeric,dualr' e1 + e2 ## S4 method for signature 'dualr,dualr' e1 - e2 ## S4 method for signature 'dualr,numeric' e1 - e2 ## S4 method for signature 'numeric,dualr' e1 - e2 ## S4 method for signature 'dualr,dualr' e1 * e2 ## S4 method for signature 'dualr,numeric' e1 * e2 ## S4 method for signature 'numeric,dualr' e1 * e2 ## S4 method for signature 'dualr,dualr' e1 / e2 ## S4 method for signature 'dualr,numeric' e1 / e2 ## S4 method for signature 'numeric,dualr' e1 / e2 ## S4 method for signature 'dualr,dualr' e1 ^ e2 ## S4 method for signature 'dualr,numeric' e1 ^ e2 ## S4 method for signature 'numeric,dualr' e1 ^ e2 ## S4 method for signature 'dualr,dualr' Ops(e1, e2) ## S4 method for signature 'dualr,numeric' Ops(e1, e2) ## S4 method for signature 'numeric,dualr' Ops(e1, e2) ## S4 method for signature 'dualr,missing' e1 + e2 ## S4 method for signature 'dualr,missing' e1 - e2 ## S4 method for signature 'dualr' !x## S4 method for signature 'dualr,dualr' e1 + e2 ## S4 method for signature 'dualr,numeric' e1 + e2 ## S4 method for signature 'numeric,dualr' e1 + e2 ## S4 method for signature 'dualr,dualr' e1 - e2 ## S4 method for signature 'dualr,numeric' e1 - e2 ## S4 method for signature 'numeric,dualr' e1 - e2 ## S4 method for signature 'dualr,dualr' e1 * e2 ## S4 method for signature 'dualr,numeric' e1 * e2 ## S4 method for signature 'numeric,dualr' e1 * e2 ## S4 method for signature 'dualr,dualr' e1 / e2 ## S4 method for signature 'dualr,numeric' e1 / e2 ## S4 method for signature 'numeric,dualr' e1 / e2 ## S4 method for signature 'dualr,dualr' e1 ^ e2 ## S4 method for signature 'dualr,numeric' e1 ^ e2 ## S4 method for signature 'numeric,dualr' e1 ^ e2 ## S4 method for signature 'dualr,dualr' Ops(e1, e2) ## S4 method for signature 'dualr,numeric' Ops(e1, e2) ## S4 method for signature 'numeric,dualr' Ops(e1, e2) ## S4 method for signature 'dualr,missing' e1 + e2 ## S4 method for signature 'dualr,missing' e1 - e2 ## S4 method for signature 'dualr' !x
e1, e2
|
Dual or numeric operands. |
x |
A dual number (for unary |
A dual for arithmetic ops; logical for comparisons.
x <- dual_variable(3) y <- dual_variable(4) value(x + y) deriv(x * x) value(x^2) deriv(x^2) x < y x == yx <- dual_variable(3) y <- dual_variable(4) value(x + y) deriv(x * x) value(x^2) deriv(x^2) x < y x == y
Two-argument arctangent for dual numbers
## S4 method for signature 'dualr,dualr' atan2(y, x) ## S4 method for signature 'dualr,numeric' atan2(y, x) ## S4 method for signature 'numeric,dualr' atan2(y, x)## S4 method for signature 'dualr,dualr' atan2(y, x) ## S4 method for signature 'dualr,numeric' atan2(y, x) ## S4 method for signature 'numeric,dualr' atan2(y, x)
y |
A dual or numeric. |
x |
A dual or numeric. |
A dual representing atan2(y, x) with correct derivative.
y <- dual_variable(1) x <- dual_constant(1) result <- atan2(y, x) value(result)y <- dual_variable(1) x <- dual_constant(1) result <- atan2(y, x) value(result)
Extracts the primal value, discarding the derivative.
## S4 method for signature 'dualr' as.numeric(x, ...)## S4 method for signature 'dualr' as.numeric(x, ...)
x |
A |
... |
Ignored. |
Numeric value.
x <- dual(3.14, 1) as.numeric(x)x <- dual(3.14, 1) as.numeric(x)
Combine dual numbers into a dual_vector
## S4 method for signature 'dualr' c(x, ..., recursive = FALSE)## S4 method for signature 'dualr' c(x, ..., recursive = FALSE)
x |
A |
... |
Additional duals or numerics. |
recursive |
Ignored. |
A dual_vector.
x <- dual_variable(1) y <- dual_variable(2) dv <- c(x, y) length(dv)x <- dual_variable(1) y <- dual_variable(2) dv <- c(x, y) length(dv)
Returns TRUE for dual numbers so that defensive type checks pass.
## S4 method for signature 'dualr' is.numeric(x)## S4 method for signature 'dualr' is.numeric(x)
x |
A |
TRUE.
is.numeric(dual(1, 0))is.numeric(dual(1, 0))
Logarithm with optional base for dual numbers
## S4 method for signature 'dualr' log(x, base = exp(1))## S4 method for signature 'dualr' log(x, base = exp(1))
x |
A dual number. |
base |
Numeric base (default: |
A dual representing log(x, base).
x <- dual_variable(8) value(log(x, base = 2)) deriv(log(x, base = 2))x <- dual_variable(8) value(log(x, base = 2)) deriv(log(x, base = 2))
Implements all standard mathematical functions for dual numbers via
the chain rule: f(dual(a, b)) = dual(f(a), df(a) * b).
Supported functions: abs, sign, sqrt, floor,
ceiling, trunc, round,
exp, expm1, log, log2, log10, log1p,
cos, sin, tan, cospi, sinpi, tanpi,
acos, asin, atan,
cosh, sinh, tanh, acosh, asinh, atanh,
gamma, lgamma, digamma, trigamma,
cumsum, factorial, lfactorial.
## S4 method for signature 'dualr' exp(x) ## S4 method for signature 'dualr' sqrt(x) ## S4 method for signature 'dualr' Math(x)## S4 method for signature 'dualr' exp(x) ## S4 method for signature 'dualr' sqrt(x) ## S4 method for signature 'dualr' Math(x)
x |
A |
A dual with the function applied to the value and the
derivative propagated via the chain rule.
x <- dual_variable(pi / 4) value(sin(x)) deriv(sin(x)) y <- dual_variable(2) value(exp(y)) deriv(exp(y)) deriv(log(y))x <- dual_variable(pi / 4) value(sin(x)) deriv(sin(x)) y <- dual_variable(2) value(exp(y)) deriv(exp(y)) deriv(log(y))
Implements round and signif for dual numbers. These are
piecewise constant functions, so the derivative is zero almost everywhere.
## S4 method for signature 'dualr' Math2(x, digits)## S4 method for signature 'dualr' Math2(x, digits)
x |
A |
digits |
Integer; number of digits for rounding. |
A dual with the rounded value and zero derivative.
x <- dual_variable(3.14159) value(round(x, 2)) deriv(round(x, 2))x <- dual_variable(3.14159) value(round(x, 2)) deriv(round(x, 2))
Compares on value and propagates the derivative of the selected branch.
## S4 method for signature 'dualr' max(x, ..., na.rm = FALSE) ## S4 method for signature 'dualr' min(x, ..., na.rm = FALSE)## S4 method for signature 'dualr' max(x, ..., na.rm = FALSE) ## S4 method for signature 'dualr' min(x, ..., na.rm = FALSE)
x |
A dual number. |
... |
Additional dual or numeric values. |
na.rm |
Ignored. |
A dual representing the max or min.
x <- dual_variable(3) y <- dual_variable(5) value(max(x, y)) value(min(x, y))x <- dual_variable(3) y <- dual_variable(5) value(max(x, y)) value(min(x, y))
Display a dual number
## S4 method for signature 'dualr' show(object) ## S4 method for signature 'dual_vector' show(object)## S4 method for signature 'dualr' show(object) ## S4 method for signature 'dual_vector' show(object)
object |
A |
Invisible NULL; called for side effect of printing.
x <- dual(3, 1) x dv <- dual_vector(dual(1, 0), dual(2, 1)) dvx <- dual(3, 1) x dv <- dual_vector(dual(1, 0), dual(2, 1)) dv
Implements sum, prod, min, max, range,
any, and all for dual numbers. Derivatives are propagated
correctly through sum (additive) and prod (multiplicative).
## S4 method for signature 'dualr' Summary(x, ..., na.rm = FALSE)## S4 method for signature 'dualr' Summary(x, ..., na.rm = FALSE)
x |
A dual number. |
... |
Additional dual or numeric values. |
na.rm |
Logical; ignored (present for generic compatibility). |
A dual for sum/prod/min/max; a dual_vector for range;
logical for any/all.
x <- dual_variable(2) y <- dual_variable(5) value(sum(x, y)) value(prod(x, y))x <- dual_variable(2) y <- dual_variable(5) value(sum(x, y)) value(prod(x, y))
S4 class representing a dual number
where . The value slot holds the primal
value and the deriv slot holds the tangent (derivative) component.
Both slots accept ANY type to support nested duals for higher-order
derivatives.
valueThe primal (function) value. Numeric for first-order duals, or another dual for higher-order.
derivThe tangent (derivative) component. Numeric for first-order duals, or another dual for higher-order.
Computes .
erf(x) ## S4 method for signature 'numeric' erf(x) ## S4 method for signature 'dualr' erf(x)erf(x) ## S4 method for signature 'numeric' erf(x) ## S4 method for signature 'dualr' erf(x)
x |
A numeric or dual value. |
The error function value. For dual input, returns a dual with
derivative .
erf(1) x <- dual_variable(1) value(erf(x))erf(1) x <- dual_variable(1) value(erf(x))
Computes .
erfc(x) ## S4 method for signature 'numeric' erfc(x) ## S4 method for signature 'dualr' erfc(x)erfc(x) ## S4 method for signature 'numeric' erfc(x) ## S4 method for signature 'dualr' erfc(x)
x |
A numeric or dual value. |
The complementary error function value.
erfc(1) x <- dual_variable(0) value(erfc(x))erfc(1) x <- dual_variable(0) value(erfc(x))
Evaluates the gradient of f at x using forward-mode AD.
Equivalent to D(f, x) for scalar-valued f.
gradient(f, x)gradient(f, x)
f |
A function taking a parameter vector (numeric or dual) and
returning a scalar. Parameters are accessed via |
x |
A numeric vector of parameter values. |
The function should use x[1], x[2], etc. to access
parameters. This is compatible with the standard R convention used by
optim.
A numeric vector of length p containing the gradient.
f <- function(x) -(x[1] - 3)^2 - (x[2] - 5)^2 gradient(f, c(1, 2))f <- function(x) -(x[1] - 3)^2 - (x[2] - 5)^2 gradient(f, c(1, 2))
Computes the matrix of second partial derivatives of f at x
using forward-mode AD. Equivalent to D(f, x, order = 2).
hessian(f, x)hessian(f, x)
f |
A function taking a parameter vector and returning a scalar. |
x |
A numeric vector of parameter values. |
A p x p numeric matrix (the Hessian).
f <- function(x) -(x[1] - 3)^2 - (x[2] - 5)^2 hessian(f, c(1, 2))f <- function(x) -(x[1] - 3)^2 - (x[2] - 5)^2 hessian(f, c(1, 2))
Test whether an object is a dual number
is_dual(x)is_dual(x)
x |
An object. |
Logical.
is_dual(dual(1, 0)) is_dual(42)is_dual(dual(1, 0)) is_dual(42)
Computes the first derivative of f at x using forward-mode
AD. Equivalent to D(f, x). For f: R^p -> R^m, returns an
m x p matrix. For scalar-valued f, returns a length-p
gradient vector.
jacobian(f, x)jacobian(f, x)
f |
A function taking a parameter vector and returning a scalar,
list of scalars, or a |
x |
A numeric vector of parameter values (length |
An m x p numeric matrix for vector-valued f, or
a numeric vector of length p for scalar-valued f.
f <- function(x) { a <- x[1]; b <- x[2] list(a * b, a^2, sin(b)) } jacobian(f, c(2, pi/4)) g <- function(x) x[1]^2 + x[2]^2 jacobian(g, c(3, 4))f <- function(x) { a <- x[1]; b <- x[2] list(a * b, a^2, sin(b)) } jacobian(f, c(2, pi/4)) g <- function(x) x[1]^2 + x[2]^2 jacobian(g, c(3, 4))
Log-beta function for dual numbers
lbeta(a, b) ## S4 method for signature 'numeric,numeric' lbeta(a, b) ## S4 method for signature 'dualr,dualr' lbeta(a, b) ## S4 method for signature 'dualr,numeric' lbeta(a, b) ## S4 method for signature 'numeric,dualr' lbeta(a, b)lbeta(a, b) ## S4 method for signature 'numeric,numeric' lbeta(a, b) ## S4 method for signature 'dualr,dualr' lbeta(a, b) ## S4 method for signature 'dualr,numeric' lbeta(a, b) ## S4 method for signature 'numeric,dualr' lbeta(a, b)
a |
A numeric or dual value. |
b |
A numeric or dual value. |
lbeta(a, b) with derivative via digamma.
lbeta(2, 3) a <- dual_variable(2) value(lbeta(a, 3))lbeta(2, 3) a <- dual_variable(2) value(lbeta(a, 3))
Computes where is the derivative order.
The derivative of is .
psigamma(x, deriv = 0L) ## S4 method for signature 'numeric' psigamma(x, deriv = 0L) ## S4 method for signature 'dualr' psigamma(x, deriv = 0L)psigamma(x, deriv = 0L) ## S4 method for signature 'numeric' psigamma(x, deriv = 0L) ## S4 method for signature 'dualr' psigamma(x, deriv = 0L)
x |
A numeric or dual value. |
deriv |
Integer derivative order (0 = digamma, 1 = trigamma, etc.). |
The polygamma function value.
psigamma(1, deriv = 0) x <- dual_variable(2) value(psigamma(x, deriv = 1))psigamma(1, deriv = 0) x <- dual_variable(2) value(psigamma(x, deriv = 1))
Extract the value (primal) part of a dual number
value(d) ## S4 method for signature 'dualr' value(d) ## S4 method for signature 'numeric' value(d)value(d) ## S4 method for signature 'dualr' value(d) ## S4 method for signature 'numeric' value(d)
d |
A |
The value slot.
value(dual(3, 1))value(dual(3, 1))