Skip to contents

This document follows a genetic evaluation in the order it actually happens, and at each step it says three things: what the matrices are and what they mean, what the algorithm does with them, and which function runs it. The formulas are the ones the package computes, not the textbook version they descend from; where the implementation makes a choice, the choice is stated.

The data for every example is simulated here, so each result has its truth beside it.

s <- simulate_breeding(n_founders = 60, n_generations = 3,
                       offspring_per_generation = 150, h2 = 0.4,
                       n_markers = 600, seed = 1)
str(s, max.level = 1)
#> List of 4
#>  $ pedigree :'data.frame':   510 obs. of  3 variables:
#>  $ data     :'data.frame':   510 obs. of  3 variables:
#>  $ tbv      : Named num [1:510] -0.396 0.116 -0.528 1.009 0.208 ...
#>   ..- attr(*, "names")= chr [1:510] "F001" "F002" "F003" "F004" ...
#>  $ genotypes:List of 2

1. The model

Every fit in this package is a linear mixed model,

y = X b + Z u + e,     u ~ N(0, D),     e ~ N(0, R)

where y holds the observations, b the fixed effects, u all the random effects stacked, and X and Z their incidence matrices. What separates one model from another is not the algebra but the shape of D and R: an animal model puts the pedigree relationship matrix inside D, a repeatability model adds a second block, a multi-trait model gives R a full covariance between traits, a reaction norm gives each animal a vector of coefficients instead of a scalar. Most of the literature calls that covariance G; this document reserves G for the genomic relationship matrix of section 6 and writes D for the covariance of the random effects throughout.

The package writes all of that in one formula. Fixed terms are bare, cov() marks a fixed covariate, and the marked terms are random: animal(), maternal(), sire() carry a relationship matrix, pe() and random() are independent, rn() is a random regression.

pe() is worth its full definition, because it is the term the repeatability model is named after. It is the permanent environment of a subject with repeated records: what all the records of that subject share and is NOT additive genetic, so the non-additive genetic effects land there too (Mrode and Pocrnic, 2023, Eqn 5.1). The repeatability itself is (var(animal) + var(pe)) / total, the two share cells of the printed table added together.

The unit of layout is the covariance group, not the term. Two terms that share group = go into ONE covariance matrix with the covariance between them estimated:

Var(u_g) = C_g (x) K_g

where C_g is the small covariance among the terms of the group and K_g is the relationship matrix among their levels; D is the block diagonal of these, one block per group. This is why direct-maternal, the reaction norm and the associative model have no dedicated fitter: they are the same engine with a different incidence and the same penalty.

2. The pedigree: A, F, and A inverse

The additive relationship matrix A holds twice the kinship between every pair of animals. It is never built. What the equations need is its inverse, and Henderson (1976) showed that the inverse has a closed form: for each animal i with Mendelian sampling variance d_i,

A^-1 = sum_i (1/d_i) v_i v_i',    v_i = +1 at i, -1/2 at sire, -1/2 at dam

so A^-1 is built by adding one small outer product per animal, sparse from the start, never through a dense A. The Mendelian variance depends on how much of the parents’ ancestry is already shared:

d_i = 1/2  - 1/4 (F_sire + F_dam)   both parents known
d_i = 3/4  - 1/4 F_known            one parent known
d_i = 1                             neither

F is Wright’s (1922) inbreeding coefficient, computed by the Meuwissen and Luo (1992) trace: for animal i, walk the ancestors in decreasing index order accumulating l_j contributions, and F_i = sum_j l_j^2 d_j - 1. A max-heap over the ancestors is what makes a single pass correct: every descendant of an ancestor has a larger index and has therefore already deposited its share. This trace and the earlier strategy of Quaas (1976) share the point: the diagonal of A comes out of the decomposition while A^-1 is being built, instead of storing A to read it back. Mrode and Pocrnic (2023, ch. 3) carry both rules through a small pedigree by hand, which is where an implementation gets checked against printed numbers.

p <- pedigree(s$pedigree)
head(p, 3)
#> Pedigree with 3 animals, 3 founder(s)
#> Mean F 0, maximum 0, 0 animal(s) with F > 0
#>     id sire dam F
#> 1 F001   NA  NA 0
#> 2 F002   NA  NA 0
#> 3 F003   NA  NA 0
ai <- a_inverse(s$pedigree)      # i, j, x, n: the lower triangle in triplets
c(animals = ai$n, nonzeros = length(ai$x), mean_F = round(mean(p$F), 4))
#>   animals  nonzeros    mean_F 
#>  510.0000 1842.0000    0.0063

