Skip to contents

us_sigma(theta, d) builds the d x d covariance matrix that the parameter vector of a us() block of frmtmb encodes, and us_theta(S) is its inverse: the parameter vector whose us_sigma() is S.

Usage

us_sigma(theta, d, floored = FALSE)

us_theta(S)

Arguments

theta

A numeric vector or an RTMB advector of length d + d * (d - 1) / 2.

d

The dimension of the matrix, a positive whole number.

floored

FALSE (the default) takes each standard deviation as exp() of its entry. TRUE floors the scale as the random-effect blocks of frmtmb do, so that a variance the optimizer drives toward zero keeps a finite log-density: it adds 1e-150 to each standard deviation when d >= 2, and 1e-300 to the variance when d = 1.

S

A symmetric positive definite numeric matrix.

Value

us_sigma(): a d x d matrix, an advector matrix when theta is one. us_theta(): a numeric vector of length d + d * (d - 1) / 2, the inverse of us_sigma(floored = FALSE).

Details

The first d entries of theta are the log standard deviations. The other d * (d - 1) / 2 entries fill the strict lower triangle of a unit-diagonal factor L in column-major order: L[2, 1], L[3, 1], ..., L[d, 1], L[3, 2], and so on. Each row of L is then scaled to unit length, and the correlation matrix is L L'. So every real vector gives a valid covariance matrix, and a vector of zeros gives the identity. For d up to 3 this is the same map as glmmTMB's us structure. From d = 4 the order differs: glmmTMB fills the same triangle in row-major order, so a glmmTMB theta must be reordered first.

us_sigma() is AD-safe, so a family can call it inside its density while the objective is taped. That gives a family a free covariance matrix as a family-level extra parameter (extra_pars of frmtmb_family()): declare d + d * (d - 1) / 2 values, start them at us_theta() of a starting covariance, and read them through us_sigma() in lpdf and in the simulator. The mixture_mvn() family of frmtmb.latent builds its class covariances this way. Off the tape, as.matrix() of the result is an ordinary numeric matrix. us_theta() is numeric only; it runs off the tape.

See also

frmtmb_family() for extra_pars, frmtmb-robust-dpars for the other helpers a density can call while it is taped, and frmtmb_register_covstruct() for a covariance structure whose lpdf or from_natural can use the same map.

Examples

# standard deviations 2 and 0.5, and one correlation parameter
S <- us_sigma(c(log(2), log(0.5), 1), 2)
S
#>           [,1]      [,2]
#> [1,] 4.0000000 0.7071068
#> [2,] 0.7071068 0.2500000
cov2cor(as.matrix(S))   # the correlation is 1 / sqrt(2)
#>           [,1]      [,2]
#> [1,] 1.0000000 0.7071068
#> [2,] 0.7071068 1.0000000

# zero correlation parameters give a diagonal matrix
us_sigma(c(0, 0, 0, 0, 0, 0), 3)
#>      [,1] [,2] [,3]
#> [1,]    1    0    0
#> [2,]    0    1    0
#> [3,]    0    0    1

# the parameters of a given covariance, and back
S3 <- matrix(c(4, 1, 0.5, 1, 2, 0.3, 0.5, 0.3, 1), 3)
th <- us_theta(S3)
th
#> [1] 0.6931472 0.3465736 0.0000000 0.3779645 0.2606430 0.1379193
all.equal(as.matrix(us_sigma(th, 3)), S3)
#> [1] TRUE