Empirical Quadrature Calibration (Algorithm 1: EQC)
eqc_calibrate.Rdeqc_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:
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.
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.
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_paramscontrols the item lower asymptotes; calibration scales discrimination only and uses the fixed logistic conventionD = 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. Usesac_calibratefor 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 baselinec = 1as 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 unlessallow_tangentorallow_plateau, respectively, is enabled.- root_controls
Named list of advanced topology-scanner controls. The supplied
c_boundsare never expanded.- allow_tangent
Logical. If
TRUE, a detected tangent root may be selected by an"*_any"policy. The default isFALSE.- 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 isFALSE.- 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_starCalibrated discrimination scale \(c^*\).
target_rhoTarget reliability \(\rho^*\).
achieved_rhoEmpirical quadrature estimate \(\hat\rho_M(c^*)\).
metricReliability metric used.
modelMeasurement model.
n_itemsNumber of items.
MEmpirical quadrature sample size.
theta_quadLength-M vector of quadrature abilities.
theta_varSample variance of theta_quad.
beta_vecItem difficulties from the baseline item design.
lambda_baseBaseline (unscaled) item discriminations.
lambda_scaledScaled item discriminations (
lambda_base * c_star).guessing_vecItem lower asymptotes. New Rasch/2PL objects store an all-zero vector; 3PL objects store the generated guessing parameters.
items_baseitem_params object with scale = 1 (baseline).
items_calibitem_params object with discriminations scaled by c_star.
schema_version,item_scopeAdditive result-schema and fixed-form estimand metadata.
estimand_signature,design_signatureCanonical estimand and realized-design provenance used by comparison utilities.
callMatched function call.
miscList of root-finding diagnostics, including bounds, endpoint reliabilities, global achievable range, root topology, branch selection, and a legacy-compatible
uniroot_resultfor 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 onlog(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
)
}
} # }