Init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "tm_interpreter"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
435
src/lib.rs
Normal file
435
src/lib.rs
Normal file
@@ -0,0 +1,435 @@
|
||||
mod tm_interpreter {
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
pub enum Shift {
|
||||
Left,
|
||||
Right,
|
||||
NoShift,
|
||||
}
|
||||
|
||||
// Some kind of Turing machine
|
||||
pub struct TM<G, S> {
|
||||
alphabet: Vec<G>,
|
||||
b: G,
|
||||
sigma: Vec<G>,
|
||||
q: Vec<S>,
|
||||
q0: S,
|
||||
f: Vec<S>,
|
||||
delta: Vec<((S, G), (S, G, Shift))>,
|
||||
}
|
||||
|
||||
impl<Gx, Sx> TM<Gx, Sx> {
|
||||
pub fn new<G: std::cmp::PartialEq, S: std::cmp::PartialEq>(
|
||||
alphabet: Vec<G>,
|
||||
b: G,
|
||||
sigma: Vec<G>,
|
||||
q: Vec<S>,
|
||||
q0: S,
|
||||
f: Vec<S>,
|
||||
delta: Vec<((S, G), (S, G, Shift))>,
|
||||
) -> Result<TM<G, S>, String>
|
||||
where
|
||||
S: Eq,
|
||||
S: Hash,
|
||||
S: Clone,
|
||||
{
|
||||
if !alphabet.contains(&b) {
|
||||
return Err(String::from("Blank symbol is undefined in alphabet."));
|
||||
} else if sigma.contains(&b) {
|
||||
return Err(String::from("Blank symbol is not allowed as input."));
|
||||
} else if !sigma.iter().all(|x| alphabet.contains(x)) {
|
||||
return Err(String::from("An input symbol is undefined in alphabet."));
|
||||
} else if !q.contains(&q0) {
|
||||
return Err(String::from("The initial state is undefined."));
|
||||
} else if !f.iter().all(|x| q.contains(x)) {
|
||||
return Err(String::from("A final state is undefined."));
|
||||
} else {
|
||||
let turing_machine: TM<G, S> = TM {
|
||||
alphabet: alphabet,
|
||||
b: b,
|
||||
sigma: sigma,
|
||||
q: q,
|
||||
q0: q0,
|
||||
f: f,
|
||||
delta: delta,
|
||||
};
|
||||
|
||||
// Checking transition function
|
||||
// Check parameter integrity
|
||||
for delta in turing_machine.delta.iter() {
|
||||
if !turing_machine.q.contains(&delta.0 .0) {
|
||||
return Err(String::from("Invalid input state."));
|
||||
}
|
||||
|
||||
if !turing_machine.alphabet.contains(&delta.0 .1) {
|
||||
return Err(String::from("Invalid input symbol."));
|
||||
}
|
||||
|
||||
if !turing_machine.q.contains(&delta.1 .0) {
|
||||
return Err(String::from("Invalid output state."));
|
||||
}
|
||||
|
||||
if !turing_machine.alphabet.contains(&delta.1 .1) {
|
||||
return Err(String::from("Invalid output symbol."));
|
||||
}
|
||||
}
|
||||
|
||||
// Check amount of input combinations
|
||||
if turing_machine.delta.len()
|
||||
< (turing_machine.alphabet.len()
|
||||
* (turing_machine.q.len() - turing_machine.f.len()))
|
||||
{
|
||||
return Err(String::from("Undefined behavior."));
|
||||
} else if turing_machine.delta.len()
|
||||
> (turing_machine.alphabet.len()
|
||||
* (turing_machine.q.len() - turing_machine.f.len()))
|
||||
{
|
||||
return Err(String::from("Ambiguous behavior."));
|
||||
}
|
||||
|
||||
// Check termination and state usage by calculating all possible transitions
|
||||
// Check unused states (for now only detecting direct dead states)
|
||||
for rule in turing_machine.delta.iter() {
|
||||
let is_unused: bool = turing_machine.delta.iter().all(|x| x.1 .0 != rule.0 .0);
|
||||
if is_unused {
|
||||
return Err(String::from("Unused state."));
|
||||
}
|
||||
}
|
||||
|
||||
// Check termination
|
||||
// Create map
|
||||
let mut state_map: HashMap<S, Vec<S>> = HashMap::new();
|
||||
for state in turing_machine.q.iter() {
|
||||
state_map.insert(state.clone(), vec![]);
|
||||
}
|
||||
|
||||
// Check all rules
|
||||
for rule in turing_machine.delta.iter() {
|
||||
// Get input and output state
|
||||
let input_state: S = rule.0 .0.clone();
|
||||
let output_state: S = rule.1 .0.clone();
|
||||
|
||||
// Check if input is already known to output
|
||||
// Append, if not
|
||||
if !state_map.get(&output_state).unwrap().contains(&input_state) {
|
||||
state_map
|
||||
.get_mut(&output_state)
|
||||
.unwrap()
|
||||
.push(input_state.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve terminating states
|
||||
let mut terminating_states: Vec<S> = turing_machine.f.clone();
|
||||
let mut update: bool = true;
|
||||
while update {
|
||||
update = false;
|
||||
|
||||
for state_index in 0..terminating_states.len() {
|
||||
let dependends: Vec<S> = state_map
|
||||
.get(&terminating_states[state_index])
|
||||
.unwrap()
|
||||
.to_vec();
|
||||
for dependend in dependends {
|
||||
if !terminating_states.contains(&dependend) {
|
||||
terminating_states.push(dependend);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if terminating_states.len() != turing_machine.q.len() {
|
||||
return Err(String::from("Unterminated state."));
|
||||
}
|
||||
|
||||
return Ok(turing_machine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tm_interpreter::*;
|
||||
|
||||
#[test]
|
||||
fn new_positive() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => assert_eq!(true, true),
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
panic!("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_undefined_blank() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 2;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Blank symbol is undefined in alphabet.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_blank_in_sigma() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 1;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Blank symbol is not allowed as input.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_undefined_sigma_symbol() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1, 2];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "An input symbol is undefined in alphabet.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_undefined_initial_state() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'D';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "The initial state is undefined.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_undefined_final_state() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['Q'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "A final state is undefined.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_invalid_inputt_state() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('D', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Invalid input state.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_invalid_input_symbol() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 4), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Invalid input symbol.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_undefined_behavior() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H', 'I'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Undefined behavior.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_ambigous_behavior() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Right)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Ambiguous behavior.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_unterminated_state() {
|
||||
let alphabet: Vec<u8> = vec![0, 1];
|
||||
let b: u8 = 0;
|
||||
let sigma: Vec<u8> = vec![1];
|
||||
let q: Vec<char> = vec!['A', 'B', 'C', 'D', 'H'];
|
||||
let q0: char = 'A';
|
||||
let f: Vec<char> = vec!['H'];
|
||||
let delta: Vec<((char, u8), (char, u8, Shift))> = vec![
|
||||
(('A', 0), ('B', 1, Shift::Right)),
|
||||
(('A', 1), ('C', 1, Shift::Left)),
|
||||
(('B', 0), ('A', 1, Shift::Left)),
|
||||
(('B', 1), ('B', 1, Shift::Right)),
|
||||
(('C', 0), ('B', 1, Shift::Left)),
|
||||
(('C', 1), ('H', 1, Shift::Right)),
|
||||
(('D', 0), ('D', 1, Shift::Left)),
|
||||
(('D', 1), ('D', 1, Shift::Right)),
|
||||
];
|
||||
let working_machine = TM::<char, u8>::new(alphabet, b, sigma, q, q0, f, delta);
|
||||
match working_machine {
|
||||
Ok(_) => panic!(""),
|
||||
Err(e) => {
|
||||
assert_eq!(e.as_str(), "Unterminated state.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user