1use rust_lstar::knowledge_base::{KnowledgeBaseStats, KnowledgeBaseTrait};
2use rust_lstar::query::OutputQuery;
3use rust_lstar::*;
7use std::sync::{Arc, Mutex};
8
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 println!("=== Custom Knowledge Base Example ===");
11 println!("Simulating a banking ATM protocol\n");
12
13 let kb = Arc::new(Mutex::new(ATMKnowledgeBase::new()));
14
15 let vocabulary = vec![
16 "INSERT_CARD".to_string(),
17 "ENTER_PIN".to_string(),
18 "REQUEST_WITHDRAW".to_string(),
19 "EJECT_CARD".to_string(),
20 "TIMEOUT".to_string(),
21 ];
22
23 let mut lstar = LSTAR::new(vocabulary, kb.clone(), 8, None, None);
24
25 match lstar.learn() {
26 Ok(automata) => {
27 println!("\n=== Learned ATM Protocol ===");
28 println!("{}", automata.build_dot_code());
29 println!("\nATM protocol learned successfully!");
30 }
31 Err(e) => eprintln!("Error: {}", e),
32 }
33
34 let kb_guard = kb.lock().unwrap();
35 println!("\nKnowledge Base Stats:\n{}", kb_guard.stats);
36
37 Ok(())
38}
39
40struct ATMKnowledgeBase {
42 state: ATMState,
43 stats: KnowledgeBaseStats,
44}
45
46#[derive(Clone, Copy)]
47enum ATMState {
48 Idle,
49 CardInserted,
50 Authenticated,
51 Ready,
52 Dispensing,
53}
54
55impl ATMKnowledgeBase {
56 fn new() -> Self {
57 ATMKnowledgeBase {
58 state: ATMState::Idle,
59 stats: KnowledgeBaseStats::new(),
60 }
61 }
62
63 fn process_input(&self, command: &str, current_state: ATMState) -> (ATMState, &'static str) {
64 match current_state {
65 ATMState::Idle => match command {
66 "INSERT_CARD" => (ATMState::CardInserted, "CARD_ACCEPTED"), _ => (ATMState::Idle, "INVALID_OP"), },
69 ATMState::CardInserted => match command {
70 "ENTER_PIN" => (ATMState::Authenticated, "PIN_VERIFIED"), "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"), _ => (ATMState::CardInserted, "RETRY"), },
74 ATMState::Authenticated => match command {
75 "REQUEST_WITHDRAW" => (ATMState::Ready, "ENTER_AMOUNT"), "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"), "TIMEOUT" => (ATMState::Idle, "SESSION_TIMEOUT"), _ => (ATMState::Authenticated, "INVALID_COMMAND"), },
80 ATMState::Ready => match command {
81 "REQUEST_WITHDRAW" => (ATMState::Dispensing, "DISPENSING"), "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"), _ => (ATMState::Ready, "WAIT"), },
85 ATMState::Dispensing => match command {
86 "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"), _ => (ATMState::Dispensing, "DISPENSING"), },
89 }
90 }
91}
92
93impl KnowledgeBaseTrait for ATMKnowledgeBase {
94 fn resolve_query(&mut self, query: &mut OutputQuery) -> Result<(), String> {
95 self.stats.increment_nb_query();
96 self.stats.add_nb_letter(query.input_word.len());
97 self.stats.increment_nb_submitted_query();
98 self.stats.add_nb_submitted_letter(query.input_word.len());
99 self.state = ATMState::Idle;
101
102 let mut outputs = Vec::new();
104
105 for input_letter in query.input_word.letters() {
106 let symbol = input_letter.symbols();
108 let command = symbol.as_str();
109
110 let (next_state, response) = self.process_input(command, self.state);
111 self.state = next_state;
112 outputs.push(Letter::new(response));
113 }
114
115 query.set_result(Word::from_letters(outputs));
116 Ok(())
117 }
118
119 fn add_word(&mut self, _input: &Word, _output: &Word) -> Result<(), String> {
120 Ok(())
122 }
123
124 }