Outer hyperparameter-grid integration with a user-supplied inner fit
Source:R/hyper_grid.R
tulpa_hyper_grid.RdGeneric driver for nested-Laplace-style outer integration over a small
hyperparameter block. The user supplies per-axis specs (values + optional
log-prior + log-scale / bounds / refinable metadata) and an inner_fit
callback that, at every hyperparameter cell, returns the inner log marginal
and optionally the fixed-effect posterior mode + marginal covariance.
The driver builds the Cartesian outer grid, normalises the log-marginals to
integration weights, reports per-axis posterior moments and weighted
quantiles, and (when the inner fit supplies them) law-of-total-covariance
fixed-effect posterior + mixture draws.
This factors the per-family outer-grid plumbing in tulpa_nested_laplace()
/ tulpa_nested_laplace_joint() / tulpa_re_cov_nested() into one
callback-driven entry point: downstream consumers (occupancy / N-mixture /
cover hurdle families in tulpaObs, custom user families) drop in their own
per-cell inner fit and get the outer integration for free.
Arguments
- hyper_specs
A list of axis specs. Each spec is either a
hyper_axis_spec()object or a plain list with the same fields (the driver auto-wraps); seehyper_axis_spec(). The outer grid is the Cartesian product of the per-axis grids; the joint log-prior is the sum of per-axislog_priorcontributions (axes withlog_prior = NULLare flat / improper).- inner_fit
function(hypers)returning a list with:log_marginal– scalar; the inner-solve log marginal at this cell. Non-finite values are mapped to-Inf(the cell gets zero weight).beta_mean– numeric vector of fixed-effect posterior mean at the cell. Required whencombine != "none".beta_cov–p x pnumeric matrix of fixed-effect marginal covariance at the cell. Required whencombine = "law_of_total_cov".hypersis a named numeric vector with the current cell's axis values (names matchvapply(hyper_specs,[[, character(1), "name")). Errors thrown byinner_fitare caught and treated as a failed cell (log_marginal = -Inf, no beta contribution).
- combine
How to pool per-cell fixed-effect posteriors into a single posterior over the betas. One of:
"law_of_total_cov"(default) – computeE[Cov(beta | theta)] + Cov(E[beta | theta])from the per-cell(beta_mean, beta_cov); synthesisen_drawsposterior draws by mixture sampling. Requiresbeta_meanandbeta_covper cell."weighted_mean_only"– pool only the per-cellbeta_meaninto the weighted posterior mean.beta_covis ignored; no draws."none"– do not assemble a fixed-effect posterior. Only the hyperparameter posterior is returned.beta_mean/beta_covfrominner_fitare ignored if supplied.
- n_draws
Number of posterior draws of the fixed effects to synthesise from the cell mixture (default 2000). Used only when
combine = "law_of_total_cov".0disables draw synthesis (the law-of-total-cov mean and covariance are still returned).- seed
Optional integer seed for the draw synthesis.
- beta_names
Optional character vector naming the fixed-effect coordinates. When
NULL(default) the names are taken from the first successful cell'sbeta_mean(orbeta1,beta2, ... if it is unnamed).- control
Optional list of refinement / tuning knobs:
adaptive_grid(FALSE) – run the boundary / interior refinement pass on every axis whose spec hasrefinable = TRUE. New cells are appended along the refining axis paired with the boundary modal cell's other-axis values, carrying a marginal-scale calibration so they contribute on the right scale.adaptive_grid_edge_thresh(0.02) – per-axis trigger threshold.adaptive_grid_max_passes(1L) – cap on refinement passes.var_of_means_consistency(FALSE) – run a post-integration consistency pass: for refinable axes whose marginal has collapsed onto too few nodes to carry a spread, append Laplace-guided slice points attheta_mean +/- {0.7, 1.5} * sdpinned at the modal cell,sdbeing the parabola at the modal node. One kernel call per axis.var_of_means_min_ess(.nl_diag("axis_sd_ess")) – the quadrature effective sample size an axis marginal has to reach for the pass to leave it alone. Read off the weights, so the trigger is not one SD estimator compared against the other.
Value
A list of class c("tulpa_hyper_grid", "tulpa_fit", "list") with:
theta_grid– numeric matrix[n_cells x n_axes]of outer-grid hyperparameter values; columns named after the axes.theta_names– character vector of axis names.log_marginal– numeric[n_cells]; per-cell log integrandinner$log_marginal + log_prior(theta_cell). Non-finite / failed cells are-Inf.log_prior– numeric[n_cells]; per-cell log-prior contribution (the sum across axes ofaxis$log_prior(theta_cell[axis])).0when all axes havelog_prior = NULL.weights– numeric[n_cells]summing to 1 (or allNAwith a warning when no cell carries finite mass).theta_mean,theta_sd– named numeric vectors; weighted posterior mean and SD per axis. Each SD comes from the estimator its axis's own resolution calls for – the weighted spread of the axis marginal where it is resolved, the 3-point parabola at the modal node where the marginal has collapsed onto too few nodes to have a spread.theta_sd_source,theta_sd_ess,theta_sd_stencil_declined– per axis, which estimator produced the SD, the quadrature effective sample size that decided it, and (where the parabola was wanted and could not be formed) why it declined.theta_median,theta_ci_lo,theta_ci_hi– named numeric vectors; weighted-quantile median and 2.5 / 97.5\ (the recommended summary for right-skewed scale-like axes).beta,beta_cov,draws– fixed-effect posterior, present percombine:combine = "law_of_total_cov": weighted mean, total covariance (E[V] + V[E]),[n_draws x p]mixture draws.combine = "weighted_mean_only": weighted mean only;beta_covanddrawsareNULL.combine = "none": all three areNULL.
means,param_names,process_info,n_samples,n_params,N– thetulpa_fitaccessor surface, populated when a fixed-effect posterior is assembled.hyper_specs– echoed list ofhyper_axis_specobjects (the normalised form).combine,n_failed,n_grid,refining_axis– diagnostic fields.adaptive_grid_info,var_of_means_consistency_info– present when the corresponding refinement pass fired.
See also
hyper_axis_spec() for the axis-spec constructor;
tulpa_nested_laplace_joint() for the family-specific outer-grid
driver that this helper generalises.