Skip to main content

LSTAR

Struct LSTAR 

Source
pub struct LSTAR {
    pub input_vocabulary: Vec<Letter>,
    pub knowledge_base: Arc<Mutex<dyn KnowledgeBaseTrait>>,
    pub tmp_dir: Option<String>,
    pub observation_table: Option<ObservationTable>,
    pub max_states: usize,
    pub equivalence_test: Arc<dyn EquivalenceTest>,
    /* private fields */
}
Expand description

The L* algorithm implementation

Fields§

§input_vocabulary: Vec<Letter>§knowledge_base: Arc<Mutex<dyn KnowledgeBaseTrait>>§tmp_dir: Option<String>§observation_table: Option<ObservationTable>§max_states: usize§equivalence_test: Arc<dyn EquivalenceTest>

Implementations§

Source§

impl LSTAR

Source

pub fn new( input_vocabulary: Vec<String>, knowledge_base: Arc<Mutex<dyn KnowledgeBaseTrait>>, max_states: usize, tmp_dir: Option<String>, eq_test: Option<Arc<dyn EquivalenceTest>>, ) -> Self

Create a new LSTAR learner

Examples found in repository?
examples/vending_machine.rs (line 21)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== Vending Machine Learning Example ===\n");
9
10    // Create a vending machine knowledge base (SUL)
11    let kb = Arc::new(Mutex::new(VendingMachineKB::new()));
12
13    // Define input vocabulary
14    let vocabulary = vec![
15        "INSERT_COIN".to_string(),
16        "PRESS_A".to_string(),
17        "PRESS_B".to_string(),
18    ];
19
20    // Run L* learner
21    let mut learner = LSTAR::new(vocabulary, kb.clone(), 4, None, None);
22    match learner.learn() {
23        Ok(automata) => {
24            println!("\n=== Learned Vending Machine ===\n");
25            println!("{}", automata.build_dot_code());
26        }
27        Err(e) => eprintln!("Learning error: {}", e),
28    }
29
30    let kb_guard = kb.lock().unwrap();
31    println!("\nKnowledge Base Statistics:\n{}", kb_guard.stats);
32
33    Ok(())
34}
More examples
Hide additional examples
examples/custom_kb.rs (line 23)
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}
examples/memory_kb.rs (line 31)
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}
examples/network_custom_kb.rs (line 31)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    println!("=== Network Custom KB (ATM) Example ===\n");
14
15    // Expects an independent ATM server running
16    // (see examples/custom_kb_server.rs).
17    let kb = NetworkActiveKnowledgeBase::new("127.0.0.1".to_string(), 3001, Duration::from_secs(5));
18
19    let vocabulary = vec![
20        "INSERT_CARD".to_string(),
21        "ENTER_PIN".to_string(),
22        "REQUEST_WITHDRAW".to_string(),
23        "EJECT_CARD".to_string(),
24        "TIMEOUT".to_string(),
25    ];
26
27    println!("Target Host: {}", kb.target_host());
28    println!("Target Port: {}\n", kb.target_port());
29
30    let kb: Arc<Mutex<dyn KnowledgeBaseTrait>> = Arc::new(Mutex::new(kb));
31    let mut learner = LSTAR::new(vocabulary, kb, 8, None, None);
32
33    match learner.learn() {
34        Ok(automata) => {
35            println!("\n=== Learned ATM Automaton from Network Target ===\n");
36            println!("{}", automata.build_dot_code());
37            println!(
38                "\nStates: {}\nTransitions: {}",
39                automata.get_states().len(),
40                automata.transitions.len()
41            );
42        }
43        Err(e) => {
44            eprintln!("Learning error: {}", e);
45            println!("\nTo run this example with a real connection:");
46            println!("  1. Start ATM server: cargo run --example custom_kb_server");
47            println!("  2. Run this example again: cargo run --example network_custom_kb");
48        }
49    }
50
51    Ok(())
52}
examples/network_kb.rs (line 31)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    println!("=== Network Active Knowledge Base Example ===\n");
11
12    // This example expects an independent coffee server running
13    // (see examples/coffee_server.rs).
14    let kb = NetworkActiveKnowledgeBase::new("127.0.0.1".to_string(), 3000, Duration::from_secs(5));
15
16    // Define input vocabulary
17    let vocabulary = vec![
18        "REFILL_WATER".to_string(),
19        "REFILL_COFFEE".to_string(),
20        "PRESS_BUTTON_A".to_string(),
21        "PRESS_BUTTON_B".to_string(),
22        "PRESS_BUTTON_C".to_string(),
23    ];
24
25    println!("Target Host: {}", kb.target_host());
26    println!("Target Port: {}\n", kb.target_port());
27
28    let kb: Arc<Mutex<dyn KnowledgeBaseTrait>> = Arc::new(Mutex::new(kb));
29
30    // Create learner. The network KB connects per submitted word.
31    let mut learner = LSTAR::new(vocabulary, kb, 4, None, None);
32
33    match learner.learn() {
34        Ok(automata) => {
35            println!("\n=== Learned Automaton from Network Target ===\n");
36            println!("{}", automata.build_dot_code());
37            println!(
38                "\nStates: {}\nTransitions: {}",
39                automata.get_states().len(),
40                automata.transitions.len()
41            );
42        }
43        Err(e) => {
44            eprintln!("Learning error: {}", e);
45            println!("\nTo run this example with a real connection:");
46            println!("  1. Start a coffee server: cargo run --example coffee_server");
47            println!("  2. Run this example again");
48        }
49    }
50
51    Ok(())
52}
examples/all_eqtests_custom_kb.rs (line 85)
68fn run_strategy(name: &str, builder: &EqBuilder) -> StrategyReport {
69    let vocabulary = vec![
70        "INSERT_CARD".to_string(),
71        "ENTER_PIN".to_string(),
72        "REQUEST_WITHDRAW".to_string(),
73        "EJECT_CARD".to_string(),
74        "TIMEOUT".to_string(),
75    ];
76    let input_letters = vocabulary
77        .iter()
78        .map(|s| Letter::new(s))
79        .collect::<Vec<_>>();
80    let max_states = 8;
81
82    let kb = Arc::new(Mutex::new(ATMKnowledgeBase::new()));
83    let knowledge_base: SharedKb = kb.clone();
84    let eqtest = builder(knowledge_base.clone(), input_letters, max_states);
85    let mut learner = LSTAR::new(vocabulary, knowledge_base, max_states, None, Some(eqtest));
86
87    println!("\n--- Running {name} ---");
88    let started = Instant::now();
89    let learn_result = learner.learn();
90    let elapsed_ms = started.elapsed().as_millis();
91
92    let stats = {
93        let kb_guard = kb.lock().unwrap();
94        StatsSnapshot::from_stats(&kb_guard.stats)
95    };
96
97    match learn_result {
98        Ok(automata) => {
99            let state_count = automata.get_states().len();
100            let transition_count = automata.transitions.len();
101            println!("{name}: success (states={state_count}, transitions={transition_count})");
102            StrategyReport {
103                name: name.to_string(),
104                elapsed_ms,
105                state_count: Some(state_count),
106                transition_count: Some(transition_count),
107                error: None,
108                stats,
109            }
110        }
111        Err(err) => {
112            println!("{name}: failed ({err})");
113            StrategyReport {
114                name: name.to_string(),
115                elapsed_ms,
116                state_count: None,
117                transition_count: None,
118                error: Some(err),
119                stats,
120            }
121        }
122    }
123}
Source

