# Parameter Update Functions

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

    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:

    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:

    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.