use crate::algorithms::compose_default;
use crate::fst::{Fst, MutableFst};
use crate::semiring::Semiring;
use crate::Result;
pub fn intersect<W, F1, F2, M>(fst1: &F1, fst2: &F2) -> Result<M>
where
W: Semiring,
F1: Fst<W>,
F2: Fst<W>,
M: MutableFst<W> + Default,
{
compose_default(fst1, fst2)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn test_intersect_simple() {
let mut acc1 = VectorFst::<BooleanWeight>::new();
let s0 = acc1.add_state();
let s1 = acc1.add_state();
acc1.set_start(s0);
acc1.set_final(s1, BooleanWeight::one());
acc1.add_arc(s0, Arc::new(1, 1, BooleanWeight::one(), s1));
let mut acc2 = VectorFst::<BooleanWeight>::new();
let s0 = acc2.add_state();
let s1 = acc2.add_state();
acc2.set_start(s0);
acc2.set_final(s1, BooleanWeight::one());
acc2.add_arc(s0, Arc::new(1, 1, BooleanWeight::one(), s1));
let intersection: VectorFst<BooleanWeight> = intersect(&acc1, &acc2).unwrap();
assert!(intersection.num_states() > 0);
assert!(intersection.start().is_some());
}
#[test]
fn test_intersect_disjoint() {
let mut acc1 = VectorFst::<BooleanWeight>::new();
let s0 = acc1.add_state();
let s1 = acc1.add_state();
acc1.set_start(s0);
acc1.set_final(s1, BooleanWeight::one());
acc1.add_arc(s0, Arc::new(1, 1, BooleanWeight::one(), s1));
let mut acc2 = VectorFst::<BooleanWeight>::new();
let s0 = acc2.add_state();
let s1 = acc2.add_state();
acc2.set_start(s0);
acc2.set_final(s1, BooleanWeight::one());
acc2.add_arc(s0, Arc::new(2, 2, BooleanWeight::one(), s1));
let intersection: VectorFst<BooleanWeight> = intersect(&acc1, &acc2).unwrap();
assert!(intersection.start().is_some());
}
#[test]
fn test_intersect_weighted() {
let mut acc1 = VectorFst::<TropicalWeight>::new();
let s0 = acc1.add_state();
let s1 = acc1.add_state();
acc1.set_start(s0);
acc1.set_final(s1, TropicalWeight::new(1.0));
acc1.add_arc(s0, Arc::new(1, 1, TropicalWeight::new(0.5), s1));
let mut acc2 = VectorFst::<TropicalWeight>::new();
let s0 = acc2.add_state();
let s1 = acc2.add_state();
acc2.set_start(s0);
acc2.set_final(s1, TropicalWeight::new(2.0));
acc2.add_arc(s0, Arc::new(1, 1, TropicalWeight::new(1.5), s1));
let intersection: VectorFst<TropicalWeight> = intersect(&acc1, &acc2).unwrap();
assert!(intersection.start().is_some());
assert!(intersection.num_states() > 0);
}
#[test]
fn test_intersect_empty_fsts() {
let acc1 = VectorFst::<BooleanWeight>::new();
let acc2 = VectorFst::<BooleanWeight>::new();
let result = intersect::<
BooleanWeight,
VectorFst<BooleanWeight>,
VectorFst<BooleanWeight>,
VectorFst<BooleanWeight>,
>(&acc1, &acc2);
assert!(result.is_err());
}
#[test]
fn test_intersect_single_state() {
let mut acc1 = VectorFst::<BooleanWeight>::new();
let s0 = acc1.add_state();
acc1.set_start(s0);
acc1.set_final(s0, BooleanWeight::one());
let mut acc2 = VectorFst::<BooleanWeight>::new();
let s0 = acc2.add_state();
acc2.set_start(s0);
acc2.set_final(s0, BooleanWeight::one());
let intersection: VectorFst<BooleanWeight> = intersect(&acc1, &acc2).unwrap();
assert!(intersection.start().is_some());
}
#[test]
fn test_intersect_multiple_paths() {
let mut acc1 = VectorFst::<BooleanWeight>::new();
let s0 = acc1.add_state();
let s1 = acc1.add_state();
let s2 = acc1.add_state();
acc1.set_start(s0);
acc1.set_final(s1, BooleanWeight::one());
acc1.set_final(s2, BooleanWeight::one());
acc1.add_arc(s0, Arc::new(1, 1, BooleanWeight::one(), s1)); acc1.add_arc(s0, Arc::new(2, 2, BooleanWeight::one(), s2));
let mut acc2 = VectorFst::<BooleanWeight>::new();
let s0 = acc2.add_state();
let s1 = acc2.add_state();
acc2.set_start(s0);
acc2.set_final(s1, BooleanWeight::one());
acc2.add_arc(s0, Arc::new(1, 1, BooleanWeight::one(), s1));
let intersection: VectorFst<BooleanWeight> = intersect(&acc1, &acc2).unwrap();
assert!(intersection.start().is_some());
}
}