This is a superb set of final clarifications and an excellent "API polish" for the LSS component. The decisions made are pragmatic, robust, and maintain the core elegance and efficiency of the manifold HRF approach.
Here's a full proposal incorporating these latest refinements, structured for an engineering team.
Proposal: Manifold-Guided HRF Estimation and Trial-wise Deconvolution (M-HRF-LSS)
1. Executive Summary:
This proposal outlines an advanced fMRI analysis pipeline, "Manifold-Guided HRF Estimation and Trial-wise Deconvolution (M-HRF-LSS)." It combines a novel HRF estimation technique based on manifold learning with a highly optimized Least Squares Separate (LSS) kernel for single-trial beta estimation. The M-HRF-LSS pipeline aims to provide: 1. Spatially smooth and physiologically plausible voxel-wise HRF estimates. 2. Associated per-condition activation amplitudes. 3. Accurate per-trial activation amplitudes. All components are designed for computational efficiency, primarily relying on closed-form solutions, BLAS operations, and sparse matrix algebra, making it suitable for large-scale whole-brain analyses on standard CPU hardware.
2. Core Components & Algorithmic Workflow:
Component 0: HRF Manifold Construction (Once per Study/HRF Library)
L_library
: p x N
matrix of N
candidate HRF shapes, each sampled at p
time points (e.g., from a physiological model grid, half-cosine set, FLOBS).m_manifold_dim
: Target dimensionality of the manifold (typically 3-4).k_nn_for_W
: k-Nearest Neighbors for sparse affinity matrix W
if N
is very large.W
(Self-Tuning):dists_ij
between all HRFs in L_library
.i
, find its k_local_nn
-th nearest neighbor distance σ_i
(e.g., k_local_nn=3
).W_ij = exp(-dists_ij² / (σ_i * σ_j))
. If N
is large, W
can be sparsified (e.g., k-NN graph).S
: D_inv = diag(1/rowSums(W))
, S = D_inv %*% W
.Φ_raw
: Compute top m+1
eigenvectors of S
(e.g., via RSpectra::eigs_sym
).
Φ_raw = eig_S$vectors
.Φ
: Φ = Φ_raw[, 2:(m_manifold_dim + 1)]
(an N x m_manifold_dim
matrix, discarding the trivial constant eigenvector).B_reconstructor
: B_reconstructor = L_library %*% Φ %*% solve(crossprod(Φ) + 1e-8 * diag(m_manifold_dim))
(a p x m_manifold_dim
matrix). This B_reconstructor
maps m
-dimensional manifold coordinates ξ
back to a p
-sample HRF shape: h_shape = B_reconstructor %*% ξ
.Component 1: Voxel-wise HRF Manifold Coordinate & Condition Amplitude Estimation
m
-dimensional HRF manifold coordinate ξ_v
and k
per-condition amplitudes β_v
.Y_bold
: n x V
BOLD data matrix.X_condition_list
: List of k
matrices, where X_condition_list[[c]]
is an n x p
Toeplitz design matrix for condition c
(convolving onsets with p
delta functions).Z_confounds
: (Optional) n x q_confound
matrix of nuisance regressors.B_reconstructor
: p x m
matrix from Component 0.lambda_gamma
: Ridge penalty for the (km)x(km)
GLM solve.h_ref_shape_canonical
: p x 1
canonical HRF shape for identifiability.orthogonal_approx_flag
: Boolean (default FALSE
).Z_confounds
provided):Q_Z = qr.Q(qr(Z_confounds, LAPACK=TRUE))
.Y_proj = Y_bold - Q_Z %*% tcrossprod(Q_Z, Y_bold)
.X_condition_list_proj = lapply(X_condition_list, function(X) X - Q_Z %*% tcrossprod(Q_Z, X))
.Z_list
:Z_list = lapply(X_condition_list_proj, function(Xc) Xc %*% B_reconstructor)
. Each Z_list[[c]]
is n x m
.X_tilde
and GLM Solve for Gamma_coeffs
:X_tilde = do.call(cbind, Z_list)
(an n x (km)
matrix).XtX_tilde_reg = crossprod(X_tilde) + lambda_gamma * diag(k*m)
.orthogonal_approx_flag = TRUE
:
XtX_tilde_reg = Matrix::bdiag(lapply(Z_list, function(Zc) crossprod(Zc) + (lambda_gamma/k) * diag(m)))
. (Note: distributing lambda might need care, or apply lambda to the full diag(km)
before bdiag if that's simpler conceptually even if it means lambda_gamma
has a slightly different effect). A safer way is to construct the full crossprod(X_tilde)
and then zero out off-diagonal blocks if orthogonal_approx is true, before adding the full lambda_gamma * diag(k*m)
. For now, assume XtX_tilde_reg
is the full version. The proposal's "code the full matrix; enable the block-diag shortcut only when the user explicitly requests it" implies XtX_tilde_reg
is formed from crossprod(X_tilde)
and then optionally modified if orthogonal_approx
.XtY_tilde = crossprod(X_tilde, Y_proj)
.Gamma_coeffs = solve(XtX_tilde_reg, XtY_tilde)
(a (km) x V
matrix).ξ_raw_allvox
and β_raw_allvox
via SVD (per voxel):Xi_raw_allvox = matrix(0, m, V)
and Beta_raw_allvox = matrix(0, k, V)
.vx
from 1 to V
:G_vx = matrix(Gamma_coeffs[, vx], nrow = m, ncol = k)
.svd_G_vx = svd(G_vx)
.xi_vx
, beta_vx
to zero).Xi_raw_allvox[,vx] = svd_G_vx$u[,1] * sqrt(svd_G_vx$d[1])
.Beta_raw_allvox[,vx] = svd_G_vx$v[,1] * sqrt(svd_G_vx$d[1])
.ξ
and β
):xi_ref_coord = MASS::ginv(B_reconstructor) %*% h_ref_shape_canonical
.vx
:xi_vx = Xi_raw_allvox[,vx]
, beta_vx = Beta_raw_allvox[,vx]
.sgn = sign(sum(xi_vx * xi_ref_coord))
.xi_vx = xi_vx * sgn
, beta_vx = beta_vx * sgn
.reconstructed_hrf = B_reconstructor %*% xi_vx
.scl = 1 / pmax(max(abs(reconstructed_hrf)), .Machine$double.eps)
.Xi_raw_allvox[,vx] = xi_vx * scl
.Beta_raw_allvox[,vx] = beta_vx / scl
. (Ensure zeroed if scl was based on machine epsilon).Component 2: Spatial Smoothing of Manifold Coordinates
Xi_raw_allvox
: m x V
matrix of (identifiability-constrained) manifold coordinates from Component 1.voxel_graph_laplacian_Lsp
: V x V
sparse graph Laplacian matrix.lambda_spatial_smooth
: Spatial smoothing strength.Xi_smoothed_allvox = matrix(0, m, V)
.j
from 1 to m
:Xi_smoothed_allvox[j,] = Matrix::solve(A = Diagonal(V) + lambda_spatial_smooth * voxel_graph_laplacian_Lsp, b = Xi_raw_allvox[j,])
.Xi_smoothed_allvox
(m x V
).Component 3: Trial-wise Amplitude Estimation (LSS using Smoothed Manifold HRFs)
β_trial
using the spatially smoothed, voxel-specific HRFs.Y_proj
: n x V
confound-projected BOLD data.X_trial_onset_list
: List of T
matrices, where X_trial_onset_list[[t]]
is an n x p
Toeplitz design for trial t
's onset.B_reconstructor
: p x m
from Component 0.Xi_smoothed_allvox
: m x V
from Component 2.A_lss_fixed
: n x q_lss
matrix of fixed nuisance regressors for LSS (e.g., original Z_confounds
if they were not related to task, or just an intercept).p_lss_vec
: n x 1
vector for Woodbury LSS, derived from A_lss_fixed
(see section 2 of reviewed text: MASS::ginv(A_lss_fixed)[intercept_row,]
or rep(0,n)
if no intercept in A_lss_fixed
).lambda_ridge_Alss
: Ridge penalty for (A_lss_fixedᵀA_lss_fixed + λI)⁻¹A_lss_fixedᵀ
.P_lss = (A_lss_fixedᵀA_lss_fixed + lambda_ridge_Alss * I)⁻¹A_lss_fixedᵀ
(q_lss x n
).H_shapes_allvox
:H_shapes_allvox = B_reconstructor %*% Xi_smoothed_allvox
(a p x V
matrix).R_t_allvox
matrices:t = 1...T
: R_t_allvox = X_trial_onset_list[[t]] %*% H_shapes_allvox
(an n x V
matrix).Beta_trial_allvox = matrix(0, T, V)
.v = 1...V
:
a. Construct C_v
(n x T
): C_v[,t] = (if R_t precomputed) R_t_allvox[,v] else (X_trial_onset_list[[t]] %*% H_shapes_allvox[,v])
.
b. Woodbury LSS Core (for current voxel v
):
i. U_v = P_lss %*% C_v
(q_lss x T
).
ii. V_regressors_v = C_v - A_lss_fixed %*% U_v
(n x T
). These are M_A c_t
for this voxel.
iii. pc_v_row = crossprod(p_lss_vec, C_v)
(1 x T
).
iv. cv_v_row = colSums(V_regressors_v * V_regressors_v)
(1 x T
), i.e., ||M_A c_t||²
.
v. alpha_v_row = (1 - pc_v_row) / pmax(cv_v_row, .Machine$double.eps)
.
vi. S_effective_regressors_v = sweep(V_regressors_v, MARGIN = 2, STATS = alpha_v_row, FUN = "*")
.
vii. S_effective_regressors_v = sweep(S_effective_regressors_v, MARGIN = 1, STATS = p_lss_vec, FUN = "+")
.
c. Betas for Voxel v
: Beta_trial_allvox[,v] = crossprod(S_effective_regressors_v, Y_proj[,v])
(T x 1
).6. Outputs of M-HRF-LSS Pipeline:
Xi_raw_allvox
: m x V
raw manifold coordinates.Beta_condition_allvox
: k x V
condition-level amplitudes.Xi_smoothed_allvox
: m x V
spatially smoothed manifold coordinates.H_reconstructed_smoothed_allvox
: p x V
reconstructed HRF shapes from Xi_smoothed_allvox
.Beta_trial_allvox
: T x V
trial-level LSS amplitudes.B_reconstructor
, etc.7. Engineering Considerations:
%*%
, crossprod
, solve
, svd
, qr
).Matrix
package for voxel_graph_laplacian_Lsp
and its Cholesky solve.Gamma_coeffs
and R_t_allvox
. Chunking of voxels for Component 3 might be needed for very large V
if R_t_allvox
cannot be held in RAM.parallel::mclapply
, future.apply
). Component 2 (spatial smoothing) involves m
independent large sparse solves, also parallelizable.This detailed proposal provides a comprehensive engineering blueprint for the M-HRF-LSS pipeline, incorporating all the excellent insights and refinements discussed.
Okay, let's break down the implementation of the "Manifold-Guided HRF Estimation and Trial-wise Deconvolution (M-HRF-LSS)" pipeline into a granular sprint plan with actionable tickets.
Sprint Plan: M-HRF-LSS Pipeline Implementation (MVP)
Sprint Goal: Deliver a functional R implementation of the M-HRF-LSS pipeline (Components 0-3), capable of processing moderately sized fMRI datasets, with a focus on algorithmic correctness and modularity. CPU-based, BLAS-optimized R code is the target.
User Stories (Guiding the Sprint): As a methods developer, I need a robust implementation of each M-HRF-LSS component to enable research and validation. As an fMRI researcher (early adopter), I want to run the M-HRF-LSS pipeline on a sample dataset to obtain spatially smoothed HRFs, condition betas, and trial betas.
Tickets:
Epic 0: HRF Manifold Construction (Component 0 - Once per Study/Library)
MHRF-MANIFOLD-01
: Implement HRF Library Affinity & Markov Matrix Construction
calculate_manifold_affinity(L_library, k_local_nn_for_sigma = 7, sparse_if_N_gt = 5000, k_nn_for_W_sparse = 20)
L_library
(p x N
HRF shapes).σ_i
, σ_j
(using k_local_nn_for_sigma
).W_ij = exp(-dists_ij² / (σ_i * σ_j))
.N > sparse_if_N_gt
, implement k-NN sparsification for W
.S = D_inv %*% W
.S
(and optionally W
, D_inv
). Tested with small L_library
.MHRF-MANIFOLD-02
: Implement Diffusion Map Eigendecomposition & Reconstructor B
get_manifold_basis_and_reconstructor(S_markov, L_library, m_manifold_dim)
S_markov
(N x N
), L_library
(p x N
), m_manifold_dim
.RSpectra::eigs_sym(S_markov, k = m_manifold_dim + 1, which = "LM")
to get eigenvectors.Φ = eig_S$vectors[, 2:(m_manifold_dim + 1)]
(N x m
).B_reconstructor = L_library %*% Φ %*% solve(crossprod(Φ) + 1e-8 * diag(m_manifold_dim))
(p x m
).Φ
and B_reconstructor
. Tested.Epic 1: Voxel-wise Manifold Fit (Component 1 - Per Subject/Run)
MHRF-VOXFIT-01
: Confound Projection Module
project_out_confounds(Y_data, X_list_data, Z_confounds_matrix)
qr.Q(qr(Z_confounds_matrix, LAPACK=TRUE))
for Q_Z
.Y_proj
and X_list_proj
.MHRF-VOXFIT-02
: Per-Condition Design in Manifold Basis (Z_list
)
transform_designs_to_manifold_basis(X_condition_list_proj, B_reconstructor)
Z_list
where Z_list[[c]] = X_condition_list_proj[[c]] %*% B_reconstructor
.MHRF-VOXFIT-03
: Main GLM Solve for Gamma_coeffs
Z_list
, Y_proj
, lambda_gamma
, orthogonal_approx_flag
.X_tilde = do.call(cbind, Z_list)
.XtX_tilde_reg = crossprod(X_tilde) + lambda_gamma * diag(k*m)
.orthogonal_approx_flag
modification to XtX_tilde_reg
.Gamma_coeffs
.Gamma_coeffs
((km) x V
) computed correctly.MHRF-VOXFIT-04
: SVD-based Extraction of ξ_raw
and β_raw
Gamma_coeffs
, m_manifold_dim
, k_conditions
.Xi_raw_allvox
(m x V
), Beta_raw_allvox
(k x V
).Xi
and Beta
extracted.MHRF-VOXFIT-05
: Intrinsic Identifiability for ξ
and β
Xi_raw_allvox
, Beta_raw_allvox
, B_reconstructor
, h_ref_shape_canonical
.xi_ref_coord = MASS::ginv(B_reconstructor) %*% h_ref_shape_canonical
.Xi_raw_allvox
and Beta_raw_allvox
per voxel.Xi_ident_allvox
, Beta_ident_allvox
.Epic 2: Spatial Smoothing (Component 2 - Per Subject/Run)
MHRF-SP SMOOTH-01
: Graph Laplacian Construction
make_voxel_graph_laplacian(voxel_coordinates_matrix, num_neighbors = 6)
V x 3
matrix of voxel coordinates.V x V
graph Laplacian (e.g., based on k-NN or distance threshold).L_sp
matrix generated.MHRF-SP SMOOTH-02
: Apply Spatial Smoothing to ξ
Coordinates
Xi_ident_allvox
(from MHRF-VOXFIT-05
), voxel_graph_laplacian_Lsp
, lambda_spatial_smooth
.m
times, solving the sparse system (I_V + λ_sp L_sp) ξ_j_smooth = ξ_j_ident
.Xi_smoothed_allvox
(m x V
) computed.Epic 3: Trial-wise LSS (Component 3 - Per Subject/Run)
MHRF-LSS-01
: LSS Fixed Regressor Precomputation (P_lss
, p_lss_vec
)
prepare_lss_fixed_components(A_lss_fixed, intercept_column_in_Alss = NULL, lambda_ridge_Alss = 0.1)
P_lss = (A_lss_fixedᵀA_lss_fixed + lambda_ridge_Alss * I)⁻¹A_lss_fixedᵀ
.p_lss_vec
based on A_lss_fixed
and intercept_column_in_Alss
.P_lss
and p_lss_vec
returned.MHRF-LSS-02
: Voxel-Specific HRF Shape Reconstruction
reconstruct_hrf_shapes(B_reconstructor, Xi_smoothed_allvox)
H_shapes_allvox = B_reconstructor %*% Xi_smoothed_allvox
(p x V
).MHRF-LSS-03
: Implement Core Woodbury LSS Kernel (Per Voxel)
run_lss_for_voxel(Y_proj_vx, X_trial_onset_list, H_shape_vx, A_lss_fixed, P_lss, p_lss_vec)
C_vx
, then Woodbury steps for S_vx
, then beta_trial_vx
).T x 1
trial betas for one voxel. Tested.MHRF-LSS-04
: Main LSS Loop and (Optional) R_t
Precomputation
R_t_allvox
if memory strategy allows.run_lss_for_voxel
.Beta_trial_allvox
(T x V
) computed.Epic 4: Pipeline Orchestration, Output, and Documentation (MVP)
MHRF-PIPELINE-01
: Top-Level Orchestration Function run_mhrf_lss_pipeline()
MHRF-OUTPUT-02
: Define and Implement M-HRF-LSS Output Object
Xi_raw
, Beta_condition
, Xi_smoothed
, H_reconstructed
, Beta_trial
, parameters, B_reconstructor
).print()
, summary()
, and plot()
(e.g., plot mean reconstructed HRF, map of one ξ
coordinate).MHRF-DOC-03
: Initial User Documentation and Example Script
Sprint Review Focus: Successful end-to-end execution of the M-HRF-LSS pipeline on a test dataset. Plausibility of estimated HRF shapes, condition betas, and trial betas. Modularity and correctness of individual components. Initial performance benchmarks (CPU-based R).
Post-MVP Considerations (Future Sprints):
Parallelization of voxel loops (parallel
, future.apply
, or RcppParallel
).
RcppArmadillo
optimization for computationally intensive loops (SVD, LSS kernel).
Advanced output visualization.
Robust parameter selection helpers (e.g., for m_manifold_dim
, lambda_spatial_smooth
).
* Implementation of the "Bonus Refinement" (joint spatial and manifold smoothness prior).
This granular sprint plan breaks the complex M-HRF-LSS pipeline into manageable, testable tickets, focusing on delivering a functional MVP first.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.