Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/custom_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ pub enum DFAError {
#[error("Invalid symbol: {0}")]
InvalidSymbol(&'static str),
}

#[derive(Debug, Error)]
pub enum NFAError {
#[error("Already Existing Transition {0}")]
ExistingTransition(&'static str),
}

#[derive(Debug, Error)]
pub enum AutomatonError {
#[error("DFA Error {0}")]
DFAError(DFAError),

#[error("NFA Error {0}")]
NFAError(NFAError),
}
31 changes: 17 additions & 14 deletions src/d_transition_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
use std::collections::HashMap;

use crate::{
custom_errors::DFAError, globals::State, symbol_table::Symbol,
custom_errors::{AutomatonError, DFAError},
globals::State,
symbol_table::Symbol,
transition_function::BasicFunctionsForTransitions,
};

Expand All @@ -22,19 +24,19 @@ impl BasicFunctionsForTransitions for DTransitionFunction {
state: &State,
symbol: &Symbol,
next_state: &State,
) -> Result<(), crate::custom_errors::DFAError> {
) -> Result<(), AutomatonError> {
if *symbol == Symbol::Epsilon {
return Err(DFAError::InvalidTransition(
return Err(AutomatonError::DFAError(DFAError::InvalidTransition(
"Epsilon should not be present in DFA Transitions",
));
)));
}

let entry = self.f.entry(*state).or_insert(HashMap::new());

if entry.contains_key(symbol) {
return Err(DFAError::InvalidTransition(
return Err(AutomatonError::DFAError(DFAError::InvalidTransition(
"Adding more than one state for the same transition for DFA",
));
)));
}

entry.insert(*symbol, *next_state);
Expand All @@ -49,16 +51,17 @@ impl BasicFunctionsForTransitions for DTransitionFunction {
on_states.reverse();

for &curr_state in on_states.iter() {
let mut new_transitions: HashMap<Symbol, State> = HashMap::new();
if let Some((state, symbol_state_map)) = self.f.remove_entry(&curr_state) {
let mut new_transitions: HashMap<Symbol, State> = HashMap::new();

// (curr_state, symbol) -> next_state
for (symbol, next_state) in self.f[&curr_state].iter() {
new_transitions.insert(*symbol, *next_state + increment);
}
// (state, symbol) -> next_state
for (symbol, next_state) in symbol_state_map.iter() {
new_transitions.insert(*symbol, *next_state + increment);
}

// update the transitions
self.f.insert(curr_state + increment, new_transitions);
self.f.remove_entry(&curr_state);
// update the transitions
self.f.insert(state + increment, new_transitions);
}
}
}
}
Expand Down
96 changes: 94 additions & 2 deletions src/n_transition_function.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![allow(dead_code)]

use crate::{
custom_errors::DFAError,
custom_errors::{AutomatonError, NFAError},
globals::State,
symbol_table::{Symbol, SymbolTable},
symbol_table::Symbol,
transition_function::BasicFunctionsForTransitions,
};
use std::collections::{HashMap, HashSet};

Expand All @@ -12,7 +13,98 @@ pub struct NTransitionFunction {
f: HashMap<State, HashMap<Symbol, HashSet<State>>>,
}

impl BasicFunctionsForTransitions for NTransitionFunction {
fn new() -> Self {
NTransitionFunction { f: HashMap::new() }
}

fn extend(&mut self, increment: usize) {
//
let mut on_states: Vec<State> = self.f.keys().map(|&val| val).collect();
on_states.sort();
// going through keys in decreasing order, in order to avoid overlapping issue
on_states.reverse();

for &curr_state in on_states.iter() {
if let Some((state, symbol_to_next_state_set_map)) = self.f.remove_entry(&curr_state) {
let mut new_transitions: HashMap<Symbol, HashSet<State>> = HashMap::new();

// (curr_state, symbol) -> next_state_set
for (symbol, next_state_set) in symbol_to_next_state_set_map.iter() {
// new_transitions.insert(*symbol, *next_state + increment);
let mut new_next_state_set = HashSet::new();

for &next_state in next_state_set.iter() {
new_next_state_set.insert(next_state + increment);
}

new_transitions.insert(*symbol, new_next_state_set);
}

// update the transitions
self.f.insert(state + increment, new_transitions);
}
}
}

fn add_transition(
&mut self,
state: &State,
symbol: &Symbol,
next_state: &State,
) -> Result<(), AutomatonError> {
let state_transitions = self.f.entry(*state).or_insert(HashMap::new());
let state_symbol_transitions = state_transitions.entry(*symbol).or_insert(HashSet::new());

if state_symbol_transitions.contains(next_state) {
return Err(AutomatonError::NFAError(NFAError::ExistingTransition("")));
}

state_symbol_transitions.insert(*next_state);
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn check_normal_and_multiple_transitions() {
let mut nt = NTransitionFunction::new();
let _ = nt
.add_transition(&0, &Symbol::Character('a'), &1)
.unwrap_or_else(|err| panic!("Error in adding transition : {}", err.to_string()));
let _ = nt
.add_transition(&0, &Symbol::Character('a'), &2)
.unwrap_or_else(|err| panic!("Error in adding transition : {}", err.to_string()));

assert!(nt.f.contains_key(&0));
assert!(nt.f[&0].contains_key(&Symbol::Character('a')));
assert!(nt.f[&0][&Symbol::Character('a')].contains(&1));
assert!(nt.f[&0][&Symbol::Character('a')].contains(&2));
}

#[test]
fn check_adding_epsilon_transition() {
let mut nt = NTransitionFunction::new();

let _ = nt
.add_transition(&0, &Symbol::Epsilon, &2)
.unwrap_or_else(|err| panic!("Error in adding transition : {}", err.to_string()));
assert!(nt.f.contains_key(&0));
assert!(nt.f[&0].contains_key(&Symbol::Epsilon));
assert!(nt.f[&0][&Symbol::Epsilon].contains(&2));
}

#[test]
fn check_adding_same_transition() {
let mut nt = NTransitionFunction::new();
let _ = nt
.add_transition(&0, &Symbol::Character('a'), &1)
.unwrap_or_else(|err| panic!("Error in adding transition : {}", err.to_string()));
let result = nt.add_transition(&0, &Symbol::Character('a'), &1);

assert!(result.is_err_and(|err| err.to_string().contains("Existing Transition")));
}
}
4 changes: 2 additions & 2 deletions src/transition_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::collections::HashSet;
use std::ops::Index;

use crate::custom_errors::DFAError;
use crate::custom_errors::AutomatonError;
use crate::d_transition_function;
use crate::globals::State;
use crate::n_transition_function;
Expand All @@ -26,7 +26,7 @@ pub trait BasicFunctionsForTransitions {
state: &State,
symbol: &Symbol,
next_state: &State,
) -> Result<(), DFAError>;
) -> Result<(), AutomatonError>;

fn extend(&mut self, increment: usize);
}