Adaptive Alpha with Branch Pruning
alpha_adaptive_tree_pruned.RdFactory function that creates an adaptive alpha adjustment system
supporting branch pruning. Unlike alpha_adaptive_tree,
which pre-computes a fixed schedule, this version can recompute the
schedule on a pruned subtree after each depth — giving more alpha
to surviving branches when dead branches are removed.
Usage
alpha_adaptive_tree_pruned(
node_dat,
delta_hat,
max_depth = NULL,
budget_weights = NULL,
budget_total = 1,
spending_fraction = 0.5,
switching = FALSE
)Arguments
- node_dat
A data.frame or data.table with columns
nodenum,parent,depth, andnodesize. Typically extracted from afind_blocksresult. The root node must haveparent = 0anddepth = 1.- delta_hat
Estimated standardized effect size (e.g., Cohen's d). Conservative (larger) values produce more stringent adjustment, which preserves the FWER guarantee.
- max_depth
Maximum depth to compute. Defaults to the maximum depth present in
node_dat.- budget_weights
Controls depth-wise budget allocation. Accepts the same values as
compute_adaptive_alphas_tree, plus"depth-sequential": a sequential spending process where a fixed fractionspending_fractionof the remaining budget is spent at each depth. The spending fraction is set in advance, so the resulting weights \(w_\ell\) depend only on the testing history through depth \(\ell - 1\) — they are predictable in the sense required by the budget-weighted FWER theorem with predictable denominators (Theorem B.5 in the supplement). This is the theoretical justification for the"depth-sequential"mode itself, distinct from the switching corollary controlled by theswitchingargument below."remaining"is accepted as a deprecated alias for"depth-sequential"and emits a warning.- budget_total
Initial error budget (default 1.0). The constraint \(\sum w_\ell \le\)
budget_totalguarantees FWER control.- spending_fraction
Fraction of remaining budget to spend at each depth when
budget_weights = "depth-sequential"(default 0.5). At depth \(\ell\), the weight is \(w_\ell = f \times B_\ell\) where \(f\) is the spending fraction and \(B_\ell\) is the remaining budget.- switching
Logical (default
FALSE). WhenTRUE, implements the switching corollary: after each update, if the remaining pruned error load fits within the remaining budget, all deeper depths revert to nominal alpha. This is a separate FWER guarantee from the predictable-weights mechanism that justifies"depth-sequential"mode.
Value
A list with three components:
alphafnA function with the standard alphafn interface:
function(pval, batch, nodesize, thealpha, thew0, depth). Looks up the current alpha schedule by depth.updateA function
function(pruned_node_dat, thealpha)that recomputes the alpha schedule on the given (pruned) tree. Called byfind_blocksafter each depth's testable decisions.resetA function
function(thealpha)that restores the alpha schedule to the full (unpruned) tree. Called byfind_blocksat the start of each run to ensure independence across simulation iterations.
Details
The strong-FWER guarantee claimed for this schedule DOES NOT
HOLD (2026-08 referee correction; see FIX_PLAN.md). The former
justification – predictable budget weights with the pruned load
\(D_\ell\) as a data-dependent denominator – was falsified by exact
counterexample: with valid tests and conservative power holding, the
schedule reaches FWER 0.063 at \(\alpha = 0.05\). The failure is
structural: \(D_\ell\) charges each surviving null its unconditional
reach probability, but conditional on its parent's rejection a
surviving null is one full test, so when path powers are small the
exposed-null count exceeds the charged load. The switching rule
(switching = TRUE) re-spends to nominal alpha exactly in that
regime and inherits the failure. The constructor warns accordingly.
Levels are computed as before so that existing analyses remain
reproducible; for a schedule with a proof, use
alpha_adaptive_tree with static budget weights over the
full-tree load.
When find_blocks detects a list-valued alphafn,
it extracts these three components and calls reset at
the start of each run and update after each depth.
Examples
nd <- data.frame(
nodenum = 1:7,
parent = c(0, 1, 1, 2, 2, 3, 3),
depth = c(1, 2, 2, 3, 3, 3, 3),
nodesize = c(500, 250, 250, 125, 125, 100, 150)
)
obj <- alpha_adaptive_tree_pruned(node_dat = nd, delta_hat = 0.5)
#> Warning: alpha_adaptive_tree_pruned(): the strong-FWER guarantee for the pruned-load alpha schedule (and its switching rule) does not hold; the underlying theorem was falsified by exact counterexample (2026-08, see FIX_PLAN.md). Levels are computed as before for reproducibility. For a schedule with a proof, use alpha_adaptive_tree() with static budget weights.
# obj$alphafn -- pass to find_blocks
# obj$update(pruned_nd, 0.05) -- recompute on surviving tree
# obj$reset(0.05) -- restore full-tree schedule