Nothing
# Outer Pareto-k-hat for the joint nested-Laplace backend (gcol33/tulpa#42).
#
# The joint hyperparameter space is heterogeneous: positive scales (sigma,
# tau, phi_*) integrate on the log scale, the BYM2 mixing weight (rho) on the
# logit scale, the copy coefficient (alpha) on the identity scale, and the
# CAR_proper correlation (rho_car) has an eigenvalue-bounded support that is
# not safely guessable -> the fit declines to quad-ESS rather than report a
# wrong k-hat. These tests cover: (1) the recovery direction (proposal-covers
# -> low k, heavier-than-proposal -> high k) through the joint transform
# driver; (2) finite k-hat on all-identifiable single-block (icar / bym2) and
# multi-block fits; (3) decline on rho_car; (4) the diagnose_k / k_samples
# gating + RNG non-perturbation.
# --------------------------------------------------------------------------- #
# Helpers #
# --------------------------------------------------------------------------- #
.jpk_chain_adj <- function(n_s) {
nbr <- lapply(seq_len(n_s),
function(s) setdiff(c(s - 1L, s + 1L), c(0L, n_s + 1L)))
n_neighbors <- vapply(nbr, length, integer(1))
list(
adj_row_ptr = as.integer(c(0L, cumsum(n_neighbors))),
adj_col_idx = as.integer(unlist(nbr)) - 1L,
n_neighbors = as.integer(n_neighbors),
n_spatial_units = n_s
)
}
# Two-arm fixture: binomial occupancy + gaussian positive sharing one spatial
# field, the positive arm copying it with coefficient alpha_true.
.jpk_sim <- function(N = 260, n_s = 24, sigma = 0.6, alpha_true = 1.0,
seed = 7) {
set.seed(seed)
spatial_idx <- sample.int(n_s, N, replace = TRUE)
rw <- cumsum(rnorm(n_s, 0, sigma / sqrt(n_s)))
phi_s <- rw - mean(rw)
x <- rnorm(N)
Xocc <- cbind(1, x)
eta_occ <- as.numeric(Xocc %*% c(-0.3, 0.5)) + phi_s[spatial_idx]
occur <- rbinom(N, 1, plogis(eta_occ))
is_pos <- occur == 1L
Xpos <- Xocc[is_pos, , drop = FALSE]
spi_pos <- spatial_idx[is_pos]
eta_pos <- as.numeric(Xpos %*% c(0.2, -0.4)) + alpha_true * phi_s[spi_pos]
y_pos <- rnorm(sum(is_pos), eta_pos, 0.5)
list(N = N, n_s = n_s, spatial_idx = as.integer(spatial_idx),
Xocc = Xocc, occur = occur,
Xpos = Xpos, y_pos = y_pos, spi_pos = as.integer(spi_pos))
}
.jpk_arms <- function(sim) {
list(
occ = list(y = as.numeric(sim$occur), n_trials = rep(1L, sim$N),
X = sim$Xocc, spatial_idx = sim$spatial_idx,
re_idx = rep(0, sim$N), n_re_groups = 0L, sigma_re = 1.0,
family = "binomial", phi = 1.0),
pos = list(y = sim$y_pos, n_trials = rep(1L, length(sim$y_pos)),
X = sim$Xpos, spatial_idx = sim$spi_pos,
re_idx = rep(0, length(sim$y_pos)), n_re_groups = 0L,
sigma_re = 1.0, family = "gaussian", phi = 0.25)
)
}
# As .jpk_arms but declares the copy coefficient on the positive arm via its
# per-arm field_coef axis (the single-block copy spec).
.jpk_arms_alpha <- function(sim, grid) {
a <- .jpk_arms(sim)
a$pos$field_coef <- list(name = "alpha", grid = grid)
a
}
# --------------------------------------------------------------------------- #
# (5) Bootstrap outer Pareto-k: per-arm + RNG hygiene (gcol33/tulpa#127) #
# --------------------------------------------------------------------------- #
# The k-hat's sampling uncertainty is bootstrapped from one batch's raw
# log-ratios. The constructed single-axis res + analytic refit exercises the
# scorer directly, fast, with a known proposal-covers target; the multi-block
# fixtures exercise the per-arm bootstrap and the global-RNG hygiene.
.jpk_cover_res <- function() {
sg <- exp(seq(-3, 3, length.out = 61))
lw <- stats::dnorm(log(sg), 0, 1.2, log = TRUE)
w <- exp(lw - max(lw)); w <- w / sum(w)
list(theta_grid = matrix(sg, ncol = 1, dimnames = list(NULL, "sigma")),
weights = w, prior = list(type = "icar"))
}
# lt -> N(0, 0.8^2): target narrower than the grid-moment proposal (low k).
.jpk_cover_refit <- function(tm) { u <- log(tm[, "sigma"]); -0.5 * (u / 0.8)^2 - u }
test_that("control$k_refine / k_max_rounds validation (gcol33/tulpa#131)", {
sim <- .jpk_sim(seed = 95)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0))
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_refine = "bogus")), "k_refine")
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_max_rounds = -1L)), "k_max_rounds")
})
skip_on_cran_budget()
test_that(".joint_pareto_k declines a fit carrying an unguessable axis, and NAMES it", {
skip_on_cran_budget()
# A car_proper-typed single block with a rho_car axis: the resolver must
# decline rather than guess the eigenvalue-bounded support -- and say which
# axis stopped it, since that decline is PERMANENT for this family
# (gcol33/tulpa#295).
res <- list(theta_grid = matrix(c(0.5, 1.0, 0.8, 0.9), ncol = 2,
dimnames = list(NULL, c("sigma", "rho_car"))),
weights = c(0.5, 0.5), prior = list(type = "car_proper"))
tags <- .joint_pareto_axis_tags(res)
expect_true(tulpa:::.k_is_decline(tags))
expect_identical(tulpa:::.k_decline_label(tags), "unguessable_axis: rho_car")
kd <- .joint_pareto_k(res, function(tm) rep(0, nrow(tm)), n_samples = 200L)
expect_true(is.na(kd$pareto_k))
expect_identical(kd$declined, "unguessable_axis: rho_car")
expect_true(tulpa:::.k_decline_is_permanent(kd$declined))
})
test_that("each outer Pareto-k decline path reports its own reason", {
skip_on_cran_budget()
# gcol33/tulpa#295: "you turned it off", "this family can never be scored"
# and "the grid carries no weight" used to be one indistinguishable NA.
lm0 <- function(tm) rep(0, nrow(tm))
# A sub-floor draw budget: nothing about the fit is wrong.
ok <- list(theta_grid = matrix(c(0.5, 1, 2), ncol = 1,
dimnames = list(NULL, "sigma")),
weights = c(0.2, 0.5, 0.3), prior = list(type = "icar"))
expect_identical(.joint_pareto_k(ok, lm0, n_samples = 5L)$declined,
"draws_too_few")
# Weights that carry no mass -- a signal about the FIT.
dead <- ok; dead$weights <- c(0, 0, 0)
expect_identical(.joint_pareto_k(dead, lm0, n_samples = 200L)$declined,
"grid_too_small: no positive integration weight")
# A weight vector that does not match the grid -- an engine bug.
torn <- ok; torn$weights <- c(0.5, 0.5)
expect_identical(.joint_pareto_k(torn, lm0, n_samples = 200L)$declined,
"internal_inconsistency: weights do not match theta_grid rows")
# No grid at all.
expect_match(.joint_pareto_k(list(), lm0, n_samples = 200L)$declined,
"^not_applicable")
# A one-value axis: nothing to importance-sample along.
pinned <- list(theta_grid = matrix(c(1, 1), ncol = 1,
dimnames = list(NULL, "sigma")),
weights = c(0.5, 0.5), prior = list(type = "icar"))
expect_identical(.joint_pareto_k(pinned, lm0, n_samples = 200L)$declined,
"no_varying_axis")
})
test_that(".k_decline_note reads each reason back, and only unguessable_axis is permanent", {
skip_on_cran_budget()
for (r in tulpa:::.K_DECLINE_REASONS) {
expect_true(is.character(tulpa:::.k_decline_note(r)))
}
expect_null(tulpa:::.k_decline_note(NA_character_))
expect_true(tulpa:::.k_decline_is_permanent("unguessable_axis: rho_car"))
expect_false(tulpa:::.k_decline_is_permanent("not_requested"))
expect_false(tulpa:::.k_decline_is_permanent(NA_character_))
expect_error(tulpa:::.k_decline("nonsense"), "Unknown Pareto-k decline reason")
})
# --------------------------------------------------------------------------- #
# (6) Bootstrap outer Pareto-k uncertainty (gcol33/tulpa#127) #
# --------------------------------------------------------------------------- #
# The k-hat is a single fixed number for a fit + proposal; its sampling
# uncertainty is bootstrapped from ONE batch's raw importance log-ratios (no new
# inner solves). k_samples is the precision knob; k_tail_points an expert
# tail-threshold guard; k_conf_bands configurable band boundaries.
test_that(".psis_tail_len: automatic PSIS rule and the 20%-of-draws cap", {
skip_on_cran_budget()
expect_identical(.psis_tail_len(500L), 68L) # ceil(min(100, 3*sqrt(500)))
expect_identical(.psis_tail_len(5000L), 213L) # ceil(min(1000, 3*sqrt(5000)))
expect_identical(.psis_tail_len(500L, 60L), 60L) # below ceiling: honoured
expect_identical(.psis_tail_len(500L, 300L), 100L) # above floor(0.2*500): capped
expect_error(.psis_tail_len(500L, 0L), "positive integer")
})
test_that(".k_band_b / .within_one_band_b use (-Inf,0.5] (0.5,0.7] (0.7,Inf)", {
skip_on_cran_budget()
b <- c(0.5, 0.7)
expect_identical(.k_band_b(0.30, b), 0L) # good
expect_identical(.k_band_b(0.50, b), 0L) # boundary belongs to good (strict >)
expect_identical(.k_band_b(0.60, b), 1L) # ok
expect_identical(.k_band_b(0.70, b), 1L) # boundary belongs to ok
expect_identical(.k_band_b(0.80, b), 2L) # unreliable
expect_identical(.k_band_b(NA_real_, b), NA_integer_)
expect_true(.within_one_band_b(0.20, 0.45, b)) # both good
expect_true(.within_one_band_b(0.55, 0.69, b)) # both ok
expect_false(.within_one_band_b(0.45, 0.55, b)) # crosses 0.5
expect_false(.within_one_band_b(0.65, 0.75, b)) # crosses 0.7
expect_false(.within_one_band_b(NA_real_, 0.30, b)) # non-finite endpoint
})
# --------------------------------------------------------------------------- #
# Sample-size-dependent reliability boundary (gcol33/tulpa#128) #
# --------------------------------------------------------------------------- #
test_that(".ps_khat_threshold is the sample-size-dependent usable boundary", {
skip_on_cran_budget()
expect_equal(.ps_khat_threshold(100), 0.5, tolerance = 1e-9)
expect_equal(.ps_khat_threshold(200), 1 - 1 / log10(200), tolerance = 1e-12)
expect_equal(round(.ps_khat_threshold(200), 4), 0.5654)
# Cap at 0.7: 1 - 1/log10(S) = 0.7 at S ~ 2154, and the cap binds above it.
expect_equal(.ps_khat_threshold(2154), 0.7, tolerance = 1e-3)
expect_equal(.ps_khat_threshold(10000), 0.7)
expect_lt(.ps_khat_threshold(200), 0.7) # tighter than the fixed cap
})
test_that(".ps_conf_bands keeps the good cut at 0.5 with a size-dependent usable cut", {
skip_on_cran_budget()
b200 <- .ps_conf_bands(200)
expect_length(b200, 2L)
expect_identical(b200[1L], 0.5)
expect_equal(b200[2L], .ps_khat_threshold(200))
# Very small S: the usable cut drops below 0.5, so a single reliable cut.
bsmall <- .ps_conf_bands(50)
expect_length(bsmall, 1L)
expect_lt(bsmall, 0.5)
})
test_that("the size-dependent boundary changes the band verdict vs fixed c(0.5, 0.7)", {
skip_on_cran_budget()
# A bootstrap interval [0.55, 0.62] at S = 200 crosses the size-dependent usable
# cut (~0.565), so it is NOT confidently in one band; under the fixed ok band
# (0.5, 0.7] it would read confident. The size-dependent default is stricter.
bands_s <- .ps_conf_bands(200)
expect_false(.within_one_band_b(0.55, 0.62, bands_s))
expect_true(.within_one_band_b(0.55, 0.62, c(0.5, 0.7)))
})
test_that(".joint_pareto_k warns when k_tail_points exceeds the 20% cap", {
skip_on_cran_budget()
res <- .jpk_cover_res()
set.seed(99)
# cap = floor(0.2 * 600) = 120; a request of 250 warns and the used count caps.
expect_warning(
kd <- .joint_pareto_k(res, .jpk_cover_refit, n_samples = 600L,
k_bootstrap = 200L, k_tail_points = 250L),
"20% PSIS tail cap")
expect_identical(kd$pareto_k_tail_points_requested, 250L)
expect_lte(kd$pareto_k_tail_points, 120L)
})
test_that("control validation: k_bootstrap / k_tail_points / k_conf_bands", {
skip_on_cran_budget()
sim <- .jpk_sim(seed = 95)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0))
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_bootstrap = -1L)), "k_bootstrap")
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_tail_points = 0L)), "k_tail_points")
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_conf_bands = c(0.7, 0.5))), "k_conf_bands")
})
# --------------------------------------------------------------------------- #
# k_quality reliability front door (gcol33/tulpa#129) #
# --------------------------------------------------------------------------- #
test_that("control$k_quality validation rejects unknown levels", {
skip_on_cran_budget()
sim <- .jpk_sim(seed = 95)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0))
expect_error(
tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_quality = "great")), "k_quality")
})
test_that("k_quality classifies the miss the escalation reads (gcol33/tulpa#131)", {
skip_on_cran_budget()
# The verdict reads only the k-hat, the bootstrap band-confidence flag and
# the bands, so the classification is exercised without a fit.
mk <- function(k, conf) list(pareto_k = k, pareto_k_band_confident = conf,
pareto_k_conf_bands = c(0.5, 0.7))
att <- function(k, conf, q, diag = TRUE)
.joint_attach_k_quality(mk(k, conf), q, diagnose_k = diag,
diagnose_draws = 500L)
# Reached: there is no miss to classify.
r <- att(0.2, TRUE, "good")
expect_true(r$k_quality_reached)
expect_true(is.na(r$k_quality_miss))
# Confidently outside the requested band: the integration grid is the lever.
r <- att(0.9, TRUE, "good")
expect_false(r$k_quality_reached)
expect_identical(r$k_quality_miss, "resolution")
# The bootstrap CI straddles a boundary: the k-hat ESTIMATOR is the lever,
# whatever the point estimate is -- here it already sits in the good band and
# the fit still misses, which is the case grid refinement cannot fix.
r <- att(0.2, FALSE, "good")
expect_false(r$k_quality_reached)
expect_identical(r$k_quality_miss, "precision")
expect_identical(r$k_quality_best, "uncertain")
expect_match(r$k_quality_reason, "k_samples") # names a knob that exists
# "ok" admits the second band, so the same k-hat is a miss under "good" and
# not under "ok" -- the classification follows the target, not the k-hat.
expect_identical(att(0.6, TRUE, "good")$k_quality_miss, "resolution")
expect_true(is.na(att(0.6, TRUE, "ok")$k_quality_miss))
# No target band, and no diagnostic: nothing to classify either way.
expect_true(is.na(att(0.9, TRUE, "report")$k_quality_miss))
expect_true(is.na(att(0.9, TRUE, "good", diag = FALSE)$k_quality_miss))
})
skip_on_cran()
# --------------------------------------------------------------------------- #
# (1) Recovery direction through the joint transform driver #
# --------------------------------------------------------------------------- #
# A constructed single-axis (sigma, log scale) result with an analytic
# re-evaluation closure: the effective u-space target is set by subtracting
# the log-Jacobian inside `refit`, so `.joint_pareto_k` exercises the full
# forward-transform / proposal-fit / inverse-transform-plus-Jacobian / IS-PSIS
# composition with a known answer. Mirrors test-psis.R's Gaussian-covers /
# Student-t-heavy pair.
test_that(".joint_pareto_k is low when the proposal covers the target", {
skip_on_cran()
set.seed(101)
sg <- exp(seq(-3, 3, length.out = 61))
sd_prop <- 1.2
lw <- stats::dnorm(log(sg), 0, sd_prop, log = TRUE)
w <- exp(lw - max(lw)); w <- w / sum(w)
res <- list(theta_grid = matrix(sg, ncol = 1,
dimnames = list(NULL, "sigma")),
weights = w, prior = list(type = "icar"))
sd_tgt <- 0.8 # target narrower than proposal
refit_cover <- function(tm) {
u <- log(tm[, "sigma"]); -0.5 * (u / sd_tgt)^2 - u # lt -> N(0, sd_tgt^2)
}
kd <- .joint_pareto_k(res, refit_cover, n_samples = 3000L)
expect_true(is.finite(kd$pareto_k))
expect_lt(kd$pareto_k, 0.5)
expect_gt(kd$is_ess, 0)
})
test_that(".joint_pareto_k rises when the target is heavier than the proposal", {
skip_on_cran()
set.seed(102)
sg <- exp(seq(-3, 3, length.out = 61))
lw <- stats::dnorm(log(sg), 0, 1.0, log = TRUE)
w <- exp(lw - max(lw)); w <- w / sum(w)
res <- list(theta_grid = matrix(sg, ncol = 1,
dimnames = list(NULL, "sigma")),
weights = w, prior = list(type = "icar"))
refit_heavy <- function(tm) {
u <- log(tm[, "sigma"]); stats::dt(u, df = 2, log = TRUE) - u # lt -> t_2
}
kd <- .joint_pareto_k(res, refit_heavy, n_samples = 4000L)
expect_gt(kd$pareto_k, 0.5)
})
# --------------------------------------------------------------------------- #
# (2) Finite k-hat on all-identifiable single-block fits #
# --------------------------------------------------------------------------- #
test_that("joint ICAR copy fit reports a finite outer Pareto-k-hat", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 11)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.7, 1.1))
fit <- tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5)), prior = prior,
control = list(k_samples = 150L))
# (sigma -> log, alpha -> identity): both transformable, so k-hat is a
# finite data-dependent reading. The value is not asserted (a small-n
# alpha posterior is skewed, so a high reading is correct) -- pin the
# plumbing and the ESS range, as the re_cov / single-axis tests do.
expect_true(is.finite(fit$pareto_k))
expect_true(is.finite(fit$pareto_k_is_ess))
expect_gt(fit$pareto_k_is_ess, 0)
expect_lte(fit$pareto_k_is_ess, 150 + 1e-6)
expect_equal(fit$pareto_k_scope, "outer (hyperparameter) Gaussian proposal")
})
test_that("joint BYM2 copy fit reports a finite k-hat (log + logit + identity)", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 21)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "bym2", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, scale_factor = 1.0,
sigma_grid = c(0.4, 0.8), rho_grid = c(0.3, 0.7))
fit <- tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0.5, 1.0, 1.5)), prior = prior,
control = list(k_samples = 150L))
# Exercises all three transforms together: sigma (log), rho (logit on the
# BYM2 mixing weight), alpha (identity).
expect_true(is.finite(fit$pareto_k))
expect_gt(fit$pareto_k_is_ess, 0)
expect_lte(fit$pareto_k_is_ess, 150 + 1e-6)
})
# --------------------------------------------------------------------------- #
# (3) Decline on CAR_proper's rho_car #
# --------------------------------------------------------------------------- #
test_that("joint CAR_proper copy fit declines k-hat to quad-ESS", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 31)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "car_proper", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors,
sigma_grid = c(0.5, 1.0), rho_car_grid = c(0.5, 0.9))
fit <- tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0.5, 1.0)), prior = prior,
control = list(k_samples = 100L))
# rho_car support is the adjacency eigenvalue interval -> declined, not
# guessed. The quad-ESS fallback (weights) is still available downstream.
expect_true(is.na(fit$pareto_k))
expect_true(is.na(fit$pareto_k_is_ess))
expect_gt(length(fit$weights), 1L)
})
# --------------------------------------------------------------------------- #
# (4) Multi-block path #
# --------------------------------------------------------------------------- #
test_that("joint multi-block (ICAR copy) reports a finite outer k-hat", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 41)
adj <- .jpk_chain_adj(sim$n_s)
prior_multi <- list(list(
type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.8),
spatial_idx = list(sim$spatial_idx, sim$spi_pos)))
fit <- tulpa_nested_laplace_joint(
responses = .jpk_arms(sim), prior = prior_multi,
copy = list(block = 1, arm = "pos", alpha_grid = c(0.5, 1.0, 1.5)),
control = list(k_samples = 150L))
expect_s3_class(fit, "tulpa_nested_laplace_joint_multi")
expect_true(is.finite(fit$pareto_k))
expect_gt(fit$pareto_k_is_ess, 0)
expect_lte(fit$pareto_k_is_ess, 150 + 1e-6)
})
# --------------------------------------------------------------------------- #
# (5) diagnose_k gating + RNG non-perturbation #
# --------------------------------------------------------------------------- #
test_that("diagnose_k = FALSE skips k-hat and leaves modes unchanged", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 51)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0, 1.5))
off <- tulpa_nested_laplace_joint(
responses = arms, prior = prior,
control = list(diagnose_k = FALSE))
expect_true(is.na(off$pareto_k)) # gated off
on <- tulpa_nested_laplace_joint(
responses = arms, prior = prior,
control = list(diagnose_k = TRUE, k_samples = 120L))
expect_true(is.finite(on$pareto_k))
# The inner solve is deterministic and the k-hat draws restore the RNG, so
# the integration result is bit-identical with and without the diagnostic.
expect_equal(on$log_marginal, off$log_marginal)
expect_equal(on$modes, off$modes)
})
test_that("a sub-floor k_samples declines to NA without paying the solves", {
skip_if_not_slow()
# gcol33/tulpa#51: k_samples below .PSIS_MIN_EVAL can never produce a usable
# GPD fit, so the diagnostic must decline (NA) up front rather than run every
# one of its inner solves and discard the result. The decline path costs no
# more than diagnose_k = FALSE.
sim <- .jpk_sim(seed = 71)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0, 1.5))
fit <- tulpa_nested_laplace_joint(
responses = arms, prior = prior,
control = list(diagnose_k = TRUE, k_samples = 20L))
expect_lt(20L, tulpa:::.PSIS_MIN_EVAL)
expect_true(is.na(fit$pareto_k))
expect_true(is.na(fit$pareto_k_is_ess))
# The fit itself is unaffected.
off <- tulpa_nested_laplace_joint(
responses = arms, prior = prior,
control = list(diagnose_k = FALSE))
expect_equal(fit$log_marginal, off$log_marginal)
})
test_that("warm-start + capped diagnostic iters leave the k-hat unchanged", {
skip_if_not_slow()
# The cost bound (gcol33/tulpa#51) warm-starts each diagnostic solve from the
# modal latent mode and caps its iterations. Converged draws keep their exact
# log-marginal and only negligible-weight tail draws are truncated, so the
# k-hat is unchanged. Compare the capped path against an uncapped reference
# built by overriding the cap to the full iteration budget.
sim <- .jpk_sim(seed = 73)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.8, 1.2))
arms <- .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5))
ctrl <- list(diagnose_k = TRUE, k_samples = 200L, max_iter = 80L,
adaptive_grid = FALSE)
capped <- tulpa_nested_laplace_joint(
responses = arms, prior = prior, control = ctrl)
old <- tulpa:::.K_DIAG_MAX_ITER
assignInNamespace(".K_DIAG_MAX_ITER", 10000L, ns = "tulpa")
on.exit(assignInNamespace(".K_DIAG_MAX_ITER", old, ns = "tulpa"), add = TRUE)
uncapped <- tulpa_nested_laplace_joint(
responses = arms, prior = prior, control = ctrl)
expect_true(is.finite(capped$pareto_k))
expect_equal(capped$pareto_k, uncapped$pareto_k, tolerance = 1e-3)
})
test_that("parallel diagnostic IS re-solves leave the k-hat unchanged (single-block)", {
skip_on_cran()
skip_if_not(parallel::detectCores() >= 2L,
"needs multi-core to exercise the parallel diagnostic path")
# The outer Pareto-k re-evaluates the inner joint marginal at each importance
# draw. Those re-solves are independent, so the diagnostic dispatches the
# whole batch across `n_threads_outer` (warm-started from the broadcast modal
# mode) instead of one-at-a-time. The converged per-draw log-marginal is
# warm-start- and thread-count-independent, so the k-hat must match the serial
# diagnostic to numerical noise (same RNG seed for the IS draws).
n_outer <- max(2L, min(4L, parallel::detectCores() - 1L))
sim <- .jpk_sim(seed = 83)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.8, 1.2))
ctrl <- function(n_to) list(diagnose_k = TRUE, k_samples = 200L,
n_threads = 1L, n_threads_outer = n_to,
adaptive_grid = FALSE,
var_of_means_consistency = FALSE)
serial <- tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5)), prior = prior,
control = ctrl(1L))
parallel <- tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5)), prior = prior,
control = ctrl(n_outer))
expect_true(is.finite(serial$pareto_k))
expect_equal(parallel$pareto_k, serial$pareto_k, tolerance = 1e-3)
expect_equal(parallel$pareto_k_is_ess, serial$pareto_k_is_ess,
tolerance = 1e-3 * max(1, abs(serial$pareto_k_is_ess)))
})
test_that("parallel diagnostic IS re-solves leave the k-hat unchanged (multi-block)", {
skip_on_cran()
skip_if_not(parallel::detectCores() >= 2L,
"needs multi-core to exercise the parallel diagnostic path")
n_outer <- max(2L, min(4L, parallel::detectCores() - 1L))
sim <- .jpk_sim(seed = 87)
adj <- .jpk_chain_adj(sim$n_s)
prior_multi <- list(list(
type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.8),
spatial_idx = list(sim$spatial_idx, sim$spi_pos)))
cp <- list(block = 1, arm = "pos", alpha_grid = c(0, 0.5, 1.0, 1.5))
ctrl <- function(n_to) list(diagnose_k = TRUE, k_samples = 200L,
integration = "grid",
n_threads = 1L, n_threads_outer = n_to,
var_of_means_consistency = FALSE)
serial <- tulpa_nested_laplace_joint(
responses = .jpk_arms(sim), prior = prior_multi, copy = cp,
control = ctrl(1L))
parallel <- tulpa_nested_laplace_joint(
responses = .jpk_arms(sim), prior = prior_multi, copy = cp,
control = ctrl(n_outer))
expect_true(is.finite(serial$pareto_k))
expect_equal(parallel$pareto_k, serial$pareto_k, tolerance = 1e-3)
expect_equal(parallel$pareto_k_is_ess, serial$pareto_k_is_ess,
tolerance = 1e-3 * max(1, abs(serial$pareto_k_is_ess)))
})
test_that("diagnose_k does not perturb the global RNG state", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 61)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
set.seed(123)
s0 <- .Random.seed
invisible(tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0.5, 1.0, 1.5)), prior = prior,
control = list(diagnose_k = TRUE, k_samples = 100L)))
expect_identical(.Random.seed, s0)
})
test_that("the bootstrap diagnostic carries the per-arm uncertainty (multi-block by_arm)", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 92)
adj <- .jpk_chain_adj(sim$n_s)
prior_multi <- list(list(
type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.8),
spatial_idx = list(sim$spatial_idx, sim$spi_pos)))
cp <- list(block = 1, arm = "pos", alpha_grid = c(0, 0.5, 1.0, 1.5))
fit <- tulpa_nested_laplace_joint(
responses = .jpk_arms(sim), prior = prior_multi, copy = cp,
control = list(diagnose_k = "by_arm", integration = "grid",
k_samples = 200L, k_bootstrap = 300L))
expect_false(is.null(fit$pareto_k_by_arm))
expect_false(is.null(fit$pareto_k_by_arm_se_boot))
expect_false(is.null(fit$pareto_k_by_arm_ci_low))
expect_false(is.null(fit$pareto_k_by_arm_ci_high))
expect_false(is.null(fit$pareto_k_by_arm_band_confident))
expect_true(is.logical(fit$pareto_k_by_arm_band_confident))
ok <- is.finite(fit$pareto_k_by_arm)
expect_true(any(ok))
expect_true(all(fit$pareto_k_by_arm_ci_low[ok] <= fit$pareto_k_by_arm_ci_high[ok] + 1e-12))
expect_true(all(fit$pareto_k_by_arm_se_boot[ok] >= 0 | is.na(fit$pareto_k_by_arm_se_boot[ok])))
})
test_that("the bootstrap diagnostic does not perturb the global RNG state", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 93)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
set.seed(321)
s0 <- .Random.seed
invisible(tulpa_nested_laplace_joint(
responses = .jpk_arms_alpha(sim, c(0.5, 1.0, 1.5)), prior = prior,
control = list(k_samples = 150L, k_bootstrap = 300L)))
expect_identical(.Random.seed, s0)
})
test_that("bootstrap SE recovers the across-batch SD of the k-hat", {
skip_on_cran()
# Heavy-tailed importance ratios (proposal N(0,1), target ~ N(0,2^2)):
# log w = 0.375 x^2, x ~ proposal -> a heavy right tail, so k > 0.
set.seed(127)
gen_lr <- function(N) 0.375 * rnorm(N)^2
N <- 400L
# Truth: the empirical sampling SD of the single-batch k-hat over many batches.
ks <- vapply(seq_len(150L), function(i) tulpa_psis(gen_lr(N))$pareto_k, numeric(1))
across_sd <- stats::sd(ks[is.finite(ks)])
# Bootstrap SE from a SINGLE batch (median of a few single-batch runs).
ses <- vapply(seq_len(10L), function(i)
.tulpa_psis_k_uncertainty(gen_lr(N), n_boot = 500L)$se_boot, numeric(1))
boot_se <- stats::median(ses, na.rm = TRUE)
# Both estimate the SAME sampling SD; agree within bootstrap noise.
expect_gt(boot_se / across_sd, 0.6)
expect_lt(boot_se / across_sd, 1.6)
})
test_that(".tulpa_psis_k_uncertainty returns well-formed bootstrap + formula fields", {
skip_on_cran()
set.seed(128)
lr <- 0.375 * rnorm(400L)^2
u <- .tulpa_psis_k_uncertainty(lr, n_boot = 800L, conf_bands = c(0.5, 0.7))
expect_true(is.finite(u$pareto_k))
expect_true(is.finite(u$se_boot) && u$se_boot >= 0)
expect_true(is.finite(u$ci_low) && is.finite(u$ci_high))
expect_lte(u$ci_low, u$ci_high)
expect_true(is.finite(u$se_formula) && u$se_formula > 0)
expect_identical(u$tail_points, .psis_tail_len(length(lr)))
expect_true(is.logical(u$band_confident))
# k_bootstrap = 0 -> point k only, NA uncertainty.
u0 <- .tulpa_psis_k_uncertainty(lr, n_boot = 0L)
expect_true(is.finite(u0$pareto_k))
expect_true(is.na(u0$se_boot))
})
test_that(".tulpa_psis_k_uncertainty defaults conf_bands to the size-dependent bands", {
skip_on_cran()
set.seed(321)
lr <- 0.5 * rnorm(300L)^2
S <- sum(is.finite(lr))
set.seed(7); a <- .tulpa_psis_k_uncertainty(lr, n_boot = 400L, conf_bands = NULL)
set.seed(7); b <- .tulpa_psis_k_uncertainty(lr, n_boot = 400L,
conf_bands = .ps_conf_bands(S))
expect_identical(a$band_confident, b$band_confident)
})
test_that(".joint_pareto_k reports bootstrap uncertainty end to end (cover fixture)", {
skip_on_cran()
res <- .jpk_cover_res()
set.seed(415)
kd <- .joint_pareto_k(res, .jpk_cover_refit, n_samples = 600L, k_bootstrap = 500L)
expect_true(is.finite(kd$pareto_k))
expect_true(is.finite(kd$pareto_k_se_boot) && kd$pareto_k_se_boot >= 0)
expect_true(is.finite(kd$pareto_k_ci_low) && is.finite(kd$pareto_k_ci_high))
expect_lte(kd$pareto_k_ci_low, kd$pareto_k_ci_high)
expect_true(is.finite(kd$pareto_k_se_formula))
expect_gte(kd$pareto_k_tail_points, 5L)
expect_true(is.logical(kd$pareto_k_band_confident))
expect_true(is.na(kd$pareto_k_tail_points_requested)) # automatic (NULL) request
})
test_that("the bootstrap k-hat is reproducible (RNG restored on exit)", {
skip_on_cran()
res <- .jpk_cover_res()
set.seed(417)
a <- .joint_pareto_k(res, .jpk_cover_refit, n_samples = 600L, k_bootstrap = 300L)
# No set.seed between: .joint_pareto_k restores the entry RNG state, so the
# second call draws the identical scoring + bootstrap samples.
b <- .joint_pareto_k(res, .jpk_cover_refit, n_samples = 600L, k_bootstrap = 300L)
expect_identical(a$pareto_k, b$pareto_k)
expect_identical(a$pareto_k_se_boot, b$pareto_k_se_boot)
expect_identical(a$pareto_k_band_confident, b$pareto_k_band_confident)
})
test_that("control end to end carries the bootstrap uncertainty fields", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 96)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.7, 1.1))
arms <- .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5))
fit <- tulpa_nested_laplace_joint(
responses = arms, prior = prior,
control = list(k_samples = 300L, k_bootstrap = 400L))
expect_true(is.finite(fit$pareto_k))
expect_true(is.finite(fit$pareto_k_se_boot))
expect_lte(fit$pareto_k_ci_low, fit$pareto_k_ci_high)
expect_true(is.logical(fit$pareto_k_band_confident))
expect_identical(fit$diagnose_draws, 300L)
expect_true(is.na(fit$diagnose_cost_ratio) || fit$diagnose_cost_ratio >= 0)
})
test_that("k_quality = none disables the diagnostic and reports no verdict", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 97)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0))
fit <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_quality = "none"))
expect_identical(fit$k_quality_requested, "none")
expect_true(is.na(fit$pareto_k)) # diagnostic was disabled
expect_true(is.na(fit$k_quality_reached))
expect_match(fit$k_quality_reason, "disabled")
})
test_that("k_quality reports an honest reached / best / reason quartet", {
skip_if_not_slow()
sim <- .jpk_sim(seed = 96)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.7, 1.1))
arms <- .jpk_arms_alpha(sim, c(0, 0.5, 1.0, 1.5))
rep_fit <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_quality = "report", k_samples = 300L))
expect_identical(rep_fit$k_quality_requested, "report")
expect_true(is.na(rep_fit$k_quality_reached)) # no target band
expect_true(rep_fit$k_quality_best %in%
c("good", "ok", "unreliable", "uncertain"))
# k_max_rounds = 0 keeps it single-shot (no escalation re-fits) for a fast,
# deterministic check of the verdict.
good_fit <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_quality = "good", k_max_rounds = 0L))
expect_identical(good_fit$k_quality_requested, "good")
expect_true(is.logical(good_fit$k_quality_reached) &&
!is.na(good_fit$k_quality_reached))
expect_true(nzchar(good_fit$k_quality_reason))
# "good" raised the default draw budget (k_samples not set by the caller).
expect_identical(good_fit$diagnose_draws, 2000L)
expect_identical(good_fit$k_quality_rounds, 0L) # escalation disabled
# When the target is reached, the achieved band must be the good band.
if (isTRUE(good_fit$k_quality_reached))
expect_identical(good_fit$k_quality_best, "good")
})
test_that("refinement goes first, and a precision miss survives its exhaustion (gcol33/tulpa#131)", {
skip_if_not_slow()
# The local-CCD rung cannot engage on a single-block fit (it needs a >= 4-axis
# multi-block tensor grid), so refinement is exhausted on the FIRST round --
# a deterministic way to reach the branch that decides what happens after.
# A small draw budget keeps the bootstrap CI wide enough for the precision
# miss to be the live case.
sim <- .jpk_sim(seed = 41)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.3, 0.5, 0.8))
arms <- .jpk_arms_alpha(sim, c(0, 0.5, 1.0))
ctrl <- list(k_quality = "ok", k_samples = 200L, k_refine = "ccd")
probe <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = modifyList(ctrl, list(k_max_rounds = 0L)))
skip_if(isTRUE(probe$k_quality_reached),
"the first fit already reached the band; no escalation to observe")
expect_true(probe$k_quality_miss %in% c("precision", "resolution"))
expect_identical(probe$diagnose_draws, 200L)
esc <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = modifyList(ctrl, list(k_max_rounds = 2L)))
expect_gte(esc$k_quality_rounds, 1L)
expect_length(esc$k_quality_k_trace, esc$k_quality_rounds + 1L)
if (isTRUE(esc$k_quality_reached) || esc$diagnose_draws > 200L) {
# Refinement had nothing to add and the miss was the interval's width,
# so the rounds that followed bought tail ratios -- the lever refinement
# never touches. The budget doubles per such round and nothing else.
expect_true(esc$diagnose_draws %in% c(400L, 800L))
expect_gt(esc$k_quality_rounds, 1L)
} else {
# A confidently-bad k-hat on a grid the rung cannot refine: the chase
# stops on the first round and says which rung ran out, and the caller's
# draw budget is not spent on a miss more draws cannot resolve.
expect_identical(esc$k_quality_rounds, 1L)
expect_identical(esc$diagnose_draws, 200L)
expect_match(esc$k_quality_reason, "local CCD")
}
})
test_that("k_quality_k_trace records the chase round by round (gcol33/tulpa#131)", {
skip_on_cran()
sim <- .jpk_sim(seed = 95)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.4, 0.9))
arms <- .jpk_arms_alpha(sim, c(0.5, 1.0))
# Escalation off: the trace exists and is the single fit's own k-hat, so a
# reader never has to tell "no chase" from "field absent".
fit <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = list(k_quality = "report", k_samples = 200L))
expect_identical(fit$k_quality_rounds, 0L)
expect_length(fit$k_quality_k_trace, 1L)
expect_identical(fit$k_quality_k_trace, fit$pareto_k)
})
test_that("k_refine = 'grid' refines the integration grid driven by bad k and lowers the outer k (gcol33/tulpa#131)", {
skip_if_not_slow()
# A grid that sits below the field's posterior support: the first fit does not
# reach the good band, so the k_quality ladder must REFINE THE INTEGRATION GRID
# (not spend more diagnostic draws) and re-integrate, driven by the bad k.
sim <- .jpk_sim(seed = 21, sigma = 1.2)
adj <- .jpk_chain_adj(sim$n_s)
prior <- list(type = "icar", n_spatial_units = adj$n_spatial_units,
adj_row_ptr = adj$adj_row_ptr, adj_col_idx = adj$adj_col_idx,
n_neighbors = adj$n_neighbors, sigma_grid = c(0.2, 0.35, 0.5))
arms <- .jpk_arms_alpha(sim, c(0, 0.5, 1.0))
# Both grids are stated, and a stated axis is a bound that refinement
# densifies inside; `axis_refine = "extend"` is the per-axis opt-in to
# growing it past its ends, which is what a grid below the support needs.
ctrl <- list(k_quality = "good", k_samples = 800L, k_max_rounds = 3L,
axis_refine = c(sigma = "extend", alpha = "extend"))
# k_refine = "none": the band is reported but not chased -- no escalation, the
# grid is left untouched (k_quality_rounds stays 0).
fit0 <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = modifyList(ctrl, list(k_refine = "none")))
expect_identical(fit0$k_quality_rounds, 0L)
base_cells <- nrow(fit0$theta_grid)
# k_refine = "grid" (the default): the bad k drives integration-grid
# refinement, re-fitting and re-diagnosing until the band is reached.
fit1 <- tulpa_nested_laplace_joint(responses = arms, prior = prior,
control = modifyList(ctrl, list(k_refine = "grid")))
expect_gte(fit1$k_quality_rounds, 1L) # escalation ran
expect_false(is.null(fit1$adaptive_grid_info)) # the grid was refined ...
expect_gt(nrow(fit1$theta_grid), base_cells) # ... by adding cells
# k_samples is identical across the two fits (set, not auto-raised), so the
# k improvement is the refined grid's, not the diagnostic's: the separation the
# feature is built on. Here it crosses into the good band.
expect_lt(fit1$pareto_k, fit0$pareto_k)
expect_true(isTRUE(fit1$k_quality_reached))
expect_identical(fit1$k_quality_best, "good")
# The trace carries one k-hat per round plus the first fit's, and ends on
# the k-hat the returned fit reports -- the last round is what is returned,
# not the lowest-k one, because each round's proposal is rebuilt from the
# grid that round changed.
expect_length(fit1$k_quality_k_trace, fit1$k_quality_rounds + 1L)
expect_identical(fit1$k_quality_k_trace[[fit1$k_quality_rounds + 1L]],
fit1$pareto_k)
expect_identical(fit0$k_quality_k_trace, fit0$pareto_k)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.