// 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: <One, Zero>
|
// Zero: <Zero, Zero>
|
// Plus: <a1, b1> + <a2, b2> = < (a1 + a2) , (b1 + b2) >
|
// Times: <a1, b1> * <a2, b2> = < (a1 * a2) , [(a1 * b2) + (a2 * b1)] >
|
// Division: Undefined (currently)
|
//
|
// Usually used to store the pair <probability, random_variable> so that
|
// ShortestDistance[Fst<ArcTpl<ExpectationWeight<P, V>>>]
|
// == < PosteriorProbability, Expected_Value[V] >
|
|
#ifndef FST_EXPECTATION_WEIGHT_H_
|
#define FST_EXPECTATION_WEIGHT_H_
|
|
#include <string>
|
|
#include <fst/log.h>
|
|
#include <fst/pair-weight.h>
|
#include <fst/product-weight.h>
|
|
|
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 X1, class X2>
|
class ExpectationWeight : public PairWeight<X1, X2> {
|
public:
|
using PairWeight<X1, X2>::Value1;
|
using PairWeight<X1, X2>::Value2;
|
|
using PairWeight<X1, X2>::Reverse;
|
using PairWeight<X1, X2>::Quantize;
|
using PairWeight<X1, X2>::Member;
|
|
using ReverseWeight =
|
ExpectationWeight<typename X1::ReverseWeight, typename X2::ReverseWeight>;
|
|
ExpectationWeight() : PairWeight<X1, X2>(Zero()) {}
|
|
explicit ExpectationWeight(const PairWeight<X1, X2> &weight)
|
: PairWeight<X1, X2>(weight) {}
|
|
ExpectationWeight(const X1 &x1, const X2 &x2) : PairWeight<X1, X2>(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<X1, X2> Quantize(float delta = kDelta) const {
|
return ExpectationWeight(PairWeight<X1, X2>::Quantize());
|
}
|
|
ReverseWeight Reverse() const {
|
return ReverseWeight(PairWeight<X1, X2>::Reverse());
|
}
|
|
bool Member() const { return PairWeight<X1, X2>::Member(); }
|
|
static constexpr uint64 Properties() {
|
return X1::Properties() & X2::Properties() &
|
(kLeftSemiring | kRightSemiring | kCommutative | kIdempotent);
|
}
|
};
|
|
template <class X1, class X2>
|
inline ExpectationWeight<X1, X2> Plus(const ExpectationWeight<X1, X2> &w1,
|
const ExpectationWeight<X1, X2> &w2) {
|
return ExpectationWeight<X1, X2>(Plus(w1.Value1(), w2.Value1()),
|
Plus(w1.Value2(), w2.Value2()));
|
}
|
|
template <class X1, class X2>
|
inline ExpectationWeight<X1, X2> Times(const ExpectationWeight<X1, X2> &w1,
|
const ExpectationWeight<X1, X2> &w2) {
|
return ExpectationWeight<X1, X2>(
|
Times(w1.Value1(), w2.Value1()),
|
Plus(Times(w1.Value1(), w2.Value2()), Times(w1.Value2(), w2.Value1())));
|
}
|
|
template <class X1, class X2>
|
inline ExpectationWeight<X1, X2> Divide(const ExpectationWeight<X1, X2> &w1,
|
const ExpectationWeight<X1, X2> &w2,
|
DivideType typ = DIVIDE_ANY) {
|
FSTERROR() << "ExpectationWeight::Divide: Not implemented";
|
return ExpectationWeight<X1, X2>::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 X1, class X2>
|
class WeightGenerate<ExpectationWeight<X1, X2>>
|
: public WeightGenerate<PairWeight<X1, X2>> {
|
public:
|
using Weight = ExpectationWeight<X1, X2>;
|
using Generate = WeightGenerate<PairWeight<X1, X2>>;
|
|
explicit WeightGenerate(bool allow_zero = true) : Generate(allow_zero) {}
|
|
Weight operator()() const { return Weight(Generate::operator()()); }
|
};
|
|
} // namespace fst
|
|
#endif // FST_EXPECTATION_WEIGHT_H_
|