Skip to main content

trustformers_debug/model_diagnostics/
auto_debug.rs

1//! Auto-debugging and automated recommendation system.
2//!
3//! This module provides intelligent debugging capabilities that automatically
4//! analyze model behavior, identify potential issues, and generate actionable
5//! recommendations for optimization and problem resolution.
6// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
7// are retained for the data model, serialization completeness, and future consumers that
8// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
9#![allow(dead_code)]
10
11use anyhow::Result;
12use std::collections::{HashMap, VecDeque};
13
14use super::types::{
15    ConvergenceStatus, LayerActivationStats, ModelPerformanceMetrics, TrainingDynamics,
16};
17
18/// Auto-debugging system for intelligent model analysis.
19#[derive(Debug)]
20pub struct AutoDebugger {
21    /// Debugging configuration
22    config: AutoDebugConfig,
23    /// Historical performance data for analysis
24    performance_history: VecDeque<ModelPerformanceMetrics>,
25    /// Layer statistics history
26    layer_history: HashMap<String, VecDeque<LayerActivationStats>>,
27    /// Training dynamics history
28    dynamics_history: VecDeque<TrainingDynamics>,
29    /// Known issue patterns and solutions
30    issue_patterns: IssuePatternDatabase,
31    /// Current debugging session state
32    session_state: DebuggingSession,
33}
34
35/// Configuration for auto-debugging system.
36#[derive(Debug, Clone)]
37pub struct AutoDebugConfig {
38    /// Maximum history size for analysis
39    pub max_history_size: usize,
40    /// Minimum samples required for pattern detection
41    pub min_samples_for_analysis: usize,
42    /// Confidence threshold for recommendations
43    pub recommendation_confidence_threshold: f64,
44    /// Enable advanced pattern recognition
45    pub enable_advanced_patterns: bool,
46    /// Enable hyperparameter suggestions
47    pub enable_hyperparameter_suggestions: bool,
48    /// Enable architectural recommendations
49    pub enable_architectural_recommendations: bool,
50}
51
52/// Current debugging session state.
53#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
54pub struct DebuggingSession {
55    /// Session start time
56    pub session_start: chrono::DateTime<chrono::Utc>,
57    /// Issues identified in current session
58    pub identified_issues: Vec<IdentifiedIssue>,
59    /// Recommendations generated
60    pub recommendations: Vec<DebuggingRecommendation>,
61    /// Session statistics
62    pub session_stats: SessionStatistics,
63}
64
65/// An identified issue with diagnostic information.
66#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
67pub struct IdentifiedIssue {
68    /// Issue category
69    pub category: IssueCategory,
70    /// Issue description
71    pub description: String,
72    /// Severity level
73    pub severity: IssueSeverity,
74    /// Confidence in identification
75    pub confidence: f64,
76    /// Evidence supporting the identification
77    pub evidence: Vec<String>,
78    /// Potential causes
79    pub potential_causes: Vec<String>,
80    /// When issue was identified
81    pub identified_at: chrono::DateTime<chrono::Utc>,
82}
83
84/// Categories of issues that can be identified.
85#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
86pub enum IssueCategory {
87    /// Learning rate related issues
88    LearningRate,
89    /// Gradient flow problems
90    GradientFlow,
91    /// Overfitting issues
92    Overfitting,
93    /// Underfitting issues
94    Underfitting,
95    /// Data quality problems
96    DataQuality,
97    /// Architecture inefficiencies
98    Architecture,
99    /// Memory management issues
100    Memory,
101    /// Convergence problems
102    Convergence,
103    /// Numerical stability issues
104    NumericalStability,
105}
106
107/// Severity levels for identified issues.
108#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
109pub enum IssueSeverity {
110    /// Minor issue with low impact
111    Minor,
112    /// Moderate issue affecting performance
113    Moderate,
114    /// Major issue requiring attention
115    Major,
116    /// Critical issue requiring immediate action
117    Critical,
118}
119
120/// Auto-generated debugging recommendation.
121#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
122pub struct DebuggingRecommendation {
123    /// Recommendation category
124    pub category: RecommendationCategory,
125    /// Recommendation title
126    pub title: String,
127    /// Detailed description
128    pub description: String,
129    /// Specific actions to take
130    pub actions: Vec<String>,
131    /// Expected impact
132    pub expected_impact: String,
133    /// Confidence in recommendation
134    pub confidence: f64,
135    /// Priority level
136    pub priority: AutoDebugRecommendationPriority,
137    /// Relevant hyperparameters to adjust
138    pub hyperparameter_suggestions: Vec<HyperparameterSuggestion>,
139}
140
141/// Categories of recommendations.
142#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
143pub enum RecommendationCategory {
144    /// Hyperparameter adjustments
145    HyperparameterTuning,
146    /// Architectural changes
147    ArchitecturalModification,
148    /// Data preprocessing recommendations
149    DataPreprocessing,
150    /// Training strategy changes
151    TrainingStrategy,
152    /// Debugging and monitoring
153    DebuggingAndMonitoring,
154    /// Resource optimization
155    ResourceOptimization,
156}
157
158/// Priority levels for recommendations.
159#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
160pub enum AutoDebugRecommendationPriority {
161    /// Low priority suggestion
162    Low,
163    /// Medium priority recommendation
164    Medium,
165    /// High priority action needed
166    High,
167    /// Urgent action required
168    Urgent,
169}
170
171/// Hyperparameter adjustment suggestion.
172#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
173pub struct HyperparameterSuggestion {
174    /// Parameter name
175    pub parameter_name: String,
176    /// Current value (if known)
177    pub current_value: Option<f64>,
178    /// Suggested value
179    pub suggested_value: f64,
180    /// Adjustment reasoning
181    pub reasoning: String,
182    /// Expected effect
183    pub expected_effect: String,
184}
185
186/// Database of known issue patterns and solutions.
187#[derive(Debug, Clone)]
188pub struct IssuePatternDatabase {
189    /// Learning rate patterns
190    pub learning_rate_patterns: Vec<IssuePattern>,
191    /// Gradient patterns
192    pub gradient_patterns: Vec<IssuePattern>,
193    /// Convergence patterns
194    pub convergence_patterns: Vec<IssuePattern>,
195    /// Layer behavior patterns
196    pub layer_patterns: Vec<IssuePattern>,
197}
198
199/// Pattern for identifying specific issues.
200#[derive(Debug, Clone)]
201pub struct IssuePattern {
202    /// Pattern name
203    pub name: String,
204    /// Pattern description
205    pub description: String,
206    /// Conditions that must be met
207    pub conditions: Vec<PatternCondition>,
208    /// Associated issue category
209    pub issue_category: IssueCategory,
210    /// Confidence weight for this pattern
211    pub confidence_weight: f64,
212    /// Recommended solutions
213    pub solutions: Vec<String>,
214}
215
216/// Condition for pattern matching.
217#[derive(Debug, Clone)]
218pub struct PatternCondition {
219    /// Metric name
220    pub metric: String,
221    /// Comparison operator
222    pub operator: ComparisonOperator,
223    /// Threshold value
224    pub threshold: f64,
225    /// Number of consecutive occurrences required
226    pub consecutive_count: usize,
227}
228
229/// Comparison operators for pattern conditions.
230#[derive(Debug, Clone)]
231pub enum ComparisonOperator {
232    /// Greater than
233    GreaterThan,
234    /// Less than
235    LessThan,
236    /// Equal to (within tolerance)
237    EqualTo,
238    /// Increasing trend
239    Increasing,
240    /// Decreasing trend
241    Decreasing,
242    /// Oscillating pattern
243    Oscillating,
244}
245
246/// Session statistics for debugging analysis.
247#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
248pub struct SessionStatistics {
249    /// Total issues identified
250    pub total_issues: usize,
251    /// Issues by category
252    pub issues_by_category: HashMap<IssueCategory, usize>,
253    /// Total recommendations generated
254    pub total_recommendations: usize,
255    /// Average confidence of recommendations
256    pub avg_recommendation_confidence: f64,
257    /// Analysis time taken
258    pub analysis_duration: chrono::Duration,
259}
260
261impl Default for AutoDebugConfig {
262    fn default() -> Self {
263        Self {
264            max_history_size: 1000,
265            min_samples_for_analysis: 10,
266            recommendation_confidence_threshold: 0.7,
267            enable_advanced_patterns: true,
268            enable_hyperparameter_suggestions: true,
269            enable_architectural_recommendations: true,
270        }
271    }
272}
273
274impl AutoDebugger {
275    /// Create a new auto-debugger.
276    pub fn new() -> Self {
277        Self {
278            config: AutoDebugConfig::default(),
279            performance_history: VecDeque::new(),
280            layer_history: HashMap::new(),
281            dynamics_history: VecDeque::new(),
282            issue_patterns: IssuePatternDatabase::new(),
283            session_state: DebuggingSession::new(),
284        }
285    }
286
287    /// Create auto-debugger with custom configuration.
288    pub fn with_config(config: AutoDebugConfig) -> Self {
289        Self {
290            config,
291            performance_history: VecDeque::new(),
292            layer_history: HashMap::new(),
293            dynamics_history: VecDeque::new(),
294            issue_patterns: IssuePatternDatabase::new(),
295            session_state: DebuggingSession::new(),
296        }
297    }
298
299    /// Record performance metrics for analysis.
300    pub fn record_performance_metrics(&mut self, metrics: ModelPerformanceMetrics) {
301        self.performance_history.push_back(metrics);
302
303        while self.performance_history.len() > self.config.max_history_size {
304            self.performance_history.pop_front();
305        }
306    }
307
308    /// Record layer statistics for analysis.
309    pub fn record_layer_stats(&mut self, stats: LayerActivationStats) {
310        let layer_name = stats.layer_name.clone();
311
312        let layer_history = self.layer_history.entry(layer_name).or_default();
313        layer_history.push_back(stats);
314
315        while layer_history.len() > self.config.max_history_size {
316            layer_history.pop_front();
317        }
318    }
319
320    /// Record training dynamics for analysis.
321    pub fn record_training_dynamics(&mut self, dynamics: TrainingDynamics) {
322        self.dynamics_history.push_back(dynamics);
323
324        while self.dynamics_history.len() > self.config.max_history_size {
325            self.dynamics_history.pop_front();
326        }
327    }
328
329    /// Perform comprehensive auto-debugging analysis.
330    pub fn perform_analysis(&mut self) -> Result<DebuggingReport> {
331        let analysis_start = chrono::Utc::now();
332
333        if self.performance_history.len() < self.config.min_samples_for_analysis {
334            return Err(anyhow::anyhow!("Insufficient data for analysis"));
335        }
336
337        // Clear previous session state
338        self.session_state = DebuggingSession::new();
339
340        // Analyze different aspects
341        self.analyze_learning_rate_issues()?;
342        self.analyze_convergence_issues()?;
343        self.analyze_gradient_flow_issues()?;
344        self.analyze_layer_health_issues()?;
345        self.analyze_memory_issues()?;
346        self.analyze_overfitting_underfitting()?;
347
348        // Generate recommendations based on identified issues
349        self.generate_recommendations()?;
350
351        // Update session statistics
352        self.session_state.session_stats.analysis_duration = chrono::Utc::now() - analysis_start;
353        self.update_session_statistics();
354
355        Ok(DebuggingReport {
356            session_info: self.session_state.clone(),
357            identified_issues: self.session_state.identified_issues.clone(),
358            recommendations: self.session_state.recommendations.clone(),
359            summary: self.generate_analysis_summary(),
360        })
361    }
362
363    /// Analyze learning rate related issues.
364    fn analyze_learning_rate_issues(&mut self) -> Result<()> {
365        let recent_metrics: Vec<_> = self.performance_history.iter().rev().take(20).collect();
366        if recent_metrics.len() < 10 {
367            return Ok(());
368        }
369
370        let mut issues_to_add = Vec::new();
371
372        // Check for loss explosion
373        let recent_losses: Vec<f64> = recent_metrics.iter().map(|m| m.loss).collect();
374        if let Some(max_loss) = recent_losses
375            .iter()
376            .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
377        {
378            if let Some(min_loss) = recent_losses
379                .iter()
380                .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
381            {
382                if max_loss / min_loss > 10.0 {
383                    issues_to_add.push(IdentifiedIssue {
384                        category: IssueCategory::LearningRate,
385                        description: "Learning rate too high - loss explosion detected".to_string(),
386                        severity: IssueSeverity::Critical,
387                        confidence: 0.9,
388                        evidence: vec![
389                            format!("Loss ratio: {:.2}", max_loss / min_loss),
390                            "Rapid loss increase observed".to_string(),
391                        ],
392                        potential_causes: vec![
393                            "Learning rate set too high".to_string(),
394                            "Gradient clipping disabled".to_string(),
395                            "Numerical instability".to_string(),
396                        ],
397                        identified_at: chrono::Utc::now(),
398                    });
399                }
400            }
401        }
402
403        // Check for learning stagnation
404        let loss_variance = self.calculate_variance(&recent_losses);
405        let recent_metrics_len = recent_metrics.len();
406        if loss_variance < 1e-6 && recent_metrics_len >= 15 {
407            issues_to_add.push(IdentifiedIssue {
408                category: IssueCategory::LearningRate,
409                description: "Learning rate too low - training stagnation".to_string(),
410                severity: IssueSeverity::Major,
411                confidence: 0.8,
412                evidence: vec![
413                    format!("Loss variance: {:.2e}", loss_variance),
414                    "No learning progress in recent steps".to_string(),
415                ],
416                potential_causes: vec![
417                    "Learning rate set too low".to_string(),
418                    "Learning rate decay too aggressive".to_string(),
419                    "Model has converged".to_string(),
420                ],
421                identified_at: chrono::Utc::now(),
422            });
423        }
424
425        // Add all collected issues
426        for issue in issues_to_add {
427            self.add_issue(issue);
428        }
429
430        Ok(())
431    }
432
433    /// Analyze convergence related issues.
434    fn analyze_convergence_issues(&mut self) -> Result<()> {
435        if let Some(latest_dynamics) = self.dynamics_history.back() {
436            match latest_dynamics.convergence_status {
437                ConvergenceStatus::Diverging => {
438                    self.add_issue(IdentifiedIssue {
439                        category: IssueCategory::Convergence,
440                        description: "Training is diverging".to_string(),
441                        severity: IssueSeverity::Critical,
442                        confidence: 0.95,
443                        evidence: vec!["Convergence status: Diverging".to_string()],
444                        potential_causes: vec![
445                            "Learning rate too high".to_string(),
446                            "Gradient explosion".to_string(),
447                            "Numerical instability".to_string(),
448                        ],
449                        identified_at: chrono::Utc::now(),
450                    });
451                },
452                ConvergenceStatus::Plateau => {
453                    if let Some(plateau_info) = &latest_dynamics.plateau_detection {
454                        if plateau_info.duration_steps > 100 {
455                            self.add_issue(IdentifiedIssue {
456                                category: IssueCategory::Convergence,
457                                description: "Training has plateaued".to_string(),
458                                severity: IssueSeverity::Moderate,
459                                confidence: 0.8,
460                                evidence: vec![
461                                    format!(
462                                        "Plateau duration: {} steps",
463                                        plateau_info.duration_steps
464                                    ),
465                                    format!("Plateau value: {:.4}", plateau_info.plateau_value),
466                                ],
467                                potential_causes: vec![
468                                    "Learning rate too low".to_string(),
469                                    "Model capacity insufficient".to_string(),
470                                    "Local minimum reached".to_string(),
471                                ],
472                                identified_at: chrono::Utc::now(),
473                            });
474                        }
475                    }
476                },
477                ConvergenceStatus::Oscillating => {
478                    self.add_issue(IdentifiedIssue {
479                        category: IssueCategory::NumericalStability,
480                        description: "Training is oscillating".to_string(),
481                        severity: IssueSeverity::Moderate,
482                        confidence: 0.7,
483                        evidence: vec!["Convergence status: Oscillating".to_string()],
484                        potential_causes: vec![
485                            "Learning rate too high".to_string(),
486                            "Batch size too small".to_string(),
487                            "Momentum settings suboptimal".to_string(),
488                        ],
489                        identified_at: chrono::Utc::now(),
490                    });
491                },
492                _ => {},
493            }
494        }
495
496        Ok(())
497    }
498
499    /// Analyze gradient flow issues.
500    fn analyze_gradient_flow_issues(&mut self) -> Result<()> {
501        let mut issues_to_add = Vec::new();
502
503        // Check layer statistics for gradient flow problems
504        for (layer_name, layer_history) in &self.layer_history {
505            if let Some(latest_stats) = layer_history.back() {
506                // Check for dead neurons
507                if latest_stats.dead_neurons_ratio > 0.5 {
508                    issues_to_add.push(IdentifiedIssue {
509                        category: IssueCategory::GradientFlow,
510                        description: format!("High dead neuron ratio in layer {}", layer_name),
511                        severity: IssueSeverity::Major,
512                        confidence: 0.85,
513                        evidence: vec![
514                            format!(
515                                "Dead neurons: {:.1}%",
516                                latest_stats.dead_neurons_ratio * 100.0
517                            ),
518                            format!("Layer: {}", layer_name),
519                        ],
520                        potential_causes: vec![
521                            "Dying ReLU problem".to_string(),
522                            "Poor weight initialization".to_string(),
523                            "Learning rate too high".to_string(),
524                        ],
525                        identified_at: chrono::Utc::now(),
526                    });
527                }
528
529                // Check for activation saturation
530                if latest_stats.saturated_neurons_ratio > 0.3 {
531                    issues_to_add.push(IdentifiedIssue {
532                        category: IssueCategory::GradientFlow,
533                        description: format!("High activation saturation in layer {}", layer_name),
534                        severity: IssueSeverity::Moderate,
535                        confidence: 0.8,
536                        evidence: vec![
537                            format!(
538                                "Saturated neurons: {:.1}%",
539                                latest_stats.saturated_neurons_ratio * 100.0
540                            ),
541                            format!("Layer: {}", layer_name),
542                        ],
543                        potential_causes: vec![
544                            "Vanishing gradient problem".to_string(),
545                            "Poor activation function choice".to_string(),
546                            "Input normalization issues".to_string(),
547                        ],
548                        identified_at: chrono::Utc::now(),
549                    });
550                }
551            }
552        }
553
554        // Add all collected issues
555        for issue in issues_to_add {
556            self.add_issue(issue);
557        }
558
559        Ok(())
560    }
561
562    /// Analyze layer health issues.
563    fn analyze_layer_health_issues(&mut self) -> Result<()> {
564        let mut issues_to_add = Vec::new();
565
566        for (layer_name, layer_history) in &self.layer_history {
567            if layer_history.len() >= 5 {
568                let recent_stats: Vec<_> = layer_history.iter().rev().take(5).collect();
569
570                // Check for activation variance trends
571                let variances: Vec<f64> = recent_stats.iter().map(|s| s.std_activation).collect();
572                let avg_variance = variances.iter().sum::<f64>() / variances.len() as f64;
573
574                if avg_variance < 0.01 {
575                    issues_to_add.push(IdentifiedIssue {
576                        category: IssueCategory::Architecture,
577                        description: format!("Low activation variance in layer {}", layer_name),
578                        severity: IssueSeverity::Minor,
579                        confidence: 0.6,
580                        evidence: vec![
581                            format!("Average variance: {:.4}", avg_variance),
582                            format!("Layer: {}", layer_name),
583                        ],
584                        potential_causes: vec![
585                            "Poor weight initialization".to_string(),
586                            "Input normalization too aggressive".to_string(),
587                            "Activation function saturation".to_string(),
588                        ],
589                        identified_at: chrono::Utc::now(),
590                    });
591                }
592            }
593        }
594
595        // Add all collected issues
596        for issue in issues_to_add {
597            self.add_issue(issue);
598        }
599
600        Ok(())
601    }
602
603    /// Analyze memory usage issues.
604    fn analyze_memory_issues(&mut self) -> Result<()> {
605        if self.performance_history.len() >= 10 {
606            let recent_memory: Vec<f64> = self
607                .performance_history
608                .iter()
609                .rev()
610                .take(10)
611                .map(|m| m.memory_usage_mb)
612                .collect();
613
614            // Check for memory leaks
615            let memory_trend = self.calculate_trend(&recent_memory);
616            if memory_trend > 10.0 {
617                // MB per step
618                self.add_issue(IdentifiedIssue {
619                    category: IssueCategory::Memory,
620                    description: "Memory leak detected".to_string(),
621                    severity: IssueSeverity::Critical,
622                    confidence: 0.9,
623                    evidence: vec![
624                        format!("Memory growth rate: {:.2} MB/step", memory_trend),
625                        "Increasing memory usage trend".to_string(),
626                    ],
627                    potential_causes: vec![
628                        "Gradient accumulation without clearing".to_string(),
629                        "Cached tensors not being released".to_string(),
630                        "Memory fragmentation".to_string(),
631                    ],
632                    identified_at: chrono::Utc::now(),
633                });
634            }
635
636            // Check for excessive memory usage
637            if let Some(max_memory) = recent_memory
638                .iter()
639                .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
640            {
641                if *max_memory > 16384.0 {
642                    // 16GB
643                    self.add_issue(IdentifiedIssue {
644                        category: IssueCategory::Memory,
645                        description: "Excessive memory usage detected".to_string(),
646                        severity: IssueSeverity::Major,
647                        confidence: 0.8,
648                        evidence: vec![
649                            format!("Peak memory: {:.0} MB", max_memory),
650                            "High memory consumption".to_string(),
651                        ],
652                        potential_causes: vec![
653                            "Batch size too large".to_string(),
654                            "Model too large for available memory".to_string(),
655                            "Inefficient memory allocation".to_string(),
656                        ],
657                        identified_at: chrono::Utc::now(),
658                    });
659                }
660            }
661        }
662
663        Ok(())
664    }
665
666    /// Analyze overfitting and underfitting issues.
667    fn analyze_overfitting_underfitting(&mut self) -> Result<()> {
668        let mut issues_to_add = Vec::new();
669
670        if let Some(latest_dynamics) = self.dynamics_history.back() {
671            // Check for overfitting indicators
672            for indicator in &latest_dynamics.overfitting_indicators {
673                if let super::types::OverfittingIndicator::TrainValidationGap { gap } = indicator {
674                    if *gap > 0.1 {
675                        issues_to_add.push(IdentifiedIssue {
676                            category: IssueCategory::Overfitting,
677                            description: "Large training-validation gap detected".to_string(),
678                            severity: IssueSeverity::Major,
679                            confidence: 0.85,
680                            evidence: vec![
681                                format!("Train-validation gap: {:.3}", gap),
682                                "Overfitting indicator present".to_string(),
683                            ],
684                            potential_causes: vec![
685                                "Model complexity too high".to_string(),
686                                "Insufficient regularization".to_string(),
687                                "Training set too small".to_string(),
688                            ],
689                            identified_at: chrono::Utc::now(),
690                        });
691                    }
692                }
693            }
694
695            // Check for underfitting indicators
696            for indicator in &latest_dynamics.underfitting_indicators {
697                match indicator {
698                    super::types::UnderfittingIndicator::HighTrainingLoss { loss, threshold } => {
699                        issues_to_add.push(IdentifiedIssue {
700                            category: IssueCategory::Underfitting,
701                            description: "High training loss indicates underfitting".to_string(),
702                            severity: IssueSeverity::Moderate,
703                            confidence: 0.7,
704                            evidence: vec![
705                                format!("Training loss: {:.3}", loss),
706                                format!("Threshold: {:.3}", threshold),
707                            ],
708                            potential_causes: vec![
709                                "Model capacity too low".to_string(),
710                                "Learning rate too low".to_string(),
711                                "Insufficient training time".to_string(),
712                            ],
713                            identified_at: chrono::Utc::now(),
714                        });
715                    },
716                    super::types::UnderfittingIndicator::SlowConvergence {
717                        steps_taken,
718                        expected,
719                    } => {
720                        issues_to_add.push(IdentifiedIssue {
721                            category: IssueCategory::Underfitting,
722                            description: "Slow convergence detected".to_string(),
723                            severity: IssueSeverity::Minor,
724                            confidence: 0.6,
725                            evidence: vec![
726                                format!("Steps taken: {}", steps_taken),
727                                format!("Expected: {}", expected),
728                            ],
729                            potential_causes: vec![
730                                "Learning rate too conservative".to_string(),
731                                "Optimizer choice suboptimal".to_string(),
732                                "Poor initialization".to_string(),
733                            ],
734                            identified_at: chrono::Utc::now(),
735                        });
736                    },
737                    _ => {},
738                }
739            }
740        }
741
742        // Add all collected issues
743        for issue in issues_to_add {
744            self.add_issue(issue);
745        }
746
747        Ok(())
748    }
749
750    /// Generate recommendations based on identified issues.
751    fn generate_recommendations(&mut self) -> Result<()> {
752        for issue in &self.session_state.identified_issues {
753            let recommendations = self.generate_recommendations_for_issue(issue);
754            self.session_state.recommendations.extend(recommendations);
755        }
756
757        // Sort recommendations by priority and confidence
758        self.session_state.recommendations.sort_by(|a, b| {
759            b.priority
760                .partial_cmp(&a.priority)
761                .unwrap_or(std::cmp::Ordering::Equal)
762                .then(b.confidence.partial_cmp(&a.confidence).unwrap_or(std::cmp::Ordering::Equal))
763        });
764
765        Ok(())
766    }
767
768    /// Generate specific recommendations for an issue.
769    fn generate_recommendations_for_issue(
770        &self,
771        issue: &IdentifiedIssue,
772    ) -> Vec<DebuggingRecommendation> {
773        match issue.category {
774            IssueCategory::LearningRate => {
775                if issue.description.contains("too high") {
776                    vec![DebuggingRecommendation {
777                        category: RecommendationCategory::HyperparameterTuning,
778                        title: "Reduce Learning Rate".to_string(),
779                        description: "Lower the learning rate to stabilize training".to_string(),
780                        actions: vec![
781                            "Reduce learning rate by factor of 2-10".to_string(),
782                            "Enable gradient clipping".to_string(),
783                            "Consider learning rate scheduling".to_string(),
784                        ],
785                        expected_impact: "Stabilized training with reduced loss oscillations"
786                            .to_string(),
787                        confidence: 0.9,
788                        priority: AutoDebugRecommendationPriority::High,
789                        hyperparameter_suggestions: vec![HyperparameterSuggestion {
790                            parameter_name: "learning_rate".to_string(),
791                            current_value: None,
792                            suggested_value: 0.0001,
793                            reasoning: "Reduce to prevent loss explosion".to_string(),
794                            expected_effect: "More stable training".to_string(),
795                        }],
796                    }]
797                } else if issue.description.contains("too low") {
798                    vec![DebuggingRecommendation {
799                        category: RecommendationCategory::HyperparameterTuning,
800                        title: "Increase Learning Rate".to_string(),
801                        description: "Increase learning rate to improve convergence speed"
802                            .to_string(),
803                        actions: vec![
804                            "Increase learning rate by factor of 2-5".to_string(),
805                            "Use learning rate warmup".to_string(),
806                            "Consider adaptive learning rate methods".to_string(),
807                        ],
808                        expected_impact: "Faster convergence and better final performance"
809                            .to_string(),
810                        confidence: 0.8,
811                        priority: AutoDebugRecommendationPriority::Medium,
812                        hyperparameter_suggestions: vec![HyperparameterSuggestion {
813                            parameter_name: "learning_rate".to_string(),
814                            current_value: None,
815                            suggested_value: 0.001,
816                            reasoning: "Increase to improve learning speed".to_string(),
817                            expected_effect: "Faster convergence".to_string(),
818                        }],
819                    }]
820                } else {
821                    Vec::new()
822                }
823            },
824            IssueCategory::Memory => {
825                vec![DebuggingRecommendation {
826                    category: RecommendationCategory::ResourceOptimization,
827                    title: "Optimize Memory Usage".to_string(),
828                    description: "Implement memory optimization strategies".to_string(),
829                    actions: vec![
830                        "Reduce batch size".to_string(),
831                        "Enable gradient checkpointing".to_string(),
832                        "Clear cached tensors regularly".to_string(),
833                        "Use mixed precision training".to_string(),
834                    ],
835                    expected_impact: "Reduced memory consumption and stable training".to_string(),
836                    confidence: 0.85,
837                    priority: AutoDebugRecommendationPriority::High,
838                    hyperparameter_suggestions: vec![HyperparameterSuggestion {
839                        parameter_name: "batch_size".to_string(),
840                        current_value: None,
841                        suggested_value: 16.0,
842                        reasoning: "Reduce to lower memory usage".to_string(),
843                        expected_effect: "Lower memory consumption".to_string(),
844                    }],
845                }]
846            },
847            IssueCategory::Overfitting => {
848                vec![DebuggingRecommendation {
849                    category: RecommendationCategory::TrainingStrategy,
850                    title: "Address Overfitting".to_string(),
851                    description: "Implement regularization strategies to reduce overfitting"
852                        .to_string(),
853                    actions: vec![
854                        "Add dropout layers".to_string(),
855                        "Increase weight decay".to_string(),
856                        "Use data augmentation".to_string(),
857                        "Reduce model complexity".to_string(),
858                        "Implement early stopping".to_string(),
859                    ],
860                    expected_impact: "Better generalization and validation performance".to_string(),
861                    confidence: 0.8,
862                    priority: AutoDebugRecommendationPriority::Medium,
863                    hyperparameter_suggestions: vec![HyperparameterSuggestion {
864                        parameter_name: "dropout_rate".to_string(),
865                        current_value: None,
866                        suggested_value: 0.1,
867                        reasoning: "Add regularization to reduce overfitting".to_string(),
868                        expected_effect: "Better generalization".to_string(),
869                    }],
870                }]
871            },
872            IssueCategory::GradientFlow => {
873                vec![DebuggingRecommendation {
874                    category: RecommendationCategory::ArchitecturalModification,
875                    title: "Improve Gradient Flow".to_string(),
876                    description: "Address gradient flow issues in the network".to_string(),
877                    actions: vec![
878                        "Use different activation functions (e.g., Leaky ReLU, Swish)".to_string(),
879                        "Add batch normalization".to_string(),
880                        "Implement residual connections".to_string(),
881                        "Adjust weight initialization".to_string(),
882                    ],
883                    expected_impact: "Better gradient flow and training stability".to_string(),
884                    confidence: 0.75,
885                    priority: AutoDebugRecommendationPriority::Medium,
886                    hyperparameter_suggestions: Vec::new(),
887                }]
888            },
889            _ => Vec::new(),
890        }
891    }
892
893    /// Add an issue to the current session.
894    fn add_issue(&mut self, issue: IdentifiedIssue) {
895        self.session_state.identified_issues.push(issue);
896    }
897
898    /// Calculate variance of a sequence of values.
899    fn calculate_variance(&self, values: &[f64]) -> f64 {
900        if values.len() < 2 {
901            return 0.0;
902        }
903
904        let mean = values.iter().sum::<f64>() / values.len() as f64;
905        let variance =
906            values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (values.len() - 1) as f64;
907
908        variance
909    }
910
911    /// Calculate trend (slope) of a sequence of values.
912    fn calculate_trend(&self, values: &[f64]) -> f64 {
913        if values.len() < 2 {
914            return 0.0;
915        }
916
917        let n = values.len() as f64;
918        let x_mean = (n - 1.0) / 2.0;
919        let y_mean = values.iter().sum::<f64>() / n;
920
921        let numerator: f64 = values
922            .iter()
923            .enumerate()
924            .map(|(i, &y)| (i as f64 - x_mean) * (y - y_mean))
925            .sum();
926
927        let denominator: f64 = (0..values.len()).map(|i| (i as f64 - x_mean).powi(2)).sum();
928
929        if denominator == 0.0 {
930            0.0
931        } else {
932            numerator / denominator
933        }
934    }
935
936    /// Update session statistics.
937    fn update_session_statistics(&mut self) {
938        let mut issues_by_category = HashMap::new();
939        for issue in &self.session_state.identified_issues {
940            *issues_by_category.entry(issue.category.clone()).or_insert(0) += 1;
941        }
942
943        let avg_confidence = if self.session_state.recommendations.is_empty() {
944            0.0
945        } else {
946            self.session_state.recommendations.iter().map(|r| r.confidence).sum::<f64>()
947                / self.session_state.recommendations.len() as f64
948        };
949
950        self.session_state.session_stats = SessionStatistics {
951            total_issues: self.session_state.identified_issues.len(),
952            issues_by_category,
953            total_recommendations: self.session_state.recommendations.len(),
954            avg_recommendation_confidence: avg_confidence,
955            analysis_duration: self.session_state.session_stats.analysis_duration,
956        };
957    }
958
959    /// Generate analysis summary.
960    fn generate_analysis_summary(&self) -> String {
961        let critical_issues = self
962            .session_state
963            .identified_issues
964            .iter()
965            .filter(|i| i.severity == IssueSeverity::Critical)
966            .count();
967
968        let major_issues = self
969            .session_state
970            .identified_issues
971            .iter()
972            .filter(|i| i.severity == IssueSeverity::Major)
973            .count();
974
975        let high_priority_recommendations = self
976            .session_state
977            .recommendations
978            .iter()
979            .filter(|r| r.priority == AutoDebugRecommendationPriority::High)
980            .count();
981
982        format!(
983            "Auto-debugging analysis completed. Found {} critical issues, {} major issues. \
984            Generated {} recommendations with {} high-priority actions. \
985            Average recommendation confidence: {:.2}",
986            critical_issues,
987            major_issues,
988            self.session_state.recommendations.len(),
989            high_priority_recommendations,
990            self.session_state.session_stats.avg_recommendation_confidence
991        )
992    }
993}
994
995/// Comprehensive debugging report.
996#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
997pub struct DebuggingReport {
998    /// Session information
999    pub session_info: DebuggingSession,
1000    /// All identified issues
1001    pub identified_issues: Vec<IdentifiedIssue>,
1002    /// Generated recommendations
1003    pub recommendations: Vec<DebuggingRecommendation>,
1004    /// Analysis summary
1005    pub summary: String,
1006}
1007
1008impl IssuePatternDatabase {
1009    /// Create a new pattern database with default patterns.
1010    pub fn new() -> Self {
1011        Self {
1012            learning_rate_patterns: Self::create_learning_rate_patterns(),
1013            gradient_patterns: Self::create_gradient_patterns(),
1014            convergence_patterns: Self::create_convergence_patterns(),
1015            layer_patterns: Self::create_layer_patterns(),
1016        }
1017    }
1018
1019    /// Create default learning rate patterns.
1020    fn create_learning_rate_patterns() -> Vec<IssuePattern> {
1021        vec![IssuePattern {
1022            name: "Loss Explosion".to_string(),
1023            description: "Rapid increase in loss indicating learning rate too high".to_string(),
1024            conditions: vec![PatternCondition {
1025                metric: "loss".to_string(),
1026                operator: ComparisonOperator::Increasing,
1027                threshold: 2.0,
1028                consecutive_count: 3,
1029            }],
1030            issue_category: IssueCategory::LearningRate,
1031            confidence_weight: 0.9,
1032            solutions: vec![
1033                "Reduce learning rate by factor of 10".to_string(),
1034                "Enable gradient clipping".to_string(),
1035            ],
1036        }]
1037    }
1038
1039    /// Create default gradient patterns.
1040    fn create_gradient_patterns() -> Vec<IssuePattern> {
1041        vec![]
1042    }
1043
1044    /// Create default convergence patterns.
1045    fn create_convergence_patterns() -> Vec<IssuePattern> {
1046        vec![]
1047    }
1048
1049    /// Create default layer patterns.
1050    fn create_layer_patterns() -> Vec<IssuePattern> {
1051        vec![]
1052    }
1053}
1054
1055impl DebuggingSession {
1056    /// Create a new debugging session.
1057    fn new() -> Self {
1058        Self {
1059            session_start: chrono::Utc::now(),
1060            identified_issues: Vec::new(),
1061            recommendations: Vec::new(),
1062            session_stats: SessionStatistics {
1063                total_issues: 0,
1064                issues_by_category: HashMap::new(),
1065                total_recommendations: 0,
1066                avg_recommendation_confidence: 0.0,
1067                analysis_duration: chrono::Duration::zero(),
1068            },
1069        }
1070    }
1071}
1072
1073impl Default for AutoDebugger {
1074    fn default() -> Self {
1075        Self::new()
1076    }
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081    use super::*;
1082
1083    #[test]
1084    fn test_auto_debugger_creation() {
1085        let debugger = AutoDebugger::new();
1086        assert_eq!(debugger.performance_history.len(), 0);
1087        assert_eq!(debugger.layer_history.len(), 0);
1088    }
1089
1090    #[test]
1091    fn test_issue_identification() {
1092        let mut debugger = AutoDebugger::new();
1093
1094        let issue = IdentifiedIssue {
1095            category: IssueCategory::LearningRate,
1096            description: "Test issue".to_string(),
1097            severity: IssueSeverity::Major,
1098            confidence: 0.8,
1099            evidence: vec!["Test evidence".to_string()],
1100            potential_causes: vec!["Test cause".to_string()],
1101            identified_at: chrono::Utc::now(),
1102        };
1103
1104        debugger.add_issue(issue);
1105        assert_eq!(debugger.session_state.identified_issues.len(), 1);
1106    }
1107
1108    #[test]
1109    fn test_variance_calculation() {
1110        let debugger = AutoDebugger::new();
1111        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1112        let variance = debugger.calculate_variance(&values);
1113        assert!(variance > 0.0);
1114    }
1115
1116    #[test]
1117    fn test_trend_calculation() {
1118        let debugger = AutoDebugger::new();
1119        let increasing_values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1120        let trend = debugger.calculate_trend(&increasing_values);
1121        assert!(trend > 0.0);
1122    }
1123}