scirs2_interpolate/advanced_coordinator_modules/
pattern_analysis.rs

1//! Data pattern analysis system for interpolation optimization
2//!
3//! This module provides sophisticated pattern recognition and analysis capabilities
4//! for automatically identifying optimal interpolation methods based on data characteristics.
5
6use super::types::*;
7use crate::error::InterpolateResult;
8use scirs2_core::numeric::Float;
9use std::collections::HashMap;
10use std::fmt::Debug;
11
12/// Data pattern analyzer for intelligent interpolation
13#[derive(Debug)]
14pub struct DataPatternAnalyzer<F: Float + Debug> {
15    /// Pattern database
16    pattern_db: HashMap<PatternSignature, PatternData<F>>,
17    /// Current analysis state
18    analysis_state: AnalysisState<F>,
19    /// Pattern recognition model
20    recognition_model: PatternRecognitionModel<F>,
21}
22
23/// Pattern signature for identification and classification
24#[derive(Debug, Clone, Hash, Eq, PartialEq)]
25pub struct PatternSignature {
26    /// Pattern type
27    pattern_type: DataPatternType,
28    /// Size characteristics
29    size_range: (usize, usize),
30    /// Smoothness characteristics
31    smoothness_profile: SmoothnessProfile,
32}
33
34/// Smoothness profile classification
35#[derive(Debug, Clone, Hash, Eq, PartialEq)]
36pub enum SmoothnessProfile {
37    /// Very smooth (C∞)
38    VerySmooth,
39    /// Smooth (C²)
40    Smooth,
41    /// Moderately smooth (C¹)
42    ModeratelySmooth,
43    /// Continuous (C⁰)
44    Continuous,
45    /// Discontinuous
46    Discontinuous,
47}
48
49/// Analysis state for pattern recognition
50#[derive(Debug)]
51pub struct AnalysisState<F: Float> {
52    /// Current data being analyzed
53    current_data: Option<DataProfile<F>>,
54    /// Analysis progress (0-1)
55    progress: f64,
56    /// Intermediate results
57    intermediate_results: HashMap<String, f64>,
58    /// Current analysis stage
59    current_stage: AnalysisStage,
60}
61
62/// Pattern recognition model
63#[derive(Debug)]
64pub struct PatternRecognitionModel<F: Float> {
65    /// Feature extractors
66    feature_extractors: Vec<FeatureExtractor<F>>,
67    /// Classification weights
68    classification_weights: HashMap<String, f64>,
69    /// Model accuracy
70    model_accuracy: f64,
71}
72
73/// Feature extractor for pattern recognition
74#[derive(Debug)]
75pub struct FeatureExtractor<F: Float> {
76    /// Feature name
77    pub name: String,
78    /// Feature extraction function
79    pub extractor: fn(&[F]) -> f64,
80    /// Feature importance weight
81    pub importance: f64,
82}
83
84/// Pattern analysis result
85#[derive(Debug, Clone)]
86pub struct PatternAnalysisResult<F: Float> {
87    /// Identified pattern signature
88    pub pattern_signature: PatternSignature,
89    /// Confidence in pattern identification (0-1)
90    pub confidence: f64,
91    /// Extracted features
92    pub features: HashMap<String, f64>,
93    /// Recommended interpolation methods
94    pub recommended_methods: Vec<InterpolationMethodType>,
95    /// Performance predictions
96    pub performance_predictions: HashMap<InterpolationMethodType, PerformanceCharacteristics>,
97    /// Analysis metadata
98    pub analysis_metadata: AnalysisMetadata<F>,
99}
100
101/// Metadata about the analysis process
102#[derive(Debug, Clone)]
103pub struct AnalysisMetadata<F: Float> {
104    /// Time taken for analysis
105    pub analysis_time_ms: f64,
106    /// Data quality score
107    pub data_quality_score: F,
108    /// Number of features extracted
109    pub feature_count: usize,
110    /// Model version used
111    pub model_version: String,
112}
113
114impl<F: Float + Debug> DataPatternAnalyzer<F> {
115    /// Create a new data pattern analyzer
116    pub fn new() -> InterpolateResult<Self> {
117        Ok(Self {
118            pattern_db: HashMap::new(),
119            analysis_state: AnalysisState::new()?,
120            recognition_model: PatternRecognitionModel::new()?,
121        })
122    }
123
124    /// Analyze data patterns and recommend optimal interpolation methods
125    pub fn analyze_patterns(
126        &mut self,
127        data_profile: &DataProfile<F>,
128    ) -> InterpolateResult<PatternAnalysisResult<F>> {
129        let start_time = std::time::Instant::now();
130
131        // Update analysis state
132        self.analysis_state.current_data = Some(data_profile.clone());
133        self.analysis_state.progress = 0.0;
134        self.analysis_state.current_stage = AnalysisStage::DataLoading;
135
136        // Extract features from data profile
137        self.analysis_state.current_stage = AnalysisStage::FeatureExtraction;
138        let features = self.extract_features(data_profile)?;
139        self.analysis_state.progress = 0.3;
140
141        // Identify pattern signature
142        self.analysis_state.current_stage = AnalysisStage::PatternRecognition;
143        let pattern_signature = self.identify_pattern_signature(data_profile, &features)?;
144        self.analysis_state.progress = 0.6;
145
146        // Generate method recommendations
147        self.analysis_state.current_stage = AnalysisStage::MethodRecommendation;
148        let recommended_methods = self.recommend_methods(&pattern_signature, &features)?;
149        self.analysis_state.progress = 0.8;
150
151        // Predict performance for each method
152        self.analysis_state.current_stage = AnalysisStage::PerformancePrediction;
153        let performance_predictions =
154            self.predict_performance(&recommended_methods, data_profile, &features)?;
155        self.analysis_state.progress = 0.9;
156
157        // Calculate confidence
158        let confidence = self.calculate_pattern_confidence(&pattern_signature, &features);
159
160        // Create analysis metadata
161        let analysis_time = start_time.elapsed().as_millis() as f64;
162        let metadata = AnalysisMetadata {
163            analysis_time_ms: analysis_time,
164            data_quality_score: self.assess_data_quality(data_profile),
165            feature_count: features.len(),
166            model_version: "1.0.0".to_string(),
167        };
168
169        self.analysis_state.current_stage = AnalysisStage::Completed;
170        self.analysis_state.progress = 1.0;
171
172        Ok(PatternAnalysisResult {
173            pattern_signature,
174            confidence,
175            features,
176            recommended_methods,
177            performance_predictions,
178            analysis_metadata: metadata,
179        })
180    }
181
182    /// Extract features from data profile
183    fn extract_features(
184        &self,
185        data_profile: &DataProfile<F>,
186    ) -> InterpolateResult<HashMap<String, f64>> {
187        let mut features = HashMap::new();
188
189        // Basic statistical features
190        features.insert("data_size".to_string(), data_profile.size as f64);
191        features.insert(
192            "dimensionality".to_string(),
193            data_profile.dimensionality as f64,
194        );
195        features.insert(
196            "smoothness".to_string(),
197            data_profile.smoothness.to_f64().unwrap_or(0.5),
198        );
199        features.insert(
200            "noise_level".to_string(),
201            data_profile.noise_level.to_f64().unwrap_or(0.1),
202        );
203        features.insert(
204            "sparsity".to_string(),
205            data_profile.sparsity.to_f64().unwrap_or(0.0),
206        );
207
208        // Value range features
209        let value_range = data_profile.value_range.1 - data_profile.value_range.0;
210        features.insert(
211            "value_range".to_string(),
212            value_range.to_f64().unwrap_or(1.0),
213        );
214
215        // Gradient features
216        features.insert(
217            "mean_gradient".to_string(),
218            data_profile
219                .gradient_stats
220                .mean_magnitude
221                .to_f64()
222                .unwrap_or(0.0),
223        );
224        features.insert(
225            "gradient_variance".to_string(),
226            data_profile.gradient_stats.variance.to_f64().unwrap_or(0.0),
227        );
228        features.insert(
229            "max_gradient".to_string(),
230            data_profile
231                .gradient_stats
232                .max_gradient
233                .to_f64()
234                .unwrap_or(0.0),
235        );
236
237        // Frequency features
238        features.insert(
239            "dominant_frequency".to_string(),
240            data_profile
241                .frequency_content
242                .dominant_frequency
243                .to_f64()
244                .unwrap_or(0.0),
245        );
246        features.insert(
247            "high_freq_ratio".to_string(),
248            data_profile
249                .frequency_content
250                .high_freq_ratio
251                .to_f64()
252                .unwrap_or(0.0),
253        );
254        features.insert(
255            "low_freq_ratio".to_string(),
256            data_profile
257                .frequency_content
258                .low_freq_ratio
259                .to_f64()
260                .unwrap_or(0.0),
261        );
262
263        // Derived features
264        let complexity_score = self.calculate_complexity_score(data_profile);
265        features.insert("complexity_score".to_string(), complexity_score);
266
267        let regularity_score = self.calculate_regularity_score(data_profile);
268        features.insert("regularity_score".to_string(), regularity_score);
269
270        let interpolation_difficulty = self.calculate_interpolation_difficulty(data_profile);
271        features.insert(
272            "interpolation_difficulty".to_string(),
273            interpolation_difficulty,
274        );
275
276        Ok(features)
277    }
278
279    /// Identify pattern signature based on data characteristics
280    fn identify_pattern_signature(
281        &self,
282        data_profile: &DataProfile<F>,
283        features: &HashMap<String, f64>,
284    ) -> InterpolateResult<PatternSignature> {
285        // Classify pattern type
286        let pattern_type = self.classify_pattern_type(features);
287
288        // Determine size range
289        let size_range = match data_profile.size {
290            0..=1000 => (0, 1000),
291            1001..=10000 => (1001, 10000),
292            10001..=100000 => (10001, 100000),
293            _ => (100001, usize::MAX),
294        };
295
296        // Classify smoothness profile
297        let smoothness_profile = self.classify_smoothness_profile(features);
298
299        Ok(PatternSignature {
300            pattern_type,
301            size_range,
302            smoothness_profile,
303        })
304    }
305
306    /// Classify data pattern type based on features
307    fn classify_pattern_type(&self, features: &HashMap<String, f64>) -> DataPatternType {
308        let smoothness = features.get("smoothness").copied().unwrap_or(0.5);
309        let noise_level = features.get("noise_level").copied().unwrap_or(0.1);
310        let sparsity = features.get("sparsity").copied().unwrap_or(0.0);
311        let high_freq_ratio = features.get("high_freq_ratio").copied().unwrap_or(0.0);
312        let regularity = features.get("regularity_score").copied().unwrap_or(0.5);
313
314        if noise_level > 0.2 {
315            DataPatternType::Noisy
316        } else if sparsity > 0.3 {
317            DataPatternType::Sparse
318        } else if high_freq_ratio > 0.6 {
319            DataPatternType::Oscillatory
320        } else if smoothness > 0.8 && regularity > 0.7 {
321            DataPatternType::Smooth
322        } else if regularity > 0.8 {
323            DataPatternType::Structured
324        } else if smoothness < 0.3 {
325            DataPatternType::Irregular
326        } else {
327            // Check for monotonicity
328            let gradient_variance = features.get("gradient_variance").copied().unwrap_or(1.0);
329            if gradient_variance < 0.1 {
330                DataPatternType::Monotonic
331            } else {
332                DataPatternType::PiecewiseContinuous
333            }
334        }
335    }
336
337    /// Classify smoothness profile
338    fn classify_smoothness_profile(&self, features: &HashMap<String, f64>) -> SmoothnessProfile {
339        let smoothness = features.get("smoothness").copied().unwrap_or(0.5);
340        let gradient_variance = features.get("gradient_variance").copied().unwrap_or(1.0);
341        let max_gradient = features.get("max_gradient").copied().unwrap_or(1.0);
342
343        if smoothness >= 0.95 && gradient_variance < 0.01 {
344            SmoothnessProfile::VerySmooth
345        } else if smoothness >= 0.8 && gradient_variance < 0.1 {
346            SmoothnessProfile::Smooth
347        } else if smoothness >= 0.6 && max_gradient < 10.0 {
348            SmoothnessProfile::ModeratelySmooth
349        } else if smoothness >= 0.3 {
350            SmoothnessProfile::Continuous
351        } else {
352            SmoothnessProfile::Discontinuous
353        }
354    }
355
356    /// Recommend interpolation methods based on pattern
357    fn recommend_methods(
358        &self,
359        pattern_signature: &PatternSignature,
360        features: &HashMap<String, f64>,
361    ) -> InterpolateResult<Vec<InterpolationMethodType>> {
362        let mut methods = Vec::new();
363        let data_size = features.get("data_size").copied().unwrap_or(1000.0) as usize;
364        let dimensionality = features.get("dimensionality").copied().unwrap_or(1.0) as usize;
365
366        match &pattern_signature.pattern_type {
367            DataPatternType::Smooth => {
368                methods.push(InterpolationMethodType::CubicSpline);
369                methods.push(InterpolationMethodType::BSpline);
370                if data_size < 5000 {
371                    methods.push(InterpolationMethodType::Polynomial);
372                }
373            }
374            DataPatternType::Noisy => {
375                methods.push(InterpolationMethodType::BSpline);
376                methods.push(InterpolationMethodType::Linear);
377                if dimensionality <= 3 {
378                    methods.push(InterpolationMethodType::Kriging);
379                }
380            }
381            DataPatternType::Oscillatory => {
382                methods.push(InterpolationMethodType::AkimaSpline);
383                methods.push(InterpolationMethodType::PchipInterpolation);
384                methods.push(InterpolationMethodType::BSpline);
385            }
386            DataPatternType::Sparse => {
387                methods.push(InterpolationMethodType::RadialBasisFunction);
388                methods.push(InterpolationMethodType::NaturalNeighbor);
389                if dimensionality <= 3 {
390                    methods.push(InterpolationMethodType::ThinPlateSpline);
391                }
392            }
393            DataPatternType::Irregular => {
394                methods.push(InterpolationMethodType::RadialBasisFunction);
395                methods.push(InterpolationMethodType::ShepardsMethod);
396                methods.push(InterpolationMethodType::NaturalNeighbor);
397            }
398            DataPatternType::Monotonic => {
399                methods.push(InterpolationMethodType::PchipInterpolation);
400                methods.push(InterpolationMethodType::AkimaSpline);
401                methods.push(InterpolationMethodType::CubicSpline);
402            }
403            DataPatternType::Structured => {
404                methods.push(InterpolationMethodType::BSpline);
405                methods.push(InterpolationMethodType::CubicSpline);
406                if data_size > 1000 {
407                    methods.push(InterpolationMethodType::Linear);
408                }
409            }
410            DataPatternType::PiecewiseContinuous => {
411                methods.push(InterpolationMethodType::Linear);
412                methods.push(InterpolationMethodType::PchipInterpolation);
413                methods.push(InterpolationMethodType::BSpline);
414            }
415        }
416
417        // Add quantum-inspired method for complex patterns
418        let complexity = features.get("complexity_score").copied().unwrap_or(0.5);
419        if complexity > 0.8 && data_size < 10000 {
420            methods.push(InterpolationMethodType::QuantumInspired);
421        }
422
423        // Ensure we have at least some methods
424        if methods.is_empty() {
425            methods.push(InterpolationMethodType::Linear);
426            methods.push(InterpolationMethodType::CubicSpline);
427        }
428
429        // Limit to top 5 methods
430        methods.truncate(5);
431
432        Ok(methods)
433    }
434
435    /// Predict performance for recommended methods
436    fn predict_performance(
437        &self,
438        methods: &[InterpolationMethodType],
439        data_profile: &DataProfile<F>,
440        features: &HashMap<String, f64>,
441    ) -> InterpolateResult<HashMap<InterpolationMethodType, PerformanceCharacteristics>> {
442        let mut predictions = HashMap::new();
443
444        for &method in methods {
445            let characteristics =
446                self.predict_method_performance(method, data_profile, features)?;
447            predictions.insert(method, characteristics);
448        }
449
450        Ok(predictions)
451    }
452
453    /// Predict performance characteristics for a specific method
454    fn predict_method_performance(
455        &self,
456        method: InterpolationMethodType,
457        data_profile: &DataProfile<F>,
458        features: &HashMap<String, f64>,
459    ) -> InterpolateResult<PerformanceCharacteristics> {
460        let data_size = data_profile.size;
461        let complexity = features.get("complexity_score").copied().unwrap_or(0.5);
462        let noise_level = features.get("noise_level").copied().unwrap_or(0.1);
463
464        let (base_time, base_memory, base_accuracy, base_robustness) = match method {
465            InterpolationMethodType::Linear => (1.0, 1.0, 0.7, 0.9),
466            InterpolationMethodType::CubicSpline => (2.0, 1.5, 0.9, 0.7),
467            InterpolationMethodType::BSpline => (3.0, 2.0, 0.92, 0.8),
468            InterpolationMethodType::RadialBasisFunction => (10.0, 5.0, 0.95, 0.6),
469            InterpolationMethodType::Kriging => (15.0, 8.0, 0.98, 0.9),
470            InterpolationMethodType::Polynomial => (5.0, 3.0, 0.85, 0.5),
471            InterpolationMethodType::PchipInterpolation => (2.5, 1.8, 0.88, 0.85),
472            InterpolationMethodType::AkimaSpline => (2.8, 2.2, 0.87, 0.82),
473            InterpolationMethodType::ThinPlateSpline => (12.0, 6.0, 0.93, 0.75),
474            InterpolationMethodType::NaturalNeighbor => (8.0, 4.0, 0.86, 0.8),
475            InterpolationMethodType::ShepardsMethod => (6.0, 3.0, 0.75, 0.7),
476            InterpolationMethodType::QuantumInspired => (20.0, 10.0, 0.99, 0.95),
477        };
478
479        // Adjust for data size
480        let size_factor = (data_size as f64).log10() / 3.0; // Normalize to log10(1000)
481        let time_multiplier = base_time * (1.0 + size_factor * complexity);
482        let memory_multiplier = base_memory * (1.0 + size_factor * 0.5);
483
484        // Adjust accuracy for noise
485        let accuracy_penalty = noise_level * 0.3;
486        let expected_accuracy = (base_accuracy - accuracy_penalty).max(0.1);
487
488        // Adjust robustness
489        let robustness_bonus = if noise_level > 0.1 { 0.1 } else { 0.0 };
490        let robustness_score = (base_robustness + robustness_bonus).min(1.0);
491
492        Ok(PerformanceCharacteristics {
493            throughput: 1.0 / time_multiplier.max(0.1), // Convert time multiplier to throughput
494            memory_efficiency: 1.0 / memory_multiplier.max(0.1), // Convert memory multiplier to efficiency
495            accuracy_score: expected_accuracy,
496            stability: robustness_score,
497            scalability: 1.0, // Default scalability value
498        })
499    }
500
501    /// Calculate pattern identification confidence
502    fn calculate_pattern_confidence(
503        &self,
504        _pattern_signature: &PatternSignature,
505        features: &HashMap<String, f64>,
506    ) -> f64 {
507        // Simple confidence calculation based on feature clarity
508        let smoothness = features.get("smoothness").copied().unwrap_or(0.5);
509        let noise_level = features.get("noise_level").copied().unwrap_or(0.1);
510        let regularity = features.get("regularity_score").copied().unwrap_or(0.5);
511
512        // Higher confidence for clear patterns
513        let clarity_score = (smoothness + regularity) / 2.0;
514        let noise_penalty = noise_level * 0.5;
515
516        ((clarity_score - noise_penalty) * self.recognition_model.model_accuracy)
517            .max(0.1)
518            .min(1.0)
519    }
520
521    /// Assess data quality
522    fn assess_data_quality(&self, data_profile: &DataProfile<F>) -> F {
523        let noise_factor = F::one() - data_profile.noise_level.min(F::one());
524        let sparsity_factor = F::one() - data_profile.sparsity.min(F::one());
525        let size_factor = if data_profile.size > 100 {
526            F::one()
527        } else {
528            F::from(data_profile.size as f64 / 100.0).unwrap()
529        };
530
531        (noise_factor + sparsity_factor + size_factor) / F::from(3.0).unwrap()
532    }
533
534    /// Calculate complexity score for data
535    fn calculate_complexity_score(&self, data_profile: &DataProfile<F>) -> f64 {
536        let gradient_complexity = data_profile.gradient_stats.variance.to_f64().unwrap_or(0.0);
537        let frequency_complexity = data_profile
538            .frequency_content
539            .frequency_spread
540            .to_f64()
541            .unwrap_or(0.0);
542        let dimensional_complexity = (data_profile.dimensionality as f64).log10();
543
544        (gradient_complexity + frequency_complexity + dimensional_complexity) / 3.0
545    }
546
547    /// Calculate regularity score
548    fn calculate_regularity_score(&self, data_profile: &DataProfile<F>) -> f64 {
549        let smoothness = data_profile.smoothness.to_f64().unwrap_or(0.5);
550        let low_freq_dominance = data_profile
551            .frequency_content
552            .low_freq_ratio
553            .to_f64()
554            .unwrap_or(0.5);
555        let gradient_consistency =
556            1.0 / (1.0 + data_profile.gradient_stats.variance.to_f64().unwrap_or(1.0));
557
558        (smoothness + low_freq_dominance + gradient_consistency) / 3.0
559    }
560
561    /// Calculate interpolation difficulty
562    fn calculate_interpolation_difficulty(&self, data_profile: &DataProfile<F>) -> f64 {
563        let noise_difficulty = data_profile.noise_level.to_f64().unwrap_or(0.1);
564        let sparsity_difficulty = data_profile.sparsity.to_f64().unwrap_or(0.0);
565        let irregularity_difficulty = 1.0 - data_profile.smoothness.to_f64().unwrap_or(0.5);
566        let size_difficulty = if data_profile.size > 100000 { 0.3 } else { 0.0 };
567
568        (noise_difficulty + sparsity_difficulty + irregularity_difficulty + size_difficulty) / 4.0
569    }
570
571    /// Get current analysis state
572    pub fn get_analysis_state(&self) -> &AnalysisState<F> {
573        &self.analysis_state
574    }
575
576    /// Get pattern database statistics
577    pub fn get_pattern_statistics(&self) -> HashMap<String, usize> {
578        let mut stats = HashMap::new();
579
580        stats.insert("total_patterns".to_string(), self.pattern_db.len());
581
582        // Count patterns by type
583        let mut type_counts = HashMap::new();
584        for signature in self.pattern_db.keys() {
585            let pattern_name = format!("{:?}", signature.pattern_type);
586            *type_counts.entry(pattern_name).or_insert(0) += 1;
587        }
588
589        for (pattern_type, count) in type_counts {
590            stats.insert(pattern_type, count);
591        }
592
593        stats
594    }
595
596    /// Add pattern to database
597    pub fn add_pattern(&mut self, signature: PatternSignature, data: PatternData<F>) {
598        self.pattern_db.insert(signature, data);
599    }
600
601    /// Update recognition model
602    pub fn update_recognition_model(
603        &mut self,
604        feedback: &[(PatternSignature, bool)],
605    ) -> InterpolateResult<()> {
606        if feedback.len() >= 10 {
607            let success_rate = feedback.iter().filter(|(_, success)| *success).count() as f64
608                / feedback.len() as f64;
609            self.recognition_model.model_accuracy = success_rate * 0.9 + 0.1; // Add baseline confidence
610        }
611        Ok(())
612    }
613}
614
615impl<F: Float> AnalysisState<F> {
616    /// Create a new analysis state
617    pub fn new() -> InterpolateResult<Self> {
618        Ok(Self {
619            current_data: None,
620            progress: 0.0,
621            intermediate_results: HashMap::new(),
622            current_stage: AnalysisStage::DataLoading,
623        })
624    }
625
626    /// Get current analysis progress (0-1)
627    pub fn get_progress(&self) -> f64 {
628        self.progress
629    }
630
631    /// Get current analysis stage
632    pub fn get_current_stage(&self) -> &AnalysisStage {
633        &self.current_stage
634    }
635
636    /// Get intermediate results
637    pub fn get_intermediate_results(&self) -> &HashMap<String, f64> {
638        &self.intermediate_results
639    }
640}
641
642impl<F: Float> PatternRecognitionModel<F> {
643    /// Create a new pattern recognition model
644    pub fn new() -> InterpolateResult<Self> {
645        let mut model = Self {
646            feature_extractors: Vec::new(),
647            classification_weights: HashMap::new(),
648            model_accuracy: 0.8, // Initial confidence
649        };
650
651        // Initialize with default feature extractors
652        model.initialize_default_extractors();
653
654        Ok(model)
655    }
656
657    /// Initialize with default feature extractors
658    fn initialize_default_extractors(&mut self) {
659        // Statistical features
660        self.feature_extractors.push(FeatureExtractor {
661            name: "mean".to_string(),
662            extractor: |data| {
663                data.iter().map(|x| x.to_f64().unwrap_or(0.0)).sum::<f64>() / data.len() as f64
664            },
665            importance: 0.6,
666        });
667
668        self.feature_extractors.push(FeatureExtractor {
669            name: "variance".to_string(),
670            extractor: |data| {
671                let mean =
672                    data.iter().map(|x| x.to_f64().unwrap_or(0.0)).sum::<f64>() / data.len() as f64;
673                data.iter()
674                    .map(|x| {
675                        let diff = x.to_f64().unwrap_or(0.0) - mean;
676                        diff * diff
677                    })
678                    .sum::<f64>()
679                    / data.len() as f64
680            },
681            importance: 0.8,
682        });
683
684        // Add classification weights
685        self.classification_weights
686            .insert("smoothness_weight".to_string(), 0.4);
687        self.classification_weights
688            .insert("noise_weight".to_string(), 0.3);
689        self.classification_weights
690            .insert("complexity_weight".to_string(), 0.3);
691    }
692
693    /// Get model accuracy
694    pub fn get_model_accuracy(&self) -> f64 {
695        self.model_accuracy
696    }
697
698    /// Update model accuracy
699    pub fn update_accuracy(&mut self, accuracy: f64) {
700        self.model_accuracy = accuracy.max(0.0).min(1.0);
701    }
702}
703
704#[cfg(test)]
705mod tests {
706    use super::*;
707
708    #[test]
709    fn test_pattern_analyzer_creation() {
710        let analyzer: DataPatternAnalyzer<f64> = DataPatternAnalyzer::new().unwrap();
711        assert_eq!(analyzer.pattern_db.len(), 0);
712        assert_eq!(analyzer.analysis_state.progress, 0.0);
713    }
714
715    #[test]
716    fn test_smoothness_profile_classification() {
717        let analyzer: DataPatternAnalyzer<f64> = DataPatternAnalyzer::new().unwrap();
718        let mut features = HashMap::new();
719
720        features.insert("smoothness".to_string(), 0.95);
721        features.insert("gradient_variance".to_string(), 0.005);
722        let profile = analyzer.classify_smoothness_profile(&features);
723        assert!(matches!(profile, SmoothnessProfile::VerySmooth));
724
725        features.insert("smoothness".to_string(), 0.2);
726        let profile = analyzer.classify_smoothness_profile(&features);
727        assert!(matches!(profile, SmoothnessProfile::Discontinuous));
728    }
729
730    #[test]
731    fn test_pattern_type_classification() {
732        let analyzer: DataPatternAnalyzer<f64> = DataPatternAnalyzer::new().unwrap();
733        let mut features = HashMap::new();
734
735        // Test noisy pattern
736        features.insert("noise_level".to_string(), 0.3);
737        features.insert("smoothness".to_string(), 0.5);
738        features.insert("sparsity".to_string(), 0.1);
739        let pattern = analyzer.classify_pattern_type(&features);
740        assert!(matches!(pattern, DataPatternType::Noisy));
741
742        // Test smooth pattern
743        features.insert("noise_level".to_string(), 0.05);
744        features.insert("smoothness".to_string(), 0.9);
745        features.insert("regularity_score".to_string(), 0.8);
746        let pattern = analyzer.classify_pattern_type(&features);
747        assert!(matches!(pattern, DataPatternType::Smooth));
748    }
749}