pub fn with_equivalence_test(self, eq_test: Arc<dyn EquivalenceTest>) -> Self

Set a custom equivalence test

Examples found in repository?
examples/random_walk_eq.rs (line 51)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    println!("=== Random Walk Equivalence Test Example ===\n");
11
12    // Create a simple system
13    let mut kb = DemoKnowledgeBase::new();
14
15    // Define a simple state machine:
16    // S0 -a/0-> S1   (initial state)
17    // S0 -b/1-> S0
18    // S1 -a/0-> S2
19    // S1 -b/1-> S0
20    // S2 -a/0-> S2
21    // S2 -b/1-> S1
22
23    // Make outputs state-dependent so learner must distinguish states
24    kb.add_transition("s0", "a", "0", "s1");
25    kb.add_transition("s0", "b", "1", "s0");
26    kb.add_transition("s1", "a", "1", "s2");
27    kb.add_transition("s1", "b", "0", "s0");
28    kb.add_transition("s2", "a", "1", "s2");
29    kb.add_transition("s2", "b", "0", "s1");
30
31    let knowledge_base = Arc::new(Mutex::new(kb));
32
33    // Create vocabulary
34    let vocabulary = vec!["a".to_string(), "b".to_string()];
35
36    // Create learner
37    let mut lstar = LSTAR::new(vocabulary.clone(), knowledge_base.clone(), 5, None, None);
38
39    // Use random walk equivalence test instead of W-method
40    let input_letters = vocabulary
41        .iter()
42        .map(|s| Letter::new(s))
43        .collect::<Vec<_>>();
44    let random_walk = RandomWalkMethod::new(
45        knowledge_base.clone(),
46        input_letters,
47        10000, // max_steps: 10000 steps
48        0.75,  // restart_probability: 75%
49    );
50
51    lstar = lstar.with_equivalence_test(Arc::new(random_walk));
52
53    // Run learning
54    match lstar.learn() {
55        Ok(automata) => {
56            println!("\n=== Learned Automaton (Random Walk Test) ===\n");
57            println!("{}", automata.build_dot_code());
58            println!("\nLearning completed successfully!");
59
60            // Print statistics
61            println!("\nStatistics:");
62            println!("  Number of states: {}", automata.get_states().len());
63            println!("  Number of transitions: {}", automata.transitions.len());
64        }
65        Err(e) => eprintln!("Error during learning: {}", e),
66    }
67
68    let kb_guard = knowledge_base.lock().unwrap();
69    println!("\nKnowledge Base Statistics:\n{}", kb_guard.stats);
70
71    Ok(())
72}
Source

