Stochastic Approximation Calibration (Algorithm 2: SAC)
sac_calibrate.Rdsac_calibrate() uses branch-guarded Robbins–Monro stochastic
approximation to choose a positive global discrimination multiplier that
targets a marginal reliability estimand for a unidimensional Rasch, 2PL, or
3PL item generator.
Usage
sac_calibrate(
target_rho,
n_items,
model = c("rasch", "2pl", "3pl"),
latent_shape = "normal",
item_source = "parametric",
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,
root_policy = "lowest_increasing",
preflight_controls = list(),
evaluation_controls = list()
)
# S3 method for class 'sac_result'
print(x, digits = 4, ...)
# S3 method for class 'sac_result'
summary(object, ...)
# S3 method for class 'summary.sac_result'
print(x, digits = 4, ...)
# S3 method for class 'sac_result'
coef(object, ...)
# S3 method for class 'sac_result'
predict(object, newdata = NULL, theta_vec = NULL, ...)Arguments
- target_rho
Finite numeric scalar in
(0, 1). Target marginal reliability.- n_items
Positive integer. Number of items per generated form.
- model
Character. One of
"rasch","2pl", or"3pl". Rasch fixes baseline discriminations at one. In the 3PL model,item_params$guessing_params(orcustom_params$guessingfor a custom source) supplies the lower asymptotes. SAC scales discrimination only and uses the fixed logistic conventionD = 1.- latent_shape
Character shape passed to
sim_latentG().- item_source
Character source passed to
sim_item_params(). The default,"parametric", has no external data dependency;"irw"requires the optional Item Response Warehouse package.- latent_params
Named list of additional arguments passed to
sim_latentG().- item_params
Named list of additional arguments passed to
sim_item_params().- reliability_metric
Character reliability estimand.
"msem"(the default) and its synonym"bar"target reciprocal-information MSEM reliability, \(\bar w\)."info"and its synonym"tilde"target average-information reliability, \(\tilde\rho\). The storedmetricis canonicalized to"msem"or"info". Population MSEM is rejected for the built-in untruncated"heavy_tail"distribution because its reciprocal-information expectation is not finite.- c_init
NULL, a positive numeric scalar, or aneqc_result. WithNULL, 3PL uses the selected preflight root; Rasch/2PL uses APC when APC lies inside the selected branch and otherwise uses the preflight root. A numeric initializer is projected into the effective branch. An EQC warm start is accepted only when target, model, item count, canonical metric, fixed-form scope, realized item form, and increasing branch agree.- M_per_iter
Positive integer. Ability draws per Robbins–Monro iteration. Default
500L.- M_pre
Integer at least two. Draws used once to estimate the population latent variance held fixed during calibration. Default
10000L.- n_iter
Positive integer. Robbins–Monro iterations. Default
300L.- burn_in
Non-negative integer less than
n_iter. Iterations throughburn_inare excluded from Polyak–Ruppert averaging. The default isfloor(n_iter / 2).- step_params
Named list overriding
a = 1,A = 50, orgamma = 0.67in \(a_n=a/(n+A)^\gamma\).amust be positive,Anon-negative, andgammain(0.5, 1].- c_bounds
Positive increasing length-two numeric vector. The preflight scanner never expands these requested bounds. Iterates are projected to the selected increasing branch after applying its safety margin.
- resample_items
Logical.
FALSEcalibrates one realized fixed form and setsitem_scope = "fixed_form".TRUE(the default) draws a form at each iteration, targets the item-superpopulation mean, and setsitem_scope = "item_superpopulation".- seed
Optional integer seed. When supplied, the caller's RNG state is restored on exit; isolated deterministic substreams are used for preflight and independent post-calibration evaluation.
- verbose
Logical or non-negative numeric verbosity level. Level one reports checkpoints; level two reports every iteration.
- root_policy
Character root-selection policy:
"lowest_increasing","nearest_increasing","lowest_any", or"highest_any". The default selects the lowest admissible increasing root. Tangent and plateau roots are not made admissible by SAC's public controls.- preflight_controls
Named list of branch-preflight overrides:
n_forms(default8Lfor item-superpopulation calibration),M(defaultmin(M_pre, max(500L, M_per_iter))),split_check(defaultresample_items),split_log_tolerance(defaultlog(1.5)),root_controls(a named list passed to the topology scanner),branch_margin(default0.01),max_consecutive_hits(default5L), andmax_post_burn_hit_rate(default0.10). Unknown names are rejected.- evaluation_controls
Named list controlling the independent final evaluation:
n_forms(default20L),Mper form (defaultmax(1000L, M_per_iter)),conf_level(default0.95), andprobs(defaultc(0.025, 0.5, 0.975)). Unknown names are rejected. For a fixed form, theta blocks are concatenated before computingachieved_rho; for item-superpopulation calibration, form reliabilities are averaged.- x
A
sac_resultorsummary.sac_result, as appropriate.- digits
Number of decimal places used by print methods.
- ...
Additional arguments passed to or from methods. Current SAC methods do not otherwise use them.
- object
A
sac_result.- newdata
Optional numeric vector of positive discrimination scales for
predict.sac_result().NULLreturns the storedachieved_rho.- theta_vec
Optional finite ability vector for prediction. When supplied, its sample variance defines the prediction variance basis.
Value
sac_calibrate() returns a sac_result list. Its historical fields
remain present and v0.3 metadata are appended:
- Calibration
c_staris the Polyak–Ruppert scale;c_finalis the last iterate;target_rho,achieved_rho,achieved_se,achieved_distribution,metric, andcalibration_statusdescribe the independently evaluated result.M_finalis the total number of final evaluation theta draws.- Trajectories
trajectorystores updated scales andrho_trajectorystores reliabilities recomputed at those same scales.evaluation_trajectory,rho_update_trajectory,raw_trajectory,step_size_trajectory,gradient_trajectory,projected,projection_side,projection_source, anditeration_tracepreserve the full update audit trail.- Algorithm settings
theta_var,model,n_items,n_iter,burn_in,M_per_iter,M_pre,step_params,c_bounds,requested_c_bounds,c_init,init_method,preflight_controls, andevaluation_controlsrecord the effective run settings.- Item design
beta_vec,lambda_base,lambda_scaled,guessing_vec,items_base,items_calib,item_design, anditem_scopedescribe the representative stored form. Rasch/2PL results store zero guessing; 3PL results preserve the generated lower asymptotes. For item-superpopulation runs the representative form is not itself the estimand.- Contracts and diagnostics
schema_version,estimand_signature,design_signature,calibration_design,evaluation_design,convergence,preflight,branch,rng_provenance,warm_start,representative_achieved_rho,theta_quad, andcallpreserve estimand, topology, evaluation, RNG, and provenance diagnostics.
print() returns its input invisibly; summary() returns a
summary.sac_result; coef() returns calibrated item parameters (including
guessing for 3PL); and predict() returns stored or recomputed reliability.
Details
The first 18 arguments preserve the v0.2 positional API. The v0.3 branch
and evaluation controls are appended after verbose.
Estimand and branch contract
SAC first scans the requested log-scale interval and must resolve an
admissible increasing root branch. A classed preflight error is raised when
the target is infeasible, a stable branch cannot be resolved, or only an
inadmissible boundary/decreasing branch is available. The effective branch
bounds are then used as projection guards. Repeated branch-bound contact or
a non-positive final branch slope produces calibration_status = "branch_lost" rather than silently treating the run as converged.
reliability_metric and item_scope are both part of the estimand. Thus an
EQC result (metric = "info", fixed form) is directly comparable to SAC
only when SAC also uses reliability_metric = "info" and
resample_items = FALSE on that same form. Passing the compatible EQC object
as c_init without overriding item-generation arguments reuses its form.
3PL and external validation
The 3PL probability and Fisher-information kernels use D = 1; the global
scale multiplies discrimination and never guessing. The package's public
compute_reliability_tam() helper intentionally supports Rasch and 2PL only
because the validated TAM workflow requires both WLE and EAP outputs. Phase
7's 3PL external oracle is an EAP-only validation path; TAM 3PL WLE is not a
supported public-package workflow. Do not interpret WLE and EAP as ordered
versions of the same estimand.
spc_calibrate() remains a deprecated forwarding alias.
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.
Examples
# \donttest{
# Small fixed-form 3PL calibration with explicit lower asymptotes.
form <- list(
custom_params = list(
beta = c(-1.1, -0.55, -0.1, 0.35, 0.8, 1.25),
lambda = c(0.75, 0.9, 1.05, 1.2, 1.35, 1.5),
guessing = c(0.08, 0.12, 0.16, 0.20, 0.24, 0.28)
),
center_difficulties = FALSE
)
fit <- sac_calibrate(
target_rho = 0.40,
n_items = 6L,
model = "3pl",
item_source = "custom",
item_params = form,
reliability_metric = "info",
M_per_iter = 128L,
M_pre = 512L,
n_iter = 8L,
burn_in = 4L,
c_bounds = c(0.1, 3),
resample_items = FALSE,
seed = 7601L,
preflight_controls = list(
M = 256L,
split_check = FALSE,
root_controls = list(min_grid = 65L, max_evals = 257L)
),
evaluation_controls = list(n_forms = 4L, M = 512L)
)
print(fit)
#>
#> =======================================================
#> Stochastic Approximation Calibration (SAC) Results
#> =======================================================
#>
#> Calibration Summary:
#> Model : 3PL
#> Item scope : fixed_form
#> Target reliability (rho*) : 0.4000
#> Achieved reliability : 0.3955
#> Achieved reliability SE : 0.0022
#> Evaluation forms : 4
#> Absolute error : 4.50e-03
#> Scaling factor (c*) : 0.9408
#> Calibration status : ok
#> Selected preflight root : 0.9384
#> Selected branch : id=1, increasing, [0.1, 3]
#> Root policy : lowest_increasing
#> Guessing (min/mean/max) : 0.0800 / 0.1800 / 0.2800
#>
#> Algorithm Settings:
#> Number of items (I) : 6
#> M per iteration : 128
#> M for variance pre-calc : 512
#> Total iterations : 8
#> Burn-in : 4
#> Reliability metric : Average-information (tilde)
#> Step params: a=1.00, A=50, gamma=0.67
#>
#> Convergence Diagnostics:
#> Initialization method : preflight_root
#> Initial c_0 : 0.9384
#> Final iterate c_n : 0.9412
#> Polyak-Ruppert c* : 0.9408
#> Pre-calculated theta_var : 0.8879
#> Converged : Yes
#> Post-burn-in SD : 0.0007
#> Final iter gradient : +0.0017
#> Gradient at c* : -0.0045
#> Projection count : 0 (0.0%)
#> Status flags : ok
#>
coef(fit)
#> item_id beta lambda_base lambda_scaled c_star guessing
#> 1 1 -1.10 0.75 0.7055645 0.9407526 0.08
#> 2 2 -0.55 0.90 0.8466774 0.9407526 0.12
#> 3 3 -0.10 1.05 0.9877903 0.9407526 0.16
#> 4 4 0.35 1.20 1.1289032 0.9407526 0.20
#> 5 5 0.80 1.35 1.2700161 0.9407526 0.24
#> 6 6 1.25 1.50 1.4111290 0.9407526 0.28
predict(fit, newdata = c(0.5, 1))
#> c=0.5 c=1.0
#> 0.1905445 0.4176017
# }