ruvector_memopt/neural/
engine.rs1use std::path::Path;
4use chrono::{Datelike, Timelike};
5use tracing::{debug, info};
6
7use crate::core::config::OptimizerConfig;
8use crate::core::optimizer::OptimizationDecision;
9use crate::core::patterns::{MemoryPattern, LabeledPattern};
10use crate::windows::memory::{MemoryStatus, OptimizationResult};
11
12use super::hnsw_patterns::PatternIndex;
13use super::ewc_learner::EWCLearner;
14use super::attention::AttentionScorer;
15
16pub struct NeuralDecisionEngine {
17 pattern_index: PatternIndex,
18 attention: AttentionScorer,
19 ewc: EWCLearner,
20 config: OptimizerConfig,
21 history: Vec<LabeledPattern>,
22}
23
24impl NeuralDecisionEngine {
25 pub fn new(config: &OptimizerConfig) -> Result<Self, String> {
26 let pattern_index = PatternIndex::new(MemoryPattern::DIM)
27 .map_err(|e| format!("Failed to create pattern index: {}", e))?;
28 let attention = AttentionScorer::new();
29 let ewc = EWCLearner::new(config.ewc_lambda);
30 let history = Self::load_history(&config.model_path).unwrap_or_default();
31 info!("Neural engine initialized with {} historical patterns", history.len());
32 Ok(Self { pattern_index, attention, ewc, config: config.clone(), history })
33 }
34
35 pub async fn decide(&self, pattern: &MemoryPattern, status: &MemoryStatus) -> Result<OptimizationDecision, String> {
36 let pattern_vec = pattern.to_vector();
37 let similar = self.pattern_index.search(&pattern_vec, 5)?;
38 let (_, base_confidence) = self.analyze_similar_patterns(&similar);
39 let attention_score = self.attention.score(pattern, status);
40 let ewc_adjustment = self.ewc.get_confidence_adjustment(pattern);
41 let final_confidence = (base_confidence * 0.5 + attention_score * 0.3 + ewc_adjustment * 0.2).clamp(0.0, 1.0);
42 let should_optimize = status.memory_load_percent >= self.config.pressure_threshold || final_confidence > 0.7;
43 let aggressive = status.memory_load_percent >= self.config.critical_threshold || (should_optimize && final_confidence > 0.9);
44 let reason = format!("Neural: conf={:.2}, attn={:.2}, similar={}", final_confidence, attention_score, similar.len());
45 debug!("{}", reason);
46 Ok(OptimizationDecision { should_optimize, aggressive, confidence: final_confidence, reason, target_processes: vec![] })
47 }
48
49 fn analyze_similar_patterns(&self, similar: &[(usize, f32)]) -> (bool, f32) {
50 if similar.is_empty() { return (false, 0.5); }
51 let mut success_weight = 0.0f32;
52 let mut total_weight = 0.0f32;
53 for (idx, similarity) in similar {
54 if let Some(labeled) = self.history.get(*idx) {
55 if labeled.success { success_weight += similarity; }
56 total_weight += similarity;
57 }
58 }
59 if total_weight > 0.0 { (success_weight / total_weight > 0.5, success_weight / total_weight) } else { (false, 0.5) }
60 }
61
62 pub async fn learn_from_result(&mut self, decision: &OptimizationDecision, result: &OptimizationResult, success: bool) {
63 let now = chrono::Local::now();
64 let pattern = LabeledPattern {
65 pattern: MemoryPattern {
66 load: (result.before_available_mb / 100.0) as f32,
67 consumption_rate: 0.0,
68 available_ratio: (result.before_available_mb / 32000.0) as f32,
69 page_file_ratio: 0.0,
70 process_count: result.processes_trimmed as u32,
71 hour: now.hour() as u8,
72 day_of_week: now.weekday().num_days_from_monday() as u8,
73 time_since_last_opt: 0.0,
74 },
75 optimized: true,
76 aggressive: decision.aggressive,
77 freed_mb: result.freed_mb as f32,
78 success,
79 };
80 let vec = pattern.pattern.to_vector();
81 let _ = self.pattern_index.add(&vec);
82 self.ewc.update(&pattern);
83 self.history.push(pattern);
84 if self.history.len() % 100 == 0 { let _ = self.save_history(&self.config.model_path); }
85 info!("Learned: success={}, freed={:.1}MB", success, result.freed_mb);
86 }
87
88 fn load_history(path: &Path) -> Result<Vec<LabeledPattern>, String> {
89 let file_path = path.join("patterns.json");
90 if !file_path.exists() { return Ok(vec![]); }
91 let content = std::fs::read_to_string(&file_path).map_err(|e| e.to_string())?;
92 serde_json::from_str(&content).map_err(|e| e.to_string())
93 }
94
95 fn save_history(&self, path: &Path) -> Result<(), String> {
96 std::fs::create_dir_all(path).map_err(|e| e.to_string())?;
97 let content = serde_json::to_string_pretty(&self.history).map_err(|e| e.to_string())?;
98 std::fs::write(path.join("patterns.json"), content).map_err(|e| e.to_string())
99 }
100
101 pub fn pattern_count(&self) -> usize { self.history.len() }
102}