Skip to contents

eqc_calibrate() implements Algorithm 1 (Empirical Quadrature Calibration, EQC) for reliability-targeted IRT simulation.

Given a target marginal reliability \(\rho^*\), a latent distribution generator sim_latentG() (for \(G\)) and an item parameter generator sim_item_params() (for \(H\)), the function searches for a global discrimination scale \(c^* > 0\) such that a selected empirical quadrature approximation \(\hat\rho_M(c)\) for the Rasch, 2PL, or 3PL model matches \(\rho^*\). Population accuracy is a Monte Carlo approximation and should be assessed on independent draws.

The key idea is to:

  1. Draw a large fixed "quadrature" sample \(\{\theta_m\}_{m=1}^M \sim G\) and item parameters \(\{(\beta_i, \lambda_{i,0})\}_{i=1}^I \sim H\) once.

  2. For any scale \(c\), form \(\lambda_i(c) = c \cdot \lambda_{i,0}\) and compute the empirical approximation to population reliability \(\hat\rho_M(c)\) from the test information function.

  3. Scan the explicit scale interval on a logarithmic grid, enumerate all detected roots of \(\hat\rho_M(c^*) = \rho^*\), and apply the requested branch-selection policy.

Usage

eqc_calibrate(
  target_rho,
  n_items,
  model = c("rasch", "2pl", "3pl"),
  latent_shape = "normal",
  item_source = "parametric",
  latent_params = list(),
  item_params = list(),
  reliability_metric = "info",
  M = 10000L,
  c_bounds = c(0.3, 3),
  tol = 1e-04,
  seed = NULL,
  verbose = FALSE,
  root_policy = "lowest_increasing",
  root_controls = list(),
  allow_tangent = FALSE,
  allow_plateau = FALSE
)

# S3 method for class 'eqc_result'
print(x, digits = 4, ...)

# S3 method for class 'eqc_result'
summary(object, ...)

Arguments

target_rho

Numeric in (0, 1). Target marginal reliability \(\rho^*\).

n_items

Integer. Number of items in the test form.

model

Character. Measurement model: "rasch", "2pl", or "3pl". For "rasch", all baseline discriminations are set to 1 before scaling. For "3pl", item_params$guessing_params controls the item lower asymptotes; calibration scales discrimination only and uses the fixed logistic convention D = 1.

latent_shape

Character. Shape argument passed to sim_latentG() (e.g. "normal", "bimodal", "heavy_tail", ...).

item_source

Character. Source argument passed to sim_item_params() (e.g. "parametric", "irw", "hierarchical", "custom"). Defaults to "parametric" so core workflows do not require external item-pool data. Use "irw" for empirically-grounded difficulties when the Item Response Warehouse package is installed.

latent_params

List. Additional arguments passed to sim_latentG().

item_params

List. Additional arguments passed to sim_item_params().

reliability_metric

Character. Reliability definition used inside EQC:

"info"

Average-information reliability (default, recommended for EQC). Targets \(\tilde{\rho}\), which is well behaved on practical EQC search intervals and is bracket-checked before root-finding.

"tilde"

Synonym for "info".

"msem", "bar"

Rejected by eqc_calibrate() because direct MSEM targeting can be non-monotone under EQC root-finding. Use sac_calibrate for direct MSEM-based calibration.

M

Integer. Size of the empirical quadrature sample (default: 10000).

c_bounds

Numeric length-2 vector. Search bounds for \(c\). Default: c(0.3, 3).

tol

Numeric. Root-polishing tolerance. Default: 1e-4.

seed

Optional integer for reproducibility.

verbose

Logical. If TRUE, print progress messages.

root_policy

Character. Root-selection policy used when the fixed-form reliability curve has multiple roots. The default, "lowest_increasing", selects the lowest-scale root with positive local slope. "nearest_increasing" uses the unscaled baseline c = 1 as its reference. "lowest_any" and "highest_any" select the lowest- or highest-scale admissible root regardless of slope direction. Tangent and plateau roots remain inadmissible under the "*_any" policies unless allow_tangent or allow_plateau, respectively, is enabled.

root_controls

Named list of advanced topology-scanner controls. The supplied c_bounds are never expanded.

allow_tangent

Logical. If TRUE, a detected tangent root may be selected by an "*_any" policy. The default is FALSE.

allow_plateau

Logical. If TRUE, the geometric midpoint of a detected target plateau may be selected by an "*_any" policy. The complete plateau interval remains recorded in the root table. The default is FALSE.

x

An object of class "eqc_result".

digits

Integer. Number of decimal places for printing.

...

Additional arguments passed to or from other methods.

object

An object of class "eqc_result".

Value

An object of class "eqc_result" (a list) with elements:

c_star

Calibrated discrimination scale \(c^*\).

target_rho

Target reliability \(\rho^*\).

achieved_rho

Empirical quadrature estimate \(\hat\rho_M(c^*)\).

metric

Reliability metric used.

model

Measurement model.

n_items

Number of items.

M

Empirical quadrature sample size.

theta_quad

Length-M vector of quadrature abilities.

theta_var

Sample variance of theta_quad.

beta_vec

Item difficulties from the baseline item design.

