Stochastic Approximation Calibration (Algorithm 2: SPC/SAC)
Source:R/spc_calibrate.R
spc_calibrate.Rdspc_calibrate() implements Algorithm 2 (Stochastic Approximation
Calibration, SPC/SAC) for reliability-targeted IRT simulation using the
Robbins-Monro stochastic approximation algorithm.
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 iteratively searches for a
global discrimination scale \(c^* > 0\) such that the population
reliability \(\rho(c)\) of the Rasch/2PL model is approximately equal to
\(\rho^*\).
SPC complements EQC (Algorithm 1) by:
Providing an independent validation of EQC calibration results.
Enabling calibration to the exact marginal reliability \(\bar{w}\) (not just the average-information approximation \(\tilde{\rho}\)).
Handling complex data-generating processes where analytic information functions may be unavailable.
The algorithm uses the Robbins-Monro update rule: $$c_{n+1} = c_n - a_n \cdot (\hat{\rho}_n - \rho^*)$$
where \(a_n = a / (n + A)^\gamma\) is a decreasing step size sequence satisfying \(\sum a_n = \infty\) and \(\sum a_n^2 < \infty\).
Usage
spc_calibrate(
target_rho,
n_items,
model = c("rasch", "2pl"),
latent_shape = "normal",
item_source = "irw",
latent_params = list(),
item_params = list(),
reliability_metric = c("msem", "info", "bar", "tilde"),
c_init = NULL,
M_per_iter = 500L,
M_pre = 10000L,
n_iter = 300L,
burn_in = NULL,
step_params = list(),
c_bounds = c(0.01, 20),
resample_items = TRUE,
seed = NULL,
verbose = FALSE
)
sac_calibrate(
target_rho,
n_items,
model = c("rasch", "2pl"),
latent_shape = "normal",
item_source = "irw",
latent_params = list(),
item_params = list(),
reliability_metric = c("msem", "info", "bar", "tilde"),
c_init = NULL,
M_per_iter = 500L,
M_pre = 10000L,
n_iter = 300L,
burn_in = NULL,
step_params = list(),
c_bounds = c(0.01, 20),
resample_items = TRUE,
seed = NULL,
verbose = FALSE
)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"or"2pl". For"rasch", all baseline discriminations are set to 1 before scaling.- 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."irw","parametric","hierarchical","custom").- 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 SPC:
"msem"MSEM-based marginal reliability (theoretically exact, targets \(\bar{w}\)).
"info"Average-information reliability (faster, targets \(\tilde{\rho}\)).
Synonyms:
"bar"for"msem","tilde"for"info".- c_init
Numeric,
eqc_resultobject, or NULL. Initial value for the scaling factor \(c_0\).If an
eqc_resultobject is provided, itsc_staris used (warm start).If a numeric value is provided, it is used directly.
If NULL, initialized using Analytic Pre-Calibration (APC).
Providing a warm start from EQC greatly accelerates convergence.
- M_per_iter
Integer. Number of Monte Carlo samples per iteration for estimating reliability. Default: 500. Larger values reduce variance but increase computation time.
- M_pre
Integer. Number of Monte Carlo samples for pre-calculating the latent variance \(\sigma^2_\theta\). Default: 10000. This variance is fixed throughout the iterations for stability. This is a CRITICAL parameter for numerical stability.
- n_iter
Integer. Total number of Robbins-Monro iterations. Default: 300.
- burn_in
Integer. Number of initial iterations to discard before Polyak-Ruppert averaging. Default:
floor(n_iter / 2).- step_params
List. Parameters controlling the step size sequence:
aBase step size (default: 1.0)
AStabilization constant (default: 50)
gammaDecay exponent (default: 0.67, i.e., 2/3)
- c_bounds
Numeric length-2 vector. Projection bounds for \(c\). Iterates are clipped to this interval after each update. Default: c(0.01, 20).
- resample_items
Logical. If TRUE (default), resample item parameters at each iteration. If FALSE, fix item parameters across all iterations (reduces variance but may introduce bias).
- seed
Optional integer for reproducibility.
- verbose
Logical or integer. If TRUE or >= 1, print progress messages. If >= 2, print detailed iteration-level output.
Value
An object of class "spc_result" (a list) with elements:
c_starCalibrated discrimination scale (Polyak-Ruppert average).
c_finalFinal iterate \(c_{n_{iter}}\).
target_rhoTarget reliability \(\rho^*\).
achieved_rhoEstimated reliability at \(c^*\) (post-calibration).
theta_varPre-calculated latent variance used throughout.
trajectoryNumeric vector of all iterates.
rho_trajectoryNumeric vector of reliability estimates.
init_methodCharacter indicating initialization method.
metricReliability metric used.
convergenceList with convergence diagnostics.
References
Robbins, H., & Monro, S. (1951). A stochastic approximation method. The Annals of Mathematical Statistics, 22(3), 400–407.
Polyak, B. T., & Juditsky, A. B. (1992). Acceleration of stochastic approximation by averaging. SIAM Journal on Control and Optimization, 30(4), 838–855.
See also
eqc_calibrate for the faster deterministic Algorithm 1,
compute_rho_bar and compute_rho_tilde for
reliability computation utilities,
compare_eqc_spc for comparing EQC and SPC results.
Examples
if (FALSE) { # \dontrun{
# Example 1: Basic SPC calibration
spc_result <- spc_calibrate(
target_rho = 0.75,
n_items = 20,
model = "rasch",
n_iter = 200,
seed = 12345,
verbose = TRUE
)
print(spc_result)
plot(spc_result)
# Example 2: Warm start from EQC (RECOMMENDED)
eqc_result <- eqc_calibrate(
target_rho = 0.80,
n_items = 25,
model = "2pl",
M = 10000,
seed = 42
)
spc_result <- spc_calibrate(
target_rho = 0.80,
n_items = 25,
model = "2pl",
c_init = eqc_result, # Direct EQC object passing!
n_iter = 100,
seed = 42
)
# Compare EQC and SPC results
cat(sprintf("EQC c* = %.4f, SPC c* = %.4f\n",
eqc_result$c_star, spc_result$c_star))
} # }