Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved most SCC code to separate module. Can't move everything without…
… circular imports between nfa and scc :(
- Loading branch information
1 parent
affd659
commit cc4b5ad
Showing
3 changed files
with
115 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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 | |||
} | |||
} |