Skip to content

Commit

Permalink
Moved most SCC code to separate module. Can't move everything without…
Browse files Browse the repository at this point in the history
… circular imports between nfa and scc :(
  • Loading branch information
Apanatshka committed Nov 6, 2016
1 parent affd659 commit cc4b5ad
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 105 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
@@ -1,7 +1,9 @@
#![allow(dead_code)]
pub mod automaton; pub mod automaton;


pub mod nfa; pub mod nfa;
pub mod dfa; pub mod dfa;
mod scc;


#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
138 changes: 33 additions & 105 deletions src/nfa.rs
@@ -1,4 +1,3 @@
#![allow(dead_code)]
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::BTreeSet; use std::collections::BTreeSet;
Expand Down Expand Up @@ -324,119 +323,48 @@ impl<Input: Eq + Hash + Clone, Payload: Clone> NFAE<Input, Payload> {
/// } /// }
/// } /// }
/// ``` /// ```
fn scc(&self) -> (Vec<usize>, Vec<Vec<usize>>) { fn scc(&self) -> Vec<usize> {
let mut index = 0; use scc::SccMutState;
let mut st_index = vec![::std::usize::MAX; self.states.len()];
let mut st_lowlink = vec![::std::usize::MAX; self.states.len()]; let mut scc_state = SccMutState::new(self.states.len());
let mut scc_stack = Vec::new();
let mut stack_set = HashSet::new();
let mut scc_s = Vec::new();
let mut call_stack = Vec::new(); let mut call_stack = Vec::new();


for st_ref in 0..self.states.len() { for st_ref in 0..self.states.len() {
if st_index[st_ref] == ::std::usize::MAX { if !scc_state.visited(st_ref) {
call_stack.push(SccState::Init(st_ref)); let mut state = SccState::Init(st_ref);
while let Some(state) = call_stack.pop() { loop {
match state { if let SccState::Init(from) = state {
SccState::Init(from) => { scc_state.init(from);
self.scc_init(from, state = SccState::Dfs(from,
&mut index, self.states[from]
&mut st_index, .e_transition
&mut st_lowlink, .iter()
&mut scc_stack, .cloned());
&mut stack_set); }

if let SccState::RecCallReturn(from, to, iter) = state {
call_stack.push(SccState::Dfs(from, scc_state.update(from, to);
self.states[from] state = SccState::Dfs(from, iter);
.e_transition }
.iter() if let SccState::Dfs(from, mut iter) = state {
.cloned())) if let Some(to) = scc_state.next_state(from, &mut iter) {
} call_stack.push(SccState::RecCallReturn(from, to, iter));
SccState::RecCallReturn(from, to, iter) => { state = SccState::Init(to);
st_lowlink[from] = ::std::cmp::min(st_lowlink[from], st_lowlink[to]); } else {

state = SccState::SccConstruction(from);
call_stack.push(SccState::Dfs(from, iter));
}
SccState::Dfs(from, mut iter) => {
if let Some(to) = self.scc_dfs(from,
&mut st_index,
&mut st_lowlink,
&mut stack_set,
&mut iter) {
call_stack.push(SccState::RecCallReturn(from, to, iter));
call_stack.push(SccState::Init(to));
} else {
call_stack.push(SccState::SccConstruction(from));
}
} }
SccState::SccConstruction(from) => { }
self.scc_construct(from, if let SccState::SccConstruction(from) = state {
&mut st_index, scc_state.construct_scc(from);
&mut st_lowlink, if let Some(st) = call_stack.pop() {
&mut scc_stack, state = st
&mut stack_set, } else {
&mut scc_s) break;
} }
} }
} }
} }
} }
(st_lowlink, scc_s) scc_state.sccs_mapping()
}

#[inline]
fn scc_init(&self,
from: usize,
index: &mut usize,
st_index: &mut [usize],
st_lowlink: &mut [usize],
scc_stack: &mut Vec<usize>,
stack_set: &mut HashSet<usize>) {
st_index[from] = *index;
st_lowlink[from] = *index;
*index += 1;

scc_stack.push(from);
stack_set.insert(from);
}

#[inline]
fn scc_dfs<I: Iterator<Item = usize>>(&self,
from: usize,
st_index: &mut [usize],
st_lowlink: &mut [usize],
stack_set: &mut HashSet<usize>,
iter: &mut I)
-> Option<usize> {
while let Some(to) = iter.next() {
if st_index[to] == ::std::usize::MAX {
return Some(to);
} else if stack_set.contains(&to) {
st_lowlink[from] = ::std::cmp::min(st_lowlink[from], st_index[to]);
}
}
None
}

#[inline]
fn scc_construct(&self,
from: usize,
st_index: &mut [usize],
st_lowlink: &mut [usize],
scc_stack: &mut Vec<usize>,
stack_set: &mut HashSet<usize>,
scc_s: &mut Vec<Vec<usize>>) {
if st_lowlink[from] == st_index[from] {
let mut scc = Vec::new();
while let Some(st_ref) = scc_stack.pop() {
stack_set.remove(&st_ref);
scc.push(st_ref);
if st_ref == from {
break;
}
}
scc_s.push(scc);
}
} }
} }


Expand Down
80 changes: 80 additions & 0 deletions src/scc.rs
@@ -0,0 +1,80 @@
use std::collections::HashMap;

pub struct SccMutState {
count: usize, // Index
index: Vec<usize>, // StateRef -> Index
lowlink: Vec<usize>, // StateRef -> Index
scc_stack: Vec<usize>, // Stack<StateRef>
scc_set: HashMap<usize, usize>, // Map<StateRef, StackOffset> of the above stack
}

impl SccMutState {
pub fn new(states: usize) -> Self {
SccMutState {
count: 0,
index: vec![::std::usize::MAX; states],
lowlink: vec![::std::usize::MAX; states],
scc_stack: Vec::new(),
scc_set: HashMap::new(),
}
}

#[inline]
pub fn visited(&self, st_ref: usize) -> bool {
self.index[st_ref] != ::std::usize::MAX
}

#[inline]
pub fn scc_seed(&self, st_ref: usize) -> bool {
self.index[st_ref] == self.lowlink[st_ref]
}

pub fn init(&mut self, st_ref: usize) {
self.index[st_ref] = self.count;
self.lowlink[st_ref] = self.count;
self.count += 1;
self.scc_set.insert(st_ref, self.scc_stack.len());
self.scc_stack.push(st_ref);
}

pub fn update(&mut self, from: usize, to: usize) {
self.lowlink[from] = ::std::cmp::min(self.lowlink[from], self.lowlink[to]);
}

pub fn next_state<I: Iterator<Item = usize>>(&mut self,
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) {
return Some(to);
} else if self.scc_set.contains_key(&to) {
self.update(from, to);
}
}
None
}

pub fn construct_scc(&mut self, from: usize) {
if self.scc_seed(from) {
let offset = self.scc_stack[from];
let scc = self.scc_stack.split_off(offset);
for &st_ref in &scc {
self.scc_stack.remove(st_ref);
}
}
}

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_mapping(self) -> Vec<usize> {
self.lowlink
}
}

0 comments on commit cc4b5ad

Please sign in to comment.