Skip to main content

benchmark/
benchmark.rs

1/// Benchmark example to demonstrate optimization improvements
2use rust_lstar::knowledge_base::{KnowledgeBaseStats, KnowledgeBaseTrait};
3use rust_lstar::query::OutputQuery;
4use rust_lstar::*;
5use std::collections::HashMap;
6use std::sync::{Arc, Mutex};
7use std::time::Instant;
8
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    println!("=== Performance Benchmark ===\n");
11
12    // Create a more complex system to test performance
13    let mut kb = BenchmarkKnowledgeBase::new();
14
15    // Define a 4-state machine with 3 input symbols
16    // This creates a more complex learning scenario
17    kb.add_transition("s0", "a", "0", "s1");
18    kb.add_transition("s0", "b", "1", "s2");
19    kb.add_transition("s0", "c", "0", "s0");
20    
21    kb.add_transition("s1", "a", "1", "s2");
22    kb.add_transition("s1", "b", "0", "s3");
23    kb.add_transition("s1", "c", "1", "s1");
24    
25    kb.add_transition("s2", "a", "0", "s3");
26    kb.add_transition("s2", "b", "1", "s0");
27    kb.add_transition("s2", "c", "0", "s2");
28    
29    kb.add_transition("s3", "a", "1", "s0");
30    kb.add_transition("s3", "b", "0", "s1");
31    kb.add_transition("s3", "c", "1", "s3");
32
33    let knowledge_base = Arc::new(Mutex::new(kb));
34    let vocabulary = vec!["a".to_string(), "b".to_string(), "c".to_string()];
35
36    println!("Learning 4-state automaton with 3-symbol alphabet...\n");
37    
38    let start = Instant::now();
39    let mut lstar = LSTAR::new(vocabulary, knowledge_base.clone(), 6, None, None);
40    let automata = lstar.learn()?;
41    let duration = start.elapsed();
42
43    println!("\n=== Results ===" );
44    println!("Learning time: {:.2?}", duration);
45    println!("States learned: {}", automata.get_states().len());
46    println!("Transitions: {}", automata.transitions.len());
47    
48    let kb_guard = knowledge_base.lock().unwrap();
49    println!("\nQuery Statistics:");
50    println!("  Total queries: {}", kb_guard.stats.nb_query());
51    println!("  Total letters processed: {}", kb_guard.stats.nb_letter());
52    println!("  Avg letters per query: {:.2}", 
53        kb_guard.stats.nb_letter() as f64 / kb_guard.stats.nb_query() as f64);
54
55    println!("\n=== Optimization Benefits ===");
56    println!("✓ Cached transition index: Fast automata playback");
57    println!("✓ SmallVec: Reduced allocations for short words");
58    println!("✓ Enum Letter: Optimized single-symbol storage");
59    println!("✓ HashSet dedup: O(1) query deduplication");
60    println!("✓ Pre-allocated collections: Fewer reallocations");
61
62    Ok(())
63}
64
65struct BenchmarkKnowledgeBase {
66    transitions: HashMap<(String, String), (String, String)>,
67    current_state: String,
68    stats: KnowledgeBaseStats,
69}
70
71impl BenchmarkKnowledgeBase {
72    fn new() -> Self {
73        Self {
74            transitions: HashMap::new(),
75            current_state: "s0".to_string(),
76            stats: KnowledgeBaseStats::new(),
77        }
78    }
79
80    fn add_transition(&mut self, from_state: &str, input: &str, output: &str, to_state: &str) {
81        self.transitions.insert(
82            (from_state.to_string(), input.to_string()),
83            (output.to_string(), to_state.to_string()),
84        );
85    }
86}
87
88impl KnowledgeBaseTrait for BenchmarkKnowledgeBase {
89    fn resolve_query(&mut self, query: &mut OutputQuery) -> Result<(), String> {
90        self.stats.increment_nb_query();
91        self.stats.add_nb_letter(query.input_word.len());
92        self.stats.increment_nb_submitted_query();
93        self.stats.add_nb_submitted_letter(query.input_word.len());
94
95        self.current_state = "s0".to_string();
96        let mut output_letters = Vec::new();
97
98        for input_letter in query.input_word.letters() {
99            let input = input_letter.symbols();
100            let key = (self.current_state.clone(), input);
101            let (output, next_state) = self
102                .transitions
103                .get(&key)
104                .cloned()
105                .ok_or_else(|| format!("No transition for ({}, {})", key.0, key.1))?;
106
107            output_letters.push(Letter::new(output));
108            self.current_state = next_state;
109        }
110
111        query.set_result(Word::from_letters(output_letters));
112        Ok(())
113    }
114
115    fn add_word(&mut self, _input_word: &Word, _output_word: &Word) -> Result<(), String> {
116        Ok(())
117    }
118}