Two details in the implementation are worth knowing because they are silent when wrong. A parent that is cited but has no line of its own is an error, not a new founder. And when sire and dam are the same animal, the coefficients are merged BEFORE the outer product, which puts 1/d on that parent’s diagonal; emitting the terms one by one into a half-stored triangle would give 3/4 d^-1 and no error message.

Metafounders. When the base population is not one homogeneous unrelated pool (different lines, different years, animals whose parents are simply unknown), Legarra et al. (2015) replace the unknown parents with metafounders: virtual base animals with a self-relationship gamma that measures how related that base actually was. The implementation reduces to one line: a metafounder row is preloaded with F = gamma - 1 and d = gamma, and because every formula above reads only the parents’ F, the whole generalization propagates through the Mendelian variances, the trace and A^-1 with no special case. gamma must be strictly inside (0, 2), and the two ends are refused for different reasons. The upper one is Mendelian: the offspring of two copies of the same metafounder has d = 1/2 - 1/4 (2 (gamma - 1)) = 1 - gamma/2, which vanishes at gamma = 2, a base pool completely homozygous by descent, where every base animal is the same animal. The lower one is that a base pool needs a positive self-relationship to be a pool at all, and the package’s error message names both. Zero is a limit with a meaning rather than a degeneracy: gamma -> 0 is complete heterozygosity by descent, an unrelated base, and the recursion collapses onto the classical unknown parent of Meuwissen and Luo (1992) (Legarra et al., 2015; Mrode and Pocrnic, 2023, sec. 3.8).

ped_mf <- s$pedigree
ped_mf$sire[ped_mf$sire == "0"] <- "L1"
ped_mf$dam[ped_mf$dam == "0"] <- "L1"
p_mf <- pedigree(ped_mf, metafounders = "L1", gamma = 0.7)
round(mean(p_mf$F[p_mf$id %in% s$pedigree$id]), 4)   # base relatedness now shows up as F
#> [1] 0.3541

Sires and maternal grandsires. A sire model often has only the sire and the maternal grandsire of each animal. Then u_i = u_s / 2 + u_k / 4 + m_i, with the maternal granddam unknown: the grandsire path weighs 1/4, the Mendelian variance is 11/16 - F_s/4 - F_k/16, and the inverse gets (1, -1/2, -1/4) in the rules above (Mrode and Pocrnic, 2023, secs. 3.6 and 3.7). Read as a dam, the grandsire would enter with 1/2, and the A^-1 would still be symmetric and positive definite, so nothing downstream could catch it. The format is therefore declared, with sire_mgs() or pedigree(type = "sire_mgs"), and a third column named like a grandsire column is refused until it is.

3. The mixed model equations

Henderson’s equations (Henderson, 1950) solve for b and u at once. Writing W = [X Z], the package assembles

C_s = W'W + blockdiag_g [ kron(s2e * C_g^-1, K_g^-1) ],     rhs = W'y

and solves C_s sol = rhs. Two conventions matter. The system is scaled by the residual variance (the penalty carries s2e * C_g^-1, not C_g^-1), so the solution is the same BLUP but the matrix is in units of s2e. And inside a term, the column of Z for coefficient a and level l is a * n_levels + l: the level varies fastest. Reversing that convention does not break anything visibly: the model still assembles and converges, and estimates something else.

W'W is accumulated one record at a time. Each record touches a handful of columns and contributes a small clique among them, so the cost is the sum of squared row-lengths, not anything quadratic in the number of columns. The penalty is added afterwards into the same triplet list, and the triplet-to-sparse conversion sums duplicates, which is not a convenience but a requirement: in A^-1 the mate-mate term arrives once per offspring, and a build where the last write wins would silently discard part of the matrix.

The restricted likelihood, from the MME:

-2logL = (n - p) log s2e + log|D| + log|C_s| + (e'e + u'D^-1 u) / s2e

