Permalink
Browse files

Finally defined nfae->nfa in terms of SCC

  • Loading branch information...
Apanatshka committed Nov 6, 2016
1 parent cc4b5ad commit c2463da9bc381a01fb1b09c9f989dcb90c56f50c
Showing with 48 additions and 78 deletions.
  1. +35 −68 src/nfa.rs
  2. +13 −10 src/scc.rs
View
@@ -187,66 +187,14 @@ impl<Input: Eq + Hash + Clone, Payload: Clone> NFAE<Input, Payload> {
/// Cycles are replaced by single states
/// States that aren't reachable from `AUTO_START` are preserved (not by design)
pub fn to_nfa(&self) -> NFA<Input, Payload> {
// The SCCs are in reverse topo order for optimal epsilon
let (sccs, renumbering) = self.scc();
// the new states
let mut states: Vec<NFAHashState<Input, usize, Payload>> = Vec::new();
// Maps visited stateref to offset in stack
let mut visiting: HashMap<usize, usize> = HashMap::new();
// Maps staterefs that are finished to staterefs in the new NFA
let mut renumbering: Vec<usize> = vec![::std::usize::MAX; self.states.len()];
// Stack of states we've seen/ are working on.
let mut stack: Vec<usize> = vec![AUTO_START];
// Lowest non-visited
let mut unvisited = 0;
loop {
let nfae_st_ref = stack[stack.len() - 1];
let nfae_st = &self.states[nfae_st_ref];
let new_state = if !nfae_st.e_transition.is_empty() {
for &st_ref in &nfae_st.e_transition {
match visiting.get(&st_ref) {
Some(&::std::usize::MAX) => continue,
Some(&offset) => {
unimplemented!(); //TODO: loop detected
break;
}
None => {
visiting.insert(st_ref, stack.len());
stack.push(st_ref);
break;
}
}
}
// No more epsilons to do
Self::eps_state_to_nfa(nfae_st, &renumbering, &states)
} else {
if nfae_st_ref == AUTO_START && states.len() != AUTO_START {
states[AUTO_START] = nfae_st.drop_epsilons();
continue;
}
if states.len() == AUTO_START && nfae_st_ref != AUTO_START {
states.push(NFAHashState::new());
}
nfae_st.drop_epsilons()
};
renumbering[nfae_st_ref] = states.len();
states.push(new_state);
visiting.remove(&nfae_st_ref);
stack.pop();
while renumbering[unvisited] != ::std::usize::MAX && unvisited < self.states.len() {
unvisited += 1;
}
if stack.is_empty() && unvisited < self.states.len() {
stack.push(unvisited);
} else {
break;
}
}
let mut states: Vec<NFAHashState<Input, usize, Payload>> = Vec::with_capacity(sccs.len());
for state in &mut states {
for (_, st_refs) in &mut state.transitions {
let new_st_refs = st_refs.iter().map(|&st_ref| renumbering[st_ref]).collect();
mem::replace(st_refs, new_st_refs);
}
for scc in sccs {
states[renumbering[scc[0]]] =
Self::scc_to_nfa_state(&scc, &self.states, &renumbering, &states);
}
NFA {
@@ -255,18 +203,37 @@ impl<Input: Eq + Hash + Clone, Payload: Clone> NFAE<Input, Payload> {
}
}
fn eps_state_to_nfa(st: &NFAEHashState<Input, usize, Payload>,
fn scc_to_nfa_state(scc: &[usize],
nfae_states: &[NFAEHashState<Input, usize, Payload>],
renumbering: &[usize],
states: &[NFAHashState<Input, usize, Payload>])
nfa_states: &[NFAHashState<Input, usize, Payload>])
-> NFAHashState<Input, usize, Payload> {
let mut transitions: HashMap<Input, HashSet<usize>> = st.transitions.clone();
for &st_ref in &st.e_transition {
renumbering[st_ref];
transitions.extend(states[st_ref].transitions.clone());
use std::iter::FromIterator;
macro_rules! renumber {
($st:expr) => {
$st.transitions
.iter()
.map(|(i, to)| (i.clone(), to.iter().map(|&s| renumbering[s]).collect()))
}
}
let scc_set = HashSet::from_iter(scc.iter().cloned());
let mut transition_set: HashSet<usize> = HashSet::new();
for &st_ref in scc {
let st = &nfae_states[st_ref];
for st_ref in st.transitions.values() {
transition_set.extend(st_ref.difference(&scc_set));
}
transition_set.extend(st.e_transition.difference(&scc_set));
}
let mut transitions: HashMap<Input, HashSet<usize>> = scc_set.into_iter()
.flat_map(|st_ref| renumber!(nfae_states[st_ref]))
.collect();
for st_ref in transition_set {
transitions.extend(nfa_states[renumbering[st_ref]].transitions.clone());
}
NFAHashState {
transitions: st.transitions.clone(),
payload: st.payload.clone(),
transitions: transitions,
payload: nfae_states[scc[0]].payload.clone(),
}
}
@@ -323,7 +290,7 @@ impl<Input: Eq + Hash + Clone, Payload: Clone> NFAE<Input, Payload> {
/// }
/// }
/// ```
fn scc(&self) -> Vec<usize> {
fn scc(&self) -> (Vec<Vec<usize>>, Vec<usize>) {
use scc::SccMutState;
let mut scc_state = SccMutState::new(self.states.len());
@@ -364,7 +331,7 @@ impl<Input: Eq + Hash + Clone, Payload: Clone> NFAE<Input, Payload> {
}
}
}
scc_state.sccs_mapping()
scc_state.sccs_and_mapping()
}
}
View
@@ -6,6 +6,7 @@ pub struct SccMutState {
lowlink: Vec<usize>, // StateRef -> Index
scc_stack: Vec<usize>, // Stack<StateRef>
scc_set: HashMap<usize, usize>, // Map<StateRef, StackOffset> of the above stack
sccs: Vec<Vec<usize>>, // Stack<Set<StateRef>> the SCCs in reverse topo order
}
impl SccMutState {
@@ -16,6 +17,7 @@ impl SccMutState {
lowlink: vec![::std::usize::MAX; states],
scc_stack: Vec::new(),
scc_set: HashMap::new(),
sccs: Vec::new(),
}
}
@@ -42,9 +44,9 @@ impl SccMutState {
}
pub fn next_state<I: Iterator<Item = usize>>(&mut self,
from: usize,
iter: &mut I)
-> Option<usize> {
from: usize,
iter: &mut I)
-> Option<usize> {
// Note that the `iter` doesn't have to be fully traversed
for to in iter {
if !self.visited(to) {
@@ -63,18 +65,19 @@ impl SccMutState {
for &st_ref in &scc {
self.scc_stack.remove(st_ref);
}
self.sccs.push(scc);
}
}
pub fn sccs(&self) -> Vec<Vec<usize>> {
let mut sccs = vec![Vec::new(); self.count-1];
for (st_ref, &scc_idx) in self.lowlink.iter().enumerate() {
sccs[scc_idx].push(st_ref);
}
sccs
pub fn sccs(self) -> Vec<Vec<usize>> {
self.sccs
}
pub fn sccs_mapping(self) -> Vec<usize> {
self.lowlink
}
}
pub fn sccs_and_mapping(self) -> (Vec<Vec<usize>>, Vec<usize>) {
(self.sccs, self.lowlink)
}
}

0 comments on commit c2463da

Please sign in to comment.