--- title: "Parameter Update Functions" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Parameter Update Functions} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(meow) ``` Parameter update functions re-estimate person and item parameters from the responses administered so far. They are the estimation engine of a `meow` simulation and can form the bulk of your runtime. For the full module contract, see `vignette("extending-meow")`. # Function signature Every parameter update function has the signature ```r update_fun <- function(pers, item, R, admin, ...) { # ... re-estimate parameters ... list(pers = updated_pers, item = updated_item) } ``` It receives the current person and item parameter estimates (`pers`, `item`), the full response matrix `R`, and the non-negative integer valued administration matrix `admin`. Parameter update functions return a list with the updated `pers` and `item` data frames. The responses to administered items are obtained from the matrix state: ```{r, eval = FALSE} idx <- which(admin != 0, arr.ind = TRUE) persons <- unique(idx[, 1]) items <- unique(idx[, 2]) resp <- R[idx] ``` or, equivalently, as a long data frame with `meow_long(R, admin)`. # Bundled updaters ## Maximum likelihood ability estimation `update_theta_mle()` treats item parameters as fixed and finds each respondent's 2PL maximum likelihood ability estimate, constrained to $[-4, 4]$. The log-likelihood is fully vectorized over the administered responses: ```{r, eval = FALSE} loglik <- function(theta) { p <- stats::plogis(item$a[item_j] * (theta[person] - item$b[item_j])) sum(resp * log(p) + (1 - resp) * log(1 - p)) } est <- stats::optim(pers$theta, loglik, lower = -4, upper = 4, method = "L-BFGS-B", control = list(fnscale = -1)) ``` ## Elo-style updates (Maths Garden) `update_maths_garden()` updates both abilities and difficulties with the on-the-fly Elo rule of Klinkenberg, Straatemeier, and van der Maas (2011): $$\hat\theta_j = \theta_j + K_\theta \sum_i (S_{ij} - E(S_{ij})), \qquad \hat b_i = b_i + K_b \sum_j (E(S_{ij}) - S_{ij}).$$ See `vignette("maths-garden-update")`. ## Paired Elo updates (Prowise Learn) `update_prowise_learn()` updates abilities with the same rule, but updates item difficulties through paired comparisons of consecutively administered items, which controls rating drift (Vermeiren et al., 2025). See `vignette("prowise-learn-update")`. # Best practices 1. **Return `list(pers, item)`** with both objects as both data frames, even if one is unchanged. 2. **Bound estimates** to a sensible range to avoid divergence. 3. **Vectorize** over the administered responses (`tapply()`, matrix indexing) rather than looping over respondents or items. 4. **Respect administration order** when it matters: The best method is to use values from the `admin` matrix, but `meow_long()` returns responses ordered by respondent and then by administration order.