use crate::semiring::Semiring;
use crate::wfst::{MutableWfst, StateId, VectorWfst};
pub fn single_state_wfst<L, W>() -> VectorWfst<L, W>
where
L: Clone + Send + Sync,
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
fst.set_start(s0);
fst.set_final(s0, W::one());
fst
}
pub fn linear_wfst<W>(num_states: usize) -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
for _ in 0..num_states {
fst.add_state();
}
if num_states > 0 {
fst.set_start(0);
fst.set_final((num_states - 1) as StateId, W::one());
for i in 0..(num_states - 1) {
let label = char::from(b'a' + (i % 26) as u8);
fst.add_arc(
i as StateId,
Some(label),
Some(label),
(i + 1) as StateId,
W::one(),
);
}
}
fst
}
pub fn linear_wfst_custom<L, W>(labels: &[(L, W)]) -> VectorWfst<L, W>
where
L: Clone + Send + Sync,
W: Semiring,
{
let num_states = labels.len() + 1;
let mut fst = VectorWfst::new();
for _ in 0..num_states {
fst.add_state();
}
if num_states > 0 {
fst.set_start(0);
fst.set_final((num_states - 1) as StateId, W::one());
for (i, (label, weight)) in labels.iter().enumerate() {
fst.add_arc(
i as StateId,
Some(label.clone()),
Some(label.clone()),
(i + 1) as StateId,
*weight,
);
}
}
fst
}
pub fn branching_wfst<W>(num_branches: usize) -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let start = fst.add_state();
fst.set_start(start);
let mut branch_states = Vec::with_capacity(num_branches);
for _ in 0..num_branches {
branch_states.push(fst.add_state());
}
let end = fst.add_state();
fst.set_final(end, W::one());
for (i, &branch) in branch_states.iter().enumerate() {
let label = char::from(b'a' + (i % 26) as u8);
fst.add_arc(start, Some(label), Some(label), branch, W::one());
}
for &branch in &branch_states {
fst.add_epsilon(branch, end, W::one());
}
fst
}
pub fn diamond_wfst<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
let s3 = fst.add_state();
fst.set_start(s0);
fst.set_final(s3, W::one());
fst.add_arc(s0, Some('a'), Some('a'), s1, W::one());
fst.add_arc(s0, Some('b'), Some('b'), s2, W::one());
fst.add_arc(s1, Some('c'), Some('c'), s3, W::one());
fst.add_arc(s2, Some('d'), Some('d'), s3, W::one());
fst
}
pub fn diamond_wfst_weighted<W>(w1: W, w2: W, w3: W, w4: W) -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
let s3 = fst.add_state();
fst.set_start(s0);
fst.set_final(s3, W::one());
fst.add_arc(s0, Some('a'), Some('a'), s1, w1);
fst.add_arc(s0, Some('b'), Some('b'), s2, w2);
fst.add_arc(s1, Some('c'), Some('c'), s3, w3);
fst.add_arc(s2, Some('d'), Some('d'), s3, w4);
fst
}
pub fn cyclic_wfst<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
fst.set_start(s0);
fst.set_final(s2, W::one());
fst.add_arc(s0, Some('a'), Some('a'), s1, W::one());
fst.add_arc(s1, Some('b'), Some('b'), s1, W::one()); fst.add_arc(s1, Some('c'), Some('c'), s2, W::one());
fst
}
pub fn epsilon_wfst<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
let s3 = fst.add_state();
fst.set_start(s0);
fst.set_final(s3, W::one());
fst.add_epsilon(s0, s1, W::one());
fst.add_arc(s1, Some('a'), Some('a'), s2, W::one());
fst.add_epsilon(s2, s3, W::one());
fst
}
pub fn epsilon_rich_wfst<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
let s3 = fst.add_state();
fst.set_start(s0);
fst.set_final(s3, W::one());
fst.add_epsilon(s0, s1, W::one());
fst.add_epsilon(s0, s2, W::one());
fst.add_epsilon(s1, s2, W::one());
fst.add_arc(s2, Some('a'), Some('a'), s3, W::one());
fst
}
pub fn nondeterministic_wfst<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
fst.set_start(s0);
fst.set_final(s1, W::one());
fst.set_final(s2, W::one());
fst.add_arc(s0, Some('a'), Some('x'), s1, W::one());
fst.add_arc(s0, Some('a'), Some('y'), s2, W::one());
fst
}
pub fn transducer<W>() -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
let s2 = fst.add_state();
fst.set_start(s0);
fst.set_final(s2, W::one());
fst.add_arc(s0, Some('a'), Some('x'), s1, W::one());
fst.add_arc(s1, Some('b'), Some('y'), s2, W::one());
fst
}
pub fn transducer_custom<L, W>(mappings: &[(L, L, W)]) -> VectorWfst<L, W>
where
L: Clone + Send + Sync,
W: Semiring,
{
let num_states = mappings.len() + 1;
let mut fst = VectorWfst::new();
for _ in 0..num_states {
fst.add_state();
}
if num_states > 0 {
fst.set_start(0);
fst.set_final((num_states - 1) as StateId, W::one());
for (i, (input, output, weight)) in mappings.iter().enumerate() {
fst.add_arc(
i as StateId,
Some(input.clone()),
Some(output.clone()),
(i + 1) as StateId,
*weight,
);
}
}
fst
}
pub fn empty_wfst<L, W>() -> VectorWfst<L, W>
where
L: Clone + Send + Sync,
W: Semiring,
{
VectorWfst::new()
}
pub fn multi_final_wfst<W>(final_weights: &[W]) -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::new();
let start = fst.add_state();
fst.set_start(start);
for (i, &weight) in final_weights.iter().enumerate() {
let state = fst.add_state();
let label = char::from(b'a' + (i % 26) as u8);
fst.add_arc(start, Some(label), Some(label), state, W::one());
fst.set_final(state, weight);
}
fst
}
pub fn complete_dfa<W>(num_states: usize, alphabet: &[char]) -> VectorWfst<char, W>
where
W: Semiring,
{
let mut fst = VectorWfst::with_capacity(num_states);
for _ in 0..num_states {
fst.add_state();
}
if num_states > 0 {
fst.set_start(0);
fst.set_final((num_states - 1) as StateId, W::one());
for from in 0..num_states {
for (i, &label) in alphabet.iter().enumerate() {
let to = (from + i + 1) % num_states;
fst.add_arc(
from as StateId,
Some(label),
Some(label),
to as StateId,
W::one(),
);
}
}
}
fst
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::TropicalWeight;
use crate::test_utils::assertions::{has_no_epsilon, is_acyclic, is_deterministic};
use crate::wfst::Wfst;
#[test]
fn test_single_state_wfst() {
let fst: VectorWfst<char, TropicalWeight> = single_state_wfst();
assert_eq!(fst.num_states(), 1);
assert_eq!(fst.start(), 0);
assert!(fst.is_final(0));
}
#[test]
fn test_linear_wfst() {
let fst: VectorWfst<char, TropicalWeight> = linear_wfst(5);
assert_eq!(fst.num_states(), 5);
assert_eq!(fst.start(), 0);
assert!(fst.is_final(4));
assert!(is_acyclic(&fst));
assert!(is_deterministic(&fst));
}
#[test]
fn test_diamond_wfst() {
let fst: VectorWfst<char, TropicalWeight> = diamond_wfst();
assert_eq!(fst.num_states(), 4);
assert!(is_acyclic(&fst));
assert!(has_no_epsilon(&fst));
}
#[test]
fn test_cyclic_wfst() {
let fst: VectorWfst<char, TropicalWeight> = cyclic_wfst();
assert!(!is_acyclic(&fst));
}
#[test]
fn test_epsilon_wfst() {
let fst: VectorWfst<char, TropicalWeight> = epsilon_wfst();
assert!(!has_no_epsilon(&fst));
}
#[test]
fn test_nondeterministic_wfst() {
let fst: VectorWfst<char, TropicalWeight> = nondeterministic_wfst();
assert!(!is_deterministic(&fst));
}
#[test]
fn test_transducer() {
let fst: VectorWfst<char, TropicalWeight> = transducer();
assert_eq!(fst.num_states(), 3);
let trans = fst.transitions(0);
assert_eq!(trans.len(), 1);
assert_ne!(trans[0].input, trans[0].output);
}
}