use crate::ml_analyzer::{MLAnalyzer, MLPrediction};
use crate::ml_metrics::ModelMetrics;
use crate::behavioral::{AccessEvent, Anomaly};
use chrono::{DateTime, Utc, Duration};
use serde::Serialize;
use std::collections::VecDeque;
use crate::model_optimizer::{OptimizationConfig, OptimizationResult};
#[derive(Debug)]
pub struct AdaptiveAnalyzer {
ml_analyzer: MLAnalyzer,
config: AdaptiveConfig,
performance_history: VecDeque<ModelMetrics>,
retraining_schedule: RetrainingSchedule,
}
#[derive(Clone)]
pub struct AdaptiveConfig {
pub performance_window_size: usize,
pub min_performance_threshold: f64,
pub max_history_size: usize,
pub auto_retrain: bool,
}
#[derive(Debug, Serialize)]
pub struct AdaptiveMetrics {
pub current_performance: ModelMetrics,
pub performance_trend: PerformanceTrend,
pub last_retrain: DateTime<Utc>,
pub model_health: ModelHealth,
}
#[derive(Debug, Serialize)]
pub enum PerformanceTrend {
Improving,
Stable,
Degrading,
}
#[derive(Debug, Serialize)]
pub enum ModelHealth {
Healthy,
NeedsAttention,
Critical,
}
struct RetrainingSchedule {
last_retrain: DateTime<Utc>,
next_scheduled: DateTime<Utc>,
performance_threshold: f64,
}
impl AdaptiveAnalyzer {
pub fn new(config: AdaptiveConfig) -> Self {
Self {
ml_analyzer: MLAnalyzer::new(),
config,
performance_history: VecDeque::with_capacity(config.max_history_size),
retraining_schedule: RetrainingSchedule {
last_retrain: Utc::now(),
next_scheduled: Utc::now() + Duration::hours(24),
performance_threshold: config.min_performance_threshold,
},
}
}
pub fn analyze(&mut self, event: &AccessEvent) -> Option<AdaptivePrediction> {
let prediction = self.ml_analyzer.predict(event)?;
let model_health = self.check_model_health();
if matches!(model_health, ModelHealth::Critical) && self.config.auto_retrain {
self.schedule_retraining();
}
Some(AdaptivePrediction {
base_prediction: prediction,
confidence_adjustment: self.calculate_confidence_adjustment(),
model_health,
})
}
pub fn update_model(&mut self, events: &[AccessEvent], anomalies: &[Anomaly]) -> Option<AdaptiveMetrics> {
let metrics = self.ml_analyzer.update_model(events, anomalies)?;
self.update_performance_history(metrics.clone());
Some(AdaptiveMetrics {
current_performance: metrics,
performance_trend: self.calculate_performance_trend(),
last_retrain: self.retraining_schedule.last_retrain,
model_health: self.check_model_health(),
})
}
fn update_performance_history(&mut self, metrics: ModelMetrics) {
if self.performance_history.len() >= self.config.max_history_size {
self.performance_history.pop_front();
}
self.performance_history.push_back(metrics);
}
fn calculate_performance_trend(&self) -> PerformanceTrend {
if self.performance_history.len() < 2 {
return PerformanceTrend::Stable;
}
let recent_performances: Vec<f64> = self.performance_history
.iter()
.rev()
.take(self.config.performance_window_size)
.map(|m| m.f1_score)
.collect();
if recent_performances.len() < 2 {
return PerformanceTrend::Stable;
}
let trend = recent_performances.windows(2)
.map(|w| w[1] - w[0])
.sum::<f64>();
match trend {
t if t > 0.05 => PerformanceTrend::Improving,
t if t < -0.05 => PerformanceTrend::Degrading,
_ => PerformanceTrend::Stable,
}
}
fn check_model_health(&self) -> ModelHealth {
if let Some(latest) = self.performance_history.back() {
let f1_score = latest.f1_score;
match f1_score {
score if score >= 0.8 => ModelHealth::Healthy,
score if score >= 0.6 => ModelHealth::NeedsAttention,
_ => ModelHealth::Critical,
}
} else {
ModelHealth::NeedsAttention
}
}
fn calculate_confidence_adjustment(&self) -> f64 {
if let Some(latest) = self.performance_history.back() {
match latest.f1_score {
score if score >= 0.9 => 1.0,
score if score >= 0.7 => 0.8,
score if score >= 0.5 => 0.6,
_ => 0.4,
}
} else {
0.5
}
}
fn schedule_retraining(&mut self) {
self.retraining_schedule.next_scheduled = Utc::now() + Duration::hours(1);
}
pub fn optimize_model(&mut self) -> Option<OptimizationResult> {
let optimizer = ModelOptimizer::new(OptimizationConfig {
learning_rate_range: (0.001, 0.1),
batch_size_range: (16, 128),
max_iterations: 50,
early_stopping_patience: 5,
validation_split: 0.2,
});
if let Some(latest_metrics) = self.performance_history.back() {
let trend = self.calculate_performance_trend();
if let Some(optimal_params) = optimizer.optimize(latest_metrics, &trend) {
self.ml_analyzer.update_parameters(optimal_params.clone());
Some(OptimizationResult {
best_params: optimal_params,
performance_improvement: self.calculate_improvement(),
training_time: std::time::Duration::from_secs(0), optimization_history: Vec::new(), })
} else {
None
}
} else {
None
}
}
fn calculate_improvement(&self) -> f64 {
if self.performance_history.len() < 2 {
return 0.0;
}
let before = self.performance_history
.iter()
.rev()
.nth(1)
.map(|m| m.f1_score)
.unwrap_or(0.0);
let after = self.performance_history
.back()
.map(|m| m.f1_score)
.unwrap_or(0.0);
after - before
}
}
#[derive(Debug, Serialize)]
pub struct AdaptivePrediction {
pub base_prediction: MLPrediction,
pub confidence_adjustment: f64,
pub model_health: ModelHealth,
}