Skip to main content

custom_kb/
custom_kb.rs

1use rust_lstar::knowledge_base::{KnowledgeBaseStats, KnowledgeBaseTrait};
2use rust_lstar::query::OutputQuery;
3/// Example: Custom Knowledge Base Implementation
4/// This example shows how to implement your own knowledge base
5/// for a real system (in practice, this could be a network service, hardware device, etc.)
6use 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
40/// Custom knowledge base for an ATM system
41struct 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"), // CARD_ACCEPTED
67                _ => (ATMState::Idle, "INVALID_OP"),                        // INVALID_OP
68            },
69            ATMState::CardInserted => match command {
70                "ENTER_PIN" => (ATMState::Authenticated, "PIN_VERIFIED"), // PIN_VERIFIED
71                "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"),         // CARD_EJECTED
72                _ => (ATMState::CardInserted, "RETRY"),                   // RETRY
73            },
74            ATMState::Authenticated => match command {
75                "REQUEST_WITHDRAW" => (ATMState::Ready, "ENTER_AMOUNT"), // ENTER_AMOUNT
76                "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"),        // CARD_EJECTED
77                "TIMEOUT" => (ATMState::Idle, "SESSION_TIMEOUT"),        // SESSION_TIMEOUT
78                _ => (ATMState::Authenticated, "INVALID_COMMAND"),       // INVALID
79            },
80            ATMState::Ready => match command {
81                "REQUEST_WITHDRAW" => (ATMState::Dispensing, "DISPENSING"), // DISPENSING
82                "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"),           // CARD_EJECTED
83                _ => (ATMState::Ready, "WAIT"),                             // WAIT
84            },
85            ATMState::Dispensing => match command {
86                "EJECT_CARD" => (ATMState::Idle, "CARD_EJECTED"), // CARD_EJECTED
87                _ => (ATMState::Dispensing, "DISPENSING"),        // DISPENSING
88            },
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        // Reset to initial state for each query
100        self.state = ATMState::Idle;
101
102        // let mut state = self.state.lock().unwrap();
103        let mut outputs = Vec::new();
104
105        for input_letter in query.input_word.letters() {
106            // Extract command from letter name (format: "Letter('x')")
107            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        // Not needed for this simple example
121        Ok(())
122    }
123
124    // fn stats(&self) -> &KnowledgeBaseStats {
125    //     &self.stats
126    // }
127
128    // fn stats_mut(&mut self) -> &mut KnowledgeBaseStats {
129    //     &mut self.stats
130    // }
131
132    // fn load_cache(&mut self, _cache_path: &PathBuf) -> Result<(), String> {
133    //     Ok(())
134    // }
135
136    // fn write_cache(&self, _cache_path: &PathBuf) -> Result<(), String> {
137    //     Ok(())
138    // }
139
140    // fn clear_cache(&mut self) {
141    //     // Not needed for this simple example
142    // }
143}