//! # rtx-neuro-connectivity //! //! Functional and effective connectivity analysis for MEG/EEG data. //! //! ## Features //! //! - **Spectral Connectivity**: Coherence, imaginary coherence //! - **Phase Connectivity**: PLV, wPLI, dwPLI //! - **Effective Connectivity**: Granger causality (coming soon) //! - **Cross-Frequency**: Phase-amplitude coupling //! //! ## Example //! //! ```ignore //! use rtx_neuro_connectivity::{spectral_connectivity, ConnectivityMethod}; //! //! let conn = spectral_connectivity(&epochs, ConnectivityMethod::Coherence, sfreq)?; //! ``` #![warn(missing_docs)] pub mod coherence; pub mod granger; pub mod pac; pub mod plv; pub mod utils; pub mod wpli; // Re-export main types pub use coherence::{coherence, coherence_pairs, imaginary_coherence}; pub use granger::{ GrangerConfig, GrangerResult, SpectralGrangerResult, VarModel, granger_causality, spectral_granger, }; pub use pac::{PacMethod, phase_amplitude_coupling}; pub use plv::{ciplv, plv, plv_epochs, wplv}; pub use wpli::{dwpli, wpli}; /// Connectivity analysis error types #[derive(Debug, thiserror::Error)] pub enum ConnectivityError { /// Invalid parameters #[error("Invalid parameters: {0}")] InvalidParameters(String), /// Dimension mismatch #[error("Dimension mismatch: {0}")] DimensionMismatch(String), /// Computation error #[error("Computation error: {0}")] ComputationError(String), /// Insufficient data #[error("Insufficient data: {0}")] InsufficientData(String), } /// Result type for connectivity operations pub type ConnectivityResult = Result; /// Connectivity method enumeration #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ConnectivityMethod { /// Magnitude-squared coherence Coherence, /// Imaginary coherence (robust to volume conduction) ImaginaryCoherence, /// Phase locking value Plv, /// Weighted phase lag index Wpli, /// Debiased weighted phase lag index DwPli, /// Pairwise phase consistency Ppc, } /// Result of connectivity computation #[derive(Debug, Clone)] pub struct ConnectivityResult2D { /// Connectivity matrix [n_pairs x n_freqs] pub data: Vec>, /// Frequency vector pub freqs: Vec, /// Source indices for pairs pub sources: Vec, /// Target indices for pairs pub targets: Vec, /// Method used pub method: ConnectivityMethod, /// Number of epochs used pub n_epochs: usize, } impl ConnectivityResult2D { /// Get connectivity for a specific pair pub fn get_pair(&self, source: usize, target: usize) -> Option<&[f64]> { for (i, (&s, &t)) in self.sources.iter().zip(&self.targets).enumerate() { if s == source && t == target { return Some(&self.data[i]); } } None } /// Convert to symmetric matrix at a specific frequency pub fn to_matrix(&self, freq_idx: usize, n_channels: usize) -> Vec> { let mut matrix = vec![vec![0.0; n_channels]; n_channels]; for (i, (&s, &t)) in self.sources.iter().zip(&self.targets).enumerate() { if freq_idx < self.data[i].len() { matrix[s][t] = self.data[i][freq_idx]; matrix[t][s] = self.data[i][freq_idx]; // Symmetric } } // Diagonal is 1 for most methods for i in 0..n_channels { matrix[i][i] = 1.0; } matrix } /// Get mean connectivity across frequencies pub fn mean_connectivity(&self) -> Vec { self.data .iter() .map(|pair| pair.iter().sum::() / pair.len() as f64) .collect() } } /// Compute spectral connectivity across all channel pairs pub fn spectral_connectivity( epochs: &[Vec>], // [n_epochs][n_channels][n_times] method: ConnectivityMethod, sfreq: f64, fmin: f64, fmax: f64, n_fft: Option, ) -> ConnectivityResult { if epochs.is_empty() { return Err(ConnectivityError::InsufficientData( "No epochs provided".to_string(), )); } let n_channels = epochs[0].len(); let n_times = epochs[0][0].len(); let n_fft = n_fft.unwrap_or(n_times); // Generate all pairs let mut sources = Vec::new(); let mut targets = Vec::new(); for i in 0..n_channels { for j in (i + 1)..n_channels { sources.push(i); targets.push(j); } } // Compute connectivity for each pair let data: Vec> = match method { ConnectivityMethod::Coherence => { coherence::coherence_all_pairs(epochs, sfreq, fmin, fmax, n_fft)? } ConnectivityMethod::ImaginaryCoherence => { coherence::imag_coherence_all_pairs(epochs, sfreq, fmin, fmax, n_fft)? } ConnectivityMethod::Plv => plv::plv_all_pairs(epochs, sfreq, fmin, fmax, n_fft)?, ConnectivityMethod::Wpli => wpli::wpli_all_pairs(epochs, sfreq, fmin, fmax, n_fft)?, ConnectivityMethod::DwPli => wpli::dwpli_all_pairs(epochs, sfreq, fmin, fmax, n_fft)?, ConnectivityMethod::Ppc => plv::ppc_all_pairs(epochs, sfreq, fmin, fmax, n_fft)?, }; // Compute frequency vector let freqs = utils::fft_freqs(sfreq, n_fft, fmin, fmax); Ok(ConnectivityResult2D { data, freqs, sources, targets, method, n_epochs: epochs.len(), }) }