Skip to main content

scirs2_ndimage/
comprehensive_validation.rs

1//! # Enhanced Validation Framework for Advanced Mode
2//!
3//! This module provides comprehensive validation and error handling
4//! capabilities for Advanced mode operations, ensuring robust
5//! and reliable performance in production environments.
6
7use scirs2_core::ndarray::{Array2, ArrayView2};
8use scirs2_core::numeric::{Float, FromPrimitive};
9use std::collections::HashMap;
10use std::fmt::Debug;
11use std::time::{Duration, Instant};
12
13use crate::advanced_fusion_algorithms::{AdvancedConfig, AdvancedState};
14use crate::error::{NdimageError, NdimageResult};
15
16/// Comprehensive validation framework for Advanced operations
17#[derive(Debug, Clone)]
18pub struct ComprehensiveValidator {
19    /// Validation configuration
20    config: ValidationConfig,
21    /// Performance benchmarks
22    benchmarks: HashMap<String, PerformanceBenchmark>,
23    /// Error tracking
24    errorhistory: Vec<ValidationError>,
25}
26
27/// Validation configuration parameters
28#[derive(Debug, Clone)]
29pub struct ValidationConfig {
30    /// Enable strict numerical validation
31    pub strict_numerical: bool,
32    /// Maximum allowed processing time per pixel (nanoseconds)
33    pub max_time_per_pixel: u64,
34    /// Minimum output quality threshold
35    pub min_quality_threshold: f64,
36    /// Enable memory usage monitoring
37    pub monitor_memory: bool,
38    /// Enable quantum coherence validation
39    pub validate_quantum_coherence: bool,
40    /// Enable consciousness state validation
41    pub validate_consciousnessstate: bool,
42}
43
44impl Default for ValidationConfig {
45    fn default() -> Self {
46        Self {
47            strict_numerical: true,
48            max_time_per_pixel: 1000, // 1 microsecond per pixel
49            min_quality_threshold: 0.95,
50            monitor_memory: true,
51            validate_quantum_coherence: true,
52            validate_consciousnessstate: true,
53        }
54    }
55}
56
57/// Performance benchmark data
58#[derive(Debug, Clone)]
59pub struct PerformanceBenchmark {
60    /// Operation name
61    pub operation: String,
62    /// Average execution time
63    pub avg_time: Duration,
64    /// Memory usage in bytes
65    pub memory_usage: usize,
66    /// Quality score (0.0 to 1.0)
67    pub quality_score: f64,
68    /// Number of samples
69    pub sample_count: usize,
70}
71
72/// Validation error information
73#[derive(Debug, Clone)]
74pub struct ValidationError {
75    /// Error type
76    pub error_type: String,
77    /// Error message
78    pub message: String,
79    /// Timestamp
80    pub timestamp: Instant,
81    /// Associated operation
82    pub operation: String,
83}
84
85impl ComprehensiveValidator {
86    /// Create new validator with default configuration
87    pub fn new() -> Self {
88        Self::with_config(ValidationConfig::default())
89    }
90
91    /// Create new validator with custom configuration
92    pub fn with_config(config: ValidationConfig) -> Self {
93        Self {
94            config,
95            benchmarks: HashMap::new(),
96            errorhistory: Vec::new(),
97        }
98    }
99
100    /// Validate Advanced configuration
101    pub fn validate_config(&mut self, config: &AdvancedConfig) -> NdimageResult<()> {
102        // Validate consciousness depth
103        if config.consciousness_depth == 0 || config.consciousness_depth > 20 {
104            return Err(NdimageError::ConfigurationError(
105                "Consciousness depth must be between 1 and 20".to_string(),
106            ));
107        }
108
109        // Validate meta-learning rate
110        if config.meta_learning_rate <= 0.0 || config.meta_learning_rate > 1.0 {
111            return Err(NdimageError::ConfigurationError(
112                "Meta-learning rate must be between 0.0 and 1.0".to_string(),
113            ));
114        }
115
116        // Validate advanced-dimensions
117        if config.advanced_dimensions == 0 || config.advanced_dimensions > 64 {
118            return Err(NdimageError::ConfigurationError(
119                "Advanced-dimensions must be between 1 and 64".to_string(),
120            ));
121        }
122
123        // Validate temporal window
124        if config.temporal_window > 1000 {
125            return Err(NdimageError::ConfigurationError(
126                "Temporal window too large (max 1000)".to_string(),
127            ));
128        }
129
130        // Validate quantum coherence threshold
131        if config.quantum_coherence_threshold < 0.0 || config.quantum_coherence_threshold > 1.0 {
132            return Err(NdimageError::ConfigurationError(
133                "Quantum coherence threshold must be between 0.0 and 1.0".to_string(),
134            ));
135        }
136
137        Ok(())
138    }
139
140    /// Validate input image
141    pub fn validate_inputimage<T>(&mut self, image: ArrayView2<T>) -> NdimageResult<()>
142    where
143        T: Float + FromPrimitive + Copy + Debug,
144    {
145        let (height, width) = image.dim();
146
147        // Check minimum dimensions
148        if height < 2 || width < 2 {
149            return Err(NdimageError::DimensionError(
150                "Image must be at least 2x2 pixels".to_string(),
151            ));
152        }
153
154        // Check maximum dimensions for performance
155        if height > 10000 || width > 10000 {
156            return Err(NdimageError::DimensionError(
157                "Image too large for Advanced processing (max 10000x10000)".to_string(),
158            ));
159        }
160
161        if self.config.strict_numerical {
162            // Check for invalid values
163            for &pixel in image.iter() {
164                if !pixel.is_finite() {
165                    return Err(NdimageError::ComputationError(
166                        "Input image contains non-finite values".to_string(),
167                    ));
168                }
169            }
170        }
171
172        Ok(())
173    }
174
175    /// Validate processing output
176    pub fn validate_output<T>(
177        &mut self,
178        output: &Array2<T>,
179        state: &AdvancedState,
180        processing_time: Duration,
181    ) -> NdimageResult<ValidationReport>
182    where
183        T: Float + FromPrimitive + Copy + Debug,
184    {
185        let mut report = ValidationReport::new();
186        let (height, width) = output.dim();
187        let total_pixels = height * width;
188
189        // Performance validation
190        let time_per_pixel = processing_time.as_nanos() / total_pixels as u128;
191        if time_per_pixel > self.config.max_time_per_pixel as u128 {
192            report.warnings.push(format!(
193                "Processing _time per pixel ({} ns) exceeds threshold ({} ns)",
194                time_per_pixel, self.config.max_time_per_pixel
195            ));
196        }
197
198        // Numerical validation
199        if self.config.strict_numerical {
200            for &pixel in output.iter() {
201                if !pixel.is_finite() {
202                    return Err(NdimageError::ComputationError(
203                        "Output contains non-finite values".to_string(),
204                    ));
205                }
206            }
207        }
208
209        // Quality validation
210        let quality_score = self.compute_quality_score(output)?;
211        if quality_score < self.config.min_quality_threshold {
212            report.warnings.push(format!(
213                "Output quality ({:.3}) below threshold ({:.3})",
214                quality_score, self.config.min_quality_threshold
215            ));
216        }
217
218        // State validation
219        if self.config.validate_consciousnessstate {
220            self.validate_consciousnessstate(state, &mut report)?;
221        }
222
223        // Update benchmarks
224        self.update_benchmark("enhanced_processing", processing_time, 0, quality_score);
225
226        report.quality_score = quality_score;
227        report.processing_time = processing_time;
228        report.total_pixels = total_pixels;
229
230        Ok(report)
231    }
232
233    /// Compute quality score for output
234    fn compute_quality_score<T>(&self, output: &Array2<T>) -> NdimageResult<f64>
235    where
236        T: Float + FromPrimitive + Copy,
237    {
238        let mean = output
239            .iter()
240            .map(|&x| x.to_f64().unwrap_or(0.0))
241            .sum::<f64>()
242            / output.len() as f64;
243
244        let variance = output
245            .iter()
246            .map(|&x| {
247                let val = x.to_f64().unwrap_or(0.0);
248                (val - mean).powi(2)
249            })
250            .sum::<f64>()
251            / output.len() as f64;
252
253        let std_dev = variance.sqrt();
254
255        // Quality score based on distribution properties
256        let dynamic_range = if std_dev > 0.0 { std_dev.min(1.0) } else { 0.5 };
257        let mean_quality = if mean.is_finite() && mean >= 0.0 && mean <= 1.0 {
258            1.0
259        } else {
260            0.5
261        };
262
263        Ok((dynamic_range + mean_quality) / 2.0)
264    }
265
266    /// Validate consciousness state
267    fn validate_consciousnessstate(
268        &self,
269        state: &AdvancedState,
270        report: &mut ValidationReport,
271    ) -> NdimageResult<()> {
272        if state.processing_cycles == 0 {
273            report
274                .warnings
275                .push("No processing cycles recorded".to_string());
276        }
277
278        if state.processing_cycles > 1000 {
279            report.warnings.push(format!(
280                "Excessive processing cycles: {}",
281                state.processing_cycles
282            ));
283        }
284
285        Ok(())
286    }
287
288    /// Update performance benchmark
289    fn update_benchmark(&mut self, operation: &str, time: Duration, memory: usize, quality: f64) {
290        let benchmark =
291            self.benchmarks
292                .entry(operation.to_string())
293                .or_insert(PerformanceBenchmark {
294                    operation: operation.to_string(),
295                    avg_time: time,
296                    memory_usage: memory,
297                    quality_score: quality,
298                    sample_count: 0,
299                });
300
301        // Update running averages
302        let count = benchmark.sample_count as f64;
303        benchmark.avg_time = Duration::from_nanos(
304            ((benchmark.avg_time.as_nanos() as f64 * count + time.as_nanos() as f64)
305                / (count + 1.0)) as u64,
306        );
307        benchmark.memory_usage =
308            ((benchmark.memory_usage as f64 * count + memory as f64) / (count + 1.0)) as usize;
309        benchmark.quality_score = (benchmark.quality_score * count + quality) / (count + 1.0);
310        benchmark.sample_count += 1;
311    }
312
313    /// Get performance summary
314    pub fn get_performance_summary(&self) -> PerformanceSummary {
315        PerformanceSummary {
316            benchmarks: self.benchmarks.clone(),
317            total_operations: self.benchmarks.values().map(|b| b.sample_count).sum(),
318            error_count: self.errorhistory.len(),
319        }
320    }
321}
322
323/// Validation report
324#[derive(Debug, Clone)]
325pub struct ValidationReport {
326    /// Quality score (0.0 to 1.0)
327    pub quality_score: f64,
328    /// Processing time
329    pub processing_time: Duration,
330    /// Total pixels processed
331    pub total_pixels: usize,
332    /// Warnings encountered
333    pub warnings: Vec<String>,
334    /// Validation passed
335    pub passed: bool,
336}
337
338impl ValidationReport {
339    fn new() -> Self {
340        Self {
341            quality_score: 0.0,
342            processing_time: Duration::default(),
343            total_pixels: 0,
344            warnings: Vec::new(),
345            passed: true,
346        }
347    }
348
349    /// Check if validation passed
350    pub fn is_valid(&self) -> bool {
351        self.passed && self.warnings.is_empty()
352    }
353
354    /// Get performance metrics
355    pub fn get_pixels_per_second(&self) -> f64 {
356        if self.processing_time.as_secs_f64() > 0.0 {
357            self.total_pixels as f64 / self.processing_time.as_secs_f64()
358        } else {
359            0.0
360        }
361    }
362}
363
364/// Performance summary
365#[derive(Debug, Clone)]
366pub struct PerformanceSummary {
367    /// All benchmarks
368    pub benchmarks: HashMap<String, PerformanceBenchmark>,
369    /// Total operations performed
370    pub total_operations: usize,
371    /// Total errors encountered
372    pub error_count: usize,
373}
374
375impl PerformanceSummary {
376    /// Get average quality score across all operations
377    pub fn average_quality(&self) -> f64 {
378        if self.benchmarks.is_empty() {
379            return 0.0;
380        }
381
382        self.benchmarks
383            .values()
384            .map(|b| b.quality_score)
385            .sum::<f64>()
386            / self.benchmarks.len() as f64
387    }
388
389    /// Get total processing time
390    pub fn total_processing_time(&self) -> Duration {
391        self.benchmarks
392            .values()
393            .map(|b| b.avg_time)
394            .fold(Duration::default(), |acc, t| acc + t)
395    }
396}
397
398/// Comprehensive summary of validation and performance results
399///
400/// This is a type alias for [`PerformanceSummary`], providing a more descriptive
401/// name when used as the final output of a complete validation run.
402pub type ComprehensiveSummary = PerformanceSummary;
403
404/// Enhanced Advanced processing with validation
405#[allow(dead_code)]
406pub fn validated_advanced_processing<T>(
407    image: ArrayView2<T>,
408    config: &AdvancedConfig,
409    previousstate: Option<AdvancedState>,
410    validator: &mut ComprehensiveValidator,
411) -> NdimageResult<(Array2<T>, AdvancedState, ValidationReport)>
412where
413    T: Float + FromPrimitive + Copy + Send + Sync + Debug,
414{
415    // Pre-processing validation
416    validator.validate_config(config)?;
417    validator.validate_inputimage(image)?;
418
419    let start_time = Instant::now();
420
421    // Perform Advanced processing
422    let (output, state) =
423        crate::advanced_fusion_algorithms::fusion_processing(image, config, previousstate)?;
424
425    let processing_time = start_time.elapsed();
426
427    // Post-processing validation
428    let report = validator.validate_output(&output, &state, processing_time)?;
429
430    Ok((output, state, report))
431}
432
433#[cfg(test)]
434mod tests {
435    use super::*;
436    use scirs2_core::ndarray::Array2;
437
438    #[test]
439    fn test_validator_creation() {
440        let validator = ComprehensiveValidator::new();
441        assert!(validator.benchmarks.is_empty());
442        assert!(validator.errorhistory.is_empty());
443    }
444
445    #[test]
446    fn test_input_validation() {
447        let mut validator = ComprehensiveValidator::new();
448        let validimage = Array2::<f64>::ones((10, 10));
449        assert!(validator.validate_inputimage(validimage.view()).is_ok());
450
451        let smallimage = Array2::<f64>::ones((1, 1));
452        assert!(validator.validate_inputimage(smallimage.view()).is_err());
453    }
454
455    #[test]
456    fn test_config_validation() {
457        let mut validator = ComprehensiveValidator::new();
458        let mut config = crate::advanced_fusion_algorithms::AdvancedConfig::default();
459
460        // Valid configuration should pass
461        assert!(validator.validate_config(&config).is_ok());
462
463        // Invalid consciousness depth should fail
464        config.consciousness_depth = 0;
465        assert!(validator.validate_config(&config).is_err());
466    }
467
468    #[test]
469    fn test_quality_score_computation() {
470        let validator = ComprehensiveValidator::new();
471        let output = Array2::<f64>::ones((10, 10));
472        let quality = validator
473            .compute_quality_score(&output)
474            .expect("Operation failed");
475        assert!(quality > 0.0 && quality <= 1.0);
476    }
477}