// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Cartesian power weight semiring operation definitions. #ifndef FST_POWER_WEIGHT_H_ #define FST_POWER_WEIGHT_H_ #include #include #include namespace fst { // Cartesian power semiring: W ^ n // // Forms: // - a left semimodule when W is a left semiring, // - a right semimodule when W is a right semiring, // - a bisemimodule when W is a semiring, // the free semimodule of rank n over W // The Times operation is overloaded to provide the left and right scalar // products. template class PowerWeight : public TupleWeight { public: using ReverseWeight = PowerWeight; PowerWeight() {} explicit PowerWeight(const TupleWeight &weight) : TupleWeight(weight) {} template PowerWeight(Iterator begin, Iterator end) : TupleWeight(begin, end) {} // Initialize component `index` to `weight`; initialize all other components // to `default_weight` PowerWeight(size_t index, const W &weight, const W &default_weight = W::Zero()) : TupleWeight(index, weight, default_weight) {} static const PowerWeight &Zero() { static const PowerWeight zero(TupleWeight::Zero()); return zero; } static const PowerWeight &One() { static const PowerWeight one(TupleWeight::One()); return one; } static const PowerWeight &NoWeight() { static const PowerWeight no_weight(TupleWeight::NoWeight()); return no_weight; } static const string &Type() { static const string *const type = new string(W::Type() + "_^" + std::to_string(n)); return *type; } static constexpr uint64 Properties() { return W::Properties() & (kLeftSemiring | kRightSemiring | kCommutative | kIdempotent); } PowerWeight Quantize(float delta = kDelta) const { return PowerWeight(TupleWeight::Quantize(delta)); } ReverseWeight Reverse() const { return ReverseWeight(TupleWeight::Reverse()); } }; // Semiring plus operation. template inline PowerWeight Plus(const PowerWeight &w1, const PowerWeight &w2) { PowerWeight result; for (size_t i = 0; i < n; ++i) { result.SetValue(i, Plus(w1.Value(i), w2.Value(i))); } return result; } // Semiring times operation. template inline PowerWeight Times(const PowerWeight &w1, const PowerWeight &w2) { PowerWeight result; for (size_t i = 0; i < n; ++i) { result.SetValue(i, Times(w1.Value(i), w2.Value(i))); } return result; } // Semiring divide operation. template inline PowerWeight Divide(const PowerWeight &w1, const PowerWeight &w2, DivideType type = DIVIDE_ANY) { PowerWeight result; for (size_t i = 0; i < n; ++i) { result.SetValue(i, Divide(w1.Value(i), w2.Value(i), type)); } return result; } // Semimodule left scalar product. template inline PowerWeight Times(const W &scalar, const PowerWeight &weight) { PowerWeight result; for (size_t i = 0; i < n; ++i) { result.SetValue(i, Times(scalar, weight.Value(i))); } return result; } // Semimodule right scalar product. template inline PowerWeight Times(const PowerWeight &weight, const W &scalar) { PowerWeight result; for (size_t i = 0; i < n; ++i) { result.SetValue(i, Times(weight.Value(i), scalar)); } return result; } // Semimodule dot product. template inline W DotProduct(const PowerWeight &w1, const PowerWeight &w2) { W result(W::Zero()); for (size_t i = 0; i < n; ++i) { result = Plus(result, Times(w1.Value(i), w2.Value(i))); } return result; } // This function object generates weights over the Cartesian power of rank // n over the underlying weight. This is intended primarily for testing. template class WeightGenerate> { public: using Weight = PowerWeight; using Generate = WeightGenerate; explicit WeightGenerate(bool allow_zero = true) : generate_(allow_zero) {} Weight operator()() const { Weight result; for (size_t i = 0; i < n; ++i) result.SetValue(i, generate_()); return result; } private: Generate generate_; }; } // namespace fst #endif // FST_POWER_WEIGHT_H_