Skip to main content

trustformers_debug/gradient_debugger/
enhanced_analysis.rs

1//! Enhanced Layer Analysis and Network-Level Insights
2//!
3//! This module provides comprehensive enhanced analysis capabilities including
4//! detailed layer-wise analysis, network-level gradient insights, and optimization
5//! priority ranking for gradient debugging.
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 super::types::*;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15/// Enhanced layer-wise gradient analysis
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct EnhancedLayerGradientAnalysis {
18    pub layer_details: HashMap<String, LayerGradientDetails>,
19    pub network_level_analysis: NetworkLevelAnalysis,
20    pub gradient_hierarchy: GradientHierarchy,
21    pub optimization_priorities: Vec<OptimizationPriority>,
22}
23
24/// Detailed gradient analysis for a specific layer
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct LayerGradientDetails {
27    pub layer_name: String,
28    pub gradient_statistics: GradientStatistics,
29    pub flow_characteristics: FlowCharacteristics,
30    pub health_metrics: LayerHealthMetrics,
31    pub optimization_suggestions: Vec<LayerOptimizationSuggestion>,
32    pub comparative_analysis: ComparativeAnalysis,
33}
34
35/// Network-level gradient analysis
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct NetworkLevelAnalysis {
38    pub overall_gradient_health: LayerHealth,
39    pub gradient_distribution: GradientDistribution,
40    pub layer_interactions: Vec<LayerInteraction>,
41    pub convergence_indicators: ConvergenceIndicators,
42    pub training_dynamics: TrainingDynamics,
43    pub stability_assessment: StabilityAssessment,
44}
45
46/// Distribution of gradients across the network
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct GradientDistribution {
49    pub mean_gradient_norm: f64,
50    pub gradient_variance: f64,
51    pub gradient_skewness: f64,
52    pub gradient_kurtosis: f64,
53    pub layer_gradient_ratios: HashMap<String, f64>,
54    pub distribution_type: DistributionType,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub enum DistributionType {
59    Normal,
60    Skewed,
61    HeavyTailed,
62    Multimodal,
63    Degenerate,
64}
65
66/// Interaction between layers in gradient flow
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct LayerInteraction {
69    pub layer1: String,
70    pub layer2: String,
71    pub interaction_strength: f64,
72    pub interaction_type: InteractionType,
73    pub impact_score: f64,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub enum InteractionType {
78    Cooperative,
79    Competitive,
80    Neutral,
81    Disruptive,
82}
83
84/// Indicators of training convergence
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct ConvergenceIndicators {
87    pub gradient_convergence_score: f64,
88    pub parameter_convergence_score: f64,
89    pub loss_convergence_score: f64,
90    pub convergence_trend: ConvergenceTrend,
91    pub estimated_steps_to_convergence: Option<usize>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub enum ConvergenceTrend {
96    Converging,
97    Stable,
98    Diverging,
99    Oscillating,
100    Unknown,
101}
102
103/// Training dynamics analysis
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct TrainingDynamics {
106    pub learning_phase: LearningPhase,
107    pub gradient_momentum: f64,
108    pub learning_velocity: f64,
109    pub adaptation_rate: f64,
110    pub plateau_detection: PlateauDetection,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub enum LearningPhase {
115    InitialLearning,
116    RapidLearning,
117    Refinement,
118    Convergence,
119    Plateau,
120    Overfitting,
121}
122
123/// Plateau detection in training
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct PlateauDetection {
126    pub is_plateau: bool,
127    pub plateau_duration: usize,
128    pub plateau_severity: PlateauSeverity,
129    pub suggested_actions: Vec<String>,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub enum PlateauSeverity {
134    Mild,
135    Moderate,
136    Severe,
137}
138
139/// Network stability assessment
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct StabilityAssessment {
142    pub overall_stability: f64,
143    pub stability_trend: StabilityTrend,
144    pub instability_sources: Vec<InstabilitySource>,
145    pub stability_forecast: StabilityForecast,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub enum StabilityTrend {
150    Improving,
151    Stable,
152    Degrading,
153}
154
155/// Source of instability in the network
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct InstabilitySource {
158    pub source_type: InstabilityType,
159    pub affected_layers: Vec<String>,
160    pub severity: f64,
161    pub description: String,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub enum InstabilityType {
166    GradientExplosion,
167    GradientVanishing,
168    Oscillation,
169    Stagnation,
170    Chaos,
171}
172
173/// Forecast of stability trends
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct StabilityForecast {
176    pub short_term_outlook: StabilityOutlook,
177    pub long_term_outlook: StabilityOutlook,
178    pub confidence_level: f64,
179    pub recommended_monitoring: Vec<String>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub enum StabilityOutlook {
184    Stable,
185    Improving,
186    Deteriorating,
187    Uncertain,
188}
189
190/// Hierarchical organization of gradient information
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct GradientHierarchy {
193    pub layer_groups: Vec<LayerGroup>,
194    pub hierarchy_levels: Vec<HierarchyLevel>,
195    pub cross_level_interactions: Vec<CrossLevelInteraction>,
196}
197
198/// Group of related layers
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct LayerGroup {
201    pub group_name: String,
202    pub layers: Vec<String>,
203    pub group_characteristics: GroupCharacteristics,
204    pub internal_coherence: f64,
205}
206
207/// Characteristics of a layer group
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct GroupCharacteristics {
210    pub average_gradient_norm: f64,
211    pub gradient_synchronization: f64,
212    pub learning_rate_sensitivity: f64,
213    pub optimization_difficulty: OptimizationDifficulty,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub enum OptimizationDifficulty {
218    Easy,
219    Moderate,
220    Difficult,
221    VeryDifficult,
222}
223
224/// Level in the gradient hierarchy
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct HierarchyLevel {
227    pub level_id: usize,
228    pub level_name: String,
229    pub layer_groups: Vec<String>,
230    pub level_importance: f64,
231    pub optimization_impact: f64,
232}
233
234/// Interaction between hierarchy levels
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct CrossLevelInteraction {
237    pub from_level: usize,
238    pub to_level: usize,
239    pub interaction_strength: f64,
240    pub interaction_direction: InteractionDirection,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
244pub enum InteractionDirection {
245    TopDown,
246    BottomUp,
247    Bidirectional,
248}
249
250/// Optimization priority for layers or groups
251#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct OptimizationPriority {
253    pub target_name: String,
254    pub target_type: OptimizationTarget,
255    pub priority_score: f64,
256    pub urgency_level: UrgencyLevel,
257    pub optimization_potential: f64,
258    pub recommended_actions: Vec<PrioritizedAction>,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub enum OptimizationTarget {
263    IndividualLayer,
264    LayerGroup,
265    NetworkLevel,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub enum UrgencyLevel {
270    Low,
271    Medium,
272    High,
273    Critical,
274}
275
276/// Prioritized optimization action
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct PrioritizedAction {
279    pub action_name: String,
280    pub action_type: ActionType,
281    pub expected_impact: f64,
282    pub implementation_effort: ImplementationEffort,
283    pub prerequisites: Vec<String>,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub enum ActionType {
288    ParameterAdjustment,
289    ArchitecturalChange,
290    OptimizationTechnique,
291    RegularizationMethod,
292    LearningRateScheduling,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub enum ImplementationEffort {
297    Minimal,
298    Low,
299    Moderate,
300    High,
301    Extensive,
302}
303
304/// Layer-specific optimization suggestion
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct LayerOptimizationSuggestion {
307    pub suggestion_type: SuggestionType,
308    pub description: String,
309    pub rationale: String,
310    pub expected_improvement: f64,
311    pub implementation_complexity: ImplementationComplexity,
312    pub side_effects: Vec<String>,
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
316pub enum SuggestionType {
317    WeightInitialization,
318    LearningRateAdjustment,
319    RegularizationAdd,
320    ArchitecturalModification,
321    OptimizationAlgorithm,
322    BatchNormalization,
323    DropoutAdjustment,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
327pub enum ImplementationComplexity {
328    Simple,
329    Moderate,
330    Complex,
331    RequiresRetraining,
332}
333
334/// Enhanced gradient analyzer
335#[derive(Debug)]
336pub struct EnhancedGradientAnalyzer {
337    analysis_depth: AnalysisDepth,
338    convergence_window: usize,
339    stability_threshold: f64,
340}
341
342#[derive(Debug, Clone)]
343pub enum AnalysisDepth {
344    Basic,
345    Standard,
346    Comprehensive,
347    Expert,
348}
349
350impl Default for EnhancedGradientAnalyzer {
351    fn default() -> Self {
352        Self {
353            analysis_depth: AnalysisDepth::Standard,
354            convergence_window: 100,
355            stability_threshold: 0.8,
356        }
357    }
358}
359
360impl EnhancedGradientAnalyzer {
361    pub fn new(depth: AnalysisDepth, window: usize, threshold: f64) -> Self {
362        Self {
363            analysis_depth: depth,
364            convergence_window: window,
365            stability_threshold: threshold,
366        }
367    }
368
369    pub fn generate_enhanced_analysis(
370        &self,
371        gradient_histories: &HashMap<String, GradientHistory>,
372    ) -> EnhancedLayerGradientAnalysis {
373        let layer_details = self.generate_layer_details(gradient_histories);
374        let network_level_analysis = self.analyze_network_level_gradients(&layer_details);
375        let gradient_hierarchy = self.build_gradient_hierarchy(&layer_details);
376        let optimization_priorities =
377            self.rank_optimization_priorities(&layer_details, &network_level_analysis);
378
379        EnhancedLayerGradientAnalysis {
380            layer_details,
381            network_level_analysis,
382            gradient_hierarchy,
383            optimization_priorities,
384        }
385    }
386
387    fn generate_layer_details(
388        &self,
389        gradient_histories: &HashMap<String, GradientHistory>,
390    ) -> HashMap<String, LayerGradientDetails> {
391        let mut layer_details = HashMap::new();
392
393        for (layer_name, history) in gradient_histories {
394            let gradient_statistics = self.compute_detailed_gradient_stats(history);
395            let flow_characteristics = self.analyze_flow_characteristics(history);
396            let health_metrics = self.compute_layer_health_metrics(history);
397            let optimization_suggestions =
398                self.generate_layer_optimization_suggestions(layer_name, history);
399            let comparative_analysis =
400                self.compare_with_other_layers(layer_name, history, gradient_histories);
401
402            let analysis = LayerGradientDetails {
403                layer_name: layer_name.clone(),
404                gradient_statistics,
405                flow_characteristics,
406                health_metrics,
407                optimization_suggestions,
408                comparative_analysis,
409            };
410
411            layer_details.insert(layer_name.clone(), analysis);
412        }
413
414        layer_details
415    }
416
417    fn compute_detailed_gradient_stats(&self, history: &GradientHistory) -> GradientStatistics {
418        if history.gradient_norms.is_empty() {
419            return GradientStatistics {
420                mean: 0.0,
421                std: 0.0,
422                median: 0.0,
423                percentile_95: 0.0,
424                percentile_5: 0.0,
425                samples: 0,
426                variance: 0.0,
427                skewness: 0.0,
428                kurtosis: 0.0,
429            };
430        }
431
432        let values: Vec<f64> = history.gradient_norms.iter().cloned().collect();
433        let n = values.len() as f64;
434        let mean = values.iter().sum::<f64>() / n;
435        let variance = values.iter().map(|&x| (x - mean).powi(2)).sum::<f64>() / n;
436        let std = variance.sqrt();
437
438        let mut sorted_values = values.clone();
439        sorted_values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
440
441        let median_idx = values.len() / 2;
442        let median = if values.len().is_multiple_of(2) {
443            (sorted_values[median_idx - 1] + sorted_values[median_idx]) / 2.0
444        } else {
445            sorted_values[median_idx]
446        };
447
448        let percentile_5_idx = (values.len() as f64 * 0.05) as usize;
449        let percentile_95_idx = (values.len() as f64 * 0.95) as usize;
450        let percentile_5 = sorted_values[percentile_5_idx];
451        let percentile_95 = sorted_values[percentile_95_idx.min(sorted_values.len() - 1)];
452
453        // Compute skewness and kurtosis
454        let skewness = if std > 0.0 {
455            values.iter().map(|&x| ((x - mean) / std).powi(3)).sum::<f64>() / n
456        } else {
457            0.0
458        };
459
460        let kurtosis = if std > 0.0 {
461            values.iter().map(|&x| ((x - mean) / std).powi(4)).sum::<f64>() / n - 3.0
462        } else {
463            0.0
464        };
465
466        GradientStatistics {
467            mean,
468            std,
469            median,
470            percentile_95,
471            percentile_5,
472            samples: values.len(),
473            variance,
474            skewness,
475            kurtosis,
476        }
477    }
478
479    fn analyze_flow_characteristics(&self, history: &GradientHistory) -> FlowCharacteristics {
480        let consistency_score = self.compute_flow_consistency(history);
481        let smoothness_index = self.compute_smoothness_index(history);
482        let trend_strength = self.compute_trend_strength(history);
483        let oscillation_frequency = self.compute_oscillation_frequency(history);
484        let stability_measure = self.compute_stability_measure(history);
485
486        FlowCharacteristics {
487            consistency_score,
488            smoothness_index,
489            trend_strength,
490            oscillation_frequency,
491            stability_measure,
492        }
493    }
494
495    fn compute_flow_consistency(&self, history: &GradientHistory) -> f64 {
496        if history.gradient_norms.len() < 2 {
497            return 1.0;
498        }
499
500        let variations: Vec<f64> = history
501            .gradient_norms
502            .iter()
503            .collect::<Vec<&f64>>()
504            .windows(2)
505            .map(|pair| (*pair[1] - *pair[0]).abs() / (*pair[0] + 1e-8))
506            .collect();
507
508        let avg_variation = variations.iter().sum::<f64>() / variations.len() as f64;
509        (1.0_f64 / (1.0 + avg_variation)).min(1.0)
510    }
511
512    fn compute_smoothness_index(&self, history: &GradientHistory) -> f64 {
513        if history.gradient_norms.len() < 3 {
514            return 1.0;
515        }
516
517        // Compute second derivatives to measure smoothness
518        let second_derivatives: Vec<f64> = history
519            .gradient_norms
520            .iter()
521            .collect::<Vec<&f64>>()
522            .windows(3)
523            .map(|window| *window[2] - 2.0 * *window[1] + *window[0])
524            .collect();
525
526        let avg_second_derivative = second_derivatives.iter().map(|&x| x.abs()).sum::<f64>()
527            / second_derivatives.len() as f64;
528        (1.0_f64 / (1.0 + avg_second_derivative)).min(1.0)
529    }
530
531    fn compute_trend_strength(&self, history: &GradientHistory) -> f64 {
532        history.get_trend_slope().map(|slope| slope.abs().min(1.0)).unwrap_or(0.0)
533    }
534
535    fn compute_oscillation_frequency(&self, history: &GradientHistory) -> f64 {
536        if history.gradient_norms.len() < 4 {
537            return 0.0;
538        }
539
540        let sign_changes = history
541            .gradient_norms
542            .iter()
543            .collect::<Vec<&f64>>()
544            .windows(2)
545            .map(|pair| *pair[1] - *pair[0])
546            .collect::<Vec<f64>>()
547            .windows(2)
548            .filter(|pair| pair[0] * pair[1] < 0.0)
549            .count();
550
551        sign_changes as f64 / history.gradient_norms.len() as f64
552    }
553
554    fn compute_stability_measure(&self, history: &GradientHistory) -> f64 {
555        if history.gradient_norms.is_empty() {
556            return 0.0;
557        }
558
559        let mean = history.gradient_norms.iter().sum::<f64>() / history.gradient_norms.len() as f64;
560        let variance = history.gradient_norms.iter().map(|&x| (x - mean).powi(2)).sum::<f64>()
561            / history.gradient_norms.len() as f64;
562
563        if mean == 0.0 {
564            return 0.0;
565        }
566
567        let coefficient_of_variation = variance.sqrt() / mean;
568        (1.0 / (1.0 + coefficient_of_variation)).min(1.0)
569    }
570
571    fn compute_layer_health_metrics(&self, history: &GradientHistory) -> LayerHealthMetrics {
572        let gradient_statistics = self.compute_detailed_gradient_stats(history);
573        let flow_characteristics = self.analyze_flow_characteristics(history);
574
575        let gradient_stability = flow_characteristics.stability_measure;
576        let information_flow_rate = self.compute_information_flow_rate(history);
577        let neuron_activity_ratio = self.estimate_neuron_activity_ratio(history);
578        let convergence_indicator = self.compute_convergence_indicator(history);
579
580        let mut risk_factors = Vec::new();
581        if gradient_statistics.mean < 1e-5 {
582            risk_factors.push("Very low gradient magnitude".to_string());
583        }
584        if gradient_statistics.mean > 100.0 {
585            risk_factors.push("Very high gradient magnitude".to_string());
586        }
587        if gradient_stability < 0.5 {
588            risk_factors.push("High gradient instability".to_string());
589        }
590        if flow_characteristics.oscillation_frequency > 0.5 {
591            risk_factors.push("High oscillation frequency".to_string());
592        }
593
594        let overall_health = if !risk_factors.is_empty() {
595            if risk_factors.len() > 2 {
596                LayerHealth::Critical
597            } else {
598                LayerHealth::Warning
599            }
600        } else {
601            LayerHealth::Healthy
602        };
603
604        LayerHealthMetrics {
605            overall_health,
606            gradient_stability,
607            information_flow_rate,
608            neuron_activity_ratio,
609            convergence_indicator,
610            risk_factors,
611        }
612    }
613
614    fn compute_information_flow_rate(&self, history: &GradientHistory) -> f64 {
615        if history.gradient_norms.len() < 2 {
616            return 0.0;
617        }
618
619        let total_change: f64 = history
620            .gradient_norms
621            .iter()
622            .collect::<Vec<&f64>>()
623            .windows(2)
624            .map(|pair| (*pair[1] - *pair[0]).abs())
625            .sum();
626
627        total_change / history.gradient_norms.len() as f64
628    }
629
630    fn estimate_neuron_activity_ratio(&self, history: &GradientHistory) -> f64 {
631        // Simplified estimation based on gradient magnitude
632        let mean_gradient =
633            history.gradient_norms.iter().sum::<f64>() / history.gradient_norms.len() as f64;
634        (mean_gradient / (mean_gradient + 1e-5)).min(1.0)
635    }
636
637    fn compute_convergence_indicator(&self, history: &GradientHistory) -> f64 {
638        if history.gradient_norms.len() < self.convergence_window {
639            return 0.5; // Neutral score if insufficient data
640        }
641
642        let recent: Vec<f64> = history
643            .gradient_norms
644            .iter()
645            .rev()
646            .take(self.convergence_window)
647            .cloned()
648            .collect();
649        let trend_slope = self.compute_trend_for_values(&recent);
650
651        // Negative slope indicates convergence (decreasing gradients)
652        if trend_slope < 0.0 {
653            (-trend_slope).min(1.0)
654        } else {
655            0.0
656        }
657    }
658
659    fn compute_trend_for_values(&self, values: &[f64]) -> f64 {
660        if values.len() < 3 {
661            return 0.0;
662        }
663
664        let n = values.len() as f64;
665        let sum_x: f64 = (0..values.len()).map(|i| i as f64).sum();
666        let sum_y: f64 = values.iter().sum();
667        let sum_xy: f64 = values.iter().enumerate().map(|(i, &y)| i as f64 * y).sum();
668        let sum_x2: f64 = (0..values.len()).map(|i| (i as f64).powi(2)).sum();
669
670        (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x.powi(2))
671    }
672
673    fn generate_layer_optimization_suggestions(
674        &self,
675        _layer_name: &str,
676        history: &GradientHistory,
677    ) -> Vec<LayerOptimizationSuggestion> {
678        let mut suggestions = Vec::new();
679        let stats = self.compute_detailed_gradient_stats(history);
680        let flow = self.analyze_flow_characteristics(history);
681
682        // Low gradient suggestions
683        if stats.mean < 1e-5 {
684            suggestions.push(LayerOptimizationSuggestion {
685                suggestion_type: SuggestionType::WeightInitialization,
686                description: "Consider better weight initialization methods".to_string(),
687                rationale: "Very low gradients may indicate poor initialization".to_string(),
688                expected_improvement: 0.7,
689                implementation_complexity: ImplementationComplexity::Simple,
690                side_effects: vec!["May require retraining from scratch".to_string()],
691            });
692        }
693
694        // High gradient suggestions
695        if stats.mean > 10.0 {
696            suggestions.push(LayerOptimizationSuggestion {
697                suggestion_type: SuggestionType::LearningRateAdjustment,
698                description: "Reduce learning rate for this layer".to_string(),
699                rationale: "High gradients may indicate learning rate is too large".to_string(),
700                expected_improvement: 0.6,
701                implementation_complexity: ImplementationComplexity::Simple,
702                side_effects: vec!["May slow down convergence".to_string()],
703            });
704        }
705
706        // High oscillation suggestions
707        if flow.oscillation_frequency > 0.5 {
708            suggestions.push(LayerOptimizationSuggestion {
709                suggestion_type: SuggestionType::RegularizationAdd,
710                description: "Add dropout or weight decay".to_string(),
711                rationale: "High oscillation may indicate overfitting or instability".to_string(),
712                expected_improvement: 0.5,
713                implementation_complexity: ImplementationComplexity::Moderate,
714                side_effects: vec!["May reduce model capacity".to_string()],
715            });
716        }
717
718        suggestions
719    }
720
721    fn compare_with_other_layers(
722        &self,
723        layer_name: &str,
724        history: &GradientHistory,
725        all_histories: &HashMap<String, GradientHistory>,
726    ) -> ComparativeAnalysis {
727        let current_stats = self.compute_detailed_gradient_stats(history);
728        let mut other_means = Vec::new();
729
730        for (other_name, other_history) in all_histories {
731            if other_name != layer_name {
732                let other_stats = self.compute_detailed_gradient_stats(other_history);
733                other_means.push(other_stats.mean);
734            }
735        }
736
737        if other_means.is_empty() {
738            return ComparativeAnalysis {
739                relative_performance: 1.0,
740                rank_among_layers: 1,
741                similar_layers: vec![],
742                performance_gap: 0.0,
743                optimization_potential: 0.5,
744            };
745        }
746
747        other_means.sort_by(|a, b| b.partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal));
748        let rank = other_means
749            .iter()
750            .position(|&x| x <= current_stats.mean)
751            .unwrap_or(other_means.len())
752            + 1;
753
754        let avg_other_mean = other_means.iter().sum::<f64>() / other_means.len() as f64;
755        let relative_performance =
756            if avg_other_mean > 0.0 { current_stats.mean / avg_other_mean } else { 1.0 };
757
758        let performance_gap = (current_stats.mean - avg_other_mean).abs();
759
760        // Find similar layers (within 20% of performance)
761        let similar_layers: Vec<String> = all_histories
762            .iter()
763            .filter(|(other_name, other_history)| {
764                if *other_name == layer_name {
765                    return false;
766                }
767                let other_stats = self.compute_detailed_gradient_stats(other_history);
768                let ratio = (current_stats.mean / (other_stats.mean + 1e-8))
769                    .max(other_stats.mean / (current_stats.mean + 1e-8));
770                ratio <= 1.2
771            })
772            .map(|(name, _)| name.clone())
773            .collect();
774
775        let optimization_potential = if relative_performance < 0.5 {
776            0.8
777        } else if relative_performance < 0.8 {
778            0.6
779        } else {
780            0.3
781        };
782
783        ComparativeAnalysis {
784            relative_performance,
785            rank_among_layers: rank,
786            similar_layers,
787            performance_gap,
788            optimization_potential,
789        }
790    }
791
792    fn analyze_network_level_gradients(
793        &self,
794        layer_details: &HashMap<String, LayerGradientDetails>,
795    ) -> NetworkLevelAnalysis {
796        let overall_gradient_health = self.assess_overall_health(layer_details);
797        let gradient_distribution = self.analyze_gradient_distribution(layer_details);
798        let layer_interactions = self.analyze_layer_interactions(layer_details);
799        let convergence_indicators = self.analyze_convergence_indicators(layer_details);
800        let training_dynamics = self.analyze_training_dynamics(layer_details);
801        let stability_assessment = self.assess_network_stability(layer_details);
802
803        NetworkLevelAnalysis {
804            overall_gradient_health,
805            gradient_distribution,
806            layer_interactions,
807            convergence_indicators,
808            training_dynamics,
809            stability_assessment,
810        }
811    }
812
813    fn assess_overall_health(
814        &self,
815        layer_details: &HashMap<String, LayerGradientDetails>,
816    ) -> LayerHealth {
817        let health_counts = layer_details
818            .values()
819            .map(|details| &details.health_metrics.overall_health)
820            .fold([0, 0, 0], |mut acc, health| {
821                match health {
822                    LayerHealth::Healthy => acc[0] += 1,
823                    LayerHealth::Warning => acc[1] += 1,
824                    LayerHealth::Critical => acc[2] += 1,
825                    LayerHealth::Unknown => {}, // Ignore unknown health status
826                }
827                acc
828            });
829
830        let total = health_counts.iter().sum::<usize>();
831        if total == 0 {
832            return LayerHealth::Healthy;
833        }
834
835        let critical_ratio = health_counts[2] as f64 / total as f64;
836        let warning_ratio = health_counts[1] as f64 / total as f64;
837
838        if critical_ratio > 0.3 {
839            LayerHealth::Critical
840        } else if critical_ratio > 0.1 || warning_ratio > 0.5 {
841            LayerHealth::Warning
842        } else {
843            LayerHealth::Healthy
844        }
845    }
846
847    fn analyze_gradient_distribution(
848        &self,
849        layer_details: &HashMap<String, LayerGradientDetails>,
850    ) -> GradientDistribution {
851        let gradient_means: Vec<f64> =
852            layer_details.values().map(|details| details.gradient_statistics.mean).collect();
853
854        if gradient_means.is_empty() {
855            return GradientDistribution {
856                mean_gradient_norm: 0.0,
857                gradient_variance: 0.0,
858                gradient_skewness: 0.0,
859                gradient_kurtosis: 0.0,
860                layer_gradient_ratios: HashMap::new(),
861                distribution_type: DistributionType::Degenerate,
862            };
863        }
864
865        let n = gradient_means.len() as f64;
866        let mean_gradient_norm = gradient_means.iter().sum::<f64>() / n;
867        let gradient_variance =
868            gradient_means.iter().map(|&x| (x - mean_gradient_norm).powi(2)).sum::<f64>() / n;
869
870        let std_dev = gradient_variance.sqrt();
871        let gradient_skewness = if std_dev > 0.0 {
872            gradient_means
873                .iter()
874                .map(|&x| ((x - mean_gradient_norm) / std_dev).powi(3))
875                .sum::<f64>()
876                / n
877        } else {
878            0.0
879        };
880
881        let gradient_kurtosis = if std_dev > 0.0 {
882            gradient_means
883                .iter()
884                .map(|&x| ((x - mean_gradient_norm) / std_dev).powi(4))
885                .sum::<f64>()
886                / n
887                - 3.0
888        } else {
889            0.0
890        };
891
892        let mut layer_gradient_ratios = HashMap::new();
893        for (layer_name, details) in layer_details {
894            let ratio = if mean_gradient_norm > 0.0 {
895                details.gradient_statistics.mean / mean_gradient_norm
896            } else {
897                1.0
898            };
899            layer_gradient_ratios.insert(layer_name.clone(), ratio);
900        }
901
902        let distribution_type =
903            self.classify_distribution_type(gradient_skewness, gradient_kurtosis);
904
905        GradientDistribution {
906            mean_gradient_norm,
907            gradient_variance,
908            gradient_skewness,
909            gradient_kurtosis,
910            layer_gradient_ratios,
911            distribution_type,
912        }
913    }
914
915    fn classify_distribution_type(&self, skewness: f64, kurtosis: f64) -> DistributionType {
916        if skewness.abs() > 2.0 {
917            DistributionType::Skewed
918        } else if kurtosis > 3.0 {
919            DistributionType::HeavyTailed
920        } else if kurtosis < -1.0 {
921            DistributionType::Multimodal
922        } else {
923            DistributionType::Normal
924        }
925    }
926
927    fn analyze_layer_interactions(
928        &self,
929        layer_details: &HashMap<String, LayerGradientDetails>,
930    ) -> Vec<LayerInteraction> {
931        let mut interactions = Vec::new();
932
933        let layer_names: Vec<String> = layer_details.keys().cloned().collect();
934        for i in 0..layer_names.len() {
935            for j in (i + 1)..layer_names.len() {
936                let layer1 = &layer_names[i];
937                let layer2 = &layer_names[j];
938
939                if let (Some(details1), Some(details2)) =
940                    (layer_details.get(layer1), layer_details.get(layer2))
941                {
942                    let interaction_strength =
943                        self.compute_interaction_strength(details1, details2);
944                    let interaction_type = self.classify_interaction_type(details1, details2);
945                    let impact_score = interaction_strength * 0.5; // Simplified impact calculation
946
947                    interactions.push(LayerInteraction {
948                        layer1: layer1.clone(),
949                        layer2: layer2.clone(),
950                        interaction_strength,
951                        interaction_type,
952                        impact_score,
953                    });
954                }
955            }
956        }
957
958        interactions
959    }
960
961    fn compute_interaction_strength(
962        &self,
963        details1: &LayerGradientDetails,
964        details2: &LayerGradientDetails,
965    ) -> f64 {
966        let mean_diff =
967            (details1.gradient_statistics.mean - details2.gradient_statistics.mean).abs();
968        let stability_diff = (details1.flow_characteristics.stability_measure
969            - details2.flow_characteristics.stability_measure)
970            .abs();
971
972        // Interaction strength is inversely related to differences
973        let combined_diff = mean_diff + stability_diff;
974        1.0 / (1.0 + combined_diff)
975    }
976
977    fn classify_interaction_type(
978        &self,
979        details1: &LayerGradientDetails,
980        details2: &LayerGradientDetails,
981    ) -> InteractionType {
982        let convergence_diff = (details1.health_metrics.convergence_indicator
983            - details2.health_metrics.convergence_indicator)
984            .abs();
985
986        if convergence_diff < 0.1 {
987            InteractionType::Cooperative
988        } else if convergence_diff > 0.5 {
989            InteractionType::Competitive
990        } else {
991            InteractionType::Neutral
992        }
993    }
994
995    fn analyze_convergence_indicators(
996        &self,
997        layer_details: &HashMap<String, LayerGradientDetails>,
998    ) -> ConvergenceIndicators {
999        let convergence_scores: Vec<f64> = layer_details
1000            .values()
1001            .map(|details| details.health_metrics.convergence_indicator)
1002            .collect();
1003
1004        let gradient_convergence_score =
1005            convergence_scores.iter().sum::<f64>() / convergence_scores.len().max(1) as f64;
1006        let parameter_convergence_score = gradient_convergence_score * 0.8; // Simplified
1007        let loss_convergence_score = gradient_convergence_score * 0.9; // Simplified
1008
1009        let convergence_trend = if gradient_convergence_score > 0.8 {
1010            ConvergenceTrend::Converging
1011        } else if gradient_convergence_score > 0.6 {
1012            ConvergenceTrend::Stable
1013        } else if gradient_convergence_score < 0.3 {
1014            ConvergenceTrend::Diverging
1015        } else {
1016            ConvergenceTrend::Unknown
1017        };
1018
1019        let estimated_steps_to_convergence = if gradient_convergence_score > 0.1 {
1020            Some(((1.0 - gradient_convergence_score) * 1000.0) as usize)
1021        } else {
1022            None
1023        };
1024
1025        ConvergenceIndicators {
1026            gradient_convergence_score,
1027            parameter_convergence_score,
1028            loss_convergence_score,
1029            convergence_trend,
1030            estimated_steps_to_convergence,
1031        }
1032    }
1033
1034    fn analyze_training_dynamics(
1035        &self,
1036        layer_details: &HashMap<String, LayerGradientDetails>,
1037    ) -> TrainingDynamics {
1038        let avg_convergence = layer_details
1039            .values()
1040            .map(|details| details.health_metrics.convergence_indicator)
1041            .sum::<f64>()
1042            / layer_details.len().max(1) as f64;
1043
1044        let learning_phase = match avg_convergence {
1045            x if x < 0.2 => LearningPhase::InitialLearning,
1046            x if x < 0.4 => LearningPhase::RapidLearning,
1047            x if x < 0.6 => LearningPhase::Refinement,
1048            x if x < 0.8 => LearningPhase::Convergence,
1049            _ => LearningPhase::Plateau,
1050        };
1051
1052        let gradient_momentum = avg_convergence * 0.8; // Simplified
1053        let learning_velocity = avg_convergence * 1.2; // Simplified
1054        let adaptation_rate = 1.0 - avg_convergence; // Simplified
1055
1056        let plateau_detection = PlateauDetection {
1057            is_plateau: avg_convergence > 0.9,
1058            plateau_duration: if avg_convergence > 0.9 { 10 } else { 0 },
1059            plateau_severity: if avg_convergence > 0.95 {
1060                PlateauSeverity::Severe
1061            } else {
1062                PlateauSeverity::Mild
1063            },
1064            suggested_actions: if avg_convergence > 0.9 {
1065                vec![
1066                    "Consider learning rate reduction".to_string(),
1067                    "Add regularization".to_string(),
1068                ]
1069            } else {
1070                vec![]
1071            },
1072        };
1073
1074        TrainingDynamics {
1075            learning_phase,
1076            gradient_momentum,
1077            learning_velocity,
1078            adaptation_rate,
1079            plateau_detection,
1080        }
1081    }
1082
1083    fn assess_network_stability(
1084        &self,
1085        layer_details: &HashMap<String, LayerGradientDetails>,
1086    ) -> StabilityAssessment {
1087        let stability_scores: Vec<f64> = layer_details
1088            .values()
1089            .map(|details| details.flow_characteristics.stability_measure)
1090            .collect();
1091
1092        let overall_stability =
1093            stability_scores.iter().sum::<f64>() / stability_scores.len().max(1) as f64;
1094
1095        let stability_trend = if overall_stability > self.stability_threshold {
1096            StabilityTrend::Stable
1097        } else {
1098            StabilityTrend::Degrading
1099        };
1100
1101        let instability_sources = self.identify_instability_sources(layer_details);
1102
1103        let stability_forecast = StabilityForecast {
1104            short_term_outlook: if overall_stability > 0.7 {
1105                StabilityOutlook::Stable
1106            } else {
1107                StabilityOutlook::Deteriorating
1108            },
1109            long_term_outlook: if overall_stability > 0.8 {
1110                StabilityOutlook::Stable
1111            } else {
1112                StabilityOutlook::Uncertain
1113            },
1114            confidence_level: overall_stability,
1115            recommended_monitoring: vec![
1116                "Monitor gradient norms".to_string(),
1117                "Track convergence indicators".to_string(),
1118            ],
1119        };
1120
1121        StabilityAssessment {
1122            overall_stability,
1123            stability_trend,
1124            instability_sources,
1125            stability_forecast,
1126        }
1127    }
1128
1129    fn identify_instability_sources(
1130        &self,
1131        layer_details: &HashMap<String, LayerGradientDetails>,
1132    ) -> Vec<InstabilitySource> {
1133        let mut sources = Vec::new();
1134
1135        for (layer_name, details) in layer_details {
1136            if details.gradient_statistics.mean > 100.0 {
1137                sources.push(InstabilitySource {
1138                    source_type: InstabilityType::GradientExplosion,
1139                    affected_layers: vec![layer_name.clone()],
1140                    severity: details.gradient_statistics.mean / 100.0,
1141                    description: format!("High gradient magnitude in layer {}", layer_name),
1142                });
1143            }
1144
1145            if details.gradient_statistics.mean < 1e-5 {
1146                sources.push(InstabilitySource {
1147                    source_type: InstabilityType::GradientVanishing,
1148                    affected_layers: vec![layer_name.clone()],
1149                    severity: 1.0 - (details.gradient_statistics.mean * 1e5),
1150                    description: format!("Very low gradient magnitude in layer {}", layer_name),
1151                });
1152            }
1153
1154            if details.flow_characteristics.oscillation_frequency > 0.5 {
1155                sources.push(InstabilitySource {
1156                    source_type: InstabilityType::Oscillation,
1157                    affected_layers: vec![layer_name.clone()],
1158                    severity: details.flow_characteristics.oscillation_frequency,
1159                    description: format!("High oscillation frequency in layer {}", layer_name),
1160                });
1161            }
1162        }
1163
1164        sources
1165    }
1166
1167    fn build_gradient_hierarchy(
1168        &self,
1169        layer_details: &HashMap<String, LayerGradientDetails>,
1170    ) -> GradientHierarchy {
1171        // Simplified hierarchy building - group layers by similar characteristics
1172        let mut layer_groups = Vec::new();
1173        let mut hierarchy_levels = Vec::new();
1174        let cross_level_interactions = Vec::new(); // Simplified - would compute actual interactions
1175
1176        // Group by gradient magnitude ranges
1177        let high_gradient_layers: Vec<String> = layer_details
1178            .iter()
1179            .filter(|(_, details)| details.gradient_statistics.mean > 1.0)
1180            .map(|(name, _)| name.clone())
1181            .collect();
1182
1183        let medium_gradient_layers: Vec<String> = layer_details
1184            .iter()
1185            .filter(|(_, details)| {
1186                details.gradient_statistics.mean >= 0.1 && details.gradient_statistics.mean <= 1.0
1187            })
1188            .map(|(name, _)| name.clone())
1189            .collect();
1190
1191        let low_gradient_layers: Vec<String> = layer_details
1192            .iter()
1193            .filter(|(_, details)| details.gradient_statistics.mean < 0.1)
1194            .map(|(name, _)| name.clone())
1195            .collect();
1196
1197        if !high_gradient_layers.is_empty() {
1198            layer_groups.push(LayerGroup {
1199                group_name: "High Gradient Layers".to_string(),
1200                layers: high_gradient_layers.clone(),
1201                group_characteristics: GroupCharacteristics {
1202                    average_gradient_norm: 2.0, // Simplified
1203                    gradient_synchronization: 0.8,
1204                    learning_rate_sensitivity: 0.9,
1205                    optimization_difficulty: OptimizationDifficulty::Difficult,
1206                },
1207                internal_coherence: 0.7,
1208            });
1209
1210            hierarchy_levels.push(HierarchyLevel {
1211                level_id: 0,
1212                level_name: "High Gradient Level".to_string(),
1213                layer_groups: vec!["High Gradient Layers".to_string()],
1214                level_importance: 0.9,
1215                optimization_impact: 0.8,
1216            });
1217        }
1218
1219        if !medium_gradient_layers.is_empty() {
1220            layer_groups.push(LayerGroup {
1221                group_name: "Medium Gradient Layers".to_string(),
1222                layers: medium_gradient_layers,
1223                group_characteristics: GroupCharacteristics {
1224                    average_gradient_norm: 0.5,
1225                    gradient_synchronization: 0.6,
1226                    learning_rate_sensitivity: 0.5,
1227                    optimization_difficulty: OptimizationDifficulty::Moderate,
1228                },
1229                internal_coherence: 0.8,
1230            });
1231
1232            hierarchy_levels.push(HierarchyLevel {
1233                level_id: 1,
1234                level_name: "Medium Gradient Level".to_string(),
1235                layer_groups: vec!["Medium Gradient Layers".to_string()],
1236                level_importance: 0.7,
1237                optimization_impact: 0.6,
1238            });
1239        }
1240
1241        if !low_gradient_layers.is_empty() {
1242            layer_groups.push(LayerGroup {
1243                group_name: "Low Gradient Layers".to_string(),
1244                layers: low_gradient_layers,
1245                group_characteristics: GroupCharacteristics {
1246                    average_gradient_norm: 0.05,
1247                    gradient_synchronization: 0.4,
1248                    learning_rate_sensitivity: 0.3,
1249                    optimization_difficulty: OptimizationDifficulty::Easy,
1250                },
1251                internal_coherence: 0.5,
1252            });
1253
1254            hierarchy_levels.push(HierarchyLevel {
1255                level_id: 2,
1256                level_name: "Low Gradient Level".to_string(),
1257                layer_groups: vec!["Low Gradient Layers".to_string()],
1258                level_importance: 0.5,
1259                optimization_impact: 0.4,
1260            });
1261        }
1262
1263        GradientHierarchy {
1264            layer_groups,
1265            hierarchy_levels,
1266            cross_level_interactions,
1267        }
1268    }
1269
1270    fn rank_optimization_priorities(
1271        &self,
1272        layer_details: &HashMap<String, LayerGradientDetails>,
1273        network_analysis: &NetworkLevelAnalysis,
1274    ) -> Vec<OptimizationPriority> {
1275        let mut priorities = Vec::new();
1276
1277        for (layer_name, details) in layer_details {
1278            let priority_score = self.calculate_priority_score(details, network_analysis);
1279            let urgency_level = self.determine_urgency_level(details);
1280            let optimization_potential = details.comparative_analysis.optimization_potential;
1281            let recommended_actions = self.generate_prioritized_actions(details);
1282
1283            priorities.push(OptimizationPriority {
1284                target_name: layer_name.clone(),
1285                target_type: OptimizationTarget::IndividualLayer,
1286                priority_score,
1287                urgency_level,
1288                optimization_potential,
1289                recommended_actions,
1290            });
1291        }
1292
1293        // Sort by priority score
1294        priorities.sort_by(|a, b| {
1295            b.priority_score
1296                .partial_cmp(&a.priority_score)
1297                .unwrap_or(std::cmp::Ordering::Equal)
1298        });
1299
1300        priorities
1301    }
1302
1303    fn calculate_priority_score(
1304        &self,
1305        details: &LayerGradientDetails,
1306        network_analysis: &NetworkLevelAnalysis,
1307    ) -> f64 {
1308        let health_weight = match details.health_metrics.overall_health {
1309            LayerHealth::Critical => 1.0,
1310            LayerHealth::Warning => 0.7,
1311            LayerHealth::Healthy => 0.3,
1312            LayerHealth::Unknown => 0.5, // Default moderate weight for unknown health
1313        };
1314
1315        let stability_weight = 1.0 - details.flow_characteristics.stability_measure;
1316        let optimization_weight = details.comparative_analysis.optimization_potential;
1317        let network_impact_weight = details.health_metrics.information_flow_rate
1318            / network_analysis.gradient_distribution.mean_gradient_norm.max(1e-8);
1319
1320        (health_weight * 0.4
1321            + stability_weight * 0.3
1322            + optimization_weight * 0.2
1323            + network_impact_weight * 0.1)
1324            .min(1.0)
1325    }
1326
1327    fn determine_urgency_level(&self, details: &LayerGradientDetails) -> UrgencyLevel {
1328        match details.health_metrics.overall_health {
1329            LayerHealth::Critical => UrgencyLevel::Critical,
1330            LayerHealth::Warning => {
1331                if details.flow_characteristics.stability_measure < 0.3 {
1332                    UrgencyLevel::High
1333                } else {
1334                    UrgencyLevel::Medium
1335                }
1336            },
1337            LayerHealth::Healthy => UrgencyLevel::Low,
1338            LayerHealth::Unknown => UrgencyLevel::Medium, // Default moderate urgency for unknown health
1339        }
1340    }
1341
1342    fn generate_prioritized_actions(
1343        &self,
1344        details: &LayerGradientDetails,
1345    ) -> Vec<PrioritizedAction> {
1346        let mut actions = Vec::new();
1347
1348        if details.gradient_statistics.mean < 1e-5 {
1349            actions.push(PrioritizedAction {
1350                action_name: "Weight Initialization Improvement".to_string(),
1351                action_type: ActionType::ParameterAdjustment,
1352                expected_impact: 0.8,
1353                implementation_effort: ImplementationEffort::Moderate,
1354                prerequisites: vec!["Model architecture review".to_string()],
1355            });
1356        }
1357
1358        if details.gradient_statistics.mean > 10.0 {
1359            actions.push(PrioritizedAction {
1360                action_name: "Learning Rate Reduction".to_string(),
1361                action_type: ActionType::LearningRateScheduling,
1362                expected_impact: 0.7,
1363                implementation_effort: ImplementationEffort::Minimal,
1364                prerequisites: vec![],
1365            });
1366        }
1367
1368        if details.flow_characteristics.stability_measure < 0.5 {
1369            actions.push(PrioritizedAction {
1370                action_name: "Gradient Clipping".to_string(),
1371                action_type: ActionType::OptimizationTechnique,
1372                expected_impact: 0.6,
1373                implementation_effort: ImplementationEffort::Low,
1374                prerequisites: vec!["Hyperparameter tuning".to_string()],
1375            });
1376        }
1377
1378        actions
1379    }
1380
1381    /// Analyze gradients and generate enhanced analysis results
1382    pub fn analyze_gradients(
1383        &self,
1384        gradient_histories: &HashMap<String, GradientHistory>,
1385    ) -> EnhancedLayerGradientAnalysis {
1386        // Use existing method to generate the analysis
1387        self.generate_enhanced_analysis(gradient_histories)
1388    }
1389}