e = y - Xb - Zu are the residuals at the MME solution. At that solution e'e + u'D^-1 u equals y'y - sol'rhs, the form the MME suggest, but the package forms it from the residuals. y'y - sol'rhs subtracts two numbers of the order of n (mean y)^2 and inherits the error of the solution at first order. So a constant added to y, which the intercept absorbs and REML ignores, used to move the -2logL: 1.1e-8 relative at 1000 standard deviations and 1.1e-6 at 1e4. The residual form is stationary in the solution and does not carry the mean.

D is the covariance of the random effects of section 1, and it carries the same s2e scaling as C_s: per group the code accumulates nl log|C_g / s2e| + dim log|K_g|. With weights =, a - sum_i log w_i term joins the expression, the Jacobian of the weighted rescaling, constant in theta, so it moves the value and not the optimum.

The package computes the same quantity a second way, through the dense V = Z D Z' + R, and the tests demand the two agree. They share nothing but the model, so agreement is evidence; a single path checked against itself would be none.

d <- s$data
ev <- eval_internal(y ~ cg + animal(id), d, s$pedigree, theta = c(0.4, 0.6))
c(mme = ev$neg2logl, dense_V = ev$neg2logl_V, difference = abs(ev$neg2logl - ev$neg2logl_V))
#>          mme      dense_V   difference 
#> 4.681071e+02 4.681071e+02 1.705303e-12

4. Solving: sparse Cholesky and the selected inverse

C_s is factored as L L' by an up-looking sparse Cholesky, preceded by a minimum degree ordering (George and Liu, 1989) that reduces fill-in and by a symbolic analysis that computes the pattern of L once. On a clique, minimum degree would cost the cube of its size rather than scale with the nonzeros, so a node whose degree passes 80 percent of the nodes still alive leaves the graph and goes to the end of the order; at the start, a node is set aside when its degree passes both 10 sqrt(n), the dense-row rule of AMD (Amestoy, Davis and Duff, 1996), and 0.8 of the 99th percentile of the degrees, provided the set aside is at most a quarter of the graph. Ordering never changes a result, only speed and fill. The symbolic factorization is cached across REML iterations, which is sound only because the pattern of C_s does not depend on the variance components: the assembly pushes the same slots every time, explicit zeros included.

What the dense nodes leave behind is a completely full block at the end of L: k columns that cost about k^3 / 3 flops per factorization, which dominates the fit once k is large. The fit reports it as fit$dense_block = c(dense = k, columns = n); in a single step without APY, k is at least the number of genotyped animals. That block is factored in tiles of 64 x 64 on the threads that br_threads() sets (OpenMP). Each output number is written by one thread and every sum runs in a fixed order, so the factor is the same bit for bit with 1 thread or with 16.

Prediction error variances need the diagonal of C_s^-1, and the full inverse of a sparse matrix is dense, and for a pedigree of any size unaffordable. The identity of Takahashi, Fagan and Chin (1973) gives exactly the elements of the inverse that sit on the pattern of L, which is all the diagonal needs:

ch <- sparse_chol(ai)
si <- selected_inverse(ai)
c(logdet = round(ch$logdet, 4), dense_block = ch$dense_block)
#>      logdet dense_block 
#>    312.6306     69.0000

A position outside the pattern is not zero; it is unknown. The function returns only what it computed.

5. Estimating the variance components

REML maximizes the likelihood of error contrasts instead of the likelihood of y. What that removes is not a bias in b (the fixed effects come out as the same GLS solution under either criterion) but the downward bias maximum likelihood carries IN THE VARIANCE COMPONENTS, whose cause is that those fixed effects were estimated from the same records. Mrode and Pocrnic (2023, ch. 17) write the restricted likelihood as three terms: a weighted sum of squares of the residuals, log|V|, and log|X'V^-1X|, the last of them a penalty for having estimated b and the one maximum likelihood leaves out (Patterson and Thompson, 1971). The n - p in the exponent of section 3 is that same correction seen from the side of the mixed model equations.

The package maximizes that restricted likelihood by average information REML (Gilmour, Thompson and Cullis, 1995; the animal-breeding derivation is in Mrode and Pocrnic, 2023, ch. 17), which needs three ingredients per iteration.

The score. For a covariance group with matrix C_g, define the quadratic of the solution and the trace from the selected inverse,

Q[a,b] = u_a' K^-1 u_b
T[a,b] = s2e * tr( K^-1 [C_s^-1]_{a,b} )
M_g    = nl * C_g^-1 - C_g^-1 (Q + T) C_g^-1