lambda_base

Baseline (unscaled) item discriminations.

lambda_scaled

Scaled item discriminations (lambda_base * c_star).

guessing_vec

Item lower asymptotes. New Rasch/2PL objects store an all-zero vector; 3PL objects store the generated guessing parameters.

items_base

item_params object with scale = 1 (baseline).

items_calib

item_params object with discriminations scaled by c_star.

schema_version, item_scope

Additive result-schema and fixed-form estimand metadata.

estimand_signature, design_signature

Canonical estimand and realized-design provenance used by comparison utilities.

call

Matched function call.

misc

List of root-finding diagnostics, including bounds, endpoint reliabilities, global achievable range, root topology, branch selection, and a legacy-compatible uniroot_result for an interior crossing.

The input object, invisibly.

An object of class "summary.eqc_result" containing key calibration results.

Details

Reliability Metrics

The function calibrates the average-information reliability definition:

  • Average-information ("info"/"tilde", default): Uses the arithmetic mean, \(\tilde{\rho}(c) = \sigma^2_\theta \bar{\mathcal{J}}(c) / (\sigma^2_\theta \bar{\mathcal{J}}(c) + 1)\). By Jensen's inequality, \(\tilde{\rho} \geq \bar{w}\), so this metric typically yields higher reliability values. This is the recommended default for EQC because the objective function \(\tilde{\rho}(c) - \rho^*\) is stable on practical search intervals. The implementation nevertheless scans the complete user-supplied interval on log(c), polishes detected local extrema and successfully bracketed sign-changing crossings, records any near-target fallback separately, and applies an explicit root policy. It does not assume that the empirical curve is globally monotone or unimodal.

MSEM-based ("msem"/"bar") reliability uses the harmonic mean of test information, \(\bar{w}(c) = \sigma^2_\theta / (\sigma^2_\theta + E[1/\mathcal{J}(\theta;c)])\). This metric is rejected by eqc_calibrate() because the objective \(\bar{w}(c) - \rho^*\) may be non-monotone (see the reliability-targeted simulation manuscript, Section 4.3). Although the shared scanner can diagnose such topology, MSEM remains outside EQC's calibration contract. Use sac_calibrate if you need to target \(\bar{w}\) directly.

WLE vs EAP Reliability Interpretation

WLE and EAP reliability use different estimators and variance bases, so they are complementary external diagnostics rather than ordered versions of one estimand. EAP is more closely related to MSEM-based population reliability; neither coefficient is identical to EQC's information-based target. The public compute_reliability_tam() helper supports Rasch/2PL only. Phase 7's direct TAM 3PL check was EAP-only because a validated TAM 3PL WLE path was unavailable.

See also

sac_calibrate for the stochastic approximation alternative, compute_rho_bar and compute_rho_tilde for reliability computation utilities, compute_reliability_tam for TAM validation.

Examples

# Basic EQC calibration with parametric items (fast)
# \donttest{
eqc_result <- eqc_calibrate(
  target_rho = 0.80,
  n_items = 25,
  model = "rasch",
  latent_shape = "normal",
  item_source = "parametric",
  M = 5000L,
  seed = 42
)
print(eqc_result)
#> 
#> =======================================================
#>   Empirical Quadrature Calibration (EQC) Results
#> =======================================================
#> 
#> Calibration Summary:
#>   Model                        : RASCH
#>   Target reliability (rho*)    : 0.8000
#>   Achieved reliability         : 0.8000
#>   Absolute error               : 4.64e-08
#>   Scaling factor (c*)          : 0.8995
#> 
#> Design Parameters:
#>   Number of items (I)          : 25
#>   Quadrature points (M)        : 5000
#>   Reliability metric           : Average-information (tilde)
#>   Latent variance              : 1.0099
#> 
#> Convergence:
#>   Root status                  : uniroot_success
#>   Calibration status           : ok
#>   Roots detected               : 1
#>   Search bracket               : [0.300, 3.000]
#>   Bracket reliabilities        : [0.3539, 0.9550]
#> 
#> Parameter Summaries:
#>   theta:        mean = -0.014, sd = 1.005
#>   beta:         mean = 0.000, sd = 0.861, range = [-2.17, 1.45]
#>   lambda_base:  mean = 1.000, sd = 0.000
#>   lambda_scaled: mean = 0.899, sd = 0.000
#> 

# 3PL: guessing is generated once with the fixed item form and is not scaled.
eqc_3pl <- eqc_calibrate(
  target_rho = 0.70,
  n_items = 12L,
  model = "3pl",
  item_params = list(
    guessing_params = list(distribution = "fixed", value = 0.20)
  ),
  M = 1500L,
  c_bounds = c(0.1, 5),
  seed = 5102L
)
stopifnot(all(eqc_3pl$guessing_vec == 0.20))
# }

if (FALSE) { # \dontrun{
# EQC with IRW difficulties (requires irw package)
if (requireNamespace("irw", quietly = TRUE)) {
  eqc_result2 <- eqc_calibrate(
    target_rho = 0.80,
    n_items = 25,
    model = "rasch",
    item_source = "irw",
    seed = 42,
    verbose = TRUE
  )
}
} # }