--- title: "Gene-Drop Iteration Convergence" subtitle: "nprcgenekeepr: an R Package for the Genetic Management of Colonies" author: "R. Mark Sharp, Ph.D." date: "2026-06-25" output: html_document: df_print: paged vignette: > %\VignetteEngine{knitr::rmarkdown_notangle} %\VignetteIndexEntry{Gene-Drop Iteration Convergence} %\usepackage[UTF-8]{inputenc} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(nprcgenekeepr) library(knitr) library(kableExtra) ``` ## How many gene-drop iterations does a pedigree need? The Genetic Value Analysis ranks animals by mean kinship and **genome uniqueness**. Mean kinship is deterministic, but genome uniqueness (`gu`) is *estimated* by a gene-drop simulation: alleles are dropped down the pedigree a chosen number of times, and `gu` is the average result. Like any estimate from a finite number of draws, it carries sampling noise, so the precision of `gu` -- and, more importantly, the **selection order** it produces -- depends on how many iterations you run. There is no single iteration count that is right for every colony. A pedigree with many animals whose true genome uniqueness sits near a ranking boundary needs more iterations before the chosen set of animals stops changing run to run; a pedigree whose ranked animals are well separated settles almost immediately. `gvaConvergence()` answers the question *for the pedigree in hand*: it reports how reproducible the selection order is at a range of iteration counts, and the smallest count at which it has settled. ### What it measures Because the gene-drop iteration columns are independent replicates, the whole convergence picture is recoverable from a **single** gene drop. `gvaConvergence()` runs one gene drop at a budget `nMax`, then for each candidate iteration count `N` it splits the columns into two disjoint halves of `N` columns each -- two genuinely independent `N`-iteration runs -- ranks each half through the same ordering pipeline the report uses, and compares the two orderings on two criteria: - **top-`k` overlap** -- do the two runs choose the same top animals? (default `k = 20`, threshold `oMin = 0.90`) - **Kendall rank agreement** -- do the chosen animals come out in the same order? (threshold `rhoMin = 0.95`) The run is **reproducible at `N`** when both hold, and the recommended iteration count is the smallest `N` meeting both. The "Undetermined" animals (both parents unknown, no recorded origin) are a policy constant with rank `NA`; they are excluded from the order and reported separately as `nUndetermined`. This is distinct from seed reproducibility. A fixed seed already makes `gu` bit-identical run to run -- that is reproducibility of the *process*. `gvaConvergence()` reports the sampling reproducibility of the *estimate*: would a fresh, independent run lead to the same animals being chosen, in the same order? ## A pedigree where the iteration count matters No bundled pedigree exercises the diagnostic well -- after the `gu = 0` de-inflation the shipped pedigrees have no `gu` signal left to rank on, so their selection order is settled at the smallest iteration count. To show a pedigree where the count *does* matter, we build a small half-sib web in which the founders (the sources of the private alleles) are excluded from the analyzed population, so their alleles survive among the offspring only through descendants. Overlapping sire/dam mating windows give the offspring distinct true genome-uniqueness values that straddle the ranking boundary, so at low iteration counts the gene-drop estimate randomly crosses the boundary and the selection order churns. ```{r fixture-build} ## A deterministic dense-mid-range pedigree: 14 founder sires, each mated to a ## wrapping window of 5 of 15 founder dams (one offspring per pair). Windows ## overlap, so dam fan sizes vary and the 70 offspring get distinct genome ## uniqueness straddling the 10% ranking cutoff. Founders are excluded from the ## analyzed population (`pop`); the offspring are the probands. makeConvergenceFixture <- function() { w <- rep(5L, 14L) # sire window widths b <- 15L # number of founder dams a <- length(w) sids <- sprintf("S%03d", seq_len(a)) dids <- sprintf("D%03d", seq_len(b)) id <- c(sids, dids) sire <- rep(NA_character_, a + b) dam <- rep(NA_character_, a + b) sex <- c(rep("M", a), rep("F", b)) off <- character(0L) ocount <- 0L start <- 1L for (i in seq_len(a)) { for (j in seq_len(w[i])) { dj <- ((start + j - 2L) %% b) + 1L ocount <- ocount + 1L o <- sprintf("O%04d", ocount) id <- c(id, o) sire <- c(sire, sids[i]) dam <- c(dam, dids[dj]) sex <- c(sex, if (ocount %% 2L == 0L) "F" else "M") off <- c(off, o) } start <- start + max(1L, w[i] - 1L) } ped <- data.frame(id = id, sire = sire, dam = dam, sex = sex, stringsAsFactors = FALSE) ped$gen <- findGeneration(ped$id, ped$sire, ped$dam) list(ped = ped, pop = off) } fx <- makeConvergenceFixture() nrow(fx$ped) # total animals (founders + offspring) length(fx$pop) # offspring (the analyzed population) ``` We assess iteration counts from 25 up to 800 (a fixed `seed` makes the curve reproducible): ```{r fixture-convergence} conv <- gvaConvergence( fx$ped, pop = fx$pop, nMax = 1600L, grid = c(25L, 50L, 100L, 200L, 400L, 800L), seed = 11L ) kable( conv$convergence, digits = c(0L, 3L, 3L), col.names = c("Iterations (N)", "Top-20 overlap", "Kendall agreement"), caption = "Selection-order reproducibility vs. iteration count (half-sib web)." ) |> kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) conv$recommendedIter # smallest N meeting both criteria conv$converged conv$nRankable conv$nUndetermined ``` At the smallest counts the two independent half-runs disagree on both which animals are chosen and their order; both measures climb as `N` grows, and the selection order has settled by the higher counts and stays settled there. `recommendedIter` (printed below the table) reports the smallest count meeting both criteria. For this pedigree the default of 1000 iterations is in the right range, and `gvaConvergence()` is how you would confirm that rather than guess it. ## A pedigree that converges immediately Contrast the bundled `qcPed`. After the `gu = 0` de-inflation none of its ranked animals carry a non-zero genome uniqueness, so the selection order is driven by deterministic mean kinship and does not move with the iteration count. ```{r qcped-convergence} convQc <- gvaConvergence( nprcgenekeepr::qcPed, nMax = 400L, grid = c(25L, 50L, 100L, 200L), seed = 11L ) kable( convQc$convergence, digits = c(0L, 3L, 3L), col.names = c("Iterations (N)", "Top-20 overlap", "Kendall agreement"), caption = "Selection-order reproducibility vs. iteration count (qcPed)." ) |> kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) convQc$recommendedIter # converges at the grid floor convQc$nRankable convQc$nUndetermined # the excluded Undetermined set ``` Overlap and agreement are at their maximum from the smallest count, so the recommended count is the floor of the grid: this pedigree needs almost no iterations for the *order* to be reproducible. The `nUndetermined` count reports how many animals were set aside without a rank. ## Choosing an iteration count Run `gvaConvergence()` on your own pedigree and read `recommendedIter`. If `converged` is `FALSE`, no count in the grid settled the order -- raise `nMax` and extend the `grid` (each candidate `N` needs `2 * N <= nMax`), or accept that this pedigree is intrinsically near a ranking boundary and interpret the ranking with care. The thresholds `k`, `oMin`, and `rhoMin` are arguments, so you can make the definition of "reproducible" stricter or looser for your purpose. Keep two ideas separate. The per-animal sampling standard error (`guSE`, reported beside `gu` in `reportGV()`) tells you how *precise the genome uniqueness number* is; it shrinks like one over the square root of the iteration count. The *selection order* -- what `gvaConvergence()` measures -- is what actually decides which animals are chosen for breeding. A small `guSE` does not by itself mean the order has settled, which is exactly why the convergence check exists. See also `reportGV()` (the analysis whose iterations this advises on), `calcGUSE()` (the per-animal standard error), and the *Colony Manager Tutorial* vignette.