and the derivative of -2logL with respect to the element (i,j) of C_g is M_g[i,i] on the diagonal and M_g[i,j] + M_g[j,i] off it, because a symmetric element appears twice. For the residual,

d(-2logL)/ds2e = (n - p - q + trpen)/s2e - e'e/s2e^2

where q is the number of random columns and trpen the trace of the penalty against C_s^-1. The - q + trpen is not decoration: the random effects absorb degrees of freedom too, and a version without it still converges, to the wrong place, reporting convergence. That is the worst failure mode available, which is why the score is checked against central finite differences on every parameter.

The step. The average information matrix is the average of the observed and expected information, cheap because it needs no second derivatives, and the step is theta <- theta - (AI + lambda diag(AI))^-1 score. This lambda is the Levenberg-Marquardt damping (Levenberg, 1944; Marquardt, 1963), and it is a third meaning of the letter: not the s2e/s2a ratio that scales K^-1 inside the mixed model equations of section 3, and not the ridge that apy_inverse() calls lambda. The damping starts at 1e-3, multiplies by ten whenever a candidate is rejected (inadmissible covariance, singular damped matrix, or a likelihood that got worse) and divides by ten when one is accepted. Before the AI loop, a few EM rounds run: EM (Dempster, Laird and Rubin, 1977) is monotone and stays inside the cone, so it costs little and lands the search in the right basin.

Stopping. Convergence is judged on the relative change of the components, sqrt(sum(dtheta^2)/sum(theta^2)) < tol, never on an absolute threshold on the score, whose norm grows with the number of records. A small step is not an optimum, though, so converged also requires the Newton decrement g' AI^-1 g, about twice the remaining gap in -2logL, to fall under 2e-4, components resting at a boundary excluded (in model_mt(), after checks of the Karush-Kuhn-Tucker condition and of the boundary face on the likelihood, a second walk from inside the cone and a polish along the face); it is reported as newton_dec. At maxiter with the decrement already under tolerance the likelihood is flat along some direction, and the fit declares convergence and says so. Standard errors come from the inverse of the AI matrix, SE_k = sqrt(2 [AI^-1]_kk). When AI is singular at the end (an eigenvalue below 1e-8 of the largest; in model_mt() the matrix is first scaled by the standard deviation of each trait, so the verdict does not depend on the unit of a trait), the fit names the components involved and their standard errors are NaN: the data do not separate them, the reported point depends on start=, and only combinations are estimable.

fit <- model(y ~ cg + animal(id), d, s$pedigree)
fit
#> AI-REML fit of 'y'
#>   converged in 7 iteration(s), relDelta 1.55e-09, Newton decrement 5.17e-19, 0.008 s
#>   -2logL 468.1000386
#>   510 record(s), 513 column(s) in the equations
#>   fixed column(s) removed for linear dependence: cg=g2
#> 
#>      component estimate std_error  share correlation
#>    var(animal) 0.400864 0.0956138 0.4024            
#>  var(residual) 0.595274 0.0688334 0.5976            
#> 
#> fixed effects (implicit intercept; dropped columns are zero; compare by contrast):
#>   intercept       cg=g1       cg=g3 
#> 10.00302128  0.03647810  0.00221236

Two rules protect the result. A covariance that stops being positive-definite ends the fit rather than being nudged back, and the starting point comes from var(y) unless start= gives one, so no run inherits a neighbour’s answer.

6. Genomics: from markers to H

G. VanRaden (2008) builds the genomic relationship matrix from centred marker dosages. With p_j the allele frequency at marker j and Z = M - 2p,

G = Z Z' / (2 sum_j p_j (1 - p_j))

Missing genotypes are imputed with the marker mean and never with zero: zero is a valid genotype, and confusing the two changes both the frequencies and every element of G with no error to notice. Markers that are fixed or entirely missing are dropped and counted.

A22, and the trap. The single step needs the pedigree relationships among the genotyped animals, A22. That is the inverse of the genotyped block of the inverse, not the genotyped block of A^-1, two matrices of the same shape, both symmetric, only one correct. The package computes it by a sparse Schur complement,

A22^-1 = B22 - B21 B11^-1 B12

where B11 is the non-genotyped block. B11^-1 is never formed: one sparse factorization and one triangular solve per genotyped animal do the same work.

