1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::algorithms::encode::EncodeType;
use crate::algorithms::encode::EncodeType::*;
use crate::algorithms::*;
use crate::fst_properties::FstProperties;
use crate::fst_traits::{AllocableFst, MutableFst};
use crate::semirings::{SemiringProperties, WeaklyDivisibleSemiring, WeightQuantize};
use crate::Semiring;
use anyhow::Result;

pub fn optimize<
    W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
    F: MutableFst<W> + AllocableFst<W>,
>(
    fst: &mut F,
) -> Result<()>
where
    W::ReverseWeight: WeightQuantize,
{
    if fst.properties().contains(FstProperties::ACCEPTOR) {
        optimize_acceptor(fst)
    } else {
        optimize_transducer(fst)
    }
}

fn determinize<
    W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
    F: MutableFst<W> + AllocableFst<W>,
>(
    fst: &mut F,
) -> Result<()> {
    *fst = determinize::determinize(fst)?;
    Ok(())
}

fn encode_deter_mini_decode<
    W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
    F: MutableFst<W> + AllocableFst<W>,
>(
    fst: &mut F,
    encoder: EncodeType,
) -> Result<()>
where
    W::ReverseWeight: WeightQuantize,
{
    let table = encode::encode(fst, encoder)?;
    determinize(fst)?;
    minimize(fst)?;
    encode::decode(fst, table)
}

fn optimize_transducer<
    W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
    F: MutableFst<W> + AllocableFst<W>,
>(
    fst: &mut F,
) -> Result<()>
where
    W::ReverseWeight: WeightQuantize,
{
    if !fst.properties().contains(FstProperties::NO_EPSILONS) {
        rm_epsilon::rm_epsilon(fst)?;
    }

    tr_sum(fst);

    if !W::properties().contains(SemiringProperties::IDEMPOTENT) {
        if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
            if fst.properties().contains(FstProperties::ACYCLIC) {
                encode_deter_mini_decode(fst, EncodeLabels)?;
            }
        } else {
            minimize(fst)?;
        }
    } else {
        if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
            if !fst.properties().intersects(
                FstProperties::ACYCLIC
                    | FstProperties::UNWEIGHTED
                    | FstProperties::UNWEIGHTED_CYCLES,
            ) {
                encode_deter_mini_decode(fst, EncodeWeightsAndLabels)?;
                tr_sum(fst);
            } else {
                encode_deter_mini_decode(fst, EncodeLabels)?;
            }
        } else {
            minimize(fst)?;
        }
    }
    Ok(())
}

fn optimize_acceptor<
    W: Semiring + WeaklyDivisibleSemiring + WeightQuantize,
    F: MutableFst<W> + AllocableFst<W>,
>(
    fst: &mut F,
) -> Result<()>
where
    W::ReverseWeight: WeightQuantize,
{
    if !fst.properties().contains(FstProperties::NO_EPSILONS) {
        rm_epsilon::rm_epsilon(fst)?;
    }
    tr_sum(fst);
    if !W::properties().contains(SemiringProperties::IDEMPOTENT) {
        if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
            if fst.properties().contains(FstProperties::ACYCLIC) {
                determinize(fst)?;
                minimize(fst)?;
            }
        } else {
            minimize(fst)?;
        }
    } else {
        if !fst.properties().contains(FstProperties::I_DETERMINISTIC) {
            if !fst.properties().intersects(
                FstProperties::ACYCLIC
                    | FstProperties::UNWEIGHTED
                    | FstProperties::UNWEIGHTED_CYCLES,
            ) {
                encode_deter_mini_decode(fst, EncodeWeights)?;
                tr_sum(fst)
            } else {
                determinize(fst)?;
                minimize(fst)?;
            }
        } else {
            minimize(fst)?;
        }
    }
    Ok(())
}