// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Expectation semiring as described by Jason Eisner: // See: doi=10.1.1.22.9398 // Multiplex semiring operations and identities: // One: // Zero: // Plus: + = < (a1 + a2) , (b1 + b2) > // Times: * = < (a1 * a2) , [(a1 * b2) + (a2 * b1)] > // Division: Undefined (currently) // // Usually used to store the pair so that // ShortestDistance[Fst>>] // == < PosteriorProbability, Expected_Value[V] > #ifndef FST_EXPECTATION_WEIGHT_H_ #define FST_EXPECTATION_WEIGHT_H_ #include #include #include #include namespace fst { // X1 is usually a probability weight like LogWeight. // X2 is usually a random variable or vector (see SignedLogWeight or // SparsePowerWeight). // // If X1 is distinct from X2, it is required that there is an external product // between X1 and X2 and if both semriring are commutative, or left or right // semirings, then result must have those properties. template class ExpectationWeight : public PairWeight { public: using PairWeight::Value1; using PairWeight::Value2; using PairWeight::Reverse; using PairWeight::Quantize; using PairWeight::Member; using ReverseWeight = ExpectationWeight; ExpectationWeight() : PairWeight(Zero()) {} ExpectationWeight(const ExpectationWeight &weight) : PairWeight(weight) {} explicit ExpectationWeight(const PairWeight &weight) : PairWeight(weight) {} ExpectationWeight(const X1 &x1, const X2 &x2) : PairWeight(x1, x2) {} static const ExpectationWeight &Zero() { static const ExpectationWeight zero(X1::Zero(), X2::Zero()); return zero; } static const ExpectationWeight &One() { static const ExpectationWeight one(X1::One(), X2::Zero()); return one; } static const ExpectationWeight &NoWeight() { static const ExpectationWeight no_weight(X1::NoWeight(), X2::NoWeight()); return no_weight; } static const string &Type() { static const string *const type = new string("expectation_" + X1::Type() + "_" + X2::Type()); return *type; } PairWeight Quantize(float delta = kDelta) const { return ExpectationWeight(PairWeight::Quantize()); } ReverseWeight Reverse() const { return ReverseWeight(PairWeight::Reverse()); } bool Member() const { return PairWeight::Member(); } static constexpr uint64 Properties() { return X1::Properties() & X2::Properties() & (kLeftSemiring | kRightSemiring | kCommutative | kIdempotent); } }; template inline ExpectationWeight Plus(const ExpectationWeight &w1, const ExpectationWeight &w2) { return ExpectationWeight(Plus(w1.Value1(), w2.Value1()), Plus(w1.Value2(), w2.Value2())); } template inline ExpectationWeight Times(const ExpectationWeight &w1, const ExpectationWeight &w2) { return ExpectationWeight( Times(w1.Value1(), w2.Value1()), Plus(Times(w1.Value1(), w2.Value2()), Times(w1.Value2(), w2.Value1()))); } template inline ExpectationWeight Divide(const ExpectationWeight &w1, const ExpectationWeight &w2, DivideType typ = DIVIDE_ANY) { FSTERROR() << "ExpectationWeight::Divide: Not implemented"; return ExpectationWeight::NoWeight(); } // This function object generates weights by calling the underlying generators // for the template weight types, like all other pair weight types. This is // intended primarily for testing. template class WeightGenerate> : public WeightGenerate> { public: using Weight = ExpectationWeight; using Generate = WeightGenerate>; explicit WeightGenerate(bool allow_zero = true) : Generate(allow_zero) {} Weight operator()() const { return Weight(Generate::operator()()); } }; } // namespace fst #endif // FST_EXPECTATION_WEIGHT_H_