H. Genomic and pedigree information describe the same animals on two different scales, so G is first brought to the scale of A22 by an affine adjustment that matches both the mean diagonal and the mean off-diagonal, then blended:

b = (mean_diag(A22) - mean_off(A22)) / (mean_diag(G) - mean_off(G))
a = mean_off(A22) - b * mean_off(G)
G* = (1 - w) (a + b G) + w A22

The blend w (5 percent by default) keeps G* invertible and admits that markers are not the whole truth. Then the single-step inverse of Aguilar et al. (2010) and Christensen and Lund (2010) says the whole relationship matrix H has an inverse that differs from A^-1 only in the genotyped block:

H^-1 = A^-1 + [ 0        0            ]
              [ 0   G*^-1 - A22^-1    ]

This is the identity that makes the single step practical: nothing dense is needed for the non-genotyped animals, and the correction is a small block added to a sparse matrix. It is also self-checking: with blend = 1, G* becomes A22 exactly, the correction block vanishes, and H^-1 must equal A^-1 through the whole fit. That collapse is one of the package’s tests. Mrode and Pocrnic (2023, ch. 12) work the same identity through a small herd, number by number.

gen <- list(ids = s$genotypes$ids, m = s$genotypes$m)
f_ss <- model(y ~ cg + animal(id), d, s$pedigree, genotypes = gen)
f_id <- model(y ~ cg + animal(id), d, s$pedigree, genotypes = gen, blend = 1)
c(single_step = f_ss$neg2logl, blend_one = f_id$neg2logl, pedigree = fit$neg2logl)
#> single_step   blend_one    pedigree 
#>    480.9321    468.1000    468.1000

Inverting G* without paying the cube. APY (Misztal, Legarra and Aguilar, 2014; Mrode and Pocrnic, 2023, sec. 12.4) splits the genotyped into a core and the rest; every non-core animal is regressed on the core, and what is left is a scalar Mendelian residual:

