dir.create(mle_grid_root, recursive = TRUE, showWarnings = FALSE)
m10_grid_range <- as.numeric(quantile(
m10_posterior,
probs = m10_grid_range_probs,
na.rm = TRUE
))
m10_grid_values <- round(seq(m10_grid_range[1], m10_grid_range[2], length.out = m10_grid_n), 3)
m0_grid_values <- as.numeric(quantile(
m0_posterior,
probs = m0_grid_probs,
na.rm = TRUE
))
if (length(m0_grid_values) != m0_grid_n ||
any(!is.finite(m0_grid_values)) ||
anyDuplicated(m0_grid_values)) {
stop("The stacked posterior did not produce three distinct finite M0 quantiles.",
call. = FALSE)
}
natural_mortality_grid_values <- bind_rows(
tibble(
parameter = "M0", position = seq_along(m0_grid_values),
n_values = length(m0_grid_values), value = m0_grid_values,
source = "1%, 50%, and 95% combined MCMC posterior quantiles"
),
tibble(
parameter = "M10", position = seq_along(m10_grid_values),
n_values = length(m10_grid_values), value = m10_grid_values,
source = "1%-95% combined MCMC posterior range"
)
)
m10_mle_data <- base_fit$data
m10_mle_data$M_switch <-
esc31_direct_mle_grid_specification$M_switch
m10_mle_parameters <- get_parameters(m10_mle_data)
shared_mle_parameter_names <- intersect(
names(m10_mle_parameters),
names(base_fit$parameters)
)
for (parameter_name in shared_mle_parameter_names) {
if (!identical(
length(m10_mle_parameters[[parameter_name]]),
length(base_fit$parameters[[parameter_name]])
) ||
!identical(
dim(m10_mle_parameters[[parameter_name]]),
dim(base_fit$parameters[[parameter_name]])
)) {
stop(
"The direct-M grid and base parameter layouts differ for `",
parameter_name, "`.",
call. = FALSE
)
}
m10_mle_parameters[[parameter_name]] <-
base_fit$parameters[[parameter_name]]
}
base_mortality_report <- sbt_fit_report(base_fit)
m10_mle_parameters$par_log_m0 <-
log(as.numeric(base_mortality_report$par_m0))
m10_mle_parameters$par_log_m4 <-
log(as.numeric(base_mortality_report$par_m4))
m10_mle_parameters$par_log_m10 <-
log(as.numeric(base_mortality_report$par_m10))
m10_mle_parameters$par_log_m30 <-
log(as.numeric(base_mortality_report$par_m30))
m10_mle_data$priors <- get_priors(m10_mle_parameters)
m10_mle_grid <- expand.grid(
h = mle_grid_h_values,
psi = mle_grid_psi_values,
m0 = m0_grid_values,
m10 = m10_grid_values
) |>
arrange(psi, h, m0, m10) |>
mutate(Cell = row_number(), .before = 1)
if (nrow(m10_mle_grid) !=
esc31_direct_mle_grid_specification$cells ||
nrow(distinct(m10_mle_grid, h, psi, m0, m10)) !=
esc31_direct_mle_grid_specification$cells) {
stop("The direct-M dependent grid must contain 108 distinct cells.",
call. = FALSE)
}
m10_mle_map <- base_fit$map
m10_mle_map <- m10_mle_map[
intersect(names(m10_mle_map), names(m10_mle_parameters))
]
m10_mle_map$par_log_h <- factor(NA)
m10_mle_map$par_log_psi <- factor(NA)
m10_mle_map$par_log_m0 <- factor(NA)
m10_mle_map$par_log_m10 <- factor(NA)
direct_mle_fixed_parameters <-
esc31_direct_mle_grid_specification$fixed_parameters
direct_mle_estimated_parameters <-
esc31_direct_mle_grid_specification$estimated_mortality_parameters
direct_mle_parameter_is_fixed <- function(name) {
name %in% names(m10_mle_map) &&
length(m10_mle_map[[name]]) > 0L &&
all(is.na(m10_mle_map[[name]]))
}
if (!all(c(
direct_mle_fixed_parameters,
direct_mle_estimated_parameters
) %in% names(m10_mle_parameters)) ||
!all(vapply(
direct_mle_fixed_parameters,
direct_mle_parameter_is_fixed,
logical(1)
)) ||
any(vapply(
direct_mle_estimated_parameters,
direct_mle_parameter_is_fixed,
logical(1)
))) {
stop(
"The direct-M grid must fix h, psi, M0, and M10 while estimating M4 and M30.",
call. = FALSE
)
}
m10_mle_cells <- as.integer(m10_mle_grid$Cell)
m10_mle_signature <- esc31_object_md5(list(
grid_specification = esc31_grid_specification,
direct_mle_grid_specification =
esc31_direct_mle_grid_specification,
prerequisite_acceptance = grid_prerequisite_validation[
setdiff(
names(grid_prerequisite_validation),
c(
"manifest_signature",
"validator_identity_signature",
"base_posterior_source_checksum"
)
)
],
grid_files = grid_signature(grid_diagnostics$file),
combined_source_signature = combined_source_signature,
base_fit_md5 = base_fit_md5,
base_run_signature = base_fit$provenance$metadata$run_identity$signature,
mortality_model = list(
M_switch = m10_mle_data$M_switch,
function_name =
esc31_direct_mle_grid_specification$mortality_function,
fixed = esc31_direct_mle_grid_specification$fixed_parameters,
estimated =
esc31_direct_mle_grid_specification$estimated_mortality_parameters
),
m0_grid_values = m0_grid_values,
m10_grid_values = m10_grid_values,
h_grid_values = mle_grid_h_values,
psi_grid_values = mle_grid_psi_values,
# Retain this cache-schema field name, but store all 108 distinct cells.
# No representative-cell expansion or fit reuse is performed.
representative_cells = m10_mle_cells,
check_estimability = check_m10_mle_estimability,
max_gradient_limit = m10_mle_gradient_limit,
biological_state_contract = biological_state_contract(),
harvest_wall_contract = grid_harvest_wall_identity$executable,
harvest_wall_decision = grid_harvest_wall_identity$decision,
implementation =
"direct_get_M_posterior_m0_m10_estimated_m4_m30_mle_grid_108_v14"
))
m10_mle_cell_summary_passes <- function(summary) {
contract <- biological_state_contract()
is.data.frame(summary) &&
nrow(summary) == 1L &&
is.finite(summary$objective[[1L]]) &&
identical(as.integer(summary$convergence[[1L]]), 0L) &&
is.finite(summary$max_gradient[[1L]]) &&
summary$max_gradient[[1L]] <= m10_mle_gradient_limit &&
isTRUE(summary$estimable[[1L]]) &&
isTRUE(summary$state_passes[[1L]]) &&
identical(as.integer(summary$state_invalid_cells[[1L]]), 0L) &&
is.finite(summary$state_max_raw_harvest[[1L]]) &&
summary$state_max_raw_harvest[[1L]] <=
contract$hrate_limit + contract$hrate_tolerance &&
is.finite(summary$state_min_number[[1L]]) &&
summary$state_min_number[[1L]] > contract$number_tolerance &&
is.finite(summary$state_min_spawning_biomass[[1L]]) &&
summary$state_min_spawning_biomass[[1L]] > 0 &&
is.finite(summary$state_min_recruitment[[1L]]) &&
summary$state_min_recruitment[[1L]] > 0 &&
is.finite(summary$state_max_harvest_penalty[[1L]]) &&
abs(summary$state_max_harvest_penalty[[1L]]) <=
contract$penalty_tolerance &&
is.finite(summary$state_lp_penalty[[1L]]) &&
abs(summary$state_lp_penalty[[1L]]) <=
contract$penalty_tolerance &&
is.finite(summary$state_max_catch_relative_error[[1L]]) &&
summary$state_max_catch_relative_error[[1L]] <=
contract$catch_relative_tolerance &&
is.character(summary$state_checksum) &&
grepl("^[0-9a-f]{32}$", summary$state_checksum[[1L]])
}
m10_mle_optimizer_recovery <- list(
implementation =
"scaled_bounded_gradient_newton_certification_v3",
attempts = 2L,
predecessor_methods = c(
"hessian_diagonal_scaled_bounded_gradient_nlminb_v1",
"scaled_bounded_gradient_newton_certification_v2"
),
scaled = list(
max_passes = 1L,
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(
minimum_reciprocal_condition = 1e-12,
initial_alpha = 1,
fraction_to_boundary = 0.995,
backtrack_factor = 0.5,
maximum_backtracks = 12L,
armijo_c1 = 1e-4,
objective_numerical_tolerance = 1e-8,
require_gradient_improvement = TRUE
),
certification = list(
max_passes = 1L,
control = list(eval.max = 2000L, iter.max = 1000L)
)
)
m10_mle_results <- if (file.exists(m10_mle_grid_file) && !rebuild_m10_mle_grid) {
read_rds_cache(m10_mle_grid_file)
} else {
NULL
}
m10_mle_cache_signature_valid <-
is.list(m10_mle_results) &&
is.character(m10_mle_results$signature) &&
length(m10_mle_results$signature) == 1L &&
!is.na(m10_mle_results$signature) &&
grepl("^[0-9a-f]{32}$", m10_mle_results$signature)
m10_mle_cache_current <- m10_mle_cache_signature_valid &&
all(c(
"signature", "m0_quantile_probs", "m10_range_probs",
"posterior_ranges",
"natural_mortality_grid_values", "grid", "summary", "biomass",
"state_records", "optimizer_recovery"
) %in% names(m10_mle_results)) &&
identical(
m10_mle_results$optimizer_recovery,
m10_mle_optimizer_recovery
) &&
isTRUE(all.equal(
as.numeric(m10_mle_results$m0_quantile_probs),
as.numeric(m0_grid_probs),
tolerance = 0,
check.attributes = FALSE
)) &&
isTRUE(all.equal(
as.numeric(m10_mle_results$m10_range_probs),
as.numeric(m10_grid_range_probs),
tolerance = 0,
check.attributes = FALSE
)) &&
isTRUE(all.equal(
as.data.frame(m10_mle_results$natural_mortality_grid_values),
as.data.frame(natural_mortality_grid_values),
tolerance = 0,
check.attributes = FALSE
)) &&
isTRUE(all.equal(
as.data.frame(m10_mle_results$posterior_ranges),
as.data.frame(bind_rows(
tibble(
parameter = "M0",
probability = m0_grid_probs,
value = m0_grid_values
),
tibble(
parameter = "M10",
probability = m10_grid_range_probs,
value = m10_grid_range
)
)),
tolerance = 0,
check.attributes = FALSE
)) &&
isTRUE(all.equal(
as.data.frame(m10_mle_results$grid),
as.data.frame(m10_mle_grid),
tolerance = 0,
check.attributes = FALSE
)) &&
is.data.frame(m10_mle_results$summary) &&
nrow(m10_mle_results$summary) == length(m10_mle_cells) &&
all(vapply(
seq_len(nrow(m10_mle_results$summary)),
function(i) {
m10_mle_cell_summary_passes(
m10_mle_results$summary[i, , drop = FALSE]
)
},
logical(1)
)) &&
is.data.frame(m10_mle_results$biomass)
if (isTRUE(m10_mle_cache_current)) {
m10_mle_cache_current <- sbt::validate_mle_grid_state_records(
records = m10_mle_results$state_records,
saved_summary = m10_mle_results$summary,
saved_biomass = m10_mle_results$biomass,
grid = m10_mle_grid,
data = m10_mle_data,
parameters = m10_mle_parameters,
map = m10_mle_map,
cores = grid_state_diagnostic_cores
)
}
m10_mle_signature_audit <- if (
isTRUE(m10_mle_cache_current) &&
!identical(m10_mle_results$signature, m10_mle_signature)
) {
list(
source_signature = m10_mle_results$signature,
current_scientific_signature = m10_mle_signature,
compatibility = paste(
"complete 108-cell input, optimum, gradient, estimability, Hessian,",
"biological-state, biomass, and payload revalidation under the",
"unchanged direct-M scientific contract"
)
)
} else {
NULL
}
if (!isTRUE(m10_mle_cache_current)) {
if (!run_m10_mle_grid) {
stop(
"The compatible 108-cell MLE grid is unavailable. Set ",
"ESC31_RUN_MLE_GRID=true only after the approved MCMC grid passes every production gate.",
call. = FALSE
)
}
base_start <- base_fit$fit$opt$par
m10_mle_cell_dir <- file.path(
mle_grid_root,
"direct_get_M_posterior_m0_m10_mle_grid_108_cells_v2"
)
dir.create(m10_mle_cell_dir, recursive = TRUE, showWarnings = FALSE)
m10_mle_cell_file <- function(cell) {
file.path(
m10_mle_cell_dir,
sprintf("cell%03d.rds", as.integer(cell))
)
}
m10_mle_cell_record_usable <- function(record, cell) {
is.list(record) &&
identical(record$signature, m10_mle_signature) &&
identical(as.integer(record$cell), as.integer(cell)) &&
is.list(record$result) &&
is.data.frame(record$result$summary) &&
nrow(record$result$summary) == 1L &&
identical(
as.integer(record$result$summary$Cell),
as.integer(cell)
) &&
is.data.frame(record$result$biomass) &&
is.list(record$result$state_records) &&
length(record$result$state_records) == 1L
}
m10_mle_cell_record_current <- function(record, cell) {
m10_mle_cell_record_usable(record, cell) &&
m10_mle_cell_summary_passes(record$result$summary)
}
m10_mle_cell_record_start <- function(record, fallback) {
candidate <- tryCatch(
record$result$state_records[[1L]]$fitted_par,
error = function(error) NULL
)
if (is.numeric(candidate) && length(candidate) &&
!is.null(names(candidate)) && all(is.finite(candidate))) {
candidate
} else {
fallback
}
}
m10_mle_align_start <- function(cell_start, saved_start) {
if (is.null(saved_start)) return(cell_start)
cell_names <- sbt::expand_parameter_names(names(cell_start))
saved_names <- sbt::expand_parameter_names(names(saved_start))
common <- intersect(cell_names, saved_names)
if (!length(common)) {
stop("The saved cell state has no active parameters in common.",
call. = FALSE)
}
cell_start[match(common, cell_names)] <-
saved_start[match(common, saved_names)]
cell_start
}
m10_mle_staged_refinement <- function(
grid_row, saved_start, prior_history = NULL,
scaled_already_completed = FALSE) {
cell_parameters <- sbt::make_mle_grid_parameters(
grid_row,
m10_mle_parameters,
allow_new_parameters = FALSE
)[[1L]]
obj <- RTMB::MakeADFun(
func = sbt::cmb(sbt::sbt_model, m10_mle_data),
parameters = cell_parameters,
map = m10_mle_map,
random = character()
)
cell_bounds <- sbt::get_bounds(
obj = obj,
parameters = cell_parameters
)
start <- m10_mle_align_start(obj$par, saved_start)
point_diagnostics <- function(par) {
finite_parameters <- is.numeric(par) &&
length(par) == length(obj$par) &&
identical(names(par), names(obj$par)) &&
all(is.finite(par))
within_bounds <- finite_parameters &&
all(par >= cell_bounds$lower) &&
all(par <= cell_bounds$upper)
objective <- if (finite_parameters && within_bounds) {
tryCatch(as.numeric(obj$fn(par)), error = function(error) Inf)
} else {
Inf
}
finite_objective <- length(objective) == 1L &&
is.finite(objective)
gradient <- if (finite_objective) {
tryCatch(as.numeric(obj$gr(par)), error = function(error) numeric())
} else {
numeric()
}
finite_gradient <- length(gradient) == length(par) &&
all(is.finite(gradient))
list(
valid = finite_parameters && within_bounds &&
finite_objective && finite_gradient,
objective = if (finite_objective) objective else Inf,
gradient = gradient,
max_gradient = if (finite_gradient) {
max(abs(gradient))
} else {
Inf
}
)
}
start_point <- point_diagnostics(start)
if (!isTRUE(start_point$valid)) {
stop("The saved grid-cell state is not a valid refinement start.",
call. = FALSE)
}
best <- list(
par = start,
objective = start_point$objective,
gradient = start_point$gradient,
max_gradient = start_point$max_gradient,
opt = list(
par = start,
objective = start_point$objective,
convergence = 1L,
iterations = 0L,
evaluations = c("function" = 1L, "gradient" = 1L),
message = "saved state awaiting staged recovery"
)
)
history <- list()
nlminb_calls <- 0L
append_history <- function(
stage, point, result = NULL, accepted = FALSE,
scale = NULL, nonpositive_hessian_diagonal = NA_integer_,
hessian_reciprocal_condition = NA_real_, alpha = NA_real_,
armijo_pass = NA, gradient_improvement = NA) {
history[[length(history) + 1L]] <<- data.frame(
pass = length(history) + 1L,
stage = as.character(stage),
objective = as.numeric(point$objective),
max_gradient = as.numeric(point$max_gradient),
convergence = as.integer(
if (is.null(result)) NA_integer_ else result$convergence
),
accepted = isTRUE(accepted),
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),
stringsAsFactors = FALSE
)
invisible(NULL)
}
retain_candidate <- function(result, point) {
accepted <- isTRUE(point$valid) &&
point$objective <= best$objective
if (accepted) {
result$objective <- point$objective
best <<- list(
par = result$par,
objective = point$objective,
gradient = point$gradient,
max_gradient = point$max_gradient,
opt = result
)
}
accepted
}
run_bounded_nlminb <- function(stage, control, scale = NULL) {
result <- if (is.null(scale)) {
nlminb(
start = best$par,
objective = obj$fn,
gradient = obj$gr,
lower = cell_bounds$lower,
upper = cell_bounds$upper,
control = control
)
} else {
nlminb(
start = best$par,
objective = obj$fn,
gradient = obj$gr,
scale = scale,
lower = cell_bounds$lower,
upper = cell_bounds$upper,
control = control
)
}
nlminb_calls <<- nlminb_calls + 1L
point <- point_diagnostics(result$par)
accepted <- retain_candidate(result, point)
append_history(
stage = stage,
point = point,
result = result,
accepted = accepted,
scale = scale
)
list(result = result, point = point, accepted = accepted)
}
best_certified <- function() {
identical(as.integer(best$opt$convergence), 0L) &&
is.finite(best$max_gradient) &&
best$max_gradient <= m10_mle_gradient_limit
}
run_certification <- function(stage) {
for (pass in seq_len(
m10_mle_optimizer_recovery$certification$max_passes
)) {
run_bounded_nlminb(
stage = paste(stage, pass),
control = m10_mle_optimizer_recovery$certification$control
)
if (best_certified()) break
}
invisible(best_certified())
}
if (best$max_gradient <= m10_mle_gradient_limit) {
run_certification("saved-state bounded certification")
}
if (!best_certified() && !isTRUE(scaled_already_completed)) {
for (pass in seq_len(
m10_mle_optimizer_recovery$scaled$max_passes
)) {
hessian_point <- best$par
scaling_hessian <- obj$he(hessian_point)
if (!is.matrix(scaling_hessian) ||
!identical(
dim(scaling_hessian),
c(length(best$par), length(best$par))
) ||
any(!is.finite(scaling_hessian))) {
stop("The refinement scaling Hessian is invalid.", call. = FALSE)
}
hessian_diagonal <- diag(scaling_hessian)
parameter_scale <- 1 / sqrt(pmax(
abs(hessian_diagonal),
m10_mle_optimizer_recovery$scaled$hessian_diagonal_floor
))
parameter_scale <- pmin(
pmax(
parameter_scale,
m10_mle_optimizer_recovery$scaled$scale_min
),
m10_mle_optimizer_recovery$scaled$scale_max
)
stage_result <- run_bounded_nlminb(
stage = paste("scaled bounded gradient nlminb", pass),
control = m10_mle_optimizer_recovery$scaled$control,
scale = parameter_scale
)
history[[length(history)]]$
nonpositive_hessian_diagonal <-
as.integer(sum(hessian_diagonal <= 0))
if (best_certified()) break
if (isTRUE(stage_result$accepted) &&
best$max_gradient <= m10_mle_gradient_limit) {
run_certification("post-scaled bounded certification")
if (best_certified()) break
}
}
}
if (!best_certified()) {
newton_contract <- m10_mle_optimizer_recovery$newton
pre_newton <- best
newton_hessian <- obj$he(pre_newton$par)
valid_newton_hessian <- is.matrix(newton_hessian) &&
identical(
dim(newton_hessian),
c(length(pre_newton$par), length(pre_newton$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(error) error
)
hessian_rcond <- tryCatch(
as.numeric(rcond(newton_hessian)),
error = function(error) NA_real_
)
} else {
hessian_cholesky <- NULL
hessian_rcond <- NA_real_
}
hessian_acceptable <- valid_newton_hessian &&
!inherits(hessian_cholesky, "error") &&
length(hessian_rcond) == 1L &&
is.finite(hessian_rcond) &&
hessian_rcond >=
newton_contract$minimum_reciprocal_condition
if (!hessian_acceptable) {
append_history(
stage = "bounded Newton correction unavailable",
point = pre_newton,
hessian_reciprocal_condition = hessian_rcond
)
} else {
newton_step <- tryCatch(
as.numeric(backsolve(
hessian_cholesky,
forwardsolve(
t(hessian_cholesky),
matrix(pre_newton$gradient, ncol = 1L)
)
)),
error = function(error) numeric()
)
direction <- -newton_step
descent_slope <- if (
length(direction) == length(pre_newton$par) &&
all(is.finite(direction))
) {
sum(pre_newton$gradient * direction)
} else {
NA_real_
}
valid_direction <- length(direction) ==
length(pre_newton$par) &&
all(is.finite(direction)) &&
any(direction != 0) &&
is.finite(descent_slope) &&
descent_slope < 0
newton_accepted <- FALSE
if (!valid_direction) {
append_history(
stage = "bounded Newton direction unavailable",
point = pre_newton,
hessian_reciprocal_condition = hessian_rcond
)
} else {
upper_limited <- direction > 0 &
is.finite(cell_bounds$upper)
lower_limited <- direction < 0 &
is.finite(cell_bounds$lower)
feasible_limits <- c(
(
cell_bounds$upper[upper_limited] -
pre_newton$par[upper_limited]
) / direction[upper_limited],
(
cell_bounds$lower[lower_limited] -
pre_newton$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) {
for (backtrack in 0:newton_contract$maximum_backtracks) {
alpha <- initial_alpha *
newton_contract$backtrack_factor^backtrack
candidate_par <- pre_newton$par + alpha * direction
candidate_point <- point_diagnostics(candidate_par)
armijo_pass <- isTRUE(candidate_point$valid) &&
candidate_point$objective <=
pre_newton$objective +
newton_contract$armijo_c1 *
alpha * descent_slope +
newton_contract$objective_numerical_tolerance
gradient_improvement <-
is.finite(candidate_point$max_gradient) &&
candidate_point$max_gradient <
pre_newton$max_gradient
gradient_requirement_pass <-
!isTRUE(
newton_contract$require_gradient_improvement
) ||
gradient_improvement
accepted_newton <- armijo_pass &&
gradient_requirement_pass
append_history(
stage = "bounded Newton line search",
point = candidate_point,
accepted = accepted_newton,
hessian_reciprocal_condition = hessian_rcond,
alpha = alpha,
armijo_pass = armijo_pass,
gradient_improvement = gradient_improvement
)
if (accepted_newton) {
best <- list(
par = candidate_par,
objective = candidate_point$objective,
gradient = candidate_point$gradient,
max_gradient = candidate_point$max_gradient,
opt = list(
par = candidate_par,
objective = candidate_point$objective,
convergence = 1L,
iterations = 0L,
evaluations = c(
"function" = 1L,
"gradient" = 1L
),
message =
"accepted Newton correction awaiting certification"
)
)
newton_accepted <- TRUE
break
}
}
}
}
if (isTRUE(newton_accepted)) {
run_certification("post-Newton bounded certification")
}
}
}
start_objective <- start_point$objective
prior_history <- if (is.data.frame(prior_history) &&
nrow(prior_history)) {
prior_history$recovery_source <- "predecessor"
prior_history
} else {
NULL
}
current_history <- bind_rows(history)
if (nrow(current_history)) {
current_history$recovery_source <-
m10_mle_optimizer_recovery$implementation
}
obj$par <- best$par
obj$env$last.par.best <- best$par
obj$fn(best$par)
best$opt$par <- best$par
best$opt$objective <- best$objective
best$opt$convergence <- as.integer(best$opt$convergence)
obj$opt <- best$opt
obj$grid_start_fn <- start_objective
obj$grid_b0_start_multiplier <- 1
obj$grid_nlminb_passes <- nlminb_calls
obj$grid_refinement_history <- bind_rows(
prior_history,
current_history
)
list(refined_cell = obj)
}
fit_m10_mle_cell <- function(cell) {
path <- m10_mle_cell_file(cell)
record <- if (file.exists(path) && !rebuild_m10_mle_grid) {
tryCatch(read_rds_cache(path), error = function(error) NULL)
} else {
NULL
}
if (m10_mle_cell_record_current(record, cell)) {
return(record)
}
grid_row <- m10_mle_grid[
m10_mle_grid$Cell == cell,
,
drop = FALSE
]
if (!m10_mle_cell_record_usable(record, cell)) {
started <- Sys.time()
record <- tryCatch({
fits <- run_grid(
data = m10_mle_data,
grid_parameters = sbt::make_mle_grid_parameters(
grid_row,
m10_mle_parameters,
allow_new_parameters = FALSE
),
bounds = NULL,
map = m10_mle_map,
control = base_fit$control,
n_passes = 3L,
start = base_start,
b0_start_step = 1.25,
b0_start_max = 10
)
result <- sbt::summarise_mle_grid(
grid_fits = fits,
grid = grid_row,
data = m10_mle_data,
check_estimability_cells = check_m10_mle_estimability
)
list(
signature = m10_mle_signature,
cell = as.integer(cell),
primary_attempt = 1L,
recovery_method = NULL,
recovery_attempt = 0L,
start = "base_mle",
elapsed_seconds = as.numeric(
difftime(Sys.time(), started, units = "secs")
),
refinement_history = data.frame(),
result = result,
error = NULL
)
}, error = function(error) {
list(
signature = m10_mle_signature,
cell = as.integer(cell),
primary_attempt = 1L,
recovery_method = NULL,
recovery_attempt = 0L,
start = "base_mle",
elapsed_seconds = as.numeric(
difftime(Sys.time(), started, units = "secs")
),
refinement_history = data.frame(),
result = NULL,
error = conditionMessage(error)
)
})
atomic_save_rds(record, path)
if (m10_mle_cell_record_current(record, cell) ||
!m10_mle_cell_record_usable(record, cell)) {
return(record)
}
}
previous_recovery_attempt <- if (
identical(
record$recovery_method,
m10_mle_optimizer_recovery$implementation
) &&
is.numeric(record$recovery_attempt) &&
length(record$recovery_attempt) == 1L &&
is.finite(record$recovery_attempt)
) {
as.integer(record$recovery_attempt)
} else {
0L
}
if (previous_recovery_attempt >=
m10_mle_optimizer_recovery$attempts) {
return(record)
}
for (recovery_attempt in seq.int(
previous_recovery_attempt + 1L,
m10_mle_optimizer_recovery$attempts
)) {
started <- Sys.time()
prior_record <- record
continuation_start <- m10_mle_cell_record_start(
prior_record,
base_start
)
scaled_already_completed <- is.list(prior_record) &&
is.character(prior_record$recovery_method) &&
length(prior_record$recovery_method) == 1L &&
prior_record$recovery_method %in% c(
m10_mle_optimizer_recovery$implementation,
m10_mle_optimizer_recovery$predecessor_methods
) &&
is.data.frame(prior_record$refinement_history) &&
nrow(prior_record$refinement_history) > 0L
record <- tryCatch({
fits <- m10_mle_staged_refinement(
grid_row = grid_row,
saved_start = continuation_start,
prior_history = prior_record$refinement_history,
scaled_already_completed = scaled_already_completed
)
result <- sbt::summarise_mle_grid(
grid_fits = fits,
grid = grid_row,
data = m10_mle_data,
check_estimability_cells = check_m10_mle_estimability
)
list(
signature = m10_mle_signature,
cell = as.integer(cell),
primary_attempt = 1L,
recovery_method =
m10_mle_optimizer_recovery$implementation,
recovery_attempt = as.integer(recovery_attempt),
start = "previous_cell_state",
elapsed_seconds = as.numeric(
difftime(Sys.time(), started, units = "secs")
),
refinement_history =
fits[[1L]]$grid_refinement_history,
result = result,
error = NULL
)
}, error = function(error) {
list(
signature = m10_mle_signature,
cell = as.integer(cell),
primary_attempt = 1L,
recovery_method =
m10_mle_optimizer_recovery$implementation,
recovery_attempt = as.integer(recovery_attempt),
start = "previous_cell_state",
elapsed_seconds = as.numeric(
difftime(Sys.time(), started, units = "secs")
),
refinement_history = data.frame(),
result = prior_record$result,
error = conditionMessage(error)
)
})
atomic_save_rds(record, path)
if (m10_mle_cell_record_current(record, cell)) break
}
record
}
m10_mle_cell_records <- if (
.Platform$OS.type != "windows" && m10_mle_grid_cores > 1L
) {
parallel::mclapply(
m10_mle_cells,
fit_m10_mle_cell,
mc.cores = min(
m10_mle_grid_cores,
length(m10_mle_cells)
),
mc.preschedule = FALSE,
mc.set.seed = FALSE
)
} else {
lapply(m10_mle_cells, fit_m10_mle_cell)
}
failed_m10_mle_cells <- m10_mle_cells[!vapply(
seq_along(m10_mle_cell_records),
function(i) {
m10_mle_cell_record_current(
m10_mle_cell_records[[i]],
m10_mle_cells[[i]]
)
},
logical(1)
)]
if (length(failed_m10_mle_cells)) {
failure_record_index <- match(
failed_m10_mle_cells,
m10_mle_cells
)
failure_messages <- vapply(
failure_record_index,
function(i) {
m10_mle_cell_records[[i]]$error %||%
"invalid cell cache"
},
character(1)
)
stop(
"Production MLE-grid cell failures: ",
paste0(
failed_m10_mle_cells, " (", failure_messages, ")",
collapse = "; "
),
call. = FALSE
)
}
names(m10_mle_cell_records) <- as.character(m10_mle_cells)
m10_mle_grid_summary <- list(
summary = bind_rows(lapply(
m10_mle_cell_records,
function(record) record$result$summary
)),
biomass = bind_rows(lapply(
m10_mle_cell_records,
function(record) record$result$biomass
)),
state_records = lapply(
m10_mle_cell_records,
function(record) record$result$state_records[[1L]]
)
)
if (!sbt::validate_mle_grid_state_records(
records = m10_mle_grid_summary$state_records,
saved_summary = m10_mle_grid_summary$summary,
saved_biomass = m10_mle_grid_summary$biomass,
grid = m10_mle_grid,
data = m10_mle_data,
parameters = m10_mle_parameters,
map = m10_mle_map,
cores = grid_state_diagnostic_cores
)) {
stop(
"The direct-M production MLE-grid records failed independent ",
"108-cell reconstruction.",
call. = FALSE
)
}
m10_mle_results <- list(
signature = m10_mle_signature,
m0_quantile_probs = m0_grid_probs,
m10_range_probs = m10_grid_range_probs,
posterior_ranges = bind_rows(
tibble(
parameter = "M0",
probability = m0_grid_probs,
value = m0_grid_values
),
tibble(
parameter = "M10",
probability = m10_grid_range_probs,
value = m10_grid_range
)
),
natural_mortality_grid_values = natural_mortality_grid_values,
grid = m10_mle_grid,
summary = m10_mle_grid_summary$summary,
biomass = m10_mle_grid_summary$biomass,
state_records = m10_mle_grid_summary$state_records,
optimizer_recovery = m10_mle_optimizer_recovery
)
atomic_save_rds(m10_mle_results, m10_mle_grid_file)
}
m10_mle_summary <- m10_mle_results$summary |>
mutate(delta_nll = objective - min(objective, na.rm = TRUE))
required_mle_state_fields <- c(
"state_passes", "state_invalid_cells", "state_max_raw_harvest",
"state_min_number", "state_min_spawning_biomass",
"state_min_recruitment", "state_max_harvest_penalty",
"state_lp_penalty", "state_max_catch_relative_error", "state_checksum"
)
if (!all(required_mle_state_fields %in% names(m10_mle_summary)) ||
nrow(m10_mle_summary) != 108L ||
!identical(sort(as.integer(m10_mle_summary$Cell)), seq_len(108L)) ||
any(!is.finite(m10_mle_summary$objective)) ||
any(!is.finite(m10_mle_summary$max_gradient)) ||
any(m10_mle_summary$convergence != 0L) ||
any(m10_mle_summary$max_gradient > m10_mle_gradient_limit) ||
any(is.na(m10_mle_summary$estimable) | !m10_mle_summary$estimable) ||
any(is.na(m10_mle_summary$state_passes) | !m10_mle_summary$state_passes) ||
any(!is.finite(m10_mle_summary$state_invalid_cells)) ||
any(m10_mle_summary$state_invalid_cells != 0L) ||
any(!is.finite(m10_mle_summary$state_max_raw_harvest)) ||
any(m10_mle_summary$state_max_raw_harvest >
biological_state_contract()$hrate_limit +
biological_state_contract()$hrate_tolerance) ||
any(!is.finite(m10_mle_summary$state_min_number)) ||
any(m10_mle_summary$state_min_number <=
biological_state_contract()$number_tolerance) ||
any(!is.finite(m10_mle_summary$state_min_spawning_biomass) |
m10_mle_summary$state_min_spawning_biomass <= 0) ||
any(!is.finite(m10_mle_summary$state_min_recruitment) |
m10_mle_summary$state_min_recruitment <= 0) ||
any(!is.finite(m10_mle_summary$state_max_harvest_penalty)) ||
any(abs(m10_mle_summary$state_max_harvest_penalty) >
biological_state_contract()$penalty_tolerance) ||
any(!is.finite(m10_mle_summary$state_lp_penalty)) ||
any(abs(m10_mle_summary$state_lp_penalty) >
biological_state_contract()$penalty_tolerance) ||
any(!is.finite(m10_mle_summary$state_max_catch_relative_error)) ||
any(m10_mle_summary$state_max_catch_relative_error >
biological_state_contract()$catch_relative_tolerance) ||
anyNA(m10_mle_summary$state_checksum) ||
any(!grepl("^[0-9a-f]{32}$", m10_mle_summary$state_checksum))) {
stop(
"The 108-cell MLE grid contains missing, failed, non-estimable, ",
"high-gradient, or biologically invalid cells and cannot be resampled.",
call. = FALSE
)
}
m10_mle_biomass <- m10_mle_results$biomass
m10_mle_payload_checksum <- esc31_object_md5(list(
summary = m10_mle_results$summary,
biomass = m10_mle_results$biomass,
state_records = m10_mle_results$state_records
))
mle_grid_projection_map <- m10_mle_map
mle_grid_projection_map$par_log_h <- NULL
mle_grid_projection_map$par_log_psi <- NULL
mle_grid_projection_map$par_log_m0 <- NULL
mle_grid_projection_map$par_log_m10 <- NULL
obj_mle_grid_projection <- MakeADFun(
func = cmb(sbt_model, m10_mle_data),
parameters = m10_mle_parameters,
map = mle_grid_projection_map
)
mle_grid_target_par_names <-
expand_parameter_names(names(obj_mle_grid_projection$par))
mle_grid_target_sample_names <- c(mle_grid_target_par_names, "lp__")
mle_grid_conversion_identity <- esc31_sbt_function_identity(c(
"grid_to_tmbfit",
"make_mle_grid_parameters",
"expand_parameter_names"
))
mle_grid_tmbfit_signature <- esc31_object_md5(list(
# Bind the resample to the fully revalidated source artifact. The current
# scientific signature is audited separately, so package-version changes do
# not rewrite accepted source files or invalidate downstream projections.
m10_mle_signature = m10_mle_results$signature,
m10_mle_payload_checksum = m10_mle_payload_checksum,
n_samples = mle_grid_resample_n,
seed = mle_grid_resample_seed,
target_parameter_names = mle_grid_target_par_names,
target_map = mle_grid_projection_map,
optimizer_recovery = m10_mle_optimizer_recovery,
harvest_wall_contract = grid_harvest_wall_identity$executable,
harvest_wall_decision = grid_harvest_wall_identity$decision,
implementation =
"direct_get_M_mle_grid_full_state_to_tmbfit_v14_posterior_m0"
))
legacy_mle_grid_tmbfit_signature <- esc31_object_md5(list(
m10_mle_signature = m10_mle_results$signature,
m10_mle_payload_checksum = m10_mle_payload_checksum,
n_samples = mle_grid_resample_n,
seed = mle_grid_resample_seed,
target_parameter_names = mle_grid_target_par_names,
target_map = mle_grid_projection_map,
conversion_identity = mle_grid_conversion_identity,
harvest_wall_contract = grid_harvest_wall_identity$executable,
harvest_wall_decision = grid_harvest_wall_identity$decision,
implementation =
"direct_get_M_mle_grid_full_state_to_tmbfit_v12_canonical_checksum_parallel_projection_map_harvest_wall_bound"
))
mle_grid_tmbfit_audit <- list(
source_mle_grid_signature = m10_mle_results$signature,
conversion_identity = mle_grid_conversion_identity
)
expected_mle_grid_sample <- sample_grid(
grid = m10_mle_summary,
n_samples = mle_grid_resample_n,
seed = mle_grid_resample_seed
)
mle_grid_resample_payload <- function(sample, fit) {
if (!is.list(sample) ||
!identical(names(sample), names(expected_mle_grid_sample)) ||
!inherits(fit, "tmbfit") || !is.list(fit) ||
!is.array(fit$samples) || anyNA(fit$samples) ||
any(!is.finite(fit$samples)) ||
!identical(fit$par_names, mle_grid_target_par_names) ||
!identical(fit$sample_names, mle_grid_target_sample_names) ||
!identical(
dimnames(fit$samples)[[3L]],
mle_grid_target_sample_names
) ||
!identical(as.integer(fit$grid_cells),
as.integer(sample$grid_cells)) ||
!is.data.frame(fit$draw_metadata) ||
nrow(fit$draw_metadata) != length(sample$grid_cells)) {
return(NULL)
}
list(
sample = sample,
fit = list(
samples = fit$samples,
sampler_params = fit$sampler_params,
model = fit$model,
metric = fit$metric,
par_names = fit$par_names,
sample_names = fit$sample_names,
grid_cells = fit$grid_cells,
draw_metadata = fit$draw_metadata,
max_treedepth = fit$max_treedepth,
warmup = fit$warmup,
iter = fit$iter,
thin = fit$thin,
algorithm = fit$algorithm,
class = class(fit)
)
)
}
mle_grid_resample_checksum <- function(payload) {
if (is.null(payload)) return(NA_character_)
canonical_payload <- unserialize(serialize(
payload,
connection = NULL,
version = 3
))
esc31_object_md5(canonical_payload)
}
build_mle_grid_tmbfit <- function(sample = expected_mle_grid_sample) {
sbt::grid_to_tmbfit(
data = m10_mle_data,
parameters = m10_mle_parameters,
grid = m10_mle_grid,
grid_parameters = sbt::make_mle_grid_parameters(
m10_mle_grid,
m10_mle_parameters,
allow_new_parameters = FALSE
),
grid_cells = sample,
fitted_parameters = m10_mle_results$state_records,
source_map = m10_mle_map,
target_map = mle_grid_projection_map,
cores = grid_state_diagnostic_cores
)
}
mle_grid_tmbfit_cache <- if (file.exists(m10_mle_tmbfit_file)) {
read_rds_cache(m10_mle_tmbfit_file)
} else {
NULL
}
cached_mle_grid_resample_payload <- tryCatch(
mle_grid_resample_payload(
mle_grid_tmbfit_cache$sample,
mle_grid_tmbfit_cache$fit
),
error = function(error) NULL
)
mle_grid_tmbfit_cache_record_valid <- is.list(mle_grid_tmbfit_cache) &&
all(c(
"signature", "sample", "fit", "payload_checksum"
) %in% names(mle_grid_tmbfit_cache))
# The accepted cached draw sequence is part of the signed payload. Recreating
# `sample()` is not a stable identity check across R sampling implementations;
# validate the complete cached payload and its source-sensitive signature.
mle_grid_tmbfit_cache_content_current <-
mle_grid_tmbfit_cache_record_valid &&
!is.null(cached_mle_grid_resample_payload) &&
identical(
mle_grid_tmbfit_cache$payload_checksum,
mle_grid_resample_checksum(cached_mle_grid_resample_payload)
)
mle_grid_tmbfit_signature_current <-
mle_grid_tmbfit_cache_record_valid &&
is.character(mle_grid_tmbfit_cache$signature) &&
length(mle_grid_tmbfit_cache$signature) == 1L &&
!is.na(mle_grid_tmbfit_cache$signature) &&
mle_grid_tmbfit_cache$signature %in% c(
mle_grid_tmbfit_signature,
legacy_mle_grid_tmbfit_signature
)
mle_grid_tmbfit_cache_current <-
mle_grid_tmbfit_cache_content_current &&
mle_grid_tmbfit_signature_current
mle_grid_tmbfit_migration_reason <- NULL
if (mle_grid_tmbfit_cache_content_current &&
!mle_grid_tmbfit_signature_current &&
is.character(mle_grid_tmbfit_cache$signature) &&
length(mle_grid_tmbfit_cache$signature) == 1L &&
!is.na(mle_grid_tmbfit_cache$signature) &&
grepl("^[0-9a-f]{32}$", mle_grid_tmbfit_cache$signature)) {
rebuilt_mle_grid_tmbfit <- build_mle_grid_tmbfit()
rebuilt_mle_grid_payload_checksum <- mle_grid_resample_checksum(
mle_grid_resample_payload(
expected_mle_grid_sample,
rebuilt_mle_grid_tmbfit
)
)
if (identical(
mle_grid_tmbfit_cache$payload_checksum,
rebuilt_mle_grid_payload_checksum
)) {
mle_grid_tmbfit_cache_current <- TRUE
mle_grid_tmbfit_migration_reason <-
"verified_source_sensitive_signature_migration"
}
}
if (isTRUE(mle_grid_tmbfit_cache_current)) {
mle_grid_sample <- mle_grid_tmbfit_cache$sample
mle_grid_tmbfit <- mle_grid_tmbfit_cache$fit
} else {
if (!run_m10_mle_grid) {
stop(
"The compatible 108-cell MLE-grid resample is unavailable. Set ",
"ESC31_RUN_MLE_GRID=true only after the approved MCMC grid passes every ",
"production gate.",
call. = FALSE
)
}
mle_grid_sample <- expected_mle_grid_sample
mle_grid_tmbfit <- build_mle_grid_tmbfit(mle_grid_sample)
mle_grid_resample_checksum_value <- mle_grid_resample_checksum(
mle_grid_resample_payload(mle_grid_sample, mle_grid_tmbfit)
)
atomic_save_rds(
list(
signature = mle_grid_tmbfit_signature,
sample = mle_grid_sample,
fit = mle_grid_tmbfit,
payload_checksum = mle_grid_resample_checksum_value,
audit = mle_grid_tmbfit_audit
),
m10_mle_tmbfit_file
)
}
mle_grid_freq <- mle_grid_sample$grid_freq |>
mutate(delta_nll = nll - min(nll, na.rm = TRUE))
m_posterior_df <- bind_rows(
tibble(parameter = "M0", value = m0_posterior),
tibble(parameter = "M10", value = m10_posterior)
)