1use crate::error::StatsError;
7use num_cpus;
8use std::collections::HashMap;
9use std::fmt;
10
11#[derive(Debug, Clone)]
13pub struct EnhancedStatsError {
14 pub error: StatsError,
16 pub context: ErrorContext,
18 pub recovery_suggestions: Vec<RecoverySuggestion>,
20 pub documentation_links: Vec<String>,
22 pub example_snippets: Vec<CodeSnippet>,
24 pub severity: ErrorSeverity,
26 pub performance_impact: PerformanceImpact,
28}
29
30#[derive(Debug, Clone)]
32pub struct ErrorContext {
33 pub function_name: String,
35 pub module_path: String,
37 pub data_characteristics: DataCharacteristics,
39 pub system_info: SystemInfo,
41 pub computation_state: ComputationState,
43}
44
45#[derive(Debug, Clone)]
47pub struct DataCharacteristics {
48 pub size_info: Option<SizeInfo>,
50 pub type_info: String,
52 pub range_info: Option<RangeInfo>,
54 pub missingdata_info: Option<MissingDataInfo>,
56 pub distribution_info: Option<DistributionInfo>,
58}
59
60#[derive(Debug, Clone)]
62pub struct SizeInfo {
63 pub n_elements: usize,
65 pub shape: Vec<usize>,
67 pub memory_usage_mb: f64,
69}
70
71#[derive(Debug, Clone)]
73pub struct RangeInfo {
74 pub min: f64,
76 pub max: f64,
78 pub has_infinite: bool,
80 pub has_nan: bool,
82 pub has_zero: bool,
84}
85
86#[derive(Debug, Clone)]
88pub struct MissingDataInfo {
89 pub count: usize,
91 pub percentage: f64,
93 pub pattern: MissingPattern,
95}
96
97#[derive(Debug, Clone, PartialEq)]
99pub enum MissingPattern {
100 MCAR,
102 MAR,
104 MNAR,
106 Unknown,
108}
109
110#[derive(Debug, Clone)]
112pub struct DistributionInfo {
113 pub mean: Option<f64>,
115 pub variance: Option<f64>,
117 pub skewness: Option<f64>,
119 pub kurtosis: Option<f64>,
121 pub suspected_family: Option<String>,
123}
124
125#[derive(Debug, Clone)]
127pub struct SystemInfo {
128 pub available_memory_mb: Option<f64>,
130 pub cpu_cores: Option<usize>,
132 pub simd_capabilities: Vec<String>,
134 pub parallel_available: bool,
136}
137
138#[derive(Debug, Clone)]
140pub struct ComputationState {
141 pub algorithm: String,
143 pub iteration: Option<usize>,
145 pub convergence_status: Option<ConvergenceStatus>,
147 pub current_tolerance: Option<f64>,
149 pub intermediate_results: HashMap<String, f64>,
151}
152
153#[derive(Debug, Clone, PartialEq)]
155pub enum ConvergenceStatus {
156 NotStarted,
158 InProgress,
160 Converged,
162 FailedToConverge,
164 Diverged,
166}
167
168#[derive(Debug, Clone)]
170pub struct RecoverySuggestion {
171 pub suggestion_type: SuggestionType,
173 pub description: String,
175 pub action: RecoveryAction,
177 pub expected_outcome: String,
179 pub confidence: f64,
181 pub prerequisites: Vec<String>,
183}
184
185#[derive(Debug, Clone, PartialEq)]
187pub enum SuggestionType {
188 ParameterAdjustment,
190 AlgorithmChange,
192 DataPreprocessing,
194 ResourceIncrease,
196 Approximation,
198 InputValidation,
200 MemoryOptimization,
202 NumericalStability,
204}
205
206#[derive(Debug, Clone)]
208pub enum RecoveryAction {
209 AdjustParameter {
211 parameter_name: String,
212 current_value: String,
213 suggested_value: String,
214 explanation: String,
215 },
216 ChangeAlgorithm {
218 current_algorithm: String,
219 suggested_algorithm: String,
220 reasons: Vec<String>,
221 },
222 PreprocessData {
224 preprocessing_steps: Vec<PreprocessingStep>,
225 },
226 ScaleComputation {
228 current_approach: String,
229 suggested_approach: String,
230 expected_improvement: String,
231 },
232 ValidateInputs {
234 validation_checks: Vec<ValidationCheck>,
235 },
236 SimplePreprocessData,
238 SimpleValidateInputs,
240 AdjustTolerance { new_tolerance: f64 },
242 IncreaseIterations { factor: f64 },
244 SwitchAlgorithm { new_algorithm: String },
246 EnableParallelProcessing { num_threads: usize },
248 UseChunkedProcessing { chunksize: usize },
250 ApplyRegularization { regularization_strength: f64 },
252 ReducePrecision { new_precision: String },
254 UseApproximation { approximation_method: String },
256}
257
258#[derive(Debug, Clone)]
260pub struct PreprocessingStep {
261 pub name: String,
263 pub description: String,
265 pub code_example: String,
267 pub expected_impact: String,
269}
270
271#[derive(Debug, Clone)]
273pub struct ValidationCheck {
274 pub name: String,
276 pub condition: String,
278 pub fix_suggestion: String,
280}
281
282#[derive(Debug, Clone)]
284pub struct CodeSnippet {
285 pub title: String,
287 pub code: String,
289 pub language: String,
291 pub description: String,
293}
294
295#[derive(Debug, Clone, PartialEq, PartialOrd)]
297pub enum ErrorSeverity {
298 Low,
300 Medium,
302 High,
304 Critical,
306}
307
308#[derive(Debug, Clone)]
310pub struct PerformanceImpact {
311 pub memory_impact: ImpactLevel,
313 pub time_impact: ImpactLevel,
315 pub accuracy_impact: ImpactLevel,
317 pub scalability_impact: ImpactLevel,
319}
320
321#[derive(Debug, Clone, PartialEq)]
323pub enum ImpactLevel {
324 None,
326 Minor,
328 Moderate,
330 Major,
332 Severe,
334}
335
336pub struct ErrorRecoverySystem {
338 error_history: Vec<EnhancedStatsError>,
340 #[allow(dead_code)]
342 recovery_success_rates: HashMap<String, f64>,
343 config: ErrorRecoveryConfig,
345}
346
347#[derive(Debug, Clone)]
349pub struct ErrorRecoveryConfig {
350 pub max_historysize: usize,
352 pub detailed_diagnostics: bool,
354 pub auto_suggestions: bool,
356 pub performance_analysis: bool,
358 pub include_examples: bool,
360}
361
362impl Default for ErrorRecoveryConfig {
363 fn default() -> Self {
364 Self {
365 max_historysize: 100,
366 detailed_diagnostics: true,
367 auto_suggestions: true,
368 performance_analysis: true,
369 include_examples: true,
370 }
371 }
372}
373
374impl ErrorRecoverySystem {
375 pub fn new(config: ErrorRecoveryConfig) -> Self {
377 Self {
378 error_history: Vec::new(),
379 recovery_success_rates: HashMap::new(),
380 config,
381 }
382 }
383
384 pub fn enhance_error(
386 &mut self,
387 error: StatsError,
388 function_name: &str,
389 module_path: &str,
390 ) -> EnhancedStatsError {
391 let context = self.build_error_context(function_name, module_path, &error);
392 let recovery_suggestions = self.generate_recovery_suggestions(&error, &context);
393 let documentation_links = self.generate_documentation_links(&error);
394 let example_snippets = if self.config.include_examples {
395 self.generate_example_snippets(&error, &recovery_suggestions)
396 } else {
397 Vec::new()
398 };
399 let severity = self.assess_error_severity(&error, &context);
400 let performance_impact = if self.config.performance_analysis {
401 self.assess_performance_impact(&error, &context)
402 } else {
403 PerformanceImpact {
404 memory_impact: ImpactLevel::None,
405 time_impact: ImpactLevel::None,
406 accuracy_impact: ImpactLevel::None,
407 scalability_impact: ImpactLevel::None,
408 }
409 };
410
411 let enhanced_error = EnhancedStatsError {
412 error,
413 context,
414 recovery_suggestions,
415 documentation_links,
416 example_snippets,
417 severity,
418 performance_impact,
419 };
420
421 self.error_history.push(enhanced_error.clone());
423 if self.error_history.len() > self.config.max_historysize {
424 self.error_history.drain(0..1);
425 }
426
427 enhanced_error
428 }
429
430 fn build_error_context(
432 &self,
433 function_name: &str,
434 module_path: &str,
435 error: &StatsError,
436 ) -> ErrorContext {
437 let data_characteristics = self.inferdata_characteristics(error);
438 let system_info = self.gather_system_info();
439 let computation_state = self.infer_computation_state(error, function_name);
440
441 ErrorContext {
442 function_name: function_name.to_string(),
443 module_path: module_path.to_string(),
444 data_characteristics,
445 system_info,
446 computation_state,
447 }
448 }
449
450 fn inferdata_characteristics(&self, error: &StatsError) -> DataCharacteristics {
452 DataCharacteristics {
454 size_info: None,
455 type_info: "unknown".to_string(),
456 range_info: None,
457 missingdata_info: None,
458 distribution_info: None,
459 }
460 }
461
462 fn gather_system_info(&self) -> SystemInfo {
464 SystemInfo {
465 available_memory_mb: self.get_available_memory(),
466 cpu_cores: Some(num_cpus::get()),
467 simd_capabilities: self.detect_simd_capabilities(),
468 parallel_available: true,
469 }
470 }
471
472 fn get_available_memory(&self) -> Option<f64> {
474 None
476 }
477
478 fn detect_simd_capabilities(&self) -> Vec<String> {
480 let mut capabilities = Vec::new();
481
482 #[cfg(target_arch = "x86_64")]
483 {
484 if std::arch::is_x86_feature_detected!("sse") {
485 capabilities.push("SSE".to_string());
486 }
487 if std::arch::is_x86_feature_detected!("sse2") {
488 capabilities.push("SSE2".to_string());
489 }
490 if std::arch::is_x86_feature_detected!("avx") {
491 capabilities.push("AVX".to_string());
492 }
493 if std::arch::is_x86_feature_detected!("avx2") {
494 capabilities.push("AVX2".to_string());
495 }
496 }
497
498 capabilities
499 }
500
501 fn infer_computation_state(&self, error: &StatsError, functionname: &str) -> ComputationState {
503 ComputationState {
504 algorithm: functionname.to_string(),
505 iteration: None,
506 convergence_status: None,
507 current_tolerance: None,
508 intermediate_results: HashMap::new(),
509 }
510 }
511
512 fn generate_recovery_suggestions(
514 &self,
515 error: &StatsError,
516 context: &ErrorContext,
517 ) -> Vec<RecoverySuggestion> {
518 let mut suggestions = Vec::new();
519
520 match error {
521 StatsError::InvalidArgument(msg) => {
522 suggestions.extend(self.generate_invalid_argument_suggestions(msg, context));
523 }
524 StatsError::DimensionMismatch(msg) => {
525 suggestions.extend(self.generate_dimension_mismatch_suggestions(msg, context));
526 }
527 StatsError::ComputationError(msg) => {
528 suggestions.extend(self.generate_computation_error_suggestions(msg, context));
529 }
530 StatsError::ConvergenceError(msg) => {
531 suggestions.extend(self.generate_convergence_error_suggestions(msg, context));
532 }
533 _ => {
534 suggestions.push(RecoverySuggestion {
535 suggestion_type: SuggestionType::InputValidation,
536 description: "Check input data and parameters".to_string(),
537 action: RecoveryAction::ValidateInputs {
538 validation_checks: vec![ValidationCheck {
539 name: "Data finite check".to_string(),
540 condition: "All values are finite (not NaN or infinite)".to_string(),
541 fix_suggestion: "Remove or replace NaN/infinite values".to_string(),
542 }],
543 },
544 expected_outcome: "Eliminate invalid input data".to_string(),
545 confidence: 0.7,
546 prerequisites: vec![],
547 });
548 }
549 }
550
551 suggestions
552 }
553
554 fn generate_invalid_argument_suggestions(
556 &self,
557 msg: &str,
558 _context: &ErrorContext,
559 ) -> Vec<RecoverySuggestion> {
560 vec![RecoverySuggestion {
561 suggestion_type: SuggestionType::InputValidation,
562 description: "Validate input parameters before calling the function".to_string(),
563 action: RecoveryAction::ValidateInputs {
564 validation_checks: vec![ValidationCheck {
565 name: "Parameter bounds check".to_string(),
566 condition: "Parameters are within valid ranges".to_string(),
567 fix_suggestion: "Adjust parameters to valid ranges".to_string(),
568 }],
569 },
570 expected_outcome: "Function executes successfully with valid inputs".to_string(),
571 confidence: 0.9,
572 prerequisites: vec!["Input data available".to_string()],
573 }]
574 }
575
576 fn generate_dimension_mismatch_suggestions(
578 &self,
579 msg: &str,
580 _context: &ErrorContext,
581 ) -> Vec<RecoverySuggestion> {
582 vec![RecoverySuggestion {
583 suggestion_type: SuggestionType::DataPreprocessing,
584 description: "Reshape or transpose arrays to match expected dimensions".to_string(),
585 action: RecoveryAction::PreprocessData {
586 preprocessing_steps: vec![PreprocessingStep {
587 name: "Array reshape".to_string(),
588 description: "Reshape arrays to compatible dimensions".to_string(),
589 code_example: "array.intoshape((new_rows, new_cols))".to_string(),
590 expected_impact: "Arrays will have compatible dimensions".to_string(),
591 }],
592 },
593 expected_outcome: "Arrays have compatible dimensions for the operation".to_string(),
594 confidence: 0.85,
595 prerequisites: vec!["Data can be reshaped without loss".to_string()],
596 }]
597 }
598
599 fn generate_computation_error_suggestions(
601 &self,
602 msg: &str,
603 context: &ErrorContext,
604 ) -> Vec<RecoverySuggestion> {
605 let mut suggestions = Vec::new();
606
607 if msg.contains("singular") || msg.contains("invert") {
608 suggestions.push(RecoverySuggestion {
609 suggestion_type: SuggestionType::NumericalStability,
610 description: "Add regularization to improve numerical stability".to_string(),
611 action: RecoveryAction::AdjustParameter {
612 parameter_name: "regularization".to_string(),
613 current_value: "0.0".to_string(),
614 suggested_value: "1e-6".to_string(),
615 explanation: "Small regularization prevents singular matrices".to_string(),
616 },
617 expected_outcome: "Matrix inversion becomes numerically stable".to_string(),
618 confidence: 0.8,
619 prerequisites: vec!["Matrix inversion required".to_string()],
620 });
621 }
622
623 if msg.contains("memory") || msg.contains("allocation") {
624 suggestions.push(RecoverySuggestion {
625 suggestion_type: SuggestionType::MemoryOptimization,
626 description: "Use chunked processing to reduce memory usage".to_string(),
627 action: RecoveryAction::ScaleComputation {
628 current_approach: "Process entire dataset at once".to_string(),
629 suggested_approach: "Process data in smaller chunks".to_string(),
630 expected_improvement: "Reduced memory usage".to_string(),
631 },
632 expected_outcome: "Computation succeeds with available memory".to_string(),
633 confidence: 0.75,
634 prerequisites: vec!["Data can be processed in chunks".to_string()],
635 });
636 }
637
638 suggestions
639 }
640
641 fn generate_convergence_error_suggestions(
643 &self,
644 msg: &str,
645 _context: &ErrorContext,
646 ) -> Vec<RecoverySuggestion> {
647 vec![RecoverySuggestion {
648 suggestion_type: SuggestionType::ParameterAdjustment,
649 description: "Increase maximum iterations or relax tolerance".to_string(),
650 action: RecoveryAction::AdjustParameter {
651 parameter_name: "max_iterations".to_string(),
652 current_value: "unknown".to_string(),
653 suggested_value: "increased value".to_string(),
654 explanation: "More iterations allow algorithm to converge".to_string(),
655 },
656 expected_outcome: "Algorithm converges within the iteration limit".to_string(),
657 confidence: 0.7,
658 prerequisites: vec!["Algorithm is potentially convergent".to_string()],
659 }]
660 }
661
662 fn generate_documentation_links(&self, error: &StatsError) -> Vec<String> {
664 let mut links = Vec::new();
665
666 match error {
667 StatsError::InvalidArgument(_) => {
668 links.push(
669 "https://docs.rs/scirs2-stats/latest/scirs2_stats/index.html#input-validation"
670 .to_string(),
671 );
672 }
673 StatsError::DimensionMismatch(_) => {
674 links.push(
675 "https://docs.rs/scirs2-stats/latest/scirs2_stats/index.html#array-operations"
676 .to_string(),
677 );
678 }
679 StatsError::ComputationError(_) => {
680 links.push("https://docs.rs/scirs2-stats/latest/scirs2_stats/index.html#numerical-stability".to_string());
681 }
682 _ => {
683 links.push(
684 "https://docs.rs/scirs2-stats/latest/scirs2_stats/index.html".to_string(),
685 );
686 }
687 }
688
689 links
690 }
691
692 fn generate_example_snippets(
694 &self,
695 error: &StatsError,
696 suggestions: &[RecoverySuggestion],
697 ) -> Vec<CodeSnippet> {
698 let mut snippets = Vec::new();
699
700 if !suggestions.is_empty() {
701 match &suggestions[0].action {
702 RecoveryAction::AdjustParameter {
703 parameter_name,
704 suggested_value,
705 ..
706 } => {
707 snippets.push(CodeSnippet {
708 title: format!("Adjust {} parameter", parameter_name),
709 code: format!(
710 "// Set {} to {}\nlet {} = {};\n// Then retry the operation",
711 parameter_name, suggested_value, parameter_name, suggested_value
712 ),
713 language: "rust".to_string(),
714 description: "Parameter adjustment example".to_string(),
715 });
716 }
717 RecoveryAction::PreprocessData {
718 preprocessing_steps,
719 } => {
720 if !preprocessing_steps.is_empty() {
721 snippets.push(CodeSnippet {
722 title: "Data preprocessing".to_string(),
723 code: preprocessing_steps[0].code_example.clone(),
724 language: "rust".to_string(),
725 description: preprocessing_steps[0].description.clone(),
726 });
727 }
728 }
729 _ => {}
730 }
731 }
732
733 snippets
734 }
735
736 fn assess_error_severity(&self, error: &StatsError, context: &ErrorContext) -> ErrorSeverity {
738 match error {
739 StatsError::InvalidArgument(_) => ErrorSeverity::Medium,
740 StatsError::DimensionMismatch(_) => ErrorSeverity::Medium,
741 StatsError::ComputationError(_) => ErrorSeverity::High,
742 StatsError::ConvergenceError(_) => ErrorSeverity::Medium,
743 _ => ErrorSeverity::Low,
744 }
745 }
746
747 fn assess_performance_impact(
749 &self,
750 error: &StatsError,
751 context: &ErrorContext,
752 ) -> PerformanceImpact {
753 match error {
754 StatsError::ComputationError(msg) if msg.contains("memory") => PerformanceImpact {
755 memory_impact: ImpactLevel::Major,
756 time_impact: ImpactLevel::Moderate,
757 accuracy_impact: ImpactLevel::None,
758 scalability_impact: ImpactLevel::Major,
759 },
760 StatsError::ConvergenceError(_) => PerformanceImpact {
761 memory_impact: ImpactLevel::Minor,
762 time_impact: ImpactLevel::Major,
763 accuracy_impact: ImpactLevel::Moderate,
764 scalability_impact: ImpactLevel::Moderate,
765 },
766 _ => PerformanceImpact {
767 memory_impact: ImpactLevel::None,
768 time_impact: ImpactLevel::Minor,
769 accuracy_impact: ImpactLevel::Minor,
770 scalability_impact: ImpactLevel::None,
771 },
772 }
773 }
774
775 pub fn error_history(&self) -> &[EnhancedStatsError] {
777 &self.error_history
778 }
779
780 pub fn generate_error_report(&self, enhancederror: &EnhancedStatsError) -> String {
782 let mut report = String::new();
783
784 report.push_str("# Error Report\n\n");
785 report.push_str(&format!("**Error:** {}\n\n", enhancederror.error));
786 report.push_str(&format!("**Severity:** {:?}\n\n", enhancederror.severity));
787 report.push_str(&format!(
788 "**Function:** {}\n",
789 enhancederror.context.function_name
790 ));
791 report.push_str(&format!(
792 "**Module:** {}\n\n",
793 enhancederror.context.module_path
794 ));
795
796 report.push_str("## Recovery Suggestions\n\n");
797 for (i, suggestion) in enhancederror.recovery_suggestions.iter().enumerate() {
798 report.push_str(&format!(
799 "{}. **{}** (Confidence: {:.0}%)\n",
800 i + 1,
801 suggestion.description,
802 suggestion.confidence * 100.0
803 ));
804 report.push_str(&format!(" - {}\n", suggestion.expected_outcome));
805 }
806
807 if !enhancederror.example_snippets.is_empty() {
808 report.push_str("\n## Example Code\n\n");
809 for snippet in &enhancederror.example_snippets {
810 report.push_str(&format!("### {}\n\n", snippet.title));
811 report.push_str(&format!(
812 "```{}\n{}\n```\n\n",
813 snippet.language, snippet.code
814 ));
815 }
816 }
817
818 if !enhancederror.documentation_links.is_empty() {
819 report.push_str("## Documentation\n\n");
820 for link in &enhancederror.documentation_links {
821 report.push_str(&format!("- [Documentation]({})\n", link));
822 }
823 }
824
825 report
826 }
827}
828
829impl fmt::Display for EnhancedStatsError {
830 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831 write!(f, "{}", self.error)?;
832
833 if !self.recovery_suggestions.is_empty() {
834 write!(f, "\n\nSuggestions:")?;
835 for suggestion in &self.recovery_suggestions {
836 write!(f, "\n - {}", suggestion.description)?;
837 }
838 }
839
840 Ok(())
841 }
842}
843
844static mut GLOBAL_ERROR_RECOVERY: Option<ErrorRecoverySystem> = None;
846static mut ERROR_RECOVERY_INITIALIZED: bool = false;
847
848#[allow(dead_code)]
850pub fn initialize_error_recovery(config: Option<ErrorRecoveryConfig>) {
851 unsafe {
852 if !ERROR_RECOVERY_INITIALIZED {
853 GLOBAL_ERROR_RECOVERY = Some(ErrorRecoverySystem::new(config.unwrap_or_default()));
854 ERROR_RECOVERY_INITIALIZED = true;
855 }
856 }
857}
858
859#[allow(dead_code)]
861pub fn enhance_error_with_recovery(
862 error: StatsError,
863 function_name: &str,
864 module_path: &str,
865) -> EnhancedStatsError {
866 unsafe {
867 if !ERROR_RECOVERY_INITIALIZED {
868 initialize_error_recovery(None);
869 }
870
871 if let Some(ref mut system) = GLOBAL_ERROR_RECOVERY {
872 system.enhance_error(error, function_name, module_path)
873 } else {
874 EnhancedStatsError {
876 error,
877 context: ErrorContext {
878 function_name: function_name.to_string(),
879 module_path: module_path.to_string(),
880 data_characteristics: DataCharacteristics {
881 size_info: None,
882 type_info: "unknown".to_string(),
883 range_info: None,
884 missingdata_info: None,
885 distribution_info: None,
886 },
887 system_info: SystemInfo {
888 available_memory_mb: None,
889 cpu_cores: Some(num_cpus::get()),
890 simd_capabilities: vec![],
891 parallel_available: true,
892 },
893 computation_state: ComputationState {
894 algorithm: function_name.to_string(),
895 iteration: None,
896 convergence_status: None,
897 current_tolerance: None,
898 intermediate_results: HashMap::new(),
899 },
900 },
901 recovery_suggestions: vec![],
902 documentation_links: vec![],
903 example_snippets: vec![],
904 severity: ErrorSeverity::Medium,
905 performance_impact: PerformanceImpact {
906 memory_impact: ImpactLevel::None,
907 time_impact: ImpactLevel::None,
908 accuracy_impact: ImpactLevel::None,
909 scalability_impact: ImpactLevel::None,
910 },
911 }
912 }
913 }
914}
915
916#[macro_export]
918macro_rules! enhanced_error {
919 ($error:expr) => {
920 enhance_error_with_recovery($error, function_name!(), module_path!())
921 };
922}