P   = Gcc^-1 Gcn
m_j = g_jj - g_jc P_j
G_APY^-1 = [ Gcc^-1 + P Mnn^-1 P'   -P Mnn^-1 ]
           [ -Mnn^-1 P'              Mnn^-1   ]

An honest limit: the approximation cuts arithmetic, not memory. G*^-1 is a dense matrix of the genotyped animals on both paths. What H^-1 keeps of it is only the nonzeros, so with APY the dense block of the factor is at least the core size plus one rather than the whole genotyped set.

How large a core? The dimensionality of the genomic information bounds it: Pocrnic et al. (2016) take as many animals as eigenvalues of G explain 98% of its trace, drawn at random. apy_core_select() applies that rule, reports the cost of one factorization with the core against the exact one, and takes size = and include = (proven sires, say) to override the draw; apy_core = "auto" calls it inside the fit, which then keeps the core in fit$apy. Choose the core once and pass it to every fit.

gid <- gen$ids
f_apy <- model(y ~ cg + animal(id), d, s$pedigree, genotypes = gen,
               apy_core = gid[seq(1, length(gid), by = 3)])
round(c(apy = cor(ebv(f_ss, "animal"), ebv(f_apy, "animal"))), 4)
#>    apy 
#> 0.9753

Markers as equations. The other route never forms G at all. Liu et al. (2014) write the equivalent model with the marker effects as unknowns, u_g = Z g + p_g, and the joint precision turns the Schur term into blocks of A^-1, so most of the system is the same sparse matrix the pedigree already gives. snp_blup() solves it by preconditioned conjugate gradients, which need only matrix-vector products, and every application of A22^-1 uses the matrix-free identity of Masuda et al. (2017):

A22^-1 v = A^22 v - A^21 (A^11)^-1 A^12 v

one sparse factorization of the non-genotyped block, one triangular solve per iteration. Nothing dense is ever built. The variance components are given rather than estimated: this is the solver of routine evaluation, where components come from a periodic REML run.

7. What the formula can say

With the covariance group as the unit, several classical models are incidences rather than fitters.

Direct-maternal (Willham, 1972): the animal’s own genes and its dam’s maternal ability in one 2x2 matrix, with the direct-maternal covariance, usually negative, and the number the model exists for.

Reaction norm (Kirkpatrick, Lofsvold and Bulmer, 1990; in animal models, Schaeffer and Dekkers, 1994): each animal gets a vector of coefficients on an environmental gradient through rn(id, base = ...), with legendre() building the orthogonal basis. The genetic variance becomes a function of the environment, which h2_curve() reads, evaluating every random regression at the point, a permanent environment on the same basis included; h2() refuses a reaction norm, because its heritability is a curve and not a number.

Multi-trait: cbind() on the left, a full residual covariance between traits, and missingness handled by the pattern of each record rather than by dropping it.

The textbook treatment of these models is Mrode and Pocrnic (2023): the repeatability model in ch. 5, maternal traits in ch. 8, random regression in ch. 10.

model(weight ~ cg + animal(id, group = "g") + maternal(dam, group = "g"), d, ped)
model(y ~ cg + rn(id, base = c("phi0", "phi1")) + pe(id), d2, ped)
model_mt(cbind(t1, t2) ~ cg + animal(id), d, ped)

8. Reading the evaluation

The solution of the MME gives the breeding values directly. Their reliability comes from the prediction error variance, which is where the selected inverse pays off, and the accuracy of an animal’s EBV is

acc = sqrt( 1 - PEV / ((1 + F) sigma2_a) )

with the inbreeding coefficient in the denominator because an inbred animal has more additive variance to predict: var(u_i) = a_ii s2a = (1 + F_i) s2a (Mrode and Pocrnic, 2023, ch. 3). The identity underneath, PEV = var(a - a^) = C22 s2e, is Henderson (1975).

accuracy() divides by the prior the animal actually has. For a pedigree animal that is 1 + F. For a genotyped animal in a single step it is the diagonal of H, which in that block is the diagonal of G*, and that is not 1 + F_ped: on the population simulated at the top of this vignette, every animal genotyped, the two diagonals differ by up to 0.18 and an individual accuracy by up to 0.067. The herd mean does not move; the individual does. A fit with genotypes= carries the diagonal of G*, and accuracy() uses it.

Heritability is read off theta, and both halves of the ratio have to be picked rather than assumed. theta is a NAMED vector, and its first entry is the animal variance only when the formula happens to put that term first: random(lot) + animal(id) puts var(random) there. The covariances of a group = are another matter. A direct-maternal covariance is part of the phenotypic variance of a record, with coefficient 1 (Willham, 1972). h2() takes the numerator by name and divides by the phenotypic variance of the trait, covariances included, and the share column of the printed fit uses the same denominator.

The fixed effects come with the same solution vector: fit$b, named term=level, also reachable as coef(fit, effects = "fixed"). The parametrization is the implicit intercept, with linearly dependent columns dropped (dropped_x) and a dropped level holding the zero solution, while the book’s examples zero one level per factor and fit no intercept. The two conventions agree only on CONTRASTS, differences between levels of the same factor, never on the raw values; contrasts are invariant to the parametrization, individual entries are not.

e <- ebv(fit)
a <- accuracy(fit, s$pedigree)
round(c(cor_with_truth = cor(e[names(s$tbv)], s$tbv),
        mean_accuracy = mean(a), h2 = h2(fit)), 3)
#> cor_with_truth  mean_accuracy             h2 
#>          0.719          0.736          0.402

From there the decisions: selection_index() combines traits with economic weights, and rank_drift() answers what an updated evaluation actually changed.

9. The Bayesian alternative

The same models can be sampled instead of maximized. gibbs() draws all locations in one block through the same sparse Cholesky, then draws each covariance from its conjugate inverse-Wishart and the residual from a scaled inverse chi-square. The prior is a choice, prior =: "jeffreys" is p(s2) ~ 1/s2; "flat" is uniform on the variance; "uniform_sd" is uniform on the standard deviation, the one Gelman (2006) recommends for a variance with few levels; c(df =, scale =) is the proper scaled inverse chi-square of the BLUPF90 Gibbs programs; and "half_t" is the hierarchical prior of Huang and Wand (2013), each standard deviation half-t with its density flat at zero, each correlation uniform, proper and conjugate, its scale read from the design. The improper ones can leave the posterior of a weakly identified component with spurious mass near zero (Hobert and Casella, 1996). For a covariance group "jeffreys" is worse: |C|^-(d+1)/2 grows without bound as C nears a singular matrix, so the posterior has infinite mass at a correlation of +-1 even when the data identify every component, and a chain that gets there stays; gibbs() warns when a chain sits there. Left unset, each kind of variance gets the prior its validation chose: the half-t on a scalar term (no chain stuck at a small true variance, where "jeffreys" held 35 of 360 chains at zero), "flat" on a covariance group (the half-t removed the trap too but pulled a direct-maternal correlation of -0.8 toward zero, by 0.43 posterior SD, where "flat" stayed at +0.04), and "flat" on the residual. On a Gaussian trait the default also runs the interweaving step of Yu and Meng (2011) on every estimated term (asis): after the usual draw of a covariance, the effects are rewritten in the non-centred parametrization and the covariance is drawn again by Metropolis-Hastings, which leaves the posterior unchanged. Against the same chains without it the bulk ESS per iteration rose 5.2 to 10.6 times on direct-maternal and rn() groups, and 2.1 times (a planted variance of 0.05) and 3.5 times (a planted 0) on a scalar term alone. With family = "probit" the prior has to be proper. "jeffreys" leaves the posterior improper at a variance of zero, and where the random effects can reproduce the category of every record, as with one binary record per animal, the binary likelihood stays positive as the variances grow and "flat" and "uniform_sd" leave it improper too (where a level holds records of both categories the likelihood falls and they need not); there the default is half_t(df = 4) with a normal prior on the fixed effects, and "jeffreys", "flat" and "uniform_sd" are refused unless allow_improper = TRUE. The chain also has no SINGULAR verdict of its own, so a design that only the likelihood fails to identify runs without one (records on unrelated founders only: the message of the chain was empty in 30 of 30 simulated data sets, where model() on the same formula says SINGULAR in all 30). Where REML gives a point and a standard error from the information matrix, the sampler gives the whole posterior, worth the cost when a component sits near a boundary, where the normal approximation behind the standard error is least trustworthy. summary() of the chain gives the posterior quantiles and the heritability computed draw by draw. The sampler goes back to Geman and Geman (1984); Wang, Rutledge and Gianola (1993, 1994) brought it to variance components in animal models, and Mrode and Pocrnic (2023, ch. 18) set out the same sampler and the conjugate draws it uses. With family = "probit" it samples a binary trait on its liability, each record’s liability drawn from a normal truncated at the threshold and the residual fixed at 1 (Albert and Chib, 1993; Sorensen et al., 1995). Its default is half_t(df = 4) with a normal prior on the fixed effects (prior_fixed = 1). The default adds the PX-DA move of Wang and Roy (2018) (px = TRUE) and the interweaving step on each covariance group (asis = TRUE). gibbs() refuses that step under "jeffreys", because its target, the conditional of chol(C) given the non-centred effects, has no finite integral.

g <- gibbs(y ~ cg + animal(id), d, s$pedigree, n_iter = 2000, burnin = 400, thin = 4)
data.frame(component = colnames(g$samples),
           posterior_mean = round(unname(g$mean), 3),
           reml = round(unname(fit$theta), 3))
#>       component posterior_mean  reml
#> 1   var(animal)          0.398 0.401
#> 2 var(residual)          0.606 0.595

References

The complete list is in REFERENCES.md. The works this walkthrough leans on directly: Henderson (1950) for the MME; Henderson (1976) for A^-1; Wright (1922) and Meuwissen and Luo (1992) for inbreeding; Patterson and Thompson (1971) and Gilmour, Thompson and Cullis (1995) for REML and average information; Legarra et al. (2015) for metafounders; VanRaden (2008), Aguilar et al. (2010) and Christensen and Lund (2010) for the single step; Misztal, Legarra and Aguilar (2014), Pocrnic et al. (2016) for the approximate inverse; Liu et al. (2014), Masuda et al. (2017) and Vandenplas et al. (2018) for markers as equations; George and Liu (1989) and Amestoy, Davis and Duff (1996) for the ordering; Takahashi, Fagan and Chin (1973) for the selected inverse; Willham (1972), Kirkpatrick et al. (1990) and Schaeffer and Dekkers (1994) for the models of section 7; Geman and Geman (1984) and Wang, Rutledge and Gianola (1993, 1994) for the sampler, Gelman (2006), Hobert and Casella (1996) and Huang and Wand (2013) for its priors, Yu and Meng (2011) for the interweaving step, and Albert and Chib (1993) and Sorensen et al. (1995) for its probit mode. Mrode and Pocrnic (2023) is the textbook behind the whole sequence, chapter by chapter.