rustfst/algorithms/
optimize.rs1use crate::algorithms::encode::EncodeType;
2use crate::algorithms::encode::EncodeType::*;
3use crate::algorithms::*;
4use crate::fst_properties::FstProperties;
5use crate::fst_traits::{AllocableFst, MutableFst};
6use crate::semirings::{SemiringProperties, WeaklyDivisibleSemiring, WeightQuantize};
7use crate::Semiring;
8use anyhow::Result;
9
10pub fn optimize<
12 W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
13 F: MutableFst<W> + AllocableFst<W>,
14>(
15 fst: &mut F,
16) -> Result<()>
17where
18 W::ReverseWeight: WeightQuantize,
19{
20 if fst.properties().contains(FstProperties::ACCEPTOR) {
21 optimize_acceptor(fst)
22 } else {
23 optimize_transducer(fst)
24 }
25}
26
27fn determinize<
28 W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
29 F: MutableFst<W> + AllocableFst<W>,
30>(
31 fst: &mut F,
32) -> Result<()> {
33 *fst = determinize::determinize(fst)?;
34 Ok(())
35}
36
37fn encode_deter_mini_decode<
38 W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
39 F: MutableFst<W> + AllocableFst<W>,
40>(
41 fst: &mut F,
42 encoder: EncodeType,
43) -> Result<()>
44where
45 W::ReverseWeight: WeightQuantize,
46{
47 let table = encode::encode(fst, encoder)?;
48 determinize(fst)?;
49 minimize(fst)?;
50 encode::decode(fst, table)
51}
52
53fn optimize_transducer<
54 W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
55 F: MutableFst<W> + AllocableFst<W>,
56>(
57 fst: &mut F,
58) -> Result<()>
59where
60 W::ReverseWeight: WeightQuantize,
61{
62 if !fst.properties().contains(FstProperties::NO_EPSILONS) {
63 rm_epsilon::rm_epsilon(fst)?;
64 }
65
66 tr_sum(fst);
67
68 if !W::properties().contains(SemiringProperties::IDEMPOTENT) {
69 if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
70 if fst.properties().contains(FstProperties::ACYCLIC) {
71 encode_deter_mini_decode(fst, EncodeLabels)?;
72 }
73 } else {
74 minimize(fst)?;
75 }
76 } else if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
77 if !fst.properties().intersects(
78 FstProperties::ACYCLIC | FstProperties::UNWEIGHTED | FstProperties::UNWEIGHTED_CYCLES,
79 ) {
80 encode_deter_mini_decode(fst, EncodeWeightsAndLabels)?;
81 tr_sum(fst);
82 } else {
83 encode_deter_mini_decode(fst, EncodeLabels)?;
84 }
85 } else {
86 minimize(fst)?;
87 }
88
89 Ok(())
90}
91
92fn optimize_acceptor<
93 W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
94 F: MutableFst<W> + AllocableFst<W>,
95>(
96 fst: &mut F,
97) -> Result<()>
98where
99 W::ReverseWeight: WeightQuantize,
100{
101 if !fst.properties().contains(FstProperties::NO_EPSILONS) {
102 rm_epsilon::rm_epsilon(fst)?;
103 }
104 tr_sum(fst);
105 if !W::properties().contains(SemiringProperties::IDEMPOTENT) {
106 if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
107 if fst.properties().contains(FstProperties::ACYCLIC) {
108 determinize(fst)?;
109 minimize(fst)?;
110 }
111 } else {
112 minimize(fst)?;
113 }
114 } else if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
115 if !fst.properties().intersects(
116 FstProperties::ACYCLIC | FstProperties::UNWEIGHTED | FstProperties::UNWEIGHTED_CYCLES,
117 ) {
118 encode_deter_mini_decode(fst, EncodeWeights)?;
119 tr_sum(fst)
120 } else {
121 determinize(fst)?;
122 minimize(fst)?;
123 }
124 } else {
125 minimize(fst)?;
126 }
127 Ok(())
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::fst_traits::Fst;
134 use crate::prelude::{TropicalWeight, VectorFst};
135 use crate::SymbolTable;
136 use proptest::prelude::any;
137 use proptest::proptest;
138 use std::sync::Arc;
139
140 proptest! {
141 #[test]
142 fn test_proptest_optimize_keeps_symts(mut fst in any::<VectorFst::<TropicalWeight>>()) {
143 let symt = Arc::new(SymbolTable::new());
144 fst.set_input_symbols(Arc::clone(&symt));
145 fst.set_output_symbols(Arc::clone(&symt));
146
147 optimize(&mut fst).unwrap();
148
149 assert!(fst.input_symbols().is_some());
150 assert!(fst.output_symbols().is_some());
151 }
152 }
153}