pub fn stop(&mut self)

Stop the learning process

Source

pub fn learn(&mut self) -> Result<Automata, String>

Run the L* algorithm

Examples found in repository?
examples/vending_machine.rs (line 22)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== Vending Machine Learning Example ===\n");
9
10    // Create a vending machine knowledge base (SUL)
11    let kb = Arc::new(Mutex::new(VendingMachineKB::new()));
12
13    // Define input vocabulary
14    let vocabulary = vec![
15        "INSERT_COIN".to_string(),
16        "PRESS_A".to_string(),
17        "PRESS_B".to_string(),
18    ];
19
20    // Run L* learner
21    let mut learner = LSTAR::new(vocabulary, kb.clone(), 4, None, None);
22    match learner.learn() {
23        Ok(automata) => {
24            println!("\n=== Learned Vending Machine ===\n");
25            println!("{}", automata.build_dot_code());
26        }
27        Err(e) => eprintln!("Learning error: {}", e),
28    }
29
30    let kb_guard = kb.lock().unwrap();
31    println!("\nKnowledge Base Statistics:\n{}", kb_guard.stats);
32
33    Ok(())
34}
More examples
Hide additional examples
examples/custom_kb.rs (line 25)
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}
examples/memory_kb.rs (line 32)
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}
examples/network_custom_kb.rs (line 33)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    println!("=== Network Custom KB (ATM) Example ===\n");
14
15    // Expects an independent ATM server running
16    // (see examples/custom_kb_server.rs).
17    let kb = NetworkActiveKnowledgeBase::new("127.0.0.1".to_string(), 3001, Duration::from_secs(5));
18
19    let vocabulary = vec![
20        "INSERT_CARD".to_string(),
21        "ENTER_PIN".to_string(),
22        "REQUEST_WITHDRAW".to_string(),
23        "EJECT_CARD".to_string(),
24        "TIMEOUT".to_string(),
25    ];
26
27    println!("Target Host: {}", kb.target_host());
28    println!("Target Port: {}\n", kb.target_port());
29
30    let kb: Arc<Mutex<dyn KnowledgeBaseTrait>> = Arc::new(Mutex::new(kb));
31    let mut learner = LSTAR::new(vocabulary, kb, 8, None, None);
32
33    match learner.learn() {
34        Ok(automata) => {
35            println!("\n=== Learned ATM Automaton from Network Target ===\n");
36            println!("{}", automata.build_dot_code());
37            println!(
38                "\nStates: {}\nTransitions: {}",
39                automata.get_states().len(),
40                automata.transitions.len()
41            );
42        }
43        Err(e) => {
44            eprintln!("Learning error: {}", e);
45            println!("\nTo run this example with a real connection:");
46            println!("  1. Start ATM server: cargo run --example custom_kb_server");
47            println!("  2. Run this example again: cargo run --example network_custom_kb");
48        }
49    }
50
51    Ok(())
52}
examples/network_kb.rs (line 33)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    println!("=== Network Active Knowledge Base Example ===\n");
11
12    // This example expects an independent coffee server running
13    // (see examples/coffee_server.rs).
14    let kb = NetworkActiveKnowledgeBase::new("127.0.0.1".to_string(), 3000, Duration::from_secs(5));
15
16    // Define input vocabulary
17    let vocabulary = vec![
18        "REFILL_WATER".to_string(),
19        "REFILL_COFFEE".to_string(),
20        "PRESS_BUTTON_A".to_string(),
21        "PRESS_BUTTON_B".to_string(),
22        "PRESS_BUTTON_C".to_string(),
23    ];
24
25    println!("Target Host: {}", kb.target_host());
26    println!("Target Port: {}\n", kb.target_port());
27
28    let kb: Arc<Mutex<dyn KnowledgeBaseTrait>> = Arc::new(Mutex::new(kb));
29
30    // Create learner. The network KB connects per submitted word.
31    let mut learner = LSTAR::new(vocabulary, kb, 4, None, None);
32
33    match learner.learn() {
34        Ok(automata) => {
35            println!("\n=== Learned Automaton from Network Target ===\n");
36            println!("{}", automata.build_dot_code());
37            println!(
38                "\nStates: {}\nTransitions: {}",
39                automata.get_states().len(),
40                automata.transitions.len()
41            );
42        }
43        Err(e) => {
44            eprintln!("Learning error: {}", e);
45            println!("\nTo run this example with a real connection:");
46            println!("  1. Start a coffee server: cargo run --example coffee_server");
47            println!("  2. Run this example again");
48        }
49    }
50
51    Ok(())
52}
examples/all_eqtests_custom_kb.rs (line 89)
68fn run_strategy(name: &str, builder: &EqBuilder) -> StrategyReport {
69    let vocabulary = vec![
70        "INSERT_CARD".to_string(),
71        "ENTER_PIN".to_string(),
72        "REQUEST_WITHDRAW".to_string(),
73        "EJECT_CARD".to_string(),
74        "TIMEOUT".to_string(),
75    ];
76    let input_letters = vocabulary
77        .iter()
78        .map(|s| Letter::new(s))
79        .collect::<Vec<_>>();
80    let max_states = 8;
81
82    let kb = Arc::new(Mutex::new(ATMKnowledgeBase::new()));
83    let knowledge_base: SharedKb = kb.clone();
84    let eqtest = builder(knowledge_base.clone(), input_letters, max_states);
85    let mut learner = LSTAR::new(vocabulary, knowledge_base, max_states, None, Some(eqtest));
86
87    println!("\n--- Running {name} ---");
88    let started = Instant::now();
89    let learn_result = learner.learn();
90    let elapsed_ms = started.elapsed().as_millis();
91
92    let stats = {
93        let kb_guard = kb.lock().unwrap();
94        StatsSnapshot::from_stats(&kb_guard.stats)
95    };
96
97    match learn_result {
98        Ok(automata) => {
99            let state_count = automata.get_states().len();
100            let transition_count = automata.transitions.len();
101            println!("{name}: success (states={state_count}, transitions={transition_count})");
102            StrategyReport {
103                name: name.to_string(),
104                elapsed_ms,
105                state_count: Some(state_count),
106                transition_count: Some(transition_count),
107                error: None,
108                stats,
109            }
110        }
111        Err(err) => {
112            println!("{name}: failed ({err})");
113            StrategyReport {
114                name: name.to_string(),
115                elapsed_ms,
116                state_count: None,
117                transition_count: None,
118                error: Some(err),
119                stats,
120            }
121        }
122    }
123}

Auto Trait Implementations§

§

impl Freeze for LSTAR

§

impl !RefUnwindSafe for LSTAR

§

impl !Send for LSTAR

§

impl !Sync for LSTAR

§

impl Unpin for LSTAR

§

impl UnsafeUnpin for LSTAR

§

impl !UnwindSafe for LSTAR

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.