diff --git a/NEWS.md b/NEWS.md index ff022231..190769cc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # bayesplot (development version) +* Validate user-provided `pit` values in `ppc_loo_pit_data()` using `validate_pit()` to reject invalid inputs (non-numeric, out of range, NAs) at the entry point instead of in internal helpers. * Eliminate redundant data processing in `mcmc_areas_data()` by reusing the prepared MCMC array for both interval and density computation. * Validate equal chain lengths in `validate_df_with_chain()`, reject missing chain labels, and renumber data-frame chain labels internally when converting diff --git a/R/ppc-loo.R b/R/ppc-loo.R index 2f91c5b5..7f910794 100644 --- a/R/ppc-loo.R +++ b/R/ppc-loo.R @@ -302,7 +302,7 @@ ppc_loo_pit_data <- boundary_correction = TRUE, grid_len = 512) { if (!is.null(pit)) { - stopifnot(is.numeric(pit), is_vector_or_1Darray(pit)) + pit <- validate_pit(pit) inform("'pit' specified so ignoring 'y','yrep','lw' if specified.") } else { suggested_package("rstantools") @@ -795,14 +795,6 @@ ppc_loo_ribbon <- # Generate boundary corrected values via a linear convolution using a # 1-D Gaussian window filter. This method uses the "reflection method" # to estimate these pvalues and helps speed up the code - if (any(is.infinite(x))) { - warn(paste( - "Ignored", sum(is.infinite(x)), - "Non-finite PIT values are invalid for KDE boundary correction method" - )) - x <- x[is.finite(x)] - } - if (grid_len < 100) { grid_len <- 100 } @@ -824,6 +816,10 @@ ppc_loo_ribbon <- xs <- (grid_breaks[2:n_breaks] + grid_breaks[1:(n_breaks - 1)]) / 2 + if (all(is.na(bc_pvals))) { + abort("KDE boundary correction produced all NA values.") + } + first_nonNA <- utils::head(which(!is.na(bc_pvals)), 1) last_nonNA <- utils::tail(which(!is.na(bc_pvals)), 1) bc_pvals[1:first_nonNA] <- bc_pvals[first_nonNA] diff --git a/tests/testthat/test-ppc-loo.R b/tests/testthat/test-ppc-loo.R index 83cdaf50..d910a8c8 100644 --- a/tests/testthat/test-ppc-loo.R +++ b/tests/testthat/test-ppc-loo.R @@ -59,17 +59,23 @@ test_that("ppc_loo_pit_overlay works with boundary_correction=FALSE", { expect_gg(p1) }) -test_that(".kde_correction warns when PIT values are non-finite", { - set.seed(123) - pit_vals <- c(stats::runif(500), Inf) - expect_warning( - out <- .kde_correction(pit_vals, bw = "nrd0", grid_len = 128), - "Non-finite PIT values are invalid" +test_that("ppc_loo_pit_data validates user-provided pit values", { + expect_error( + ppc_loo_pit_data(pit = c(0.5, Inf)), + "between 0 and 1" + ) + expect_error( + ppc_loo_pit_data(pit = c(-1, 0.5)), + "between 0 and 1" + ) + expect_error( + ppc_loo_pit_data(pit = c(0.5, NA)), + "NAs not allowed" + ) + expect_error( + ppc_loo_pit_data(pit = "not numeric"), + "is.numeric" ) - expect_type(out, "list") - expect_true(all(c("xs", "bc_pvals") %in% names(out))) - expect_equal(length(out$xs), 128) - expect_equal(length(out$bc_pvals), 128) }) test_that("ppc_loo_pit_qq returns ggplot object", {