Skip to main content

agentic_evolve_core/optimization/
optimizer.rs

1//! PatternOptimizer — optimizes pattern storage by deduplication and pruning.
2
3use crate::types::pattern::Pattern;
4
5/// Result of optimization.
6#[derive(Debug, Clone)]
7pub struct OptimizationReport {
8    pub patterns_before: usize,
9    pub patterns_after: usize,
10    pub duplicates_removed: usize,
11    pub pruned: usize,
12    pub merged: usize,
13    pub bytes_saved: usize,
14}
15
16/// Optimizes pattern storage.
17#[derive(Debug, Default)]
18pub struct PatternOptimizer;
19
20impl PatternOptimizer {
21    pub fn new() -> Self {
22        Self
23    }
24
25    pub fn find_duplicates(&self, patterns: &[&Pattern]) -> Vec<(String, String)> {
26        let mut duplicates = Vec::new();
27        for i in 0..patterns.len() {
28            for j in (i + 1)..patterns.len() {
29                if patterns[i].content_hash == patterns[j].content_hash {
30                    duplicates.push((
31                        patterns[i].id.as_str().to_string(),
32                        patterns[j].id.as_str().to_string(),
33                    ));
34                }
35            }
36        }
37        duplicates
38    }
39
40    pub fn find_similar(
41        &self,
42        patterns: &[&Pattern],
43        threshold: f64,
44    ) -> Vec<(String, String, f64)> {
45        let mut similar = Vec::new();
46        for i in 0..patterns.len() {
47            for j in (i + 1)..patterns.len() {
48                let sim = template_similarity(&patterns[i].template, &patterns[j].template);
49                if sim >= threshold && patterns[i].content_hash != patterns[j].content_hash {
50                    similar.push((
51                        patterns[i].id.as_str().to_string(),
52                        patterns[j].id.as_str().to_string(),
53                        sim,
54                    ));
55                }
56            }
57        }
58        similar
59    }
60
61    pub fn suggest_pruning(
62        &self,
63        patterns: &[&Pattern],
64        min_confidence: f64,
65        min_uses: u64,
66    ) -> Vec<String> {
67        patterns
68            .iter()
69            .filter(|p| p.confidence < min_confidence && p.usage_count < min_uses)
70            .map(|p| p.id.as_str().to_string())
71            .collect()
72    }
73
74    pub fn optimize_report(&self, patterns: &[&Pattern]) -> OptimizationReport {
75        let duplicates = self.find_duplicates(patterns);
76        let prunable = self.suggest_pruning(patterns, 0.2, 2);
77
78        OptimizationReport {
79            patterns_before: patterns.len(),
80            patterns_after: patterns.len() - duplicates.len() - prunable.len(),
81            duplicates_removed: duplicates.len(),
82            pruned: prunable.len(),
83            merged: 0,
84            bytes_saved: (duplicates.len() + prunable.len()) * 1024, // Estimate
85        }
86    }
87}
88
89fn template_similarity(a: &str, b: &str) -> f64 {
90    let a_lines: Vec<&str> = a.lines().collect();
91    let b_lines: Vec<&str> = b.lines().collect();
92    let max_lines = a_lines.len().max(b_lines.len());
93    if max_lines == 0 {
94        return 1.0;
95    }
96    let matching = a_lines
97        .iter()
98        .zip(b_lines.iter())
99        .filter(|(a, b)| a.trim() == b.trim())
100        .count();
101    matching as f64 / max_lines as f64
102}