Creates a modified version of a log-likelihood function that always returns
either a finite value or -Inf for each vector of parameters provided.
Usage
create_likelihood(
scalar_fn,
vectorized_fn,
on_nonfinite = c("warn", "quiet", "abort")
)Arguments
- scalar_fn, vectorized_fn
[function]
The log-likelihood function. Provide eitherscalar_fnorvectorized_fn:scalar_fn: Should accept a parameter as a numeric vector and return a single numeric value representing the log-likelihood, or-Inf.vectorized_fn: Should accept a matrix of parameter vectors (rows as samples, columns as elements of the parameter vector) and return a vector of log-likelihoods or-Infvalues for each row.
- on_nonfinite
[character]
How the sampler should handle values returned byfnormatrix_fnthat are not finite and not equal to-Inf. Must be one of:"warn": Issue a warning and return-Inf."quiet": Silently return-Inf."abort": Stop execution and signal an error.
Details
Provide model likelihoods as a log-density function, which take a vector of free parameter values and return the corresponding log-likelihood value.
Likelihoods are typically the most computationally expensive function to
evaluate in a nested sampling run. ernest allows you to implement your
likelihood as a function over a single parameter vector (scalar_fn) or over
a matrix of parameters (vectorized_fn).
ernest expects the log-likelihood function to return a
finite double or -Inf for each parameter vector. The behaviour when
encountering non-finite values other than -Inf (such as NaN, Inf, or
NA) is controlled by on_nonfinite.
If your log-likelihood depends on additional data (e.g., an observation
matrix or data frame), provide these using an
(anonymous function)rlang::as_function() (see Examples).
See also
See the cubature package for more examples of scalar and vectorized functions.
Examples
library(mvtnorm)
# Multivariate Normal Distribution
m <- 3
mean <- rep(0, m)
sigma <- diag(m)
sigma[2, 1] <- sigma[1, 2] <- 3 / 5
sigma[3, 1] <- sigma[1, 3] <- 1 / 3
sigma[3, 2] <- sigma[2, 3] <- 11 / 15
prec <- solve(sigma)
log_det <- -sum(log(diag(chol(sigma))))
# Provide a Scalar Log-Likelihood Function:
log_lik <- function(x) {
log_det - 0.5 * m * log(2 * pi) - 0.5 * (t(x) %*% prec %*% x)
}
log_lik(c(0, 0, 0))
#> [,1]
#> [1,] -2.128207
# `create_likelihood` allows scalar fns. to accept matrix inputs:
try(log_lik(matrix(rep(0, m * 2), nrow = 2)))
#> Error in t(x) %*% prec : non-conformable arguments
scalar_ll <- create_likelihood(scalar_fn = log_lik)
scalar_ll(matrix(rep(0, m * 2), nrow = 2))
#> [1] -2.128207 -2.128207
# Provide a Vectorized Log-Likelihood Function:
v_log_lik <- function(x) {
dmvnorm(x, mean = mean, sigma = sigma, log = TRUE)
}
v_log_lik(c(0, 0, 0))
#> [1] -2.128207
v_log_lik(matrix(rep(0, m * 2), nrow = 2))
#> [1] -2.128207 -2.128207
vector_ll <- create_likelihood(vectorized_fn = v_log_lik)
vector_ll
#> Vectorized Log-likelihood Function
#> function (x)
#> {
#> dmvnorm(x, mean = mean, sigma = sigma, log = TRUE)
#> }
# Control Behaviour when Nonfinite Likelihood Values are Encountered
# Default: Warn and replace with `-Inf`
vector_ll(c(0, 0, NA))
#> Warning: Replacing `NA` with `-Inf`.
#> [1] -Inf
# Signal an error
abort_ll <- create_likelihood(log_lik, on_nonfinite = "abort")
try(abort_ll(c(0, 0, NA)))
#> Error : Couldn't calculate the log-lik of 0, 0, and NA.
#> Caused by error:
#> ! log-lik. values must be either finite or `-Inf`.
#> ✖ Detected non-viable value: `NA`.
# Silently replace all non-finite values
quiet_ll <- create_likelihood(vectorized_fn = v_log_lik, on_nonfinite = "quiet")
quiet_ll(c(0, 0, NA))
#> [1] -Inf