Skip to content

Commit 3458ce8

Browse files
committed
Reject degenerate recovery simulations
1 parent 8cb3635 commit 3458ce8

4 files changed

Lines changed: 34 additions & 6 deletions

File tree

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
* DK model summaries and validation examples correctly identify learning as
3232
`gk + dk`.
3333

34+
* `validate_recovery()` now rejects degenerate generating models at the
35+
parameter boundary, where recovery diagnostics are not meaningful.
36+
3437
# version 0.7.0 2026-08-02
3538

3639
This release incorporates 0.6.0, which was tagged but never submitted to

R/model-criticism.R

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ cross_sectional_learning_score <- function(
666666
#' Performs Monte Carlo simulations to assess parameter recovery of the
667667
#' LCA model. Useful for validating estimator performance.
668668
#'
669-
#' @param true_params Named numeric vector of true parameters.
669+
#' @param true_params Named numeric vector of strictly interior true parameters.
670670
#' For no-DK model: c(gg=, gk=, kk=, gamma=)
671671
#' For DK model: c(gg=, gk=, gd=, kk=, dg=, dk=, dd=, gamma=)
672672
#' @param n Integer. Sample size per simulation. Default 500.
@@ -735,8 +735,20 @@ validate_recovery <- function(true_params, n = 500, n_items = 2,
735735
abs(sum(class_weights) - 1) > sqrt(.Machine$double.eps)) {
736736
stop("Latent-class weights in true_params must be probabilities that sum to 1.", call. = FALSE)
737737
}
738-
if (true_params[["gamma"]] < 0 || true_params[["gamma"]] > 1) {
739-
stop("true_params$gamma must be a probability between 0 and 1.", call. = FALSE)
738+
if (any(class_weights == 0 | class_weights == 1)) {
739+
stop(
740+
paste(
741+
"Latent-class weights in true_params must be strictly between 0 and 1",
742+
"for recovery validation."
743+
),
744+
call. = FALSE
745+
)
746+
}
747+
if (true_params[["gamma"]] <= 0 || true_params[["gamma"]] >= 1) {
748+
stop(
749+
"true_params$gamma must be strictly between 0 and 1 for recovery validation.",
750+
call. = FALSE
751+
)
740752
}
741753

742754
estimates <- with_preserved_seed(seed, {

man/validate_recovery.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-simulate.R

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,19 @@ test_that("validate_recovery requires a named feasible generating model", {
164164
validate_recovery(invalid_gamma, n = 100, n_sims = 2),
165165
"gamma"
166166
)
167+
boundary_weight <- valid
168+
boundary_weight["gg"] <- 0
169+
boundary_weight["kk"] <- 0.70
170+
expect_error(
171+
validate_recovery(boundary_weight, n = 100, n_sims = 2),
172+
"strictly between"
173+
)
174+
boundary_gamma <- valid
175+
boundary_gamma["gamma"] <- 0
176+
expect_error(
177+
validate_recovery(boundary_gamma, n = 100, n_sims = 2),
178+
"strictly between"
179+
)
167180
})
168181

169182
test_that("validate_recovery preserves caller RNG state", {
@@ -176,12 +189,12 @@ test_that("validate_recovery preserves caller RNG state", {
176189
expect_identical(before, after)
177190
})
178191

179-
test_that("validate_recovery surfaces a failed replicate", {
192+
test_that("validate_recovery rejects degenerate generating models", {
180193
degenerate <- c(gg = 0, gk = 0, kk = 1, gamma = 0)
181194

182195
expect_error(
183196
validate_recovery(degenerate, n = 10, n_items = 1, n_sims = 1, seed = 1),
184-
"Simulation 1 failed: Optimization did not converge"
197+
"strictly between"
185198
)
186199
})
187200

0 commit comments

Comments
 (0)