dda_rs/
types.rs

1use serde::{Deserialize, Serialize};
2
3/// Time range for analysis
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct TimeRange {
6    pub start: f64,
7    pub end: f64,
8}
9
10/// Preprocessing options
11/// Note: Preprocessing should be done before DDA analysis, not by this package
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct PreprocessingOptions {
14    pub highpass: Option<f64>,
15    pub lowpass: Option<f64>,
16}
17
18/// Algorithm variant selection
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct AlgorithmSelection {
21    pub enabled_variants: Vec<String>,
22    /// SELECT mask as 6-bit string (e.g., "1 0 1 0 0 0" for ST and CD)
23    /// Format: ST CT CD RESERVED DE SY
24    /// - ST: Single Timeseries (output: _DDA_ST)
25    /// - CT: Cross-Timeseries (output: _DDA_CT)
26    /// - CD: Cross-Dynamical (output: _CD_DDA_ST)
27    /// - RESERVED: Internal development function (not for user use)
28    /// - DE: Delay Embedding (output: _DE)
29    /// - SY: Synchronization (output: _SY)
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub select_mask: Option<String>,
32}
33
34/// Window parameters for DDA analysis
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct WindowParameters {
37    pub window_length: u32,
38    pub window_step: u32,
39    /// CT-specific window length (for Cross-Timeseries variant)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub ct_window_length: Option<u32>,
42    /// CT-specific window step (for Cross-Timeseries variant)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub ct_window_step: Option<u32>,
45}
46
47/// Delay parameters for DDA analysis
48/// These are the tau values passed directly to the -TAU CLI argument
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct DelayParameters {
51    /// List of delay values (tau) passed directly to the binary
52    /// Example: [1, 2, 3, 4, 5] will be passed as -TAU 1 2 3 4 5
53    pub delays: Vec<i32>,
54}
55
56/// MODEL parameters for DDA analysis (expert mode)
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct ModelParameters {
59    pub dm: u32,     // Embedding dimension (default: 4)
60    pub order: u32,  // Polynomial order (default: 4)
61    pub nr_tau: u32, // Number of tau values (default: 2)
62}
63
64/// Per-variant channel configuration
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct VariantChannelConfig {
67    /// Selected channel indices for single-channel variants (ST, DE, SY)
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub selected_channels: Option<Vec<usize>>,
70    /// Channel pairs for CT variant
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub ct_channel_pairs: Option<Vec<[usize; 2]>>,
73    /// Directed channel pairs for CD variant
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub cd_channel_pairs: Option<Vec<[usize; 2]>>,
76}
77
78/// Complete DDA request configuration
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct DDARequest {
81    pub file_path: String,
82    #[serde(alias = "channel_list")]
83    pub channels: Option<Vec<usize>>, // Channel indices (0-based)
84    pub time_range: TimeRange,
85    pub preprocessing_options: PreprocessingOptions,
86    pub algorithm_selection: AlgorithmSelection,
87    pub window_parameters: WindowParameters,
88    pub delay_parameters: DelayParameters,
89    /// Channel pairs for CT (Cross-Timeseries) analysis
90    /// Each pair is [channel_i, channel_j] where channels are 0-based indices
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub ct_channel_pairs: Option<Vec<[usize; 2]>>,
93    /// Channel pairs for CD (Cross-Dynamical) analysis
94    /// Each pair is [from_channel, to_channel] representing directed relationships
95    /// Format: [(1, 2), (1, 3), (1, 4)] → CH_list: 1 2 1 3 1 4
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub cd_channel_pairs: Option<Vec<[usize; 2]>>,
98    /// MODEL parameters (expert mode)
99    /// If not provided, defaults to dm=4, order=4, nr_tau=2
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub model_parameters: Option<ModelParameters>,
102    /// Per-variant channel configurations (new format)
103    /// Maps variant IDs to their specific channel configurations
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub variant_configs: Option<std::collections::HashMap<String, VariantChannelConfig>>,
106    /// Input file sampling rate in Hz
107    /// When > 1000 Hz, the -SR argument will be added as [SR/2, SR]
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub sampling_rate: Option<f64>,
110}
111
112/// Variant-specific DDA result
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct VariantResult {
115    pub variant_id: String,      // "ST", "CT", "CD", "DE"
116    pub variant_name: String,    // "Single Timeseries (ST)", etc.
117    pub q_matrix: Vec<Vec<f64>>, // Q matrix for this variant [channels × timepoints]
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub channel_labels: Option<Vec<String>>, // Optional channel labels specific to this variant
120}
121
122/// DDA analysis result
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct DDAResult {
125    pub id: String,
126    pub file_path: String,
127    pub channels: Vec<String>,
128    pub q_matrix: Vec<Vec<f64>>, // Primary variant Q matrix (for backward compatibility)
129    pub variant_results: Option<Vec<VariantResult>>, // All variant results
130    pub raw_output: Option<String>, // Optional: keep raw output for debugging
131    pub window_parameters: WindowParameters,
132    pub delay_parameters: DelayParameters,
133    pub created_at: String,
134}
135
136impl DDAResult {
137    pub fn new(
138        id: String,
139        file_path: String,
140        channels: Vec<String>,
141        q_matrix: Vec<Vec<f64>>,
142        window_parameters: WindowParameters,
143        delay_parameters: DelayParameters,
144    ) -> Self {
145        Self {
146            id,
147            file_path,
148            channels,
149            q_matrix,
150            variant_results: None,
151            raw_output: None,
152            window_parameters,
153            delay_parameters,
154            created_at: chrono::Utc::now().to_rfc3339(),
155        }
156    }
157
158    pub fn with_raw_output(mut self, raw_output: String) -> Self {
159        self.raw_output = Some(raw_output);
160        self
161    }
162
163    pub fn with_variant_results(mut self, variant_results: Vec<VariantResult>) -> Self {
164        self.variant_results = Some(variant_results);
165        self
166    }
167}