crossnobis_plan.md

Implementation Plan – Crossnobis Support for MS-ReVE / Contrast-RSA

0 Paper Summary & Motivation

The cross-nobis (a.k.a. cross-validated Mahalanobis) distance provides an unbiased estimate of the true squared pattern distance by multiplying pattern differences that were estimated from independent data partitions. Ordinary (same-fold) distances are positively biased because noise is multiplied by itself.

Formal definition for condition pair (k=(i,j)) with (M) partitions (Eq. 5, Diedrichsen & Kriegeskorte 2017): [ \tilde d_k = \frac{1}{M(M-1)\,P}\sum_{m\neq n} \hat\delta_{k,m}^{\mathsf T}\,\hat\delta_{k,n}, \qquad \hat\delta_{k,m}=\hat b_{i,m}-\hat b_{j,m}, ] where (P) is the number of voxels/channels. Equivalent "single-fold-vs-rest" algebra can also be used.

Key properties Unbiased: (\mathbb E[\tilde d_k]=\delta_k^{\mathsf T}\delta_k/P). Can be negative when the true distance is ~0 – keep these values, do not truncate. Variance is (\tfrac{M}{M-1}) times larger than the biased estimator but decreases with more partitions. Whitening: pre-multiply patterns by (\mathbf W=\Sigma_{\text{noise}}^{-1/2}) to obtain Mahalanobis distances; crucial for fMRI.

(Sections 1–9 below incorporate this theory.)

1 High-Level Requirements

Produce unbiased squared distances … (unchanged from previous draft)

// ... existing content of sections 1–9 from crossnobis.md retained unchanged ...

9 Timeline (suggestion)

| Week | Deliverable | |------|-------------| | 1 | Helper function + unit tests pass | | 2 | Integration into train_model + searchlight plumbing | | 3 | Documentation, vignette, example rebuild | | 4 | Profiling & optional Rcpp optimisation |

Appendix A Detailed Implementation Table & Sanity-Check Code

A.1 Step-wise Implementation Table (adapted from user note)

| Step | What to compute | Suggested R objects / code changes | |------|-----------------|------------------------------------| | A | Return fold-wise condition means. | compute_crossvalidated_means_sl(return_folds = TRUE) returns a list with mean = U_hat_sl, folds = U_folds (K × V × M). | | B | Pre-whiten each fold. | Within the same helper: if W provided, U_folds[,,m] %*% W. | C | Cross-fold inner products only for m ≠ n. | New helper crossnobis_distance(U_folds, P) computes distance vector; pseudo-code shown below. | | D | Expose to RSA regression. | train_model.contrast_rsa_model() uses this distance vector when estimation_method == "crossnobis". include_vec still applied. | | E | Allow negative outputs. | No truncation; document in Roxygen. | | F | Unit tests. | Noise-only simulation: mean distance ≈ 0; biased Euclidean positive. | | G | Performance tips. | Vectorise across pairs; optionally migrate to Rcpp. |

crossnobis_distance <- function(U_folds) {
  K <- dim(U_folds)[1]; V <- dim(U_folds)[2]; M <- dim(U_folds)[3]
  if (M < 2) rlang::abort("Need at least two partitions for cross-nobis.")
  pair_mat <- utils::combn(K, 2)
  D <- ncol(pair_mat)
  out <- numeric(D)
  P <- V
  for (p in seq_len(D)) {
    i <- pair_mat[1, p]; j <- pair_mat[2, p]
    deltas <- U_folds[i, , ] - U_folds[j, , ]   # V × M
    ip <- tcrossprod(t(deltas))                 # M × M inner products
    diag(ip) <- 0
    out[p] <- sum(ip) / (P * M * (M - 1))
  }
  names(out) <- paste0(dimnames(U_folds)[[1]][pair_mat[1, ]], "_vs_", 
                       dimnames(U_folds)[[1]][pair_mat[2, ]])
  out
}

A.2 Quick Sanity-Check

set.seed(1)
K <- 4; V <- 30; M <- 8
true <- matrix(rnorm(K*V), K, V)          # ground-truth patterns
noise <- array(rnorm(K*V*M, sd = 3), c(K, V, M))
U_folds <- true + noise                   # simulated noisy means per fold
cross_d <- crossnobis_distance(U_folds)
mean(cross_d)   # ≈ 0 for pure noise case

10 Checkable Implementation Tickets

This section breaks down the implementation plan into granular, checkable tasks for the specified R files and the new helper function.

Always check off each task as you complete it.

New Helper Function (e.g., in R/crossnobis_helpers.R or similar)

R/compute_cv_means.R (Changes to compute_crossvalidated_means_sl)

R/contrast_rsa_model.R

R/msreve_design.R



bbuchsbaum/rMVPA documentation built on June 10, 2025, 8:23 p.m.