1use rust_lstar::knowledge_base::{KnowledgeBase, KnowledgeBaseStats, KnowledgeBaseTrait};
5use rust_lstar::query::OutputQuery;
6use rust_lstar::*;
7use std::sync::{Arc, Mutex};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11 println!("=== Memory Knowledge Base Learning Example ===\n");
12
13 let input_symbols = vec!["a", "b", "c"];
14 let output_symbols = vec!["0", "1", "2", "3"];
15 let target_state_count = 5;
16 let max_states = 8;
17
18 let target = build_random_machine(target_state_count, &input_symbols, &output_symbols);
19 println!(
20 "Random target generated (states={}, transitions={})",
21 target.get_states().len(),
22 target.transitions.len()
23 );
24
25 let kb = Arc::new(Mutex::new(RandomMachineKnowledgeBase::new(target.clone())));
26 let vocabulary = input_symbols
27 .iter()
28 .map(|symbol| symbol.to_string())
29 .collect::<Vec<_>>();
30
31 let mut learner = LSTAR::new(vocabulary, kb.clone(), max_states, None, None);
32 let learned = learner.learn()?;
33
34 println!("\n=== Learned Automaton ===");
35 println!("{}", learned.build_dot_code());
36
37 let kb_guard = kb.lock().unwrap();
38 println!("\nKnowledge Base Statistics:\n{}", kb_guard.stats());
39
40 Ok(())
41}
42
43struct RandomMachineKnowledgeBase {
45 base: KnowledgeBase,
46 target: Automata,
47}
48
49impl RandomMachineKnowledgeBase {
50 fn new(target: Automata) -> Self {
51 Self {
52 base: KnowledgeBase::new(),
53 target,
54 }
55 }
56
57 fn stats(&self) -> &KnowledgeBaseStats {
58 self.base.stats()
59 }
60
61 fn submit_word_to_target(&mut self, word: &Word) -> Result<Word, String> {
62 if word.is_empty() {
63 return Ok(Word::new());
64 }
65
66 let initial_state = self.target.initial_state.clone();
67 let (output_word, _) = self
68 .target
69 .play_word(word, Some(&initial_state))?;
70 Ok(output_word)
71 }
72}
73
74impl KnowledgeBaseTrait for RandomMachineKnowledgeBase {
75 fn resolve_query(&mut self, query: &mut OutputQuery) -> Result<(), String> {
76 match self.base.resolve_query(query) {
77 Ok(_) => Ok(()),
78 Err(_) => {
79 let output = self.submit_word_to_target(&query.input_word)?;
80 self.base.add_word(&query.input_word, &output)?;
81 query.set_result(output);
82 Ok(())
83 }
84 }
85 }
86
87 fn add_word(&mut self, input_word: &Word, output_word: &Word) -> Result<(), String> {
88 self.base.add_word(input_word, output_word)
89 }
90}
91
92fn build_random_machine(
93 state_count: usize,
94 input_symbols: &[&str],
95 output_symbols: &[&str],
96) -> Automata {
97 let mut rng = SimpleRng::new();
98 let mut automata = Automata::new(State::new("S0".to_string()), "RandomTarget".to_string());
99 let mut transitions = Vec::new();
100 let mut transition_id = 0usize;
101
102 for state_idx in 0..state_count {
103 let source_state = format!("S{}", state_idx);
104 for input_symbol in input_symbols {
105 let next_state_idx = rng.gen_range(0, state_count);
106 let output_idx = rng.gen_range(0, output_symbols.len());
107
108 transitions.push(Transition::new_with_source(
109 format!("t{}", transition_id),
110 source_state.clone(),
111 State::new(format!("S{}", next_state_idx)),
112 Letter::new(*input_symbol),
113 Letter::new(output_symbols[output_idx]),
114 ));
115 transition_id += 1;
116 }
117 }
118
119 automata.transitions = transitions;
120 automata
121}
122
123struct SimpleRng {
125 state: u64,
126}
127
128impl SimpleRng {
129 fn new() -> Self {
130 let seed = SystemTime::now()
131 .duration_since(UNIX_EPOCH)
132 .unwrap_or_default()
133 .as_nanos() as u64;
134 Self { state: seed }
135 }
136
137 fn next_u64(&mut self) -> u64 {
138 self.state = self.state.wrapping_mul(1664525).wrapping_add(1013904223);
139 self.state
140 }
141
142 fn gen_range(&mut self, min: usize, max: usize) -> usize {
143 if max <= min {
144 return min;
145 }
146 min + (self.next_u64() as usize) % (max - min)
147 }
148}