neuro_divergent_core/
config.rs

1//! Configuration management and builder patterns for neuro-divergent.
2//!
3//! This module provides comprehensive configuration management for all aspects
4//! of neural forecasting, including model configurations, training parameters,
5//! and system settings.
6
7use std::collections::HashMap;
8use std::fmt;
9use std::path::{Path, PathBuf};
10
11use chrono::{DateTime, Utc};
12use num_traits::Float;
13use serde::{Deserialize, Serialize};
14
15use crate::{
16    config_error,
17    error::{ErrorBuilder, NeuroDivergentError, NeuroDivergentResult},
18    traits::{ConfigBuilder, ConfigParameter, ExogenousConfig, ModelConfig},
19};
20
21/// Generic model configuration implementation
22#[derive(Debug, Clone)]
23pub struct GenericModelConfig<T: Float + Send + Sync + 'static> {
24    /// Model type identifier
25    pub model_type: String,
26    /// Forecast horizon
27    pub horizon: usize,
28    /// Input window size
29    pub input_size: usize,
30    /// Output size (usually equals horizon)
31    pub output_size: usize,
32    /// Exogenous variable configuration
33    pub exogenous_config: ExogenousConfig,
34    /// Model-specific parameters
35    pub parameters: HashMap<String, ConfigParameter<T>>,
36    /// Configuration metadata
37    pub metadata: ConfigMetadata,
38}
39
40/// Configuration metadata
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ConfigMetadata {
43    /// Configuration name
44    pub name: Option<String>,
45    /// Configuration description
46    pub description: Option<String>,
47    /// Configuration version
48    pub version: String,
49    /// Creation timestamp
50    pub created_at: DateTime<Utc>,
51    /// Last modified timestamp
52    pub modified_at: DateTime<Utc>,
53    /// Configuration author/creator
54    pub author: Option<String>,
55    /// Configuration tags
56    pub tags: Vec<String>,
57    /// Custom metadata fields
58    pub custom_fields: HashMap<String, String>,
59}
60
61/// Builder for generic model configurations
62pub struct ModelConfigBuilder<T: Float + Send + Sync + 'static> {
63    model_type: Option<String>,
64    horizon: Option<usize>,
65    input_size: Option<usize>,
66    output_size: Option<usize>,
67    exogenous_config: ExogenousConfig,
68    parameters: HashMap<String, ConfigParameter<T>>,
69    metadata: ConfigMetadata,
70}
71
72/// System-wide configuration for neuro-divergent
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct SystemConfig {
75    /// Logging configuration
76    pub logging: LoggingConfig,
77    /// Performance settings
78    pub performance: PerformanceConfig,
79    /// Memory management settings
80    pub memory: MemoryConfig,
81    /// Parallel processing configuration
82    pub parallel: ParallelConfig,
83    /// I/O configuration
84    pub io: IoConfig,
85    /// Development and debugging settings
86    pub debug: DebugConfig,
87    /// Feature flags
88    pub features: FeatureFlags,
89}
90
91/// Logging configuration
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct LoggingConfig {
94    /// Log level (trace, debug, info, warn, error)
95    pub level: String,
96    /// Log output format
97    pub format: LogFormat,
98    /// Log file path (None for stdout)
99    pub file_path: Option<PathBuf>,
100    /// Maximum log file size in MB
101    pub max_file_size_mb: Option<usize>,
102    /// Number of log files to retain
103    pub max_files: Option<usize>,
104    /// Enable structured logging
105    pub structured: bool,
106    /// Log timestamps
107    pub timestamps: bool,
108}
109
110/// Log output formats
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub enum LogFormat {
113    /// Human-readable text format
114    Text,
115    /// JSON format
116    Json,
117    /// Compact format
118    Compact,
119    /// Pretty formatted
120    Pretty,
121}
122
123/// Performance configuration
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct PerformanceConfig {
126    /// Enable SIMD optimizations
127    pub enable_simd: bool,
128    /// Enable GPU acceleration (if available)
129    pub enable_gpu: bool,
130    /// Preferred GPU device ID
131    pub gpu_device_id: Option<usize>,
132    /// Enable automatic mixed precision
133    pub enable_amp: bool,
134    /// CPU optimization level
135    pub cpu_optimization: CpuOptimization,
136    /// Enable performance profiling
137    pub enable_profiling: bool,
138    /// Performance profiling output directory
139    pub profiling_output_dir: Option<PathBuf>,
140}
141
142/// CPU optimization levels
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub enum CpuOptimization {
145    /// No specific optimization
146    None,
147    /// Optimize for current CPU
148    Native,
149    /// Optimize for specific CPU features
150    Features(Vec<String>),
151    /// Conservative optimizations for compatibility
152    Conservative,
153}
154
155/// Memory configuration
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct MemoryConfig {
158    /// Memory pool size in MB
159    pub pool_size_mb: Option<usize>,
160    /// Enable memory pool
161    pub enable_pool: bool,
162    /// Memory allocation strategy
163    pub allocation_strategy: AllocationStrategy,
164    /// Memory usage monitoring
165    pub enable_monitoring: bool,
166    /// Memory usage warning threshold (percentage)
167    pub warning_threshold: Option<f64>,
168    /// Garbage collection hints
169    pub gc_hints: bool,
170}
171
172/// Memory allocation strategies
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub enum AllocationStrategy {
175    /// Default system allocator
176    System,
177    /// Pool-based allocation
178    Pool,
179    /// Arena-based allocation
180    Arena,
181    /// Custom allocation strategy
182    Custom(String),
183}
184
185/// Parallel processing configuration
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ParallelConfig {
188    /// Number of threads (None for automatic)
189    pub num_threads: Option<usize>,
190    /// Thread pool configuration
191    pub thread_pool: ThreadPoolConfig,
192    /// Enable parallel training
193    pub enable_parallel_training: bool,
194    /// Enable parallel prediction
195    pub enable_parallel_prediction: bool,
196    /// Enable data parallelism
197    pub enable_data_parallelism: bool,
198    /// Enable model parallelism
199    pub enable_model_parallelism: bool,
200}
201
202/// Thread pool configuration
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct ThreadPoolConfig {
205    /// Thread pool type
206    pub pool_type: ThreadPoolType,
207    /// Stack size per thread in KB
208    pub stack_size_kb: Option<usize>,
209    /// Thread naming prefix
210    pub thread_name_prefix: Option<String>,
211    /// Thread priority
212    pub thread_priority: Option<ThreadPriority>,
213}
214
215/// Thread pool types
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub enum ThreadPoolType {
218    /// Global thread pool
219    Global,
220    /// Custom thread pool
221    Custom,
222    /// Work-stealing thread pool
223    WorkStealing,
224}
225
226/// Thread priority levels
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub enum ThreadPriority {
229    /// Low priority
230    Low,
231    /// Normal priority
232    Normal,
233    /// High priority
234    High,
235}
236
237/// I/O configuration
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct IoConfig {
240    /// Default data format for saving
241    pub default_format: DataFormat,
242    /// Enable compression
243    pub enable_compression: bool,
244    /// Compression level (1-9)
245    pub compression_level: Option<u8>,
246    /// I/O buffer size in KB
247    pub buffer_size_kb: usize,
248    /// Enable async I/O
249    pub enable_async_io: bool,
250    /// Network timeout in seconds
251    pub network_timeout_secs: Option<u64>,
252    /// Retry configuration for I/O operations
253    pub retry_config: RetryConfig,
254}
255
256/// Data formats
257#[derive(Debug, Clone, Serialize, Deserialize)]
258pub enum DataFormat {
259    /// JSON format
260    Json,
261    /// BSON format
262    Bson,
263    /// MessagePack format
264    MessagePack,
265    /// Binary format
266    Binary,
267    /// Parquet format
268    Parquet,
269    /// CSV format
270    Csv,
271}
272
273/// Retry configuration for I/O operations
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct RetryConfig {
276    /// Maximum number of retries
277    pub max_retries: usize,
278    /// Initial delay between retries in milliseconds
279    pub initial_delay_ms: u64,
280    /// Maximum delay between retries in milliseconds
281    pub max_delay_ms: u64,
282    /// Exponential backoff multiplier
283    pub backoff_multiplier: f64,
284    /// Enable jitter
285    pub enable_jitter: bool,
286}
287
288/// Debug configuration
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct DebugConfig {
291    /// Enable debug mode
292    pub enabled: bool,
293    /// Debug output directory
294    pub output_dir: Option<PathBuf>,
295    /// Save intermediate results
296    pub save_intermediates: bool,
297    /// Enable detailed timing
298    pub detailed_timing: bool,
299    /// Enable memory tracking
300    pub memory_tracking: bool,
301    /// Enable network visualization
302    pub network_visualization: bool,
303    /// Debug verbosity level
304    pub verbosity: DebugVerbosity,
305}
306
307/// Debug verbosity levels
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub enum DebugVerbosity {
310    /// Minimal debug output
311    Minimal,
312    /// Normal debug output
313    Normal,
314    /// Verbose debug output
315    Verbose,
316    /// Very verbose debug output
317    VeryVerbose,
318}
319
320/// Feature flags for experimental features
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct FeatureFlags {
323    /// Enable experimental GPU kernels
324    pub experimental_gpu_kernels: bool,
325    /// Enable experimental optimizations
326    pub experimental_optimizations: bool,
327    /// Enable experimental model architectures
328    pub experimental_models: bool,
329    /// Enable experimental data formats
330    pub experimental_data_formats: bool,
331    /// Enable automatic hyperparameter tuning
332    pub auto_hyperparameter_tuning: bool,
333    /// Enable automatic model selection
334    pub auto_model_selection: bool,
335    /// Enable distributed training
336    pub distributed_training: bool,
337}
338
339/// Configuration validation result
340#[derive(Debug, Clone)]
341pub struct ValidationResult {
342    /// Validation status
343    pub is_valid: bool,
344    /// Validation errors
345    pub errors: Vec<ValidationError>,
346    /// Validation warnings
347    pub warnings: Vec<ValidationWarning>,
348}
349
350/// Configuration validation error
351#[derive(Debug, Clone)]
352pub struct ValidationError {
353    /// Error field path
354    pub field: String,
355    /// Error message
356    pub message: String,
357    /// Error code
358    pub code: Option<String>,
359}
360
361/// Configuration validation warning
362#[derive(Debug, Clone)]
363pub struct ValidationWarning {
364    /// Warning field path
365    pub field: String,
366    /// Warning message
367    pub message: String,
368    /// Warning code
369    pub code: Option<String>,
370}
371
372/// Configuration file manager
373pub struct ConfigManager {
374    /// Default configuration search paths
375    search_paths: Vec<PathBuf>,
376    /// Current configuration
377    current_config: Option<SystemConfig>,
378    /// Configuration file format
379    file_format: DataFormat,
380}
381
382impl<T: Float + Send + Sync + 'static> GenericModelConfig<T> {
383    /// Create a new generic model configuration
384    pub fn new(model_type: impl Into<String>) -> Self {
385        Self {
386            model_type: model_type.into(),
387            horizon: 1,
388            input_size: 1,
389            output_size: 1,
390            exogenous_config: ExogenousConfig::default(),
391            parameters: HashMap::new(),
392            metadata: ConfigMetadata::new(),
393        }
394    }
395
396    /// Add a parameter to the configuration
397    pub fn with_parameter(mut self, key: impl Into<String>, value: ConfigParameter<T>) -> Self {
398        self.parameters.insert(key.into(), value);
399        self
400    }
401
402    /// Set multiple parameters
403    pub fn with_parameters(mut self, params: HashMap<String, ConfigParameter<T>>) -> Self {
404        self.parameters.extend(params);
405        self
406    }
407
408    /// Set configuration metadata
409    pub fn with_metadata(mut self, metadata: ConfigMetadata) -> Self {
410        self.metadata = metadata;
411        self
412    }
413
414    /// Get a parameter value
415    pub fn get_parameter(&self, key: &str) -> Option<&ConfigParameter<T>> {
416        self.parameters.get(key)
417    }
418
419    /// Get a parameter as a specific type
420    pub fn get_float_parameter(&self, key: &str) -> Option<T> {
421        match self.parameters.get(key) {
422            Some(ConfigParameter::Float(val)) => Some(*val),
423            _ => None,
424        }
425    }
426
427    /// Get an integer parameter
428    pub fn get_integer_parameter(&self, key: &str) -> Option<i64> {
429        match self.parameters.get(key) {
430            Some(ConfigParameter::Integer(val)) => Some(*val),
431            _ => None,
432        }
433    }
434
435    /// Get a string parameter
436    pub fn get_string_parameter(&self, key: &str) -> Option<&String> {
437        match self.parameters.get(key) {
438            Some(ConfigParameter::String(val)) => Some(val),
439            _ => None,
440        }
441    }
442
443    /// Get a boolean parameter
444    pub fn get_boolean_parameter(&self, key: &str) -> Option<bool> {
445        match self.parameters.get(key) {
446            Some(ConfigParameter::Boolean(val)) => Some(*val),
447            _ => None,
448        }
449    }
450
451    /// Save configuration to file
452    /// TODO: Implement serialization for generic configurations
453    #[allow(dead_code)]
454    pub fn save<P: AsRef<Path>>(&self, _path: P) -> NeuroDivergentResult<()> {
455        todo!("Configuration serialization needs to be implemented without generic type constraints")
456    }
457
458    /// Load configuration from file
459    /// TODO: Implement deserialization for generic configurations  
460    #[allow(dead_code)]
461    pub fn load<P: AsRef<Path>>(_path: P) -> NeuroDivergentResult<Self> {
462        todo!("Configuration deserialization needs to be implemented without generic type constraints")
463    }
464
465    /// Merge with another configuration
466    pub fn merge(mut self, other: Self) -> Self {
467        // Merge parameters, with other taking precedence
468        self.parameters.extend(other.parameters);
469        
470        // Update other fields if they're set in other
471        if other.horizon != 1 {
472            self.horizon = other.horizon;
473        }
474        if other.input_size != 1 {
475            self.input_size = other.input_size;
476        }
477        if other.output_size != 1 {
478            self.output_size = other.output_size;
479        }
480
481        // Merge exogenous config
482        if !other.exogenous_config.static_features.is_empty() {
483            self.exogenous_config.static_features = other.exogenous_config.static_features;
484        }
485        if !other.exogenous_config.historical_features.is_empty() {
486            self.exogenous_config.historical_features = other.exogenous_config.historical_features;
487        }
488        if !other.exogenous_config.future_features.is_empty() {
489            self.exogenous_config.future_features = other.exogenous_config.future_features;
490        }
491
492        self.metadata.modified_at = Utc::now();
493        self
494    }
495}
496
497impl<T: Float + Send + Sync + 'static> ModelConfig<T> for GenericModelConfig<T> {
498    fn validate(&self) -> NeuroDivergentResult<()> {
499        if self.horizon == 0 {
500            return Err(config_error!("Horizon must be greater than 0"));
501        }
502        
503        if self.input_size == 0 {
504            return Err(config_error!("Input size must be greater than 0"));
505        }
506        
507        if self.output_size == 0 {
508            return Err(config_error!("Output size must be greater than 0"));
509        }
510        
511        if self.model_type.is_empty() {
512            return Err(config_error!("Model type cannot be empty"));
513        }
514
515        Ok(())
516    }
517
518    fn horizon(&self) -> usize {
519        self.horizon
520    }
521
522    fn input_size(&self) -> usize {
523        self.input_size
524    }
525
526    fn output_size(&self) -> usize {
527        self.output_size
528    }
529
530    fn exogenous_config(&self) -> &ExogenousConfig {
531        &self.exogenous_config
532    }
533
534    fn model_type(&self) -> &str {
535        &self.model_type
536    }
537
538    fn to_parameters(&self) -> HashMap<String, ConfigParameter<T>> {
539        let mut params = self.parameters.clone();
540        
541        // Add basic parameters
542        params.insert("horizon".to_string(), ConfigParameter::Integer(self.horizon as i64));
543        params.insert("input_size".to_string(), ConfigParameter::Integer(self.input_size as i64));
544        params.insert("output_size".to_string(), ConfigParameter::Integer(self.output_size as i64));
545        params.insert("model_type".to_string(), ConfigParameter::String(self.model_type.clone()));
546        
547        params
548    }
549
550    fn from_parameters(params: HashMap<String, ConfigParameter<T>>) -> NeuroDivergentResult<Self> {
551        let model_type = params.get("model_type")
552            .and_then(|p| match p {
553                ConfigParameter::String(s) => Some(s.clone()),
554                _ => None,
555            })
556            .ok_or_else(|| config_error!("Missing required parameter: model_type"))?;
557
558        let horizon = params.get("horizon")
559            .and_then(|p| match p {
560                ConfigParameter::Integer(i) => Some(*i as usize),
561                _ => None,
562            })
563            .unwrap_or(1);
564
565        let input_size = params.get("input_size")
566            .and_then(|p| match p {
567                ConfigParameter::Integer(i) => Some(*i as usize),
568                _ => None,
569            })
570            .unwrap_or(1);
571
572        let output_size = params.get("output_size")
573            .and_then(|p| match p {
574                ConfigParameter::Integer(i) => Some(*i as usize),
575                _ => None,
576            })
577            .unwrap_or(1);
578
579        let mut config = Self::new(model_type);
580        config.horizon = horizon;
581        config.input_size = input_size;
582        config.output_size = output_size;
583        
584        // Filter out basic parameters and keep the rest
585        let mut remaining_params = params;
586        remaining_params.remove("model_type");
587        remaining_params.remove("horizon");
588        remaining_params.remove("input_size");
589        remaining_params.remove("output_size");
590        
591        config.parameters = remaining_params;
592        Ok(config)
593    }
594
595    fn builder() -> impl ConfigBuilder<Self, T> {
596        ModelConfigBuilder::new()
597    }
598}
599
600impl<T: Float + Send + Sync + 'static> ModelConfigBuilder<T> {
601    /// Create a new builder
602    pub fn new() -> Self {
603        Self {
604            model_type: None,
605            horizon: None,
606            input_size: None,
607            output_size: None,
608            exogenous_config: ExogenousConfig::default(),
609            parameters: HashMap::new(),
610            metadata: ConfigMetadata::new(),
611        }
612    }
613
614    /// Set the model type
615    pub fn with_model_type(mut self, model_type: impl Into<String>) -> Self {
616        self.model_type = Some(model_type.into());
617        self
618    }
619
620    /// Add a parameter
621    pub fn with_parameter(mut self, key: impl Into<String>, value: ConfigParameter<T>) -> Self {
622        self.parameters.insert(key.into(), value);
623        self
624    }
625
626    /// Set metadata
627    pub fn with_metadata(mut self, metadata: ConfigMetadata) -> Self {
628        self.metadata = metadata;
629        self
630    }
631}
632
633impl<T: Float + Send + Sync + 'static> ConfigBuilder<GenericModelConfig<T>, T> for ModelConfigBuilder<T> {
634    fn build(self) -> NeuroDivergentResult<GenericModelConfig<T>> {
635        let model_type = self.model_type.ok_or_else(|| {
636            config_error!("Model type is required")
637        })?;
638
639        let horizon = self.horizon.unwrap_or(1);
640        let input_size = self.input_size.unwrap_or(1);
641        let output_size = self.output_size.unwrap_or(horizon);
642
643        let mut config = GenericModelConfig::new(model_type);
644        config.horizon = horizon;
645        config.input_size = input_size;
646        config.output_size = output_size;
647        config.exogenous_config = self.exogenous_config;
648        config.parameters = self.parameters;
649        config.metadata = self.metadata;
650
651        config.validate()?;
652        Ok(config)
653    }
654
655    fn with_horizon(mut self, horizon: usize) -> Self {
656        self.horizon = Some(horizon);
657        self
658    }
659
660    fn with_input_size(mut self, input_size: usize) -> Self {
661        self.input_size = Some(input_size);
662        self
663    }
664
665    fn with_exogenous_config(mut self, config: ExogenousConfig) -> Self {
666        self.exogenous_config = config;
667        self
668    }
669}
670
671impl ConfigMetadata {
672    /// Create new metadata with current timestamp
673    pub fn new() -> Self {
674        let now = Utc::now();
675        Self {
676            name: None,
677            description: None,
678            version: "1.0.0".to_string(),
679            created_at: now,
680            modified_at: now,
681            author: None,
682            tags: Vec::new(),
683            custom_fields: HashMap::new(),
684        }
685    }
686
687    /// Set name
688    pub fn with_name(mut self, name: impl Into<String>) -> Self {
689        self.name = Some(name.into());
690        self
691    }
692
693    /// Set description
694    pub fn with_description(mut self, description: impl Into<String>) -> Self {
695        self.description = Some(description.into());
696        self
697    }
698
699    /// Set version
700    pub fn with_version(mut self, version: impl Into<String>) -> Self {
701        self.version = version.into();
702        self
703    }
704
705    /// Set author
706    pub fn with_author(mut self, author: impl Into<String>) -> Self {
707        self.author = Some(author.into());
708        self
709    }
710
711    /// Add tags
712    pub fn with_tags(mut self, tags: Vec<String>) -> Self {
713        self.tags = tags;
714        self
715    }
716
717    /// Add custom field
718    pub fn with_custom_field(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
719        self.custom_fields.insert(key.into(), value.into());
720        self
721    }
722}
723
724impl ConfigManager {
725    /// Create a new configuration manager
726    pub fn new() -> Self {
727        let mut search_paths = Vec::new();
728        
729        // Add default search paths
730        if let Ok(home) = std::env::var("HOME") {
731            let home_dir = PathBuf::from(home);
732            search_paths.push(home_dir.join(".config").join("neuro-divergent"));
733        }
734        
735        search_paths.push(PathBuf::from("/etc/neuro-divergent"));
736        search_paths.push(PathBuf::from("./config"));
737
738        Self {
739            search_paths,
740            current_config: None,
741            file_format: DataFormat::Json,
742        }
743    }
744
745    /// Add a search path
746    pub fn add_search_path<P: AsRef<Path>>(&mut self, path: P) {
747        self.search_paths.push(path.as_ref().to_path_buf());
748    }
749
750    /// Load configuration from the first found file
751    pub fn load_config(&mut self) -> NeuroDivergentResult<&SystemConfig> {
752        for search_path in &self.search_paths {
753            let config_file = search_path.join("config.json");
754            if config_file.exists() {
755                let config = self.load_from_file(&config_file)?;
756                self.current_config = Some(config);
757                return Ok(self.current_config.as_ref().unwrap());
758            }
759        }
760
761        // Use default configuration if no file found
762        self.current_config = Some(SystemConfig::default());
763        Ok(self.current_config.as_ref().unwrap())
764    }
765
766    /// Load configuration from specific file
767    pub fn load_from_file<P: AsRef<Path>>(&self, path: P) -> NeuroDivergentResult<SystemConfig> {
768        let content = std::fs::read_to_string(path)
769            .map_err(|e| ErrorBuilder::config(format!("Failed to read config file: {}", e)).build())?;
770
771        let config: SystemConfig = serde_json::from_str(&content)
772            .map_err(|e| ErrorBuilder::config(format!("Failed to parse config: {}", e)).build())?;
773
774        Ok(config)
775    }
776
777    /// Save current configuration
778    pub fn save_config<P: AsRef<Path>>(&self, path: P) -> NeuroDivergentResult<()> {
779        let config = self.current_config.as_ref()
780            .ok_or_else(|| config_error!("No configuration loaded"))?;
781
782        let content = serde_json::to_string_pretty(config)
783            .map_err(|e| ErrorBuilder::config(format!("Failed to serialize config: {}", e)).build())?;
784
785        std::fs::write(path, content)
786            .map_err(|e| ErrorBuilder::config(format!("Failed to write config file: {}", e)).build())?;
787
788        Ok(())
789    }
790
791    /// Get current configuration
792    pub fn config(&self) -> Option<&SystemConfig> {
793        self.current_config.as_ref()
794    }
795
796    /// Get mutable reference to current configuration
797    pub fn config_mut(&mut self) -> Option<&mut SystemConfig> {
798        self.current_config.as_mut()
799    }
800
801    /// Validate current configuration
802    pub fn validate(&self) -> ValidationResult {
803        let mut result = ValidationResult {
804            is_valid: true,
805            errors: Vec::new(),
806            warnings: Vec::new(),
807        };
808
809        if let Some(config) = &self.current_config {
810            self.validate_system_config(config, &mut result);
811        } else {
812            result.is_valid = false;
813            result.errors.push(ValidationError {
814                field: "config".to_string(),
815                message: "No configuration loaded".to_string(),
816                code: Some("NO_CONFIG".to_string()),
817            });
818        }
819
820        result
821    }
822
823    fn validate_system_config(&self, _config: &SystemConfig, _result: &mut ValidationResult) {
824        // TODO: Implement comprehensive configuration validation
825    }
826}
827
828impl Default for SystemConfig {
829    fn default() -> Self {
830        Self {
831            logging: LoggingConfig::default(),
832            performance: PerformanceConfig::default(),
833            memory: MemoryConfig::default(),
834            parallel: ParallelConfig::default(),
835            io: IoConfig::default(),
836            debug: DebugConfig::default(),
837            features: FeatureFlags::default(),
838        }
839    }
840}
841
842impl Default for LoggingConfig {
843    fn default() -> Self {
844        Self {
845            level: "info".to_string(),
846            format: LogFormat::Text,
847            file_path: None,
848            max_file_size_mb: Some(100),
849            max_files: Some(5),
850            structured: false,
851            timestamps: true,
852        }
853    }
854}
855
856impl Default for PerformanceConfig {
857    fn default() -> Self {
858        Self {
859            enable_simd: true,
860            enable_gpu: false,
861            gpu_device_id: None,
862            enable_amp: false,
863            cpu_optimization: CpuOptimization::Native,
864            enable_profiling: false,
865            profiling_output_dir: None,
866        }
867    }
868}
869
870impl Default for MemoryConfig {
871    fn default() -> Self {
872        Self {
873            pool_size_mb: None,
874            enable_pool: false,
875            allocation_strategy: AllocationStrategy::System,
876            enable_monitoring: false,
877            warning_threshold: Some(80.0),
878            gc_hints: true,
879        }
880    }
881}
882
883impl Default for ParallelConfig {
884    fn default() -> Self {
885        Self {
886            num_threads: None,
887            thread_pool: ThreadPoolConfig::default(),
888            enable_parallel_training: true,
889            enable_parallel_prediction: true,
890            enable_data_parallelism: true,
891            enable_model_parallelism: false,
892        }
893    }
894}
895
896impl Default for ThreadPoolConfig {
897    fn default() -> Self {
898        Self {
899            pool_type: ThreadPoolType::Global,
900            stack_size_kb: None,
901            thread_name_prefix: Some("neuro-divergent".to_string()),
902            thread_priority: Some(ThreadPriority::Normal),
903        }
904    }
905}
906
907impl Default for IoConfig {
908    fn default() -> Self {
909        Self {
910            default_format: DataFormat::Json,
911            enable_compression: false,
912            compression_level: Some(6),
913            buffer_size_kb: 64,
914            enable_async_io: false,
915            network_timeout_secs: Some(30),
916            retry_config: RetryConfig::default(),
917        }
918    }
919}
920
921impl Default for RetryConfig {
922    fn default() -> Self {
923        Self {
924            max_retries: 3,
925            initial_delay_ms: 100,
926            max_delay_ms: 5000,
927            backoff_multiplier: 2.0,
928            enable_jitter: true,
929        }
930    }
931}
932
933impl Default for DebugConfig {
934    fn default() -> Self {
935        Self {
936            enabled: false,
937            output_dir: None,
938            save_intermediates: false,
939            detailed_timing: false,
940            memory_tracking: false,
941            network_visualization: false,
942            verbosity: DebugVerbosity::Normal,
943        }
944    }
945}
946
947impl Default for FeatureFlags {
948    fn default() -> Self {
949        Self {
950            experimental_gpu_kernels: false,
951            experimental_optimizations: false,
952            experimental_models: false,
953            experimental_data_formats: false,
954            auto_hyperparameter_tuning: false,
955            auto_model_selection: false,
956            distributed_training: false,
957        }
958    }
959}
960
961impl Default for ConfigMetadata {
962    fn default() -> Self {
963        Self::new()
964    }
965}
966
967impl Default for ConfigManager {
968    fn default() -> Self {
969        Self::new()
970    }
971}
972
973impl<T: Float + Send + Sync + 'static> Default for ModelConfigBuilder<T> {
974    fn default() -> Self {
975        Self::new()
976    }
977}
978
979impl fmt::Display for LogFormat {
980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981        match self {
982            LogFormat::Text => write!(f, "text"),
983            LogFormat::Json => write!(f, "json"),
984            LogFormat::Compact => write!(f, "compact"),
985            LogFormat::Pretty => write!(f, "pretty"),
986        }
987    }
988}
989
990impl fmt::Display for DataFormat {
991    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
992        match self {
993            DataFormat::Json => write!(f, "json"),
994            DataFormat::Bson => write!(f, "bson"),
995            DataFormat::MessagePack => write!(f, "msgpack"),
996            DataFormat::Binary => write!(f, "binary"),
997            DataFormat::Parquet => write!(f, "parquet"),
998            DataFormat::Csv => write!(f, "csv"),
999        }
1000    }
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005    use super::*;
1006
1007    #[test]
1008    fn test_generic_config_creation() {
1009        let config = GenericModelConfig::<f64>::new("test_model")
1010            .with_parameter("learning_rate".to_string(), ConfigParameter::Float(0.01))
1011            .with_parameter("epochs".to_string(), ConfigParameter::Integer(100));
1012
1013        assert_eq!(config.model_type, "test_model");
1014        assert_eq!(config.get_float_parameter("learning_rate"), Some(0.01));
1015        assert_eq!(config.get_integer_parameter("epochs"), Some(100));
1016    }
1017
1018    #[test]
1019    fn test_config_builder() {
1020        let config = ModelConfigBuilder::<f64>::new()
1021            .with_model_type("lstm")
1022            .with_horizon(12)
1023            .with_input_size(24)
1024            .with_parameter("hidden_size".to_string(), ConfigParameter::Integer(64))
1025            .build()
1026            .unwrap();
1027
1028        assert_eq!(config.model_type, "lstm");
1029        assert_eq!(config.horizon, 12);
1030        assert_eq!(config.input_size, 24);
1031        assert_eq!(config.get_integer_parameter("hidden_size"), Some(64));
1032    }
1033
1034    #[test]
1035    fn test_config_validation() {
1036        let valid_config = GenericModelConfig::<f64>::new("test")
1037            .with_parameter("horizon".to_string(), ConfigParameter::Integer(12));
1038        
1039        valid_config.horizon = 12;
1040        assert!(valid_config.validate().is_ok());
1041
1042        let mut invalid_config = GenericModelConfig::<f64>::new("test");
1043        invalid_config.horizon = 0;
1044        assert!(invalid_config.validate().is_err());
1045    }
1046
1047    #[test]
1048    fn test_config_serialization() {
1049        let config = GenericModelConfig::<f64>::new("test_model")
1050            .with_parameter("param1".to_string(), ConfigParameter::Float(1.0))
1051            .with_parameter("param2".to_string(), ConfigParameter::String("value".to_string()));
1052
1053        let serialized = serde_json::to_string(&config).unwrap();
1054        let deserialized: GenericModelConfig<f64> = serde_json::from_str(&serialized).unwrap();
1055
1056        assert_eq!(config.model_type, deserialized.model_type);
1057        assert_eq!(config.parameters.len(), deserialized.parameters.len());
1058    }
1059
1060    #[test]
1061    fn test_system_config_defaults() {
1062        let config = SystemConfig::default();
1063        
1064        assert_eq!(config.logging.level, "info");
1065        assert!(config.performance.enable_simd);
1066        assert!(!config.debug.enabled);
1067        assert!(!config.features.experimental_gpu_kernels);
1068    }
1069
1070    #[test]
1071    fn test_config_manager() {
1072        let mut manager = ConfigManager::new();
1073        
1074        // Should load default config when no file exists
1075        let config = manager.load_config().unwrap();
1076        assert_eq!(config.logging.level, "info");
1077        
1078        // Should be able to get current config
1079        assert!(manager.config().is_some());
1080    }
1081
1082    #[test]
1083    fn test_metadata_builder() {
1084        let metadata = ConfigMetadata::new()
1085            .with_name("test_config")
1086            .with_description("Test configuration")
1087            .with_author("test_author")
1088            .with_tags(vec!["test".to_string(), "config".to_string()])
1089            .with_custom_field("custom_key", "custom_value");
1090
1091        assert_eq!(metadata.name, Some("test_config".to_string()));
1092        assert_eq!(metadata.description, Some("Test configuration".to_string()));
1093        assert_eq!(metadata.author, Some("test_author".to_string()));
1094        assert_eq!(metadata.tags, vec!["test", "config"]);
1095        assert_eq!(metadata.custom_fields.get("custom_key"), Some(&"custom_value".to_string()));
1096    }
1097}