Skip to content

Commit

Permalink
feat: initial to_fsm logic for core regex elements
Browse files Browse the repository at this point in the history
  • Loading branch information
drbh authored and brandonwillard committed Sep 10, 2024
1 parent bcd80e7 commit 33afa19
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 37 deletions.
72 changes: 53 additions & 19 deletions src/interegular/fsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,19 @@ impl From<TransitionKey> for usize {
}
}

impl From<TransitionKey> for u32 {
fn from(c: TransitionKey) -> Self {
match c {
TransitionKey::Symbol(i) => i as u32,
_ => panic!("Cannot convert `anything else` to u32"),
}
}
}

pub trait SymbolTrait: Eq + Hash + Clone + Debug + From<char> {}
impl<T: Eq + Hash + Clone + Debug + From<char>> SymbolTrait for T {}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Alphabet<T: SymbolTrait> {
pub symbol_mapping: HashMap<T, TransitionKey>,
pub by_transition: HashMap<TransitionKey, Vec<T>>,
Expand All @@ -49,6 +58,14 @@ impl<T: SymbolTrait> Alphabet<T> {
}
}

#[must_use]
pub fn empty() -> Self {
Alphabet {
symbol_mapping: HashMap::new(),
by_transition: HashMap::new(),
}
}

pub fn get(&self, item: &T) -> TransitionKey {
match self.symbol_mapping.get(item) {
Some(x) => *x,
Expand All @@ -60,7 +77,8 @@ impl<T: SymbolTrait> Alphabet<T> {
self.symbol_mapping.contains_key(item)
}

#[must_use] pub fn from_groups(groups: &[HashSet<T>]) -> Self {
#[must_use]
pub fn from_groups(groups: &[HashSet<T>]) -> Self {
let mut symbol_mapping = HashMap::new();
for (i, group) in groups.iter().enumerate() {
for symbol in group {
Expand Down Expand Up @@ -118,16 +136,17 @@ impl<T: SymbolTrait> Alphabet<T> {
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Fsm<T: SymbolTrait> {
alphabet: Alphabet<T>,
pub alphabet: Alphabet<T>,
pub states: HashSet<TransitionKey>,
pub initial: TransitionKey,
pub finals: HashSet<TransitionKey>,
pub map: HashMap<TransitionKey, HashMap<TransitionKey, TransitionKey>>,
}
impl<T: SymbolTrait> Fsm<T> {
#[must_use] pub fn new(
#[must_use]
pub fn new(
alphabet: Alphabet<T>,
states: HashSet<TransitionKey>,
initial: TransitionKey,
Expand Down Expand Up @@ -166,7 +185,8 @@ impl<T: SymbolTrait> Fsm<T> {
self.finals.contains(&state)
}

#[must_use] pub fn reduce(&self) -> Self {
#[must_use]
pub fn reduce(&self) -> Self {
self.reversed().reversed()
}

Expand Down Expand Up @@ -203,7 +223,8 @@ impl<T: SymbolTrait> Fsm<T> {
crawl(&self.alphabet, initial, final_fn, follow)
}

#[must_use] pub fn is_live(&self, state: TransitionKey) -> bool {
#[must_use]
pub fn is_live(&self, state: TransitionKey) -> bool {
let mut seen = HashSet::new();
let mut reachable = vec![state];
let mut i = 0;
Expand All @@ -226,7 +247,8 @@ impl<T: SymbolTrait> Fsm<T> {
false
}

#[must_use] pub fn is_empty(&self) -> bool {
#[must_use]
pub fn is_empty(&self) -> bool {
!self.is_live(self.initial)
}

Expand Down Expand Up @@ -268,27 +290,32 @@ impl<T: SymbolTrait> Fsm<T> {
})
}

#[must_use] pub fn union(fsms: &[Self]) -> Self {
#[must_use]
pub fn union(fsms: &[Self]) -> Self {
Self::parallel(fsms, |accepts| accepts.iter().any(|&x| x))
}

#[must_use] pub fn intersection(fsms: &[Self]) -> Self {
#[must_use]
pub fn intersection(fsms: &[Self]) -> Self {
Self::parallel(fsms, |accepts| accepts.iter().all(|&x| x))
}

#[must_use] pub fn symmetric_difference(fsms: &[Self]) -> Self {
#[must_use]
pub fn symmetric_difference(fsms: &[Self]) -> Self {
Self::parallel(fsms, |accepts| {
accepts.iter().filter(|&&x| x).count() % 2 == 1
})
}

#[must_use] pub fn difference(fsms: &[Self]) -> Self {
#[must_use]
pub fn difference(fsms: &[Self]) -> Self {
Self::parallel(fsms, |accepts| {
accepts[0] && !accepts[1..].iter().any(|&x| x)
})
}

#[must_use] pub fn concatenate(fsms: &[Self]) -> Self {
#[must_use]
pub fn concatenate(fsms: &[Self]) -> Self {
let alphabets_from_fsms: Vec<Alphabet<T>> =
fsms.iter().map(|f| f.alphabet.clone()).collect();
let alphabets = Alphabet::union(alphabets_from_fsms.as_slice());
Expand Down Expand Up @@ -362,7 +389,8 @@ impl<T: SymbolTrait> Fsm<T> {
crawl(&alphabet, initial, final_fn, follow)
}

#[must_use] pub fn star(&self) -> Self {
#[must_use]
pub fn star(&self) -> Self {
let initial = HashSet::from([self.initial]);

let follow = |state: &HashSet<TransitionKey>,
Expand Down Expand Up @@ -398,7 +426,8 @@ impl<T: SymbolTrait> Fsm<T> {
result
}

#[must_use] pub fn times(&self, multiplier: usize) -> Self {
#[must_use]
pub fn times(&self, multiplier: usize) -> Self {
// metastate is a set of iterations+states
let initial = HashSet::from([(self.initial, 0)]);
let final_fn = |state: &HashSet<(TransitionKey, usize)>| {
Expand Down Expand Up @@ -433,7 +462,8 @@ impl<T: SymbolTrait> Fsm<T> {
crawl(&self.alphabet, initial, final_fn, follow)
}

#[must_use] pub fn everythingbut(&self) -> Self {
#[must_use]
pub fn everythingbut(&self) -> Self {
let initial = HashSet::from([(self.initial, 0)]);

let follow = |current: &HashSet<(TransitionKey, usize)>,
Expand Down Expand Up @@ -522,7 +552,8 @@ impl<T: SymbolTrait> Fsm<T> {
}
}

#[must_use] pub fn null<T: SymbolTrait>(alphabet: &Alphabet<T>) -> Fsm<T> {
#[must_use]
pub fn null<T: SymbolTrait>(alphabet: &Alphabet<T>) -> Fsm<T> {
Fsm::new(
alphabet.clone(),
HashSet::from([0.into()]),
Expand All @@ -539,7 +570,8 @@ impl<T: SymbolTrait> Fsm<T> {
)
}

#[must_use] pub fn epsilon<T: SymbolTrait>(alphabet: &Alphabet<T>) -> Fsm<T> {
#[must_use]
pub fn epsilon<T: SymbolTrait>(alphabet: &Alphabet<T>) -> Fsm<T> {
Fsm::new(
alphabet.clone(),
HashSet::from([0.into()]),
Expand Down Expand Up @@ -575,7 +607,9 @@ where
for transition in alphabet.by_transition.keys() {
match follow(&state, transition) {
Some(next) => {
let j = if let Some(index) = states.iter().position(|s| s == &next) { index } else {
let j = if let Some(index) = states.iter().position(|s| s == &next) {
index
} else {
states.push_back(next.clone());
states.len() - 1
};
Expand Down
Loading

0 comments on commit 33afa19

Please sign in to comment.