use super::traits::*;
use crate::arc::{Arc, ArcIterator};
use crate::properties::{compute_properties, FstProperties};
use crate::semiring::Semiring;
use core::slice;
use smallvec::SmallVec;
const ARC_INLINE_CAPACITY: usize = 8;
type ArcVec<W> = SmallVec<[Arc<W>; ARC_INLINE_CAPACITY]>;
#[derive(Debug, Clone)]
struct VectorState<W: Semiring> {
final_weight: Option<W>,
arcs: ArcVec<W>,
}
impl<W: Semiring> Default for VectorState<W> {
fn default() -> Self {
Self {
final_weight: None,
arcs: SmallVec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct VectorFst<W: Semiring> {
states: Vec<VectorState<W>>,
start: Option<StateId>,
properties: FstProperties,
}
impl<W: Semiring> VectorFst<W> {
pub fn new() -> Self {
Self {
states: Vec::new(),
start: None,
properties: FstProperties::default(),
}
}
pub fn with_capacity(states: usize) -> Self {
Self {
states: Vec::with_capacity(states),
start: None,
properties: FstProperties::default(),
}
}
pub fn compute_properties(&mut self) {
self.properties = compute_properties(self);
}
}
impl<W: Semiring> Default for VectorFst<W> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct VectorArcIterator<'a, W: Semiring> {
arcs: slice::Iter<'a, Arc<W>>,
}
impl<W: Semiring> Iterator for VectorArcIterator<'_, W> {
type Item = Arc<W>;
fn next(&mut self) -> Option<Self::Item> {
self.arcs.next().cloned()
}
}
impl<W: Semiring> ArcIterator<W> for VectorArcIterator<'_, W> {}
impl<W: Semiring> Fst<W> for VectorFst<W> {
type ArcIter<'a>
= VectorArcIterator<'a, W>
where
W: 'a;
fn start(&self) -> Option<StateId> {
self.start
}
fn final_weight(&self, state: StateId) -> Option<&W> {
self.states
.get(state as usize)
.and_then(|s| s.final_weight.as_ref())
}
fn num_arcs(&self, state: StateId) -> usize {
self.states
.get(state as usize)
.map(|s| s.arcs.len())
.unwrap_or(0)
}
fn num_states(&self) -> usize {
self.states.len()
}
fn properties(&self) -> FstProperties {
if self.properties.known.is_empty() {
compute_properties(self)
} else {
self.properties
}
}
fn arcs(&self, state: StateId) -> Self::ArcIter<'_> {
let arcs = self
.states
.get(state as usize)
.map(|s| s.arcs.iter())
.unwrap_or_else(|| [].iter());
VectorArcIterator { arcs }
}
}
impl<W: Semiring> MutableFst<W> for VectorFst<W> {
fn add_state(&mut self) -> StateId {
let id = self.states.len() as StateId;
self.states.push(VectorState::default());
self.properties.invalidate_all();
id
}
fn add_arc(&mut self, state: StateId, arc: Arc<W>) {
if let Some(s) = self.states.get_mut(state as usize) {
s.arcs.push(arc);
self.properties.invalidate_all();
}
}
fn set_start(&mut self, state: StateId) {
self.start = Some(state);
self.properties.invalidate_all();
}
fn set_final(&mut self, state: StateId, weight: W) {
if let Some(s) = self.states.get_mut(state as usize) {
s.final_weight = if <W as num_traits::Zero>::is_zero(&weight) {
None
} else {
Some(weight)
};
self.properties.invalidate_all();
}
}
fn delete_arcs(&mut self, state: StateId) {
if let Some(s) = self.states.get_mut(state as usize) {
s.arcs.clear();
self.properties.invalidate_all();
}
}
fn delete_arc(&mut self, state: StateId, arc_idx: usize) {
if let Some(s) = self.states.get_mut(state as usize) {
if arc_idx < s.arcs.len() {
s.arcs.remove(arc_idx);
self.properties.invalidate_all();
}
}
}
fn reserve_states(&mut self, n: usize) {
self.states.reserve(n);
}
fn reserve_arcs(&mut self, state: StateId, n: usize) {
if let Some(s) = self.states.get_mut(state as usize) {
s.arcs.reserve(n);
}
}
fn clear(&mut self) {
self.states.clear();
self.start = None;
self.properties = FstProperties::default();
}
}
impl<W: Semiring> ExpandedFst<W> for VectorFst<W> {
fn arcs_slice(&self, state: StateId) -> &[Arc<W>] {
self.states
.get(state as usize)
.map(|s| s.arcs.as_slice())
.unwrap_or(&[])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::TropicalWeight;
use num_traits::One;
#[test]
fn test_empty_fst() {
let fst = VectorFst::<TropicalWeight>::new();
assert_eq!(fst.num_states(), 0);
assert!(fst.is_empty());
assert_eq!(fst.start(), None);
assert_eq!(fst.num_arcs_total(), 0);
}
#[test]
fn test_add_state() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
assert_eq!(s0, 0);
assert_eq!(s1, 1);
assert_eq!(fst.num_states(), 2);
fst.set_start(s0);
assert!(!fst.is_empty());
}
#[test]
fn test_start_state() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
assert_eq!(fst.start(), None);
fst.set_start(s0);
assert_eq!(fst.start(), Some(s0));
}
#[test]
fn test_final_states() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
assert!(!fst.is_final(s0));
assert!(!fst.is_final(s1));
fst.set_final(s1, TropicalWeight::new(2.5));
assert!(!fst.is_final(s0));
assert!(fst.is_final(s1));
assert_eq!(*fst.final_weight(s1).unwrap().value(), 2.5);
fst.remove_final(s1);
assert!(!fst.is_final(s1));
}
#[test]
fn test_add_arcs() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
assert_eq!(fst.num_arcs(s0), 0);
assert_eq!(fst.num_arcs(s1), 0);
fst.add_arc(s0, Arc::new(1, 2, TropicalWeight::new(1.5), s1));
fst.add_arc(s0, Arc::new(3, 4, TropicalWeight::new(2.0), s1));
assert_eq!(fst.num_arcs(s0), 2);
assert_eq!(fst.num_arcs(s1), 0);
assert_eq!(fst.num_arcs_total(), 2);
}
#[test]
fn test_arc_iteration() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
fst.add_arc(s0, Arc::new(1, 2, TropicalWeight::new(1.5), s1));
fst.add_arc(s0, Arc::new(3, 4, TropicalWeight::new(2.0), s1));
let arcs: Vec<_> = fst.arcs(s0).collect();
assert_eq!(arcs.len(), 2);
assert_eq!(arcs[0].ilabel, 1);
assert_eq!(arcs[0].olabel, 2);
assert_eq!(*arcs[0].weight.value(), 1.5);
assert_eq!(arcs[0].nextstate, s1);
assert_eq!(arcs[1].ilabel, 3);
assert_eq!(arcs[1].olabel, 4);
assert_eq!(*arcs[1].weight.value(), 2.0);
assert_eq!(arcs[1].nextstate, s1);
}
#[test]
fn test_reserve_states() {
let mut fst = VectorFst::<TropicalWeight>::new();
fst.reserve_states(100);
for i in 0..100 {
let state = fst.add_state();
assert_eq!(state, i);
}
assert_eq!(fst.num_states(), 100);
}
#[test]
fn test_reserve_arcs() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
fst.reserve_arcs(s0, 50);
for i in 0..50 {
fst.add_arc(s0, Arc::new(i, i, TropicalWeight::new(i as f32), s1));
}
assert_eq!(fst.num_arcs(s0), 50);
}
#[test]
fn test_clear() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
fst.set_start(s0);
fst.set_final(s1, TropicalWeight::one());
fst.add_arc(s0, Arc::new(1, 2, TropicalWeight::new(1.5), s1));
assert!(!fst.is_empty());
assert_eq!(fst.num_states(), 2);
fst.clear();
assert!(fst.is_empty());
assert_eq!(fst.num_states(), 0);
assert_eq!(fst.start(), None);
}
#[test]
fn test_state_iteration() {
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
let states: Vec<_> = fst.states().collect();
assert_eq!(states, vec![s0, s1, s2]);
}
mod proptests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn test_fst_state_consistency_property(num_states in 1..100usize) {
let mut fst = VectorFst::<TropicalWeight>::new();
for _ in 0..num_states {
fst.add_state();
}
assert_eq!(fst.num_states(), num_states);
for state in fst.states() {
assert!(state < num_states as StateId);
}
let total_arcs = fst.num_arcs_total();
let sum_arcs: usize = fst.states().map(|s| fst.num_arcs(s)).sum();
assert_eq!(total_arcs, sum_arcs);
}
}
}
}