Run Permutation Searchlight Inference
Source:R/permutation_searchlight.R
run_permutation_searchlight.RdComputes permutation-based p-values for a searchlight MVPA result by running the analysis on permuted labels, building a covariate-adjusted null distribution, and mapping p-values back to all brain voxels.
Usage
run_permutation_searchlight(
model_spec,
observed = NULL,
radius = 8,
method = c("standard", "randomized"),
perm_ctrl = permutation_control(),
metric = NULL,
...
)Arguments
- model_spec
An
mvpa_modelor compatible model specification.- observed
Optional pre-computed searchlight result (output of
run_searchlight()). IfNULL, it is computed internally. Can also be a named numeric vector of observed metric values indexed by center ID.- radius
Numeric. Searchlight radius in mm (default 8).
- method
Character. Searchlight method passed to
run_searchlight()whenobservedisNULLor whenperm_strategy = "searchlight".- perm_ctrl
A
permutation_controlobject.- metric
Character. Which performance metric to use for inference. If
NULL(default), the first metric is used.- ...
Additional arguments forwarded to
run_searchlight()(observed pass and"searchlight"permutations). For"iterate"permutations, only arguments that are formal parameters ofmvpa_iterateare forwarded; other keys are ignored for that path to avoid argument-mismatch failures (e.g.,engine = "legacy"is meaningful forrun_searchlightbut not formvpa_iterate).
Value
A permutation_result S3 object containing:
- p_map
Spatial map of raw p-values.
- p_adj_map
Spatial map of FDR-adjusted p-values (if requested).
- p_values
Numeric vector of raw p-values (all centers).
- p_adjusted
Numeric vector of adjusted p-values.
- observed
The observed searchlight result.
- diagnostics
A
"null_diagnostics"object (ifdiagnose = TRUE).- perm_ctrl
The
permutation_controlused.- metric
Metric name used for inference.
- perm_strategy
The strategy that was actually used.
Permutation strategy
The perm_strategy field in perm_ctrl determines how each
permutation pass is executed. The two strategies share the same
downstream pipeline (null construction, p-value scoring, FDR
correction) — they differ only in how null metric values are
produced. Neither strategy contains any engine-specific branching.
"iterate"(default)Calls
mvpa_iterateon a subsampled set of centers. This is the generic per-ROI iterator that works with every model type and every dataset class. Thesubsampleparameter inperm_ctrlcontrols how many centers are evaluated per permutation.Null pool size:
n_perm * n_subsampled_centers.Best for: slow classifiers, large brains, limited compute. The subsampling gives a 5–20\(\times\) speedup over a full-brain pass.
"searchlight"Calls
run_searchlighton the full brain for each permutation. Because the call goes through the standardrun_searchlightS3 dispatch, it automatically benefits from any fast engine the model qualifies for (e.g.\ SWIFT, dual-LDA) and from any user-definedrun_searchlight.<class>method. No engine-specific code exists here — it is purely the standardrun_searchlightcall.Since the full brain is computed anyway, all centers contribute to the null distribution (the
subsampleparameter is ignored and a note is logged). This yields a richer null and therefore better-calibrated p-values.Null pool size:
n_perm * all_centers.Best for: models with a fast searchlight engine, or when you want the richest possible null distribution.
Examples
# \donttest{
ds <- gen_sample_dataset(c(5, 5, 5), 20, blocks = 2, nlevels = 2)
cval <- blocked_cross_validation(ds$design$block_var)
mdl <- load_model("sda_notune")
mspec <- mvpa_model(mdl, ds$dataset, ds$design, "classification",
crossval = cval)
# Strategy 1: subsampled iterator (default, universal)
pc1 <- permutation_control(n_perm = 10, subsample = 0.2, seed = 1L)
res1 <- run_permutation_searchlight(mspec, radius = 3, perm_ctrl = pc1)
#> INFO [2026-04-14 02:48:02] Running observed searchlight (radius = 3 mm) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:48:02] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:48:02] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:48:02] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:48:02] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:48:02] creating standard searchlight
#> INFO [2026-04-14 02:48:02] running standard searchlight iterator
#> INFO [2026-04-14 02:48:12]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:48:12] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:48:12] Building searchlight iterator ...
#> INFO [2026-04-14 02:48:12] Subsampling searchlight centers ...
#> INFO [2026-04-14 02:48:13] Using 25 / 125 centers for permutation runs.
#> INFO [2026-04-14 02:48:13] Permutation 1 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:15]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:15] Permutation 2 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:17]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:17] Permutation 3 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:20]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:20] Permutation 4 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:22]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:22] Permutation 5 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:24]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:25] Permutation 6 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:27]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:27] Permutation 7 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:29]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:30] Permutation 8 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:32]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:32] Permutation 9 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:34]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:34] Permutation 10 / 10 (strategy: iterate) ...
#> INFO [2026-04-14 02:48:37]
#> MVPA Iteration Complete
#> - Total ROIs: 25
#> - Processed: 25
#> - Skipped: 0
#> INFO [2026-04-14 02:48:37] Running null diagnostics ...
#> Null Distribution Diagnostics (n_perm = 10 )
#> --------------------------------------------------
#> nfeatures [OK]
#> rho=-0.023 p=0.7178
#> No significant correlation with nfeatures.
#> --------------------------------------------------
#> INFO [2026-04-14 02:48:37] Building adjusted null distribution (adjusted, 5 bins) ...
#> INFO [2026-04-14 02:48:37] Computing p-values for 125 centers ...
#> INFO [2026-04-14 02:48:37] Building p-value spatial maps ...
#> INFO [2026-04-14 02:48:37] Done. 0 centers significant at FDR < 0.05 (fdr).
# Strategy 2: full-brain via run_searchlight (engine-aware)
pc2 <- permutation_control(n_perm = 5, perm_strategy = "searchlight",
seed = 1L)
res2 <- run_permutation_searchlight(mspec, radius = 3, perm_ctrl = pc2)
#> INFO [2026-04-14 02:48:37] Running observed searchlight (radius = 3 mm) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:48:37] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:48:37] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:48:37] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:48:37] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:48:37] creating standard searchlight
#> INFO [2026-04-14 02:48:37] running standard searchlight iterator
#> INFO [2026-04-14 02:48:47]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:48:47] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:48:47] Building searchlight iterator ...
#> INFO [2026-04-14 02:48:47] Strategy = 'searchlight': full brain computed per permutation. 'subsample' parameter ignored; all 125 centers contribute to null.
#> INFO [2026-04-14 02:48:47] Permutation 1 / 5 (strategy: searchlight) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:48:47] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:48:47] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:48:47] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:48:47] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:48:47] creating standard searchlight
#> INFO [2026-04-14 02:48:47] running standard searchlight iterator
#> INFO [2026-04-14 02:48:58]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:48:58] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:48:58] Permutation 2 / 5 (strategy: searchlight) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:48:58] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:48:58] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:48:58] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:48:58] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:48:58] creating standard searchlight
#> INFO [2026-04-14 02:48:58] running standard searchlight iterator
#> INFO [2026-04-14 02:49:08]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:49:08] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:49:08] Permutation 3 / 5 (strategy: searchlight) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:49:08] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:49:08] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:49:08] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:49:08] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:49:08] creating standard searchlight
#> INFO [2026-04-14 02:49:08] running standard searchlight iterator
#> INFO [2026-04-14 02:49:18]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:49:19] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:49:19] Permutation 4 / 5 (strategy: searchlight) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:49:19] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:49:19] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:49:19] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:49:19] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:49:19] creating standard searchlight
#> INFO [2026-04-14 02:49:19] running standard searchlight iterator
#> INFO [2026-04-14 02:49:29]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:49:29] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:49:29] Permutation 5 / 5 (strategy: searchlight) ...
#> Warning: run_searchlight preflight reported 0 failure(s) and 1 warning(s).
#> block_count: Only 2 blocks found. Leave-one-block-out CV will have only 2 folds, providing limited evaluation with high variance estimates.
#> INFO [2026-04-14 02:49:29] searchlight engine: legacy (no eligible fast path)
#> INFO [2026-04-14 02:49:29] Running standard searchlight with radius = 3
#> INFO [2026-04-14 02:49:29] shard backend: preparing shared memory for dataset (mvpa_image_dataset, mvpa_dataset, list)
#> INFO [2026-04-14 02:49:29] shard backend [volumetric]: shared 20 x 125 matrix (125 masked voxels)
#> INFO [2026-04-14 02:49:29] creating standard searchlight
#> INFO [2026-04-14 02:49:29] running standard searchlight iterator
#> INFO [2026-04-14 02:49:39]
#> MVPA Iteration Complete
#> - Total ROIs: 125
#> - Processed: 125
#> - Skipped: 0
#> INFO [2026-04-14 02:49:40] searchlight (standard): 125 ROIs processed (success=125, errors=0)
#> INFO [2026-04-14 02:49:40] Running null diagnostics ...
#> Null Distribution Diagnostics (n_perm = 5 )
#> --------------------------------------------------
#> nfeatures [OK]
#> rho=-0.077 p=0.0545
#> No significant correlation with nfeatures.
#> --------------------------------------------------
#> INFO [2026-04-14 02:49:40] Building adjusted null distribution (adjusted, 5 bins) ...
#> INFO [2026-04-14 02:49:40] Computing p-values for 125 centers ...
#> INFO [2026-04-14 02:49:40] Building p-value spatial maps ...
#> INFO [2026-04-14 02:49:40] Done. 0 centers significant at FDR < 0.05 (fdr).
# }