use crate::arc::Arc;
use crate::fst::{Fst, MutableFst};
use crate::semiring::Semiring;
use crate::Result;
pub fn union<W, F1, F2, M>(fst1: &F1, fst2: &F2) -> Result<M>
where
W: Semiring,
F1: Fst<W>,
F2: Fst<W>,
M: MutableFst<W> + Default,
{
let mut result = M::default();
let new_start = result.add_state();
result.set_start(new_start);
let mut state_map1 = vec![None; fst1.num_states()];
for state in fst1.states() {
let new_state = result.add_state();
state_map1[state as usize] = Some(new_state);
if let Some(weight) = fst1.final_weight(state) {
result.set_final(new_state, weight.clone());
}
}
if let Some(start1) = fst1.start() {
if let Some(mapped_start1) = state_map1[start1 as usize] {
result.add_arc(new_start, Arc::epsilon(W::one(), mapped_start1));
}
}
for state in fst1.states() {
if let Some(new_state) = state_map1[state as usize] {
for arc in fst1.arcs(state) {
if let Some(new_nextstate) = state_map1[arc.nextstate as usize] {
result.add_arc(
new_state,
Arc::new(arc.ilabel, arc.olabel, arc.weight.clone(), new_nextstate),
);
}
}
}
}
let mut state_map2 = vec![None; fst2.num_states()];
for state in fst2.states() {
let new_state = result.add_state();
state_map2[state as usize] = Some(new_state);
if let Some(weight) = fst2.final_weight(state) {
result.set_final(new_state, weight.clone());
}
}
if let Some(start2) = fst2.start() {
if let Some(mapped_start2) = state_map2[start2 as usize] {
result.add_arc(new_start, Arc::epsilon(W::one(), mapped_start2));
}
}
for state in fst2.states() {
if let Some(new_state) = state_map2[state as usize] {
for arc in fst2.arcs(state) {
if let Some(new_nextstate) = state_map2[arc.nextstate as usize] {
result.add_arc(
new_state,
Arc::new(arc.ilabel, arc.olabel, arc.weight.clone(), new_nextstate),
);
}
}
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
use num_traits::One;
#[test]
fn test_union_basic() {
let mut fst1 = VectorFst::<TropicalWeight>::new();
let s0 = fst1.add_state();
let s1 = fst1.add_state();
fst1.set_start(s0);
fst1.set_final(s1, TropicalWeight::one());
fst1.add_arc(s0, Arc::new(1, 1, TropicalWeight::new(1.0), s1));
let mut fst2 = VectorFst::<TropicalWeight>::new();
let t0 = fst2.add_state();
let t1 = fst2.add_state();
fst2.set_start(t0);
fst2.set_final(t1, TropicalWeight::one());
fst2.add_arc(t0, Arc::new(2, 2, TropicalWeight::new(2.0), t1));
let unioned: VectorFst<TropicalWeight> = union(&fst1, &fst2).unwrap();
assert!(unioned.num_states() >= fst1.num_states() + fst2.num_states());
assert!(unioned.start().is_some());
assert!(unioned.num_states() >= 2); }
#[test]
fn test_union_empty() {
let fst1 = VectorFst::<TropicalWeight>::new();
let mut fst2 = VectorFst::<TropicalWeight>::new();
let s0 = fst2.add_state();
fst2.set_start(s0);
fst2.set_final(s0, TropicalWeight::one());
let unioned: VectorFst<TropicalWeight> = union(&fst1, &fst2).unwrap();
assert!(unioned.start().is_some());
}
}