rustfst/algorithms/
tr_unique.rs

1use std::cmp::Ordering;
2
3use crate::fst_properties::FstProperties;
4use crate::fst_traits::MutableFst;
5use crate::semirings::Semiring;
6use crate::Tr;
7
8pub(crate) fn tr_compare<W: Semiring>(tr_1: &Tr<W>, tr_2: &Tr<W>) -> Ordering {
9    if tr_1.ilabel < tr_2.ilabel {
10        return Ordering::Less;
11    }
12    if tr_1.ilabel > tr_2.ilabel {
13        return Ordering::Greater;
14    }
15    if tr_1.olabel < tr_2.olabel {
16        return Ordering::Less;
17    }
18    if tr_1.olabel > tr_2.olabel {
19        return Ordering::Greater;
20    }
21    //if tr_1.weight < tr_2.weight {
22    //    return Ordering::Less;
23    //}
24    //if tr_1.weight > tr_2.weight {
25    //    return Ordering::Greater;
26    //}
27    if tr_1.nextstate < tr_2.nextstate {
28        return Ordering::Less;
29    }
30    if tr_1.nextstate > tr_2.nextstate {
31        return Ordering::Greater;
32    }
33    Ordering::Equal
34}
35
36/// Keep a single instance of trs leaving the same state, going to the same state and
37/// with the same input labels, output labels and weight.
38pub fn tr_unique<W: Semiring, F: MutableFst<W>>(ifst: &mut F) {
39    let props = ifst.properties();
40    unsafe {
41        for s in ifst.states_range() {
42            ifst.unique_trs_unchecked(s);
43        }
44    }
45    let mut outprops =
46        props & FstProperties::arcsort_properties() & FstProperties::delete_arcs_properties();
47    if ifst.num_states() == 0 {
48        outprops |= FstProperties::null_properties();
49    }
50    ifst.set_properties_with_mask(outprops, FstProperties::all_properties());
51}
52
53#[cfg(test)]
54mod test {
55    use crate::fst_impls::VectorFst;
56    use crate::fst_traits::MutableFst;
57    use crate::semirings::{ProbabilityWeight, Semiring};
58    use crate::Tr;
59    use anyhow::Result;
60
61    use super::*;
62
63    #[test]
64    fn test_tr_map_unique() -> Result<()> {
65        let mut fst_in = VectorFst::<ProbabilityWeight>::new();
66
67        let s1 = fst_in.add_state();
68        let s2 = fst_in.add_state();
69
70        fst_in.add_tr(s1, Tr::new(0, 0, ProbabilityWeight::new(0.3), s2))?;
71        fst_in.add_tr(s1, Tr::new(0, 1, ProbabilityWeight::new(0.3), s2))?;
72        fst_in.add_tr(s1, Tr::new(1, 0, ProbabilityWeight::new(0.3), s2))?;
73        fst_in.add_tr(s1, Tr::new(0, 0, ProbabilityWeight::new(0.3), s2))?;
74        fst_in.add_tr(s1, Tr::new(0, 0, ProbabilityWeight::new(0.1), s2))?;
75
76        fst_in.set_start(s1)?;
77        fst_in.set_final(s2, ProbabilityWeight::one())?;
78
79        let mut fst_out = VectorFst::<ProbabilityWeight>::new();
80
81        let s1 = fst_out.add_state();
82        let s2 = fst_out.add_state();
83
84        fst_out.add_tr(s1, Tr::new(0, 0, ProbabilityWeight::new(0.3), s2))?;
85        fst_out.add_tr(s1, Tr::new(0, 0, ProbabilityWeight::new(0.1), s2))?;
86        fst_out.add_tr(s1, Tr::new(0, 1, ProbabilityWeight::new(0.3), s2))?;
87        fst_out.add_tr(s1, Tr::new(1, 0, ProbabilityWeight::new(0.3), s2))?;
88
89        fst_out.set_start(s1)?;
90        fst_out.set_final(s2, ProbabilityWeight::one())?;
91
92        tr_unique(&mut fst_in);
93
94        assert_eq!(fst_in, fst_out);
95
96        Ok(())
97    }
98
99    //#[test]
100    //fn test_tr_map_unique_1() -> Result<()> {
101    //    let mut fst_in = VectorFst::<ProbabilityWeight>::new();
102
103    //    let s1 = fst_in.add_state();
104    //    let s2 = fst_in.add_state();
105
106    //    fst_in.add_tr(s1, Tr::new(1, 2, ProbabilityWeight::new(1.0), s2))?;
107    //    fst_in.add_tr(s1, Tr::new(1, 2, ProbabilityWeight::new(2.0), s2))?;
108    //    fst_in.add_tr(s1, Tr::new(1, 2, ProbabilityWeight::new(1.0), s2))?;
109
110    //    fst_in.set_start(s1)?;
111    //    fst_in.set_final(s2, ProbabilityWeight::one())?;
112
113    //    let mut fst_out = VectorFst::<ProbabilityWeight>::new();
114
115    //    let s1 = fst_out.add_state();
116    //    let s2 = fst_out.add_state();
117
118    //    fst_out.add_tr(s1, Tr::new(1, 2, ProbabilityWeight::new(1.0), s2))?;
119    //    fst_out.add_tr(s1, Tr::new(1, 2, ProbabilityWeight::new(2.0), s2))?;
120
121    //    fst_out.set_start(s1)?;
122    //    fst_out.set_final(s2, ProbabilityWeight::one())?;
123
124    //    tr_unique(&mut fst_in);
125
126    //    assert_eq!(fst_in, fst_out);
127
128    //    Ok(())
129    //}
130}