format_decimal <- function(x, digits = 3) {
out <- rep(NA_character_, length(x))
finite <- is.finite(x)
x[finite & abs(x) < 0.5 * 10^(-digits)] <- 0
out[finite] <- formatC(x[finite], format = "f", digits = digits, big.mark = ",")
out[!finite & !is.na(x)] <- as.character(x[!finite & !is.na(x)])
out
}
format_scientific <- function(x, digits = 2) {
out <- rep(NA_character_, length(x))
finite <- is.finite(x)
out[finite] <- formatC(x[finite], format = "e", digits = digits)
out[!finite & !is.na(x)] <- as.character(x[!finite & !is.na(x)])
out
}
replace_missing <- function(x, missing = "-") {
x <- as.data.frame(x)
x[] <- lapply(x, function(column) {
column <- as.character(column)
column[is.na(column) | column == "NA"] <- missing
column
})
as_tibble(x)
}
plot_cpue_osa_quiet <- function(fit) {
capture.output(p <- plot_cpue_residuals(fit))
p
}
summarize_fit <- function(label, fit) {
par_list <- fit$parameters
report <- sbt_fit_report(fit)
opt_i <- fit$fit$opt
nll <- opt_i$objective
n_parameters <- length(opt_i$par)
tibble(
Model = label,
`Convergence code` = opt_i$convergence,
`Penalized objective` = nll,
`AIC-style score` = 2 * nll + 2 * n_parameters,
`Max gradient` = fit$fit$diagnostics$max_gradient %||% NA_real_,
B0 = exp(par_list$par_log_B0),
M0 = as.numeric(report$par_m0),
M4 = as.numeric(report$par_m4),
M10 = as.numeric(report$par_m10),
M30 = as.numeric(report$par_m30),
h = exp(par_list$par_log_h),
psi = exp(par_list$par_log_psi)
)
}
has_sensitivity_fit <- function(x) {
inherits(x, "sbt_fit")
}
sensitivity_mle_thresholds <- list(
convergence = 0L,
max_gradient = 0.01,
estimability = "estimable",
biological_state = biological_state_contract()
)
sensitivity_optimizer_contract <- list(
schema_version = 2L,
implementation = "esc31_staged_bounded_nlminb_newton_v2",
primary = list(
method = "bounded_nlminb_exact_hessian",
max_passes = 1L,
control = base_fit$control,
transition = list(
policy = "single_exact_pass_then_scaled_v1",
certified = "accept",
finite_nonworsening_uncertified = "retain_best_then_scaled",
invalid_or_worsening = "rollback_then_scaled",
branch_on_message = FALSE
)
),
scaled = list(
method = "hessian_diagonal_scaled_bounded_gradient_nlminb",
max_passes = 6L,
control = list(
eval.max = 15000L,
iter.max = 5000L,
rel.tol = 1e-10,
x.tol = 1e-8
),
hessian_diagonal_floor = 1e-8,
scale_min = 1e-4,
scale_max = 10
),
newton = list(
method = "bounded_spd_newton_armijo",
enabled = TRUE,
minimum_reciprocal_condition = 1e-12,
initial_alpha = 1,
fraction_to_boundary = 0.995,
backtrack_factor = 0.5,
maximum_backtracks = 12L,
armijo_c1 = 1e-4,
require_gradient_improvement = TRUE
),
certification = list(
method = "bounded_gradient_nlminb",
max_passes = 1L,
control = list(eval.max = 2000L, iter.max = 1000L)
),
acceptance = c(
sensitivity_mle_thresholds,
list(
require_finite_parameters = TRUE,
require_finite_objective = TRUE,
require_finite_gradient = TRUE,
require_in_bounds = TRUE,
bound_tolerance = 1e-10
)
)
)
sensitivity_optimizer_contract_signature <- esc31_object_md5(
sensitivity_optimizer_contract
)
sensitivity_optimizer_provenance_passes <- function(fit) {
if (!has_sensitivity_fit(fit)) return(FALSE)
fit_diagnostics <- fit$fit$diagnostics
max_gradient <- fit_diagnostics$max_gradient %||% NA_real_
optimizer_history <- fit_diagnostics$optimizer_history
optimizer_summary <- fit_diagnostics$optimizer_summary
required_history_fields <- c(
"pass", "stage", "attempt", "objective", "max_abs_gradient",
"gradient_l2", "convergence", "within_bounds", "finite_gradient",
"accepted_as_best", "previous_objective",
"relative_objective_decrease", "gradient_ratio",
"relative_parameter_step", "transition", "transition_reason", "message"
)
primary_history <- if (
is.data.frame(optimizer_history) && "stage" %in% names(optimizer_history)
) {
optimizer_history[
optimizer_history$stage == "primary bounded nlminb",
,
drop = FALSE
]
} else {
data.frame()
}
allowed_primary_transitions <- unname(unlist(
sensitivity_optimizer_contract$primary$transition[
c(
"certified", "finite_nonworsening_uncertified",
"invalid_or_worsening"
)
],
use.names = FALSE
))
identical(
fit$optimization$method,
sensitivity_optimizer_contract$implementation
) &&
identical(
fit$provenance$metadata$optimizer_contract_signature,
sensitivity_optimizer_contract_signature
) &&
identical(
fit_diagnostics$optimizer_contract_signature,
sensitivity_optimizer_contract_signature
) &&
identical(
fit_diagnostics$optimizer_contract,
sensitivity_optimizer_contract
) &&
is.data.frame(optimizer_history) &&
nrow(optimizer_history) >= 1L &&
all(required_history_fields %in% names(optimizer_history)) &&
!anyNA(optimizer_history$transition) &&
all(nzchar(optimizer_history$transition)) &&
!any(optimizer_history$transition == "pending") &&
nrow(primary_history) == 1L &&
is.list(optimizer_summary) &&
identical(optimizer_summary$schema_version, 2L) &&
isTRUE(optimizer_summary$certified) &&
identical(
optimizer_summary$contract_signature,
sensitivity_optimizer_contract_signature
) &&
identical(
as.integer(optimizer_summary$total_nlminb_calls),
as.integer(fit$fit$diagnostics$optimizer$n_passes)
) &&
identical(
as.integer(optimizer_summary$final_convergence),
as.integer(fit$fit$opt$convergence)
) &&
isTRUE(all.equal(
as.numeric(optimizer_summary$final_objective),
as.numeric(fit$fit$opt$objective),
tolerance = 1e-10
)) &&
isTRUE(all.equal(
as.numeric(optimizer_summary$final_max_abs_gradient),
as.numeric(max_gradient),
tolerance = 1e-10
)) &&
identical(as.integer(optimizer_summary$primary_passes), 1L) &&
is.character(optimizer_summary$primary_transition) &&
length(optimizer_summary$primary_transition) == 1L &&
optimizer_summary$primary_transition %in% allowed_primary_transitions &&
is.character(optimizer_summary$primary_transition_reason) &&
length(optimizer_summary$primary_transition_reason) == 1L &&
nzchar(optimizer_summary$primary_transition_reason) &&
identical(
optimizer_summary$primary_transition,
primary_history$transition[[1L]]
) &&
identical(
optimizer_summary$primary_transition_reason,
primary_history$transition_reason[[1L]]
)
}
sensitivity_harvest_wall_report_diagnostics <- function(data_fit, report) {
fail <- function(reason) {
list(
schema_version = 1L,
decision_id = sensitivity_harvest_wall_decision$decision_id,
contract = sensitivity_harvest_wall_contract,
recomputation_tolerance =
sensitivity_harvest_wall_recomputation_tolerance,
passes = FALSE,
reason = reason
)
}
if (!is.list(data_fit) || !is.list(report)) {
return(fail("The fit data or model report is unavailable."))
}
required_data <- c(
"harvest_wall_strength", "harvest_wall_onset",
"harvest_wall_ceiling", "harvest_wall_scale"
)
required_report <- c(
"hrate_raw_ysa", "harvest_wall_penalty_ysa", "lp_harvest_wall",
"harvest_wall_strength", "harvest_wall_onset",
"harvest_wall_ceiling", "harvest_wall_scale"
)
missing_data <- setdiff(required_data, names(data_fit))
missing_report <- setdiff(required_report, names(report))
if (length(missing_data) || length(missing_report)) {
return(fail(paste0(
"Missing wall data/report fields: ",
paste(c(missing_data, missing_report), collapse = ", "), "."
)))
}
raw_harvest <- report$hrate_raw_ysa
reported_penalty <- report$harvest_wall_penalty_ysa
reported_total <- report$lp_harvest_wall
reported_scalars <- lapply(
report[c(
"harvest_wall_strength", "harvest_wall_onset",
"harvest_wall_ceiling", "harvest_wall_scale"
)],
as.numeric
)
if (!is.numeric(raw_harvest) || !length(raw_harvest) ||
any(!is.finite(raw_harvest)) ||
!is.numeric(reported_penalty) ||
length(reported_penalty) != length(raw_harvest) ||
any(!is.finite(reported_penalty)) ||
!identical(dim(reported_penalty), dim(raw_harvest)) ||
!is.numeric(reported_total) || length(reported_total) != 1L ||
!is.finite(reported_total) ||
any(lengths(reported_scalars) != 1L) ||
any(!is.finite(unlist(reported_scalars, use.names = FALSE)))) {
return(fail("The reported wall arrays or scalars are non-finite or malformed."))
}
reported_contract <- harvest_wall_contract(
strength = reported_scalars$harvest_wall_strength,
onset = reported_scalars$harvest_wall_onset,
ceiling = reported_scalars$harvest_wall_ceiling,
scale = reported_scalars$harvest_wall_scale
)
data_contract <- harvest_wall_contract(
strength = data_fit$harvest_wall_strength,
onset = data_fit$harvest_wall_onset,
ceiling = data_fit$harvest_wall_ceiling,
scale = data_fit$harvest_wall_scale
)
recomputed_penalty <- get_harvest_wall_penalty(
raw_harvest,
contract = sensitivity_harvest_wall_contract
)
maximum_penalty_error <- max(abs(
as.numeric(reported_penalty) - as.numeric(recomputed_penalty)
))
total_penalty_error <- abs(
as.numeric(reported_total) - sum(as.numeric(recomputed_penalty))
)
maximum_raw_harvest <- max(as.numeric(raw_harvest))
raw_harvest_within_ceiling <- maximum_raw_harvest <=
sensitivity_mle_thresholds$biological_state$hrate_limit +
sensitivity_mle_thresholds$biological_state$hrate_tolerance
data_contract_matches <- identical(
data_contract,
sensitivity_harvest_wall_contract
)
reported_contract_matches <- identical(
reported_contract,
sensitivity_harvest_wall_contract
)
nonnegative_penalty <- all(
as.numeric(reported_penalty) >=
-sensitivity_harvest_wall_recomputation_tolerance
)
passes <- data_contract_matches && reported_contract_matches &&
raw_harvest_within_ceiling && nonnegative_penalty &&
maximum_penalty_error <=
sensitivity_harvest_wall_recomputation_tolerance &&
total_penalty_error <= sensitivity_harvest_wall_recomputation_tolerance
list(
schema_version = 1L,
decision_id = sensitivity_harvest_wall_decision$decision_id,
contract = sensitivity_harvest_wall_contract,
recomputation_tolerance = sensitivity_harvest_wall_recomputation_tolerance,
raw_harvest_cells = length(raw_harvest),
cells_above_onset = sum(
as.numeric(raw_harvest) > sensitivity_harvest_wall_contract$onset
),
maximum_raw_harvest = maximum_raw_harvest,
total_wall_objective = as.numeric(reported_total),
maximum_cell_penalty = max(as.numeric(reported_penalty)),
maximum_penalty_recomputation_error = maximum_penalty_error,
total_penalty_recomputation_error = total_penalty_error,
data_contract_matches = data_contract_matches,
reported_contract_matches = reported_contract_matches,
raw_harvest_within_ceiling = raw_harvest_within_ceiling,
nonnegative_penalty = nonnegative_penalty,
payload_checksum = esc31_object_md5(list(
raw_harvest = raw_harvest,
reported_penalty = reported_penalty
)),
passes = passes,
reason = if (passes) "pass" else "One or more harvest-wall gates failed."
)
}
sensitivity_harvest_wall_fit_diagnostics <- function(fit) {
if (!has_sensitivity_fit(fit)) {
return(sensitivity_harvest_wall_report_diagnostics(NULL, NULL))
}
tryCatch(
sensitivity_harvest_wall_report_diagnostics(
fit$data,
sbt_fit_report(fit)
),
error = function(e) {
failed <- sensitivity_harvest_wall_report_diagnostics(NULL, NULL)
failed$reason <- paste(
"Harvest-wall diagnostic reconstruction failed:",
conditionMessage(e)
)
failed
}
)
}
sensitivity_mle_passes <- function(fit) {
if (!has_sensitivity_fit(fit)) return(FALSE)
validation <- tryCatch(
sbt_fit_validation(
fit,
scope = "mle",
verify = !identical(sensitivity_fit_validation_mode, "skip"),
require_pass = TRUE
),
error = function(e) NULL
)
max_gradient <- fit$fit$diagnostics$max_gradient %||% NA_real_
biological_state <- fit$fit$diagnostics$biological_state_mle
wall <- fit$fit$diagnostics$harvest_wall_mle
stored_wall_passes <- is.list(wall) &&
is.list(wall$identity) &&
identical(
wall$identity$decision,
sensitivity_harvest_wall_decision
) &&
identical(
wall$identity$executable,
sensitivity_harvest_wall_contract
) &&
is.finite(wall$maximum_raw_harvest) &&
wall$maximum_raw_harvest <=
sensitivity_mle_thresholds$biological_state$hrate_limit +
sensitivity_mle_thresholds$biological_state$hrate_tolerance &&
is.finite(wall$maximum_recomputation_error) &&
wall$maximum_recomputation_error <=
sensitivity_harvest_wall_recomputation_tolerance &&
is.finite(wall$maximum_continuation_penalty) &&
abs(wall$maximum_continuation_penalty) <=
sensitivity_mle_thresholds$biological_state$penalty_tolerance
!is.null(validation) &&
identical(as.integer(fit$fit$opt$convergence),
sensitivity_mle_thresholds$convergence) &&
length(max_gradient) == 1L &&
is.finite(max_gradient) &&
max_gradient <= sensitivity_mle_thresholds$max_gradient &&
identical(
fit$fit$estimability$status,
sensitivity_mle_thresholds$estimability
) &&
esc31_biological_state_diagnostics_pass(biological_state, 1L) &&
stored_wall_passes
}
sensitivity_mcmc_default_config <- list(
num_samples = 750L,
num_warmup = 150L,
chains = 4L,
cores = 4L,
metric = "dense",
init = "last.par.best",
adapt_delta = 0.999,
max_treedepth = 13L,
refresh = 200L,
skip_optimization = TRUE
)
# Key-specific implementation controls must remain provenance-bound. The
# NoPOPHSP fixed-effect Hessian is positive definite under RTMB's exact AD
# derivatives, but RTMB::sdreport()'s finite-difference Hessian is not. Passing
# the exact-Hessian covariance preserves the approved dense metric and avoids a
# false preconditioner failure without changing the sampler settings.
sensitivity_mcmc_overrides <- list(
no_pop_hsp = list(
dense_metric_precision_source =
"RTMB exact AD Hessian at source MLE",
# The 1,200-draw rerun still had maximum R-hat 1.025406 and minimum bulk
# ESS 243.3. Preserve its seed and transition controls, but extend the
# retained chain substantially so the effective sample size has a
# reasonable prospect of clearing 400 with margin.
num_samples = 3000L
),
# The first annual-terminal-LL1 run narrowly missed only the strict R-hat
# gate (1.010519 versus < 1.01). Retain its seed and transition controls and
# add 20% more retained draws.
ll1_terminal_3yr = list(
num_samples = 900L
),
# The first No-HSP run also had otherwise healthy diagnostics and missed
# only the strict R-hat gate (1.010443 versus < 1.01). Retain its seed and
# transition controls and add 20% more retained draws.
no_hsp = list(
num_samples = 900L
),
# The first 750-draw Constant-CPUE-CV run had otherwise healthy diagnostics
# but missed the strict R-hat gate narrowly (1.01069 versus < 1.01). Retain
# the seed and transition controls and add 20% more retained draws.
constant_cpue_cv = list(
num_samples = 900L
),
# The first Troll run had maximum R-hat 1.014088 with otherwise healthy
# ESS and no sampler pathologies. Preserve its seed and use longer chains.
troll = list(
num_samples = 1200L
),
# The first estimated-slope run missed only the R-hat gate narrowly at
# 1.010244. Preserve its seed and add 20% more retained draws.
estimate_m_slope = list(
num_samples = 900L
),
# The first No-tags run had no sampler pathologies, but maximum R-hat was
# 1.017 and minimum bulk ESS was 219.7 for M10. Preserve its seed and
# transition controls, and extend the retained chains to provide adequate
# effective-sample-size margin.
no_tags = list(
num_samples = 1800L
)
)
sensitivity_mcmc_thresholds <- list(
max_rhat = 1.01,
min_bulk_ess = 400,
min_tail_ess = 400,
divergences = 0L,
max_treedepth_hits = 0L,
biological_state = biological_state_contract()
)
no_pop_hsp_mcmc_acceptance <- list(
schema_version = 1L,
status = "accepted_with_explicit_divergence_exception",
decision_id =
"esc31_2026_no_pop_hsp_accept_two_divergences_12000_draws_v1",
decision_date = "2026-07-23",
model_key = "no_pop_hsp",
retained_draws_per_chain = 3000L,
chains = 4L,
retained_draws_total = 12000L,
accepted_divergences = 2L,
standard_thresholds_otherwise_unchanged = TRUE,
biological_state_exception = FALSE,
rationale = paste(
"Explicit assessment decision to accept the two divergent transitions",
"after the longer NoPOPHSP run passed R-hat, bulk ESS, tail ESS,",
"maximum-treedepth, MLE, and complete retained-draw biological-state",
"checks."
)
)
# State rescans are deterministic across worker counts, so this performance
# control is deliberately excluded from every scientific identity.
sensitivity_state_diagnostic_cores <- local({
configured <- trimws(Sys.getenv("ESC31_STATE_DIAGNOSTIC_CORES", ""))
if (nzchar(configured)) {
if (!grepl("^[1-9][0-9]*$", configured)) {
stop(
"`ESC31_STATE_DIAGNOSTIC_CORES` must be one positive integer.",
call. = FALSE
)
}
cores <- suppressWarnings(as.integer(configured))
if (is.na(cores)) {
stop(
"`ESC31_STATE_DIAGNOSTIC_CORES` is outside the supported integer range.",
call. = FALSE
)
}
cores
} else {
detected <- suppressWarnings(parallel::detectCores(logical = TRUE))
if (length(detected) != 1L || is.na(detected) || detected < 1L) {
detected <- sensitivity_mcmc_default_config$cores
}
min(16L, as.integer(detected))
}
})
# Expensive validation is performed once when a fit is completed and stored in
# the portable `sbt_fit`. Normal report and cache-check paths reuse that
# payload-bound record. Set `ESC31_FIT_VALIDATION_MODE=full` for a deliberate
# end-to-end audit or `skip` to trust the stored record without recalculating
# its compact checksums.
sensitivity_fit_validation_mode <- local({
configured <- tolower(trimws(Sys.getenv(
"ESC31_FIT_VALIDATION_MODE", "auto"
)))
if (!configured %in% c("auto", "full", "skip")) {
stop(
"`ESC31_FIT_VALIDATION_MODE` must be `auto`, `full`, or `skip`.",
call. = FALSE
)
}
configured
})
sensitivity_mcmc_requested <- function(key) {
key %in% valid_sensitivity_mcmc_keys &&
run_sensitivity_mcmc &&
("all" %in% sensitivity_mcmc_keys || key %in% sensitivity_mcmc_keys)
}
sensitivity_mcmc_config <- function(key) {
if (length(key) != 1L || is.na(key) ||
!key %in% valid_sensitivity_mcmc_keys) {
stop("The requested sensitivity MCMC key is not executable.", call. = FALSE)
}
config <- utils::modifyList(
sensitivity_mcmc_default_config,
sensitivity_mcmc_overrides[[key]] %||% list()
)
config$seed <- 73000L + match(key, sensitivity_mcmc_registry_keys)
config
}
sensitivity_mcmc_identity <- function(key, source_fit, fit_identity_signature,
sampler_config) {
if (length(key) != 1L || is.na(key) ||
!key %in% valid_sensitivity_mcmc_keys) {
stop("Cannot create an MCMC identity for a non-executable sensitivity.",
call. = FALSE)
}
esc31_workflow_identity(
esc_dir,
workflow_files = character(),
sbt_entry_points = esc31_sbt_entry_points("sensitivities"),
config = list(
stage = "sensitivity_mcmc",
mcmc_workflow_version =
"esc31_sensitivity_mcmc_v13_length_base_check_mcmc",
model_key = key,
base_run_signature =
base_fit$provenance$metadata$run_identity$signature,
base_fit_scientific_signature = esc31_fit_scientific_signature(base_fit),
fit_identity_signature = fit_identity_signature,
fit_scientific_signature = esc31_fit_scientific_signature(source_fit),
harvest_wall_contract = sensitivity_harvest_wall_contract,
harvest_wall_decision = sensitivity_harvest_wall_decision,
harvest_wall_recomputation_tolerance =
sensitivity_harvest_wall_recomputation_tolerance,
mle_acceptance_thresholds = sensitivity_mle_thresholds,
sampler = sampler_config,
thresholds = sensitivity_mcmc_thresholds
)
)
}
sensitivity_mcmc_standard_passes <- function(diagnostics) {
is.data.frame(diagnostics) && nrow(diagnostics) == 1L &&
isTRUE(diagnostics$passes)
}
sensitivity_mcmc_divergence_exception_passes <- function(diagnostics) {
state <- sensitivity_mcmc_thresholds$biological_state
is.data.frame(diagnostics) && nrow(diagnostics) == 1L &&
identical(
as.character(diagnostics$Model),
no_pop_hsp_mcmc_acceptance$model_key
) &&
identical(
as.integer(diagnostics$chains),
no_pop_hsp_mcmc_acceptance$chains
) &&
identical(
as.integer(diagnostics$samples_per_chain),
no_pop_hsp_mcmc_acceptance$retained_draws_per_chain
) &&
identical(
as.integer(diagnostics$state_draws_expected),
no_pop_hsp_mcmc_acceptance$retained_draws_total
) &&
identical(
as.integer(diagnostics$state_draws_evaluated),
no_pop_hsp_mcmc_acceptance$retained_draws_total
) &&
identical(
as.integer(diagnostics$divergences),
no_pop_hsp_mcmc_acceptance$accepted_divergences
) &&
identical(as.integer(diagnostics$convergence), 0L) &&
is.finite(diagnostics$objective) &&
isTRUE(diagnostics$estimable) &&
is.finite(diagnostics$max_rhat) &&
diagnostics$max_rhat < sensitivity_mcmc_thresholds$max_rhat &&
is.finite(diagnostics$min_bulk_ess) &&
diagnostics$min_bulk_ess >= sensitivity_mcmc_thresholds$min_bulk_ess &&
is.finite(diagnostics$min_tail_ess) &&
diagnostics$min_tail_ess >= sensitivity_mcmc_thresholds$min_tail_ess &&
identical(as.integer(diagnostics$max_treedepth_hits), 0L) &&
isTRUE(diagnostics$state_passes) &&
identical(as.integer(diagnostics$state_invalid_draws), 0L) &&
identical(as.integer(diagnostics$state_non_finite_draws), 0L) &&
identical(as.integer(diagnostics$state_invalid_cells), 0L) &&
is.finite(diagnostics$state_max_raw_harvest) &&
diagnostics$state_max_raw_harvest <=
state$hrate_limit + state$hrate_tolerance &&
is.finite(diagnostics$state_min_number) &&
diagnostics$state_min_number > state$number_tolerance &&
is.finite(diagnostics$state_max_harvest_penalty) &&
abs(diagnostics$state_max_harvest_penalty) <= state$penalty_tolerance
}
sensitivity_mcmc_passes <- function(diagnostics) {
sensitivity_mcmc_standard_passes(diagnostics) ||
sensitivity_mcmc_divergence_exception_passes(diagnostics)
}
sensitivity_mcmc_acceptance_label <- function(diagnostics) {
if (sensitivity_mcmc_standard_passes(diagnostics)) return("Pass")
if (sensitivity_mcmc_divergence_exception_passes(diagnostics)) {
return("Accepted (2 divergences)")
}
"Fail"
}
sensitivity_mcmc_identity_matches <- function(saved, expected, fit,
source_fit) {
if (!is.list(saved) || !is.list(saved$config) ||
!is.list(expected) || !is.list(expected$config)) {
return(FALSE)
}
normalized <- saved
binding_field <- "fit_identity_signature"
expected_binding <- expected$config[[binding_field]]
if (!is.null(expected_binding)) {
source_identity <-
source_fit$provenance$metadata$workflow_run_identity %||%
source_fit$provenance$metadata$run_identity
source_mcmc_binding <-
source_fit$provenance$metadata$mcmc_source_fit_identity_signature
saved_binding <- saved$config[[binding_field]]
if (!is.list(source_identity) ||
!is.character(source_identity$signature) ||
length(source_identity$signature) != 1L ||
!is.character(saved_binding) || length(saved_binding) != 1L ||
is.na(saved_binding) ||
!saved_binding %in% c(
source_identity$signature,
source_mcmc_binding,
source_fit$provenance$metadata$
mcmc_source_fit_workflow_signature,
expected_binding
)) {
return(FALSE)
}
normalized$config[[binding_field]] <- expected_binding
}
esc31_mcmc_identity_equivalent(
normalized,
expected,
fit = fit,
base_fit = base_fit
)
}
read_sensitivity_mcmc_fit <- function(file, source_fit, expected_identity) {
if (!file.exists(file)) return(NULL)
expected_key <- expected_identity$config$model_key
if (length(expected_key) != 1L || is.na(expected_key) ||
!expected_key %in% valid_sensitivity_mcmc_keys) return(NULL)
fit <- tryCatch(
sbt_fit_read(
file,
strict = TRUE,
rebuild = FALSE,
verify_validation = FALSE
),
error = function(e) NULL
)
if (is.null(fit) || is.null(fit$mcmc)) return(NULL)
diagnostics <- fit$fit$diagnostics$mcmc
saved_state <- fit$fit$diagnostics$biological_state_posterior
saved_identity <- fit$provenance$metadata$mcmc_run_identity
cache_checks <- c(
scientific_signature = identical(
esc31_fit_scientific_signature(fit),
esc31_fit_scientific_signature(source_fit)
),
mcmc_identity = sensitivity_mcmc_identity_matches(
saved_identity,
expected_identity,
fit = fit,
source_fit = source_fit
),
diagnostic_shape =
is.data.frame(diagnostics) && nrow(diagnostics) == 1L,
diagnostic_run_signature =
is.data.frame(diagnostics) && nrow(diagnostics) == 1L &&
identical(
as.character(diagnostics$run_signature),
saved_identity$signature
),
sampler_settings = identical(
esc31_mcmc_sampler_configuration(fit),
expected_identity$config$sampler
),
acceptance_thresholds = identical(
esc31_mcmc_acceptance_thresholds(fit),
expected_identity$config$thresholds
)
)
if (!all(cache_checks)) {
if (identical(
tolower(trimws(Sys.getenv("ESC31_DEBUG_MCMC_CACHE", ""))),
"true"
)) {
message(
"Rejected sensitivity MCMC cache `", expected_key, "` before ",
"recalculation: ",
paste(names(cache_checks)[!cache_checks], collapse = ", "),
"."
)
if (!cache_checks[["mcmc_identity"]] &&
is.list(saved_identity) && is.list(saved_identity$config)) {
debug_identity <- saved_identity
for (field in c(
"base_fit_scientific_signature", "fit_scientific_signature"
)) {
if (!is.null(expected_identity$config[[field]])) {
debug_identity$config[[field]] <-
expected_identity$config[[field]]
}
}
message(
"MCMC scientific-identity difference for `", expected_key, "`: ",
paste(
as.character(all.equal(
esc31_workflow_scientific_identity(debug_identity),
esc31_workflow_scientific_identity(expected_identity),
check.attributes = FALSE
)),
collapse = "; "
),
"."
)
}
}
return(NULL)
}
recalculated_fit <- tryCatch(
check_mcmc(
fit,
cores = sensitivity_state_diagnostic_cores,
stop_on_failure = FALSE,
mode = sensitivity_fit_validation_mode
),
error = function(e) NULL
)
validation_record <- if (is.null(recalculated_fit)) {
NULL
} else {
tryCatch(
sbt_fit_validation(
recalculated_fit,
scope = "mcmc",
verify = !identical(sensitivity_fit_validation_mode, "skip")
),
error = function(e) NULL
)
}
if (is.null(recalculated_fit) || is.null(validation_record) ||
!isTRUE(all.equal(
unclass(diagnostics),
unclass(recalculated_fit$fit$diagnostics$mcmc),
check.attributes = FALSE,
tolerance = 1e-12
)) ||
!isTRUE(all.equal(
saved_state,
recalculated_fit$fit$diagnostics$biological_state_posterior,
check.attributes = FALSE,
tolerance = 1e-10
))) {
if (identical(
tolower(trimws(Sys.getenv("ESC31_DEBUG_MCMC_CACHE", ""))),
"true"
)) {
message(
"Rejected sensitivity MCMC cache `", expected_key,
"` after embedded fit validation."
)
}
return(NULL)
}
recalculated_fit
}
sensitivity_dense_metric_qinv <- function(key, source_fit, sampling_object,
config) {
precision_source <- config$dense_metric_precision_source %||% NULL
if (is.null(precision_source)) return(NULL)
expected_source <- "RTMB exact AD Hessian at source MLE"
if (!identical(key, "no_pop_hsp") ||
!identical(config$metric, "dense") ||
!identical(precision_source, expected_source)) {
stop(
"The exact-Hessian dense metric is approved only for `no_pop_hsp`.",
call. = FALSE
)
}
sampling_par <- source_fit$fit$opt$par
if (length(sampling_par) != length(sampling_object$par) ||
!identical(names(sampling_par), names(sampling_object$par))) {
stop(
"The exact-Hessian metric parameters do not match the source MLE.",
call. = FALSE
)
}
sampling_object$par <- sampling_par
sampling_object$env$last.par.best <- sampling_par
objective_at_mle <- sampling_object$fn(sampling_par)
if (!isTRUE(all.equal(
as.numeric(objective_at_mle),
as.numeric(source_fit$fit$opt$objective),
tolerance = 1e-10
))) {
stop(
"The exact-Hessian metric object does not reproduce the source MLE.",
call. = FALSE
)
}
dense_hessian <- sampling_object$he(sampling_par)
if (!is.matrix(dense_hessian) ||
!identical(dim(dense_hessian), rep(length(sampling_par), 2L)) ||
any(!is.finite(dense_hessian))) {
stop("The exact dense-metric Hessian is invalid.", call. = FALSE)
}
dense_hessian <- 0.5 * (dense_hessian + t(dense_hessian))
dense_chol <- tryCatch(
chol(dense_hessian),
error = function(e) {
stop(
"The exact dense-metric Hessian is not positive definite: ",
conditionMessage(e),
call. = FALSE
)
}
)
dense_qinv <- chol2inv(dense_chol)
dense_qinv <- 0.5 * (dense_qinv + t(dense_qinv))
if (any(!is.finite(dense_qinv)) || any(diag(dense_qinv) <= 0)) {
stop("The exact dense-metric covariance is invalid.", call. = FALSE)
}
tryCatch(
chol(dense_qinv),
error = function(e) {
stop(
"The exact dense-metric covariance is not positive definite: ",
conditionMessage(e),
call. = FALSE
)
}
)
dense_qinv
}
ensure_sensitivity_mcmc_fit <- function(key, source_fit, file,
fit_identity_signature) {
if (length(key) != 1L || is.na(key) ||
!key %in% valid_sensitivity_mcmc_keys) {
stop("MCMC cannot be launched for a non-executable sensitivity key.",
call. = FALSE)
}
if (run_sensitivity_mcmc && !sensitivity_mcmc_requested(key)) return(NULL)
if (identical(key, "base")) {
return(esc31_load_base_mcmc(
file,
source_fit,
esc_dir,
validation_mode = sensitivity_fit_validation_mode
)$fit)
}
config <- sensitivity_mcmc_config(key)
expected_identity <- sensitivity_mcmc_identity(
key,
source_fit,
fit_identity_signature,
config
)
cached <- read_sensitivity_mcmc_fit(file, source_fit, expected_identity)
if (!is.null(cached) &&
(!sensitivity_mcmc_requested(key) ||
sensitivity_mcmc_passes(cached$fit$diagnostics$mcmc))) {
return(cached)
}
if (!sensitivity_mcmc_requested(key)) return(NULL)
if (!sensitivity_mle_passes(source_fit)) {
stop(
"The source MLE does not pass the convergence, maximum-gradient, and ",
"estimability gates for `", key, "`.",
call. = FALSE
)
}
if (!identical(key, "base") &&
!sensitivity_optimizer_provenance_passes(source_fit)) {
stop(
"The source sensitivity MLE does not match the current optimizer ",
"contract for `", key, "`.",
call. = FALSE
)
}
sampling_object <- sbt_obj(source_fit, fresh = TRUE)
dense_metric_qinv <- sensitivity_dense_metric_qinv(
key,
source_fit,
sampling_object,
config
)
mcmc_fit <- sbt_mcmc(
source_fit,
init = config$init,
check = FALSE,
num_samples = config$num_samples,
num_warmup = config$num_warmup,
chains = config$chains,
cores = config$cores,
metric = config$metric,
Qinv = dense_metric_qinv,
seed = config$seed,
skip_optimization = config$skip_optimization,
control = list(
adapt_delta = config$adapt_delta,
max_treedepth = config$max_treedepth
),
refresh = config$refresh
)
mcmc_fit$provenance$metadata <- utils::modifyList(
mcmc_fit$provenance$metadata,
list(
mcmc_run_identity = expected_identity,
mcmc_source_fit_identity_signature = fit_identity_signature,
mcmc_source_fit_workflow_signature = fit_identity_signature
)
)
# Preserve the assessment-specific biological-state contract together with
# the five scalar sampler gates that `check_mcmc()` evaluates. Without this
# binding, a newly sampled fit would pass its first check but appear stale
# when the complete threshold identity is verified on the next load.
mcmc_fit$mcmc$settings$acceptance_thresholds <-
sensitivity_mcmc_thresholds
source_mle_validation <- sbt_fit_validation(
source_fit,
scope = "mle",
require_pass = TRUE
)
if (!identical(
mcmc_fit$validation$records$mle,
source_mle_validation
) ||
!identical(esc31_mcmc_sampler_configuration(mcmc_fit), config) ||
!identical(
esc31_mcmc_acceptance_thresholds(mcmc_fit),
sensitivity_mcmc_thresholds
)) {
stop(
"The staged MCMC result does not preserve its source-MLE validation ",
"and production sampler contract for `", key, "`.",
call. = FALSE
)
}
sbt_fit_validate(mcmc_fit)
# Preserve an expensive sampler result before running posterior diagnostics.
sbt_fit_save(mcmc_fit, file, overwrite = TRUE)
mcmc_fit <- check_mcmc(
mcmc_fit,
cores = sensitivity_state_diagnostic_cores,
stop_on_failure = FALSE,
mode = "auto"
)
diagnostics <- mcmc_fit$fit$diagnostics$mcmc
sbt_fit_save(mcmc_fit, file, overwrite = TRUE)
if (!sensitivity_mcmc_passes(diagnostics)) {
stop(
"Sensitivity MCMC diagnostics do not satisfy the acceptance decision for `",
key, "`; the saved fit is retained for inspection and will be resampled ",
"on the next requested run.",
call. = FALSE
)
}
mcmc_fit
}
sensitivity_workflow_identity <- function(sensitivity_id, scientific_config) {
if (!is.character(sensitivity_id) || length(sensitivity_id) != 1L ||
is.na(sensitivity_id) || !nzchar(sensitivity_id)) {
stop("`sensitivity_id` must be one non-empty string.", call. = FALSE)
}
if (!is.list(scientific_config) || is.null(names(scientific_config)) ||
any(!nzchar(names(scientific_config)))) {
stop("`scientific_config` must be a named list.", call. = FALSE)
}
esc31_workflow_identity(
esc_dir,
workflow_files = character(),
sbt_entry_points = esc31_sbt_entry_points("sensitivities"),
config = list(
stage = "sensitivity",
fit_workflow_version =
"esc31_mle_sensitivity_v12_length_base_standard_ll4_ll3_hyper",
sensitivity_id = sensitivity_id,
base_fit_scientific_signature = esc31_fit_scientific_signature(base_fit),
base_run_signature =
base_fit$provenance$metadata$run_identity$signature,
harvest_wall_contract = sensitivity_harvest_wall_contract,
harvest_wall_decision = sensitivity_harvest_wall_decision,
harvest_wall_recomputation_tolerance =
sensitivity_harvest_wall_recomputation_tolerance,
optimizer = sensitivity_optimizer_contract,
mle_acceptance_thresholds = sensitivity_mle_thresholds,
scientific_config = scientific_config,
fit_seed = NA_integer_
)
)
}
sensitivity_metadata <- function(sensitivity_id, scientific_config, data_sens,
parameter_overrides = list(),
estimated_parameters = character(),
reference_obj = sbt_obj(base_fit)) {
setup <- prepare_sensitivity_model(
data_sens = data_sens,
parameter_overrides = parameter_overrides,
estimated_parameters = estimated_parameters,
reference_obj = reference_obj
)
scientific_config <- utils::modifyList(
scientific_config,
setup$scientific_config
)
metadata <- utils::modifyList(
list(
sensitivity_id = sensitivity_id,
base_fit_scientific_signature = esc31_fit_scientific_signature(base_fit),
base_run_signature =
base_fit$provenance$metadata$run_identity$signature,
optimizer_contract_signature = sensitivity_optimizer_contract_signature,
workflow_run_identity = sensitivity_workflow_identity(
sensitivity_id,
scientific_config
)
),
scientific_config
)
attr(metadata, "expected_model_data") <- setup$data
metadata
}
sensitivity_workflow_identity_equivalent <- function(saved, expected) {
if (!is.list(saved) || !is.list(expected) ||
!is.list(saved$config) || !is.list(expected$config)) {
return(FALSE)
}
base_signature_field <- "base_fit_scientific_signature"
if (!is.null(expected$config[[base_signature_field]])) {
if (!esc31_saved_fit_signature_matches(
saved$config[[base_signature_field]], base_fit)) {
return(FALSE)
}
saved$config[[base_signature_field]] <-
expected$config[[base_signature_field]]
}
scientific_identity <- function(identity) {
identity <- esc31_workflow_scientific_identity(identity)
if (is.null(identity)) return(NULL)
config <- identity$config$scientific_config
if (is.list(config)) {
config$transformed_data_md5 <- NULL
config$model_data_md5 <- NULL
# The seed records how optimisation was launched; it is not part of the
# converged MLE or the payload-bound posterior identity.
config$seeded_parameters_md5 <- NULL
identity$config$scientific_config <- config
}
identity
}
saved_scientific <- scientific_identity(saved)
expected_scientific <- scientific_identity(expected)
!is.null(saved_scientific) && !is.null(expected_scientific) &&
identical(saved_scientific, expected_scientific)
}
sensitivity_model_data_equivalent <- function(saved, expected) {
isTRUE(all.equal(
saved,
expected,
# Reconstructing the unchanged inputs after their move to sbtdata can
# differ at floating-point round-off only (approximately 2e-16 here).
tolerance = 1e-14,
check.attributes = TRUE
))
}
sensitivity_metadata_matches <- function(fit, expected) {
if (!has_sensitivity_fit(fit)) return(FALSE)
metadata <- fit$provenance$metadata
expected_model_data <- attr(expected, "expected_model_data", exact = TRUE)
!is.null(expected_model_data) &&
sensitivity_model_data_equivalent(fit$data, expected_model_data) &&
all(vapply(names(expected), function(name) {
if (identical(name, "workflow_run_identity")) {
sensitivity_workflow_identity_equivalent(
metadata[[name]],
expected[[name]]
)
} else if (identical(name, "base_fit_scientific_signature")) {
esc31_saved_fit_signature_matches(metadata[[name]], base_fit)
} else if (name %in% c(
"transformed_data_md5", "model_data_md5", "seeded_parameters_md5"
)) {
TRUE
} else {
identical(metadata[[name]], expected[[name]])
}
}, logical(1)))
}
read_saved_sensitivity_fit <- function(file, expected_metadata, required_diagnostics = character()) {
if (!file.exists(file)) return(NULL)
fit <- tryCatch(
sbt_fit_read(
file,
strict = TRUE,
rebuild = FALSE,
verify_validation = FALSE
),
error = function(e) NULL
)
initial_checks <- c(
readable = !is.null(fit),
metadata = !is.null(fit) &&
sensitivity_metadata_matches(fit, expected_metadata),
optimizer_provenance = !is.null(fit) &&
sensitivity_optimizer_provenance_passes(fit),
mle = !is.null(fit) && sensitivity_mle_passes(fit)
)
if (!all(initial_checks)) {
if (identical(
tolower(trimws(Sys.getenv("ESC31_DEBUG_MCMC_CACHE", ""))),
"true"
)) {
message(
"Rejected saved sensitivity fit `", basename(file), "`: ",
paste(names(initial_checks)[!initial_checks], collapse = ", "),
"."
)
}
return(NULL)
}
optimizer_diagnostics <- fit$fit$diagnostics
if (!identical(
optimizer_diagnostics$optimizer_contract_signature,
sensitivity_optimizer_contract_signature
) ||
!identical(
optimizer_diagnostics$optimizer_contract,
sensitivity_optimizer_contract
) ||
!identical(
esc31_object_md5(optimizer_diagnostics$optimizer_contract),
sensitivity_optimizer_contract_signature
)) return(NULL)
if (length(setdiff(required_diagnostics, names(fit$fit$diagnostics)))) return(NULL)
compatible_error <- NULL
compatible <- tryCatch(
{
sbt_obj(fit)
TRUE
},
error = function(e) {
compatible_error <<- conditionMessage(e)
FALSE
}
)
if (!compatible && identical(
tolower(trimws(Sys.getenv("ESC31_DEBUG_MCMC_CACHE", ""))),
"true"
)) {
message(
"Rejected saved sensitivity fit `", basename(file),
"` during objective reconstruction: ", compatible_error, "."
)
}
if (compatible) fit else NULL
}
seed_sensitivity_parameters <- function(parameters_sens, reference_obj) {
reference_parameters <- reference_obj$env$parList(reference_obj$env$last.par.best)
for (name in intersect(names(parameters_sens), names(reference_parameters))) {
current <- parameters_sens[[name]]
fitted <- reference_parameters[[name]]
if (is.matrix(current) && is.matrix(fitted)) {
current_rows <- rownames(current)
fitted_rows <- rownames(fitted)
current_cols <- colnames(current)
fitted_cols <- colnames(fitted)
if (!is.null(current_rows) && !is.null(fitted_rows) &&
!is.null(current_cols) && !is.null(fitted_cols)) {
shared_rows <- intersect(current_rows, fitted_rows)
shared_cols <- intersect(current_cols, fitted_cols)
current[shared_rows, shared_cols] <- fitted[shared_rows, shared_cols, drop = FALSE]
} else {
shared_rows <- seq_len(min(nrow(current), nrow(fitted)))
shared_cols <- seq_len(min(ncol(current), ncol(fitted)))
current[shared_rows, shared_cols] <- fitted[shared_rows, shared_cols, drop = FALSE]
}
parameters_sens[[name]] <- current
} else if (length(fitted) == 1L && length(current) > 1L) {
parameters_sens[[name]][] <- as.numeric(fitted)
} else {
n <- min(length(current), length(fitted))
parameters_sens[[name]][seq_len(n)] <- as.numeric(fitted)[seq_len(n)]
}
}
parameters_sens
}
sensitivity_map_contract <- list(
generator = "sbt::get_map",
ll4_selectivity = "one_active_1_x_14_block_starting_1953",
ll4_hyperparameters = "fixed_values_inherited_from_ll3",
mortality = "map follows M_switch; length exponent fixed at minus one"
)
prepare_sensitivity_model <- function(data_sens, parameter_overrides = list(),
estimated_parameters = character(),
reference_obj = sbt_obj(base_fit)) {
if (!is.list(parameter_overrides) ||
(length(parameter_overrides) &&
(is.null(names(parameter_overrides)) ||
any(!nzchar(names(parameter_overrides)))))) {
stop("`parameter_overrides` must be a named list.", call. = FALSE)
}
if (!is.character(estimated_parameters) || anyNA(estimated_parameters) ||
any(!nzchar(estimated_parameters)) || anyDuplicated(estimated_parameters)) {
stop("`estimated_parameters` must contain unique parameter names.",
call. = FALSE)
}
transformed_data_md5 <- esc31_object_md5(data_sens)
parameters_sens <- get_parameters(data = data_sens)
parameters_sens <- seed_sensitivity_parameters(parameters_sens, reference_obj)
for (name in names(parameter_overrides)) {
if (!name %in% names(parameters_sens)) {
stop("Unknown sensitivity parameter override: ", name, call. = FALSE)
}
parameters_sens[[name]] <- parameter_overrides[[name]]
}
map_sens <- get_map(parameters = parameters_sens)
for (name in estimated_parameters) {
if (!name %in% names(map_sens) || !all(is.na(map_sens[[name]]))) {
stop(
"An explicitly estimated sensitivity parameter must be fixed by the ",
"default map: ", name, ".",
call. = FALSE
)
}
map_sens[[name]] <- NULL
}
data_sens$priors <- get_priors(parameters = parameters_sens)
scientific_config <- list(
transformed_data_md5 = transformed_data_md5,
model_data_md5 = esc31_object_md5(data_sens),
seeded_parameters_md5 = esc31_object_md5(parameters_sens),
parameter_overrides = parameter_overrides,
map_contract = sensitivity_map_contract,
parameter_map_md5 = esc31_object_md5(map_sens)
)
if (length(estimated_parameters)) {
scientific_config$estimated_parameters <- estimated_parameters
}
list(
data = data_sens,
parameters = parameters_sens,
map = map_sens,
scientific_config = scientific_config
)
}
sensitivity_point_diagnostics <- function(obj, par, bounds,
bound_tolerance = 0) {
expected_names <- names(obj$par)
finite_parameters <- is.numeric(par) &&
length(par) == length(expected_names) &&
identical(names(par), expected_names) &&
all(is.finite(par))
within_bounds <- finite_parameters &&
all(par >= bounds$lower - bound_tolerance) &&
all(par <= bounds$upper + bound_tolerance)
objective <- if (finite_parameters) {
tryCatch(as.numeric(obj$fn(par)), error = function(e) Inf)
} else {
Inf
}
finite_objective <- length(objective) == 1L && is.finite(objective)
if (!finite_objective) objective <- Inf
gradient <- if (finite_parameters && finite_objective) {
tryCatch(as.numeric(obj$gr(par)), error = function(e) numeric())
} else {
numeric()
}
finite_gradient <- length(gradient) == length(par) &&
all(is.finite(gradient))
max_abs_gradient <- if (finite_gradient) max(abs(gradient)) else Inf
gradient_l2 <- if (finite_gradient) sqrt(sum(gradient^2)) else Inf
list(
valid = finite_parameters && within_bounds && finite_objective &&
finite_gradient,
finite_parameters = finite_parameters,
within_bounds = within_bounds,
finite_objective = finite_objective,
finite_gradient = finite_gradient,
objective = objective,
gradient = gradient,
max_abs_gradient = max_abs_gradient,
gradient_l2 = gradient_l2
)
}
sensitivity_optimizer_certified <- function(opt, point_diagnostics,
gradient_tolerance) {
is.list(opt) &&
length(opt$convergence) == 1L &&
is.finite(opt$convergence) &&
identical(as.integer(opt$convergence), 0L) &&
isTRUE(point_diagnostics$valid) &&
is.finite(point_diagnostics$max_abs_gradient) &&
point_diagnostics$max_abs_gradient <= gradient_tolerance
}
sensitivity_optimizer_progress <- function(previous_par, previous_point,
candidate_par, candidate_point) {
previous_objective <- previous_point$objective %||% NA_real_
candidate_objective <- candidate_point$objective %||% NA_real_
relative_objective_decrease <- if (
length(previous_objective) == 1L && is.finite(previous_objective) &&
length(candidate_objective) == 1L && is.finite(candidate_objective)
) {
(previous_objective - candidate_objective) /
max(1, abs(previous_objective))
} else {
NA_real_
}
previous_gradient <- previous_point$max_abs_gradient %||% NA_real_
candidate_gradient <- candidate_point$max_abs_gradient %||% NA_real_
gradient_ratio <- if (
length(previous_gradient) == 1L && is.finite(previous_gradient) &&
previous_gradient >= 0 &&
length(candidate_gradient) == 1L && is.finite(candidate_gradient) &&
candidate_gradient >= 0
) {
candidate_gradient / max(previous_gradient, .Machine$double.eps)
} else {
NA_real_
}
relative_parameter_step <- if (
is.numeric(previous_par) && is.numeric(candidate_par) &&
length(previous_par) == length(candidate_par) &&
identical(names(previous_par), names(candidate_par)) &&
all(is.finite(previous_par)) && all(is.finite(candidate_par))
) {
max(abs(candidate_par - previous_par) / pmax(1, abs(previous_par)))
} else {
NA_real_
}
list(
previous_objective = as.numeric(previous_objective),
relative_objective_decrease = relative_objective_decrease,
gradient_ratio = gradient_ratio,
relative_parameter_step = relative_parameter_step
)
}
fit_sensitivity <- function(
data_sens, sensitivity_id, label,
reference_obj = sbt_obj(base_fit),
max_passes = sensitivity_optimizer_contract$primary$max_passes,
parameter_overrides = list(),
estimated_parameters = character(),
gradient_tolerance = sensitivity_optimizer_contract$acceptance$max_gradient,
diagnostics = list(), metadata = list()) {
attr(metadata, "expected_model_data") <- NULL
required_metadata <- c(
"sensitivity_id", "base_fit_scientific_signature", "base_run_signature",
"optimizer_contract_signature", "workflow_run_identity"
)
if (!all(required_metadata %in% names(metadata)) ||
!identical(metadata$sensitivity_id, sensitivity_id) ||
!identical(
metadata$optimizer_contract_signature,
sensitivity_optimizer_contract_signature
) ||
!identical(
metadata$workflow_run_identity$config$optimizer,
sensitivity_optimizer_contract
) ||
!identical(
metadata$workflow_run_identity$config$harvest_wall_contract,
sensitivity_harvest_wall_contract
) ||
!identical(
metadata$workflow_run_identity$config$harvest_wall_decision,
sensitivity_harvest_wall_decision
) ||
!identical(
metadata$workflow_run_identity$config$harvest_wall_recomputation_tolerance,
sensitivity_harvest_wall_recomputation_tolerance
)) {
stop("`metadata` must be the matching per-sensitivity metadata.", call. = FALSE)
}
if (length(max_passes) != 1L || !is.numeric(max_passes) ||
!is.finite(max_passes) || max_passes != as.integer(max_passes) ||
!identical(
as.integer(max_passes),
sensitivity_optimizer_contract$primary$max_passes
)) {
stop(
"`max_passes` must match the hashed sensitivity optimizer contract.",
call. = FALSE
)
}
if (length(gradient_tolerance) != 1L ||
!is.numeric(gradient_tolerance) || !is.finite(gradient_tolerance) ||
gradient_tolerance <= 0 ||
!identical(
as.numeric(gradient_tolerance),
as.numeric(sensitivity_optimizer_contract$acceptance$max_gradient)
)) {
stop(
"`gradient_tolerance` must match the hashed sensitivity optimizer contract.",
call. = FALSE
)
}
if (!is.list(diagnostics) || !is.list(metadata)) {
stop("`diagnostics` and `metadata` must be lists.", call. = FALSE)
}
reserved_diagnostics <- c(
"initial_nll", "final_nll", "max_gradient", "gradient_l2",
"optimizer_contract", "optimizer_contract_signature",
"optimizer_history", "optimizer_summary", "biological_state_mle",
"harvest_wall_mle", "esc31_harvest_wall_mle"
)
supplied_reserved <- intersect(names(diagnostics), reserved_diagnostics)
if (length(supplied_reserved)) {
stop(
"`diagnostics` may not replace optimizer diagnostics: ",
paste(supplied_reserved, collapse = ", "), ".",
call. = FALSE
)
}
setup <- prepare_sensitivity_model(
data_sens = data_sens,
parameter_overrides = parameter_overrides,
estimated_parameters = estimated_parameters,
reference_obj = reference_obj
)
setup_matches_metadata <- all(vapply(
names(setup$scientific_config),
function(name) identical(metadata[[name]], setup$scientific_config[[name]]),
logical(1)
))
if (!setup_matches_metadata) {
stop(
"The current transformed data, parameters, or map do not match metadata for `",
sensitivity_id, "`.",
call. = FALSE
)
}
data_sens <- setup$data
parameters_sens <- setup$parameters
map_sens <- setup$map
fit <- sbt_fit(
data_sens,
control = sensitivity_optimizer_contract$primary$control,
metadata = utils::modifyList(
list(
assessment = "ESC31",
label = label
),
metadata
),
optimizer = sensitivity_optimizer_contract$implementation
)
fit <- sbt_add_parameters(fit, parameters_sens)
fit <- sbt_add_map(fit, map_sens)
fit <- sbt_add_priors(fit)
fit <- sbt_build_object(fit)
obj_sens <- sbt_obj(fit)
bounds_sens <- fit$bounds
optimizer_start <- obj_sens$par
bound_tolerance <- sensitivity_optimizer_contract$acceptance$bound_tolerance
initial_diagnostics <- sensitivity_point_diagnostics(
obj_sens,
optimizer_start,
bounds_sens,
bound_tolerance = bound_tolerance
)
if (!isTRUE(initial_diagnostics$valid)) {
stop(
label,
" has non-finite or out-of-bounds starting parameters, objective, or gradient.",
call. = FALSE
)
}
initial_nll <- initial_diagnostics$objective
history <- data.frame(
pass = integer(),
stage = character(),
attempt = integer(),
objective = numeric(),
max_abs_gradient = numeric(),
gradient_l2 = numeric(),
convergence = integer(),
iterations = integer(),
function_evaluations = integer(),
gradient_evaluations = integer(),
elapsed_seconds = numeric(),
finite_parameters = logical(),
within_bounds = logical(),
finite_objective = logical(),
finite_gradient = logical(),
accepted_as_best = logical(),
previous_objective = numeric(),
relative_objective_decrease = numeric(),
gradient_ratio = numeric(),
relative_parameter_step = numeric(),
transition = character(),
transition_reason = character(),
scale_min = numeric(),
scale_max = numeric(),
nonpositive_hessian_diagonal = integer(),
hessian_reciprocal_condition = numeric(),
alpha = numeric(),
armijo_pass = logical(),
gradient_improvement = logical(),
message = character(),
stringsAsFactors = FALSE
)
append_optimizer_history <- function(
stage, attempt, point, result = NULL, accepted_as_best = FALSE,
elapsed_seconds = NA_real_, scale = NULL,
nonpositive_hessian_diagonal = NA_integer_,
hessian_reciprocal_condition = NA_real_, alpha = NA_real_,
armijo_pass = NA, gradient_improvement = NA,
progress = list(
previous_objective = NA_real_,
relative_objective_decrease = NA_real_,
gradient_ratio = NA_real_,
relative_parameter_step = NA_real_
),
transition = "pending", transition_reason = "not classified",
message = NULL) {
evaluations <- result$evaluations %||%
c("function" = NA_integer_, "gradient" = NA_integer_)
convergence <- result$convergence %||% NA_integer_
iterations <- result$iterations %||% NA_integer_
function_evaluations <- if (
!is.null(names(evaluations)) && "function" %in% names(evaluations)
) evaluations[["function"]] else NA_integer_
gradient_evaluations <- if (
!is.null(names(evaluations)) && "gradient" %in% names(evaluations)
) evaluations[["gradient"]] else NA_integer_
result_message <- paste(
as.character(message %||% result$message %||% stage),
collapse = "; "
)
history <<- rbind(history, data.frame(
pass = nrow(history),
stage = as.character(stage),
attempt = as.integer(attempt),
objective = as.numeric(point$objective),
max_abs_gradient = as.numeric(point$max_abs_gradient),
gradient_l2 = as.numeric(point$gradient_l2),
convergence = as.integer(convergence),
iterations = as.integer(iterations),
function_evaluations = as.integer(function_evaluations),
gradient_evaluations = as.integer(gradient_evaluations),
elapsed_seconds = as.numeric(elapsed_seconds),
finite_parameters = isTRUE(point$finite_parameters),
within_bounds = isTRUE(point$within_bounds),
finite_objective = isTRUE(point$finite_objective),
finite_gradient = isTRUE(point$finite_gradient),
accepted_as_best = isTRUE(accepted_as_best),
previous_objective = as.numeric(progress$previous_objective),
relative_objective_decrease = as.numeric(
progress$relative_objective_decrease
),
gradient_ratio = as.numeric(progress$gradient_ratio),
relative_parameter_step = as.numeric(
progress$relative_parameter_step
),
transition = as.character(transition),
transition_reason = as.character(transition_reason),
scale_min = if (is.null(scale)) NA_real_ else min(scale),
scale_max = if (is.null(scale)) NA_real_ else max(scale),
nonpositive_hessian_diagonal = as.integer(
nonpositive_hessian_diagonal
),
hessian_reciprocal_condition = as.numeric(
hessian_reciprocal_condition
),
alpha = as.numeric(alpha),
armijo_pass = as.logical(armijo_pass),
gradient_improvement = as.logical(gradient_improvement),
message = as.character(result_message),
stringsAsFactors = FALSE
))
invisible(NULL)
}
set_last_optimizer_transition <- function(transition, transition_reason) {
if (!nrow(history)) {
stop("Cannot classify an empty optimizer history.", call. = FALSE)
}
updated_history <- history
updated_history$transition[[nrow(updated_history)]] <- transition
updated_history$transition_reason[[nrow(updated_history)]] <-
transition_reason
history <<- updated_history
invisible(NULL)
}
append_optimizer_history(
stage = "start",
attempt = 0L,
point = initial_diagnostics,
accepted_as_best = TRUE,
transition = "seed",
transition_reason = "seeded sensitivity parameters",
message = "seeded sensitivity parameters"
)
best <- list(par = optimizer_start, diagnostics = initial_diagnostics)
opt_sens <- NULL
final_stage <- NA_character_
nlminb_calls <- 0L
primary_passes <- 0L
scaled_passes <- 0L
certification_passes <- 0L
newton_metadata <- list(
attempted = FALSE,
accepted = FALSE,
status = "not required"
)
run_nlminb_stage <- function(stage, attempt, stage_control,
use_hessian = FALSE, scale = NULL,
nonpositive_hessian_diagonal = NA_integer_) {
previous_best <- best
start <- previous_best$par
result <- NULL
timing <- system.time({
result <- tryCatch(
{
if (isTRUE(use_hessian)) {
nlminb(
start = start,
objective = obj_sens$fn,
gradient = obj_sens$gr,
hessian = obj_sens$he,
lower = bounds_sens$lower,
upper = bounds_sens$upper,
control = stage_control
)
} else if (!is.null(scale)) {
nlminb(
start = start,
objective = obj_sens$fn,
gradient = obj_sens$gr,
scale = scale,
lower = bounds_sens$lower,
upper = bounds_sens$upper,
control = stage_control
)
} else {
nlminb(
start = start,
objective = obj_sens$fn,
gradient = obj_sens$gr,
lower = bounds_sens$lower,
upper = bounds_sens$upper,
control = stage_control
)
}
},
error = function(e) e
)
})
nlminb_calls <<- nlminb_calls + 1L
if (inherits(result, "error")) {
failed <- list(
finite_parameters = FALSE,
within_bounds = FALSE,
finite_objective = FALSE,
finite_gradient = FALSE,
objective = Inf,
max_abs_gradient = Inf,
gradient_l2 = Inf
)
progress <- sensitivity_optimizer_progress(
previous_best$par,
previous_best$diagnostics,
NULL,
failed
)
append_optimizer_history(
stage = stage,
attempt = attempt,
point = failed,
elapsed_seconds = timing[["elapsed"]],
scale = scale,
nonpositive_hessian_diagonal = nonpositive_hessian_diagonal,
progress = progress,
transition = "retain_previous_best",
transition_reason = "optimizer_error",
message = conditionMessage(result)
)
return(list(result = NULL, diagnostics = failed, accepted = FALSE))
}
point <- sensitivity_point_diagnostics(
obj_sens,
result$par,
bounds_sens,
bound_tolerance = bound_tolerance
)
if (isTRUE(point$finite_objective)) result$objective <- point$objective
progress <- sensitivity_optimizer_progress(
previous_best$par,
previous_best$diagnostics,
result$par,
point
)
accepted <- isTRUE(point$valid) &&
point$objective <= previous_best$diagnostics$objective
if (accepted) {
best <<- list(par = result$par, diagnostics = point)
}
default_transition_reason <- if (accepted) {
"finite_nonworsening_candidate"
} else if (!isTRUE(point$valid)) {
"invalid_or_nonfinite_candidate"
} else {
"objective_worsened"
}
append_optimizer_history(
stage = stage,
attempt = attempt,
point = point,
result = result,
accepted_as_best = accepted,
elapsed_seconds = timing[["elapsed"]],
scale = scale,
nonpositive_hessian_diagonal = nonpositive_hessian_diagonal,
progress = progress,
transition = if (accepted) {
"stage_candidate_retained"
} else {
"retain_previous_best"
},
transition_reason = default_transition_reason
)
list(result = result, diagnostics = point, accepted = accepted)
}
for (attempt in seq_len(max_passes)) {
primary_passes <- primary_passes + 1L
previous_best <- best
primary_fit <- NULL
primary_timing <- system.time({
primary_fit <- tryCatch(
sbt_optimise(
fit,
n_passes = 1L,
control = sensitivity_optimizer_contract$primary$control,
check = FALSE
),
error = function(error) error
)
})
nlminb_calls <- nlminb_calls + 1L
if (inherits(primary_fit, "error")) {
failed <- list(
finite_parameters = FALSE,
within_bounds = FALSE,
finite_objective = FALSE,
finite_gradient = FALSE,
objective = Inf,
max_abs_gradient = Inf,
gradient_l2 = Inf
)
append_optimizer_history(
stage = "primary bounded nlminb",
attempt = attempt,
point = failed,
elapsed_seconds = primary_timing[["elapsed"]],
transition = "retain_previous_best",
transition_reason = "optimizer_error",
message = conditionMessage(primary_fit)
)
stage_result <- list(
result = NULL,
diagnostics = failed,
accepted = FALSE
)
} else {
fit <- primary_fit
obj_sens <- sbt_obj(fit)
bounds_sens <- fit$bounds
primary_opt <- fit$fit$opt
primary_point <- sensitivity_point_diagnostics(
obj_sens,
primary_opt$par,
bounds_sens,
bound_tolerance = bound_tolerance
)
if (isTRUE(primary_point$finite_objective)) {
primary_opt$objective <- primary_point$objective
}
primary_progress <- sensitivity_optimizer_progress(
previous_best$par,
previous_best$diagnostics,
primary_opt$par,
primary_point
)
primary_accepted <- isTRUE(primary_point$valid) &&
primary_point$objective <= previous_best$diagnostics$objective
if (primary_accepted) {
best <- list(par = primary_opt$par, diagnostics = primary_point)
}
append_optimizer_history(
stage = "primary bounded nlminb",
attempt = attempt,
point = primary_point,
result = primary_opt,
accepted_as_best = primary_accepted,
elapsed_seconds = primary_timing[["elapsed"]],
progress = primary_progress,
transition = if (primary_accepted) {
"stage_candidate_retained"
} else {
"retain_previous_best"
},
transition_reason = if (primary_accepted) {
"finite_nonworsening_candidate"
} else if (!isTRUE(primary_point$valid)) {
"invalid_or_nonfinite_candidate"
} else {
"objective_worsened"
},
message = paste(
"sbt_optimise primary pass:",
primary_opt$message %||% "completed"
)
)
stage_result <- list(
result = primary_opt,
diagnostics = primary_point,
accepted = primary_accepted
)
}
primary_certified <- isTRUE(stage_result$accepted) &&
sensitivity_optimizer_certified(
stage_result$result,
stage_result$diagnostics,
gradient_tolerance
)
primary_transition <- sensitivity_optimizer_contract$primary$transition
if (primary_certified) {
set_last_optimizer_transition(
primary_transition$certified,
"strict_numeric_certification_passed"
)
opt_sens <- stage_result$result
final_stage <- "primary bounded nlminb"
break
} else if (isTRUE(stage_result$accepted)) {
normal_convergence <- is.list(stage_result$result) &&
length(stage_result$result$convergence) == 1L &&
is.numeric(stage_result$result$convergence) &&
is.finite(stage_result$result$convergence) &&
identical(as.integer(stage_result$result$convergence), 0L)
set_last_optimizer_transition(
primary_transition$finite_nonworsening_uncertified,
if (normal_convergence) {
"maximum_gradient_gate_failed"
} else {
"nonzero_numeric_convergence"
}
)
} else {
set_last_optimizer_transition(
primary_transition$invalid_or_worsening,
history$transition_reason[[nrow(history)]]
)
}
}
if (is.null(opt_sens)) {
scaled_contract <- sensitivity_optimizer_contract$scaled
for (attempt in seq_len(scaled_contract$max_passes)) {
scaling_hessian <- tryCatch(
obj_sens$he(best$par),
error = function(e) e
)
valid_hessian <- is.matrix(scaling_hessian) &&
identical(dim(scaling_hessian), c(length(best$par), length(best$par))) &&
all(is.finite(scaling_hessian))
if (!valid_hessian) {
hessian_message <- if (inherits(scaling_hessian, "error")) {
conditionMessage(scaling_hessian)
} else {
"The scaling Hessian was non-finite or had the wrong dimensions."
}
append_optimizer_history(
stage = "scaled Hessian unavailable",
attempt = attempt,
point = best$diagnostics,
transition = "advance_to_newton",
transition_reason = "invalid_or_nonfinite_scaling_hessian",
message = hessian_message
)
break
}
hessian_diagonal <- diag(scaling_hessian)
parameter_scale <- 1 / sqrt(pmax(
abs(hessian_diagonal),
scaled_contract$hessian_diagonal_floor
))
parameter_scale <- pmin(
pmax(parameter_scale, scaled_contract$scale_min),
scaled_contract$scale_max
)
scaled_passes <- scaled_passes + 1L
stage_result <- run_nlminb_stage(
stage = "scaled bounded gradient nlminb",
attempt = attempt,
stage_control = scaled_contract$control,
scale = parameter_scale,
nonpositive_hessian_diagonal = sum(hessian_diagonal <= 0)
)
scaled_certified <- isTRUE(stage_result$accepted) &&
sensitivity_optimizer_certified(
stage_result$result,
stage_result$diagnostics,
gradient_tolerance
)
if (scaled_certified) {
set_last_optimizer_transition(
"accept",
"strict_numeric_certification_passed"
)
opt_sens <- stage_result$result
final_stage <- "scaled bounded gradient nlminb"
break
} else if (isTRUE(stage_result$accepted)) {
set_last_optimizer_transition(
"continue_scaled",
"finite_nonworsening_uncertified"
)
} else {
set_last_optimizer_transition(
"retry_scaled_from_previous_best",
history$transition_reason[[nrow(history)]]
)
}
}
}
if (is.null(opt_sens) && isTRUE(sensitivity_optimizer_contract$newton$enabled)) {
newton_contract <- sensitivity_optimizer_contract$newton
newton_metadata <- list(
attempted = TRUE,
accepted = FALSE,
status = "Hessian validation pending"
)
pre_newton <- best$diagnostics
newton_hessian <- tryCatch(
obj_sens$he(best$par),
error = function(e) e
)
valid_newton_hessian <- is.matrix(newton_hessian) &&
identical(dim(newton_hessian), c(length(best$par), length(best$par))) &&
all(is.finite(newton_hessian))
if (valid_newton_hessian) {
newton_hessian <- (newton_hessian + t(newton_hessian)) / 2
hessian_cholesky <- tryCatch(
chol(newton_hessian),
error = function(e) e
)
hessian_rcond <- tryCatch(
as.numeric(rcond(newton_hessian)),
error = function(e) NA_real_
)
hessian_acceptable <- !inherits(hessian_cholesky, "error") &&
length(hessian_rcond) == 1L && is.finite(hessian_rcond) &&
hessian_rcond >= newton_contract$minimum_reciprocal_condition
} else {
hessian_cholesky <- NULL
hessian_rcond <- NA_real_
hessian_acceptable <- FALSE
}
if (!hessian_acceptable) {
newton_metadata$status <- paste0(
"skipped: Hessian was not finite, SPD, and sufficiently conditioned; rcond=",
format(hessian_rcond, digits = 6)
)
append_optimizer_history(
stage = "Newton correction skipped",
attempt = 0L,
point = pre_newton,
hessian_reciprocal_condition = hessian_rcond,
transition = "stop_newton",
transition_reason = "hessian_not_spd_or_sufficiently_conditioned",
message = newton_metadata$status
)
} else {
newton_step <- tryCatch(
as.numeric(backsolve(
hessian_cholesky,
forwardsolve(
t(hessian_cholesky),
matrix(pre_newton$gradient, ncol = 1L)
)
)),
error = function(e) numeric()
)
direction <- -newton_step
descent_slope <- if (length(direction) == length(best$par) &&
all(is.finite(direction))) {
sum(pre_newton$gradient * direction)
} else {
NA_real_
}
valid_direction <- length(direction) == length(best$par) &&
all(is.finite(direction)) && any(direction != 0) &&
is.finite(descent_slope) && descent_slope < 0
if (!valid_direction) {
newton_metadata$status <- "skipped: Newton direction was not finite and descending"
append_optimizer_history(
stage = "Newton correction skipped",
attempt = 0L,
point = pre_newton,
hessian_reciprocal_condition = hessian_rcond,
transition = "stop_newton",
transition_reason = "newton_direction_not_finite_and_descending",
message = newton_metadata$status
)
} else {
upper_limited <- direction > 0 & is.finite(bounds_sens$upper)
lower_limited <- direction < 0 & is.finite(bounds_sens$lower)
feasible_limits <- c(
(bounds_sens$upper[upper_limited] - best$par[upper_limited]) /
direction[upper_limited],
(bounds_sens$lower[lower_limited] - best$par[lower_limited]) /
direction[lower_limited]
)
feasible_limits <- feasible_limits[
is.finite(feasible_limits) & feasible_limits >= 0
]
maximum_feasible_alpha <- if (length(feasible_limits)) {
min(feasible_limits)
} else {
Inf
}
initial_alpha <- newton_contract$initial_alpha
if (is.finite(maximum_feasible_alpha)) {
initial_alpha <- min(
initial_alpha,
newton_contract$fraction_to_boundary * maximum_feasible_alpha
)
}
if (!is.finite(initial_alpha) || initial_alpha <= 0) {
newton_metadata$status <- "skipped: Newton direction had no positive bounded step"
append_optimizer_history(
stage = "Newton correction skipped",
attempt = 0L,
point = pre_newton,
hessian_reciprocal_condition = hessian_rcond,
transition = "stop_newton",
transition_reason = "no_positive_bounded_newton_step",
message = newton_metadata$status
)
} else {
for (backtrack in 0:newton_contract$maximum_backtracks) {
alpha <- initial_alpha * newton_contract$backtrack_factor^backtrack
candidate <- best$par + alpha * direction
candidate_point <- sensitivity_point_diagnostics(
obj_sens,
candidate,
bounds_sens,
bound_tolerance = 0
)
armijo_pass <- isTRUE(candidate_point$valid) &&
candidate_point$objective <=
pre_newton$objective +
newton_contract$armijo_c1 * alpha * descent_slope
gradient_improvement <- isTRUE(candidate_point$finite_gradient) &&
candidate_point$max_abs_gradient < pre_newton$max_abs_gradient
gradient_requirement_pass <-
!isTRUE(newton_contract$require_gradient_improvement) ||
gradient_improvement
accepted_newton <- armijo_pass && gradient_requirement_pass
newton_progress <- sensitivity_optimizer_progress(
best$par,
pre_newton,
candidate,
candidate_point
)
append_optimizer_history(
stage = "bounded Newton line search",
attempt = backtrack + 1L,
point = candidate_point,
accepted_as_best = accepted_newton,
hessian_reciprocal_condition = hessian_rcond,
alpha = alpha,
armijo_pass = armijo_pass,
gradient_improvement = gradient_improvement,
progress = newton_progress,
transition = if (accepted_newton) {
"retain_newton_candidate_then_certify"
} else {
"continue_newton_backtracking"
},
transition_reason = if (accepted_newton) {
"armijo_and_gradient_improvement_passed"
} else if (!armijo_pass) {
"armijo_check_failed"
} else {
"gradient_improvement_check_failed"
},
message = if (accepted_newton) {
"accepted SPD Newton correction"
} else {
"rejected Newton candidate"
}
)
if (accepted_newton) {
best <- list(par = candidate, diagnostics = candidate_point)
newton_metadata <- list(
attempted = TRUE,
accepted = TRUE,
status = "accepted; bounded nlminb certification required",
hessian_reciprocal_condition = hessian_rcond,
alpha = alpha,
max_abs_step = max(abs(alpha * direction)),
pre_objective = pre_newton$objective,
post_objective = candidate_point$objective,
pre_max_abs_gradient = pre_newton$max_abs_gradient,
post_max_abs_gradient = candidate_point$max_abs_gradient,
armijo_c1 = newton_contract$armijo_c1,
descent_slope = descent_slope
)
break
}
}
if (!isTRUE(newton_metadata$accepted)) {
newton_metadata$status <-
"no bounded Newton candidate passed Armijo and gradient checks"
set_last_optimizer_transition(
"stop_newton",
"no_newton_candidate_passed_safeguards"
)
}
}
}
}
if (isTRUE(newton_metadata$accepted)) {
certification_contract <- sensitivity_optimizer_contract$certification
for (attempt in seq_len(certification_contract$max_passes)) {
certification_passes <- certification_passes + 1L
stage_result <- run_nlminb_stage(
stage = "bounded gradient nlminb certification",
attempt = attempt,
stage_control = certification_contract$control
)
certification_passed <- isTRUE(stage_result$accepted) &&
sensitivity_optimizer_certified(
stage_result$result,
stage_result$diagnostics,
gradient_tolerance
)
if (certification_passed) {
set_last_optimizer_transition(
"accept",
"strict_numeric_certification_passed"
)
opt_sens <- stage_result$result
final_stage <- "bounded gradient nlminb certification"
break
} else if (isTRUE(stage_result$accepted)) {
set_last_optimizer_transition(
"certification_failed",
"finite_nonworsening_uncertified"
)
} else {
set_last_optimizer_transition(
"certification_failed_with_rollback",
history$transition_reason[[nrow(history)]]
)
}
}
}
}
if (is.null(opt_sens)) {
stop(
label,
" did not meet the staged optimizer contract after ",
primary_passes, " primary pass(es), ", scaled_passes,
" scaled pass(es), and ", certification_passes,
" certification pass(es); best maximum gradient = ",
signif(best$diagnostics$max_abs_gradient, 6),
", best objective = ", signif(best$diagnostics$objective, 10), ".",
call. = FALSE
)
}
final_diagnostics <- sensitivity_point_diagnostics(
obj_sens,
opt_sens$par,
bounds_sens,
bound_tolerance = bound_tolerance
)
if (!sensitivity_optimizer_certified(
opt_sens,
final_diagnostics,
gradient_tolerance
)) {
stop(
label,
" failed strict final optimizer certification after the staged fit.",
call. = FALSE
)
}
if (any(opt_sens$par < bounds_sens$lower) ||
any(opt_sens$par > bounds_sens$upper)) {
stop(label, " has final parameters outside the optimizer bounds.",
call. = FALSE)
}
opt_sens$objective <- final_diagnostics$objective
obj_sens$par <- opt_sens$par
obj_sens$env$last.par.best <- opt_sens$par
final_nll <- final_diagnostics$objective
max_gradient <- final_diagnostics$max_abs_gradient
estimability <- tryCatch(
{
final_hessian <- obj_sens$he(opt_sens$par)
if (!is.matrix(final_hessian) ||
!identical(
dim(final_hessian),
c(length(opt_sens$par), length(opt_sens$par))
) || any(!is.finite(final_hessian))) {
stop("The final Hessian is non-finite or has invalid dimensions.")
}
check_estimability(obj = obj_sens, h = final_hessian)
},
error = function(e) e
)
if (inherits(estimability, "error")) {
stop(label, " estimability check failed: ", conditionMessage(estimability), call. = FALSE)
}
if (length(estimability$WhichBad) > 0L) {
stop(label, " estimability check found non-estimable parameters.", call. = FALSE)
}
biological_state_mle <- diagnose_sbt_states(
obj_sens,
data = data_sens,
mle_par = opt_sens$par,
cores = 1L
)
if (!esc31_biological_state_diagnostics_pass(biological_state_mle, 1L)) {
stop(label, " failed the raw harvest or biological-state gate.",
call. = FALSE)
}
harvest_wall_mle <- sensitivity_harvest_wall_report_diagnostics(
data_sens,
obj_sens$report(opt_sens$par)
)
if (!isTRUE(harvest_wall_mle$passes)) {
stop(
label,
" failed the approved preventive harvest-wall gate: ",
harvest_wall_mle$reason,
call. = FALSE
)
}
symmetric_final_hessian <- (final_hessian + t(final_hessian)) / 2
final_hessian_cholesky <- !inherits(
try(chol(symmetric_final_hessian), silent = TRUE),
"try-error"
)
final_hessian_rcond <- tryCatch(
as.numeric(rcond(symmetric_final_hessian)),
error = function(e) NA_real_
)
at_lower_bound <- is.finite(bounds_sens$lower) &
abs(opt_sens$par - bounds_sens$lower) <= bound_tolerance
at_upper_bound <- is.finite(bounds_sens$upper) &
abs(opt_sens$par - bounds_sens$upper) <= bound_tolerance
primary_history <- history[
history$stage == "primary bounded nlminb",
,
drop = FALSE
]
if (nrow(primary_history) != 1L) {
stop(
"The single-pass primary optimizer contract produced an invalid history.",
call. = FALSE
)
}
optimizer_summary <- list(
schema_version = 2L,
contract_signature = sensitivity_optimizer_contract_signature,
certified = TRUE,
final_stage = final_stage,
primary_passes = primary_passes,
primary_transition = primary_history$transition[[1L]],
primary_transition_reason = primary_history$transition_reason[[1L]],
scaled_passes = scaled_passes,
newton = newton_metadata,
certification_passes = certification_passes,
total_nlminb_calls = nlminb_calls,
final_convergence = as.integer(opt_sens$convergence),
final_message = opt_sens$message %||% final_stage,
initial_objective = initial_nll,
final_objective = final_nll,
final_max_abs_gradient = max_gradient,
final_gradient_l2 = final_diagnostics$gradient_l2,
final_hessian_cholesky = final_hessian_cholesky,
final_hessian_reciprocal_condition = final_hessian_rcond,
at_lower_bound = sum(at_lower_bound),
at_upper_bound = sum(at_upper_bound),
bound_violations = 0L
)
fit <- sbt_add_optimisation(
fit,
opt = opt_sens,
estimability = estimability,
diagnostics = utils::modifyList(
list(
optimizer = list(
method = sensitivity_optimizer_contract$implementation,
n_passes = nlminb_calls
),
initial_nll = initial_nll,
final_nll = final_nll,
max_gradient = max_gradient,
gradient_l2 = final_diagnostics$gradient_l2,
optimizer_contract = sensitivity_optimizer_contract,
optimizer_contract_signature = sensitivity_optimizer_contract_signature,
optimizer_history = history,
optimizer_summary = optimizer_summary,
biological_state_mle = biological_state_mle,
esc31_harvest_wall_mle = harvest_wall_mle
),
diagnostics
),
optimizer = sensitivity_optimizer_contract$implementation,
check = FALSE
)
check_mle(
fit,
gradient_tolerance = gradient_tolerance,
cores = 1L,
mode = "full"
)
}