// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Cartesian power weight semiring operation definitions, using // SparseTupleWeight as underlying representation. #ifndef FST_SPARSE_POWER_WEIGHT_H_ #define FST_SPARSE_POWER_WEIGHT_H_ #include #include #include #include namespace fst { // Sparse 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. // // K is the key value type. kNoKey (-1) is reserved for internal use template class SparsePowerWeight : public SparseTupleWeight { public: using ReverseWeight = SparsePowerWeight; SparsePowerWeight() {} explicit SparsePowerWeight(const SparseTupleWeight &weight) : SparseTupleWeight(weight) {} template SparsePowerWeight(Iterator begin, Iterator end) : SparseTupleWeight(begin, end) {} // Initialize component `key` to `weight`, with `default_weight` for all // other components. SparsePowerWeight(const K &key, const W &weight, const W &default_weight = W::Zero()) : SparseTupleWeight(key, weight, default_weight) {} static const SparsePowerWeight &Zero() { static const SparsePowerWeight zero(SparseTupleWeight::Zero()); return zero; } static const SparsePowerWeight &One() { static const SparsePowerWeight one(SparseTupleWeight::One()); return one; } static const SparsePowerWeight &NoWeight() { static const SparsePowerWeight no_weight( SparseTupleWeight::NoWeight()); return no_weight; } // Overide this: Overwrite the Type method to reflect the key type if using // a non-default key type. static const string &Type() { static const string *const type = [] { string type = W::Type() + "_^n"; if (sizeof(K) != sizeof(uint32)) { type += "_" + std::to_string(CHAR_BIT * sizeof(K)); } return new string(type); }(); return *type; } static constexpr uint64 Properties() { return W::Properties() & (kLeftSemiring | kRightSemiring | kCommutative | kIdempotent); } SparsePowerWeight Quantize(float delta = kDelta) const { return SparsePowerWeight(SparseTupleWeight::Quantize(delta)); } ReverseWeight Reverse() const { return ReverseWeight(SparseTupleWeight::Reverse()); } }; template inline SparsePowerWeight SparsePowerWeightMap( const SparsePowerWeight &w1, const SparsePowerWeight &w2, const M &operator_mapper) { SparsePowerWeight result; SparseTupleWeightMap(&result, w1, w2, operator_mapper); return result; } // Semimodule plus operation. template inline SparsePowerWeight Plus(const SparsePowerWeight &w1, const SparsePowerWeight &w2) { return SparsePowerWeightMap(w1, w2, [](const K &k, const W &v1, const W &v2) { return Plus(v1, v2); }); } // Semimodule times operation. template inline SparsePowerWeight Times(const SparsePowerWeight &w1, const SparsePowerWeight &w2) { return SparsePowerWeightMap(w1, w2, [](const K &k, const W &v1, const W &v2) { return Times(v1, v2); }); } // Semimodule divide operation. template inline SparsePowerWeight Divide(const SparsePowerWeight &w1, const SparsePowerWeight &w2, DivideType type = DIVIDE_ANY) { return SparsePowerWeightMap(w1, w2, [type](const K &k, const W &v1, const W &v2) { return Divide(v1, v2, type); }); } // Semimodule dot product operation. template inline const W &DotProduct(const SparsePowerWeight &w1, const SparsePowerWeight &w2) { const SparsePowerWeight product = Times(w1, w2); W result(W::Zero()); for (SparseTupleWeightIterator it(product); !it.Done(); it.Next()) { result = Plus(result, it.Value().second); } return result; } template inline bool ApproxEqual(const SparsePowerWeight &w1, const SparsePowerWeight &w2, float delta = kDelta) { auto result = SparsePowerWeightMap( w1, w2, [delta](const K &k, const W &v1, const W &v2) { return ApproxEqual(v1, v2, delta) ? W::One() : W::Zero(); }); return result == SparsePowerWeight::One(); } template inline SparsePowerWeight Times(const W &k, const SparsePowerWeight &w2) { const SparseTupleWeight t2(k); const SparsePowerWeight w1(t2); return Times(w1, w2); } template inline SparsePowerWeight Times(const SparsePowerWeight &w1, const W &k) { const SparseTupleWeight t2(k); const SparsePowerWeight w2(t2); return Times(w1, w2); } template inline SparsePowerWeight Divide(const SparsePowerWeight &w1, const W &k, DivideType divide_type = DIVIDE_ANY) { const SparseTupleWeight t2(k); const SparsePowerWeight w2(t2); return Divide(w1, w2, divide_type); } // 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 = SparsePowerWeight; using Generate = WeightGenerate; explicit WeightGenerate(bool allow_zero = true, size_t sparse_power_rank = 3) : generate_(allow_zero), sparse_power_rank_(sparse_power_rank) {} Weight operator()() const { Weight weight; for (size_t i = 1; i <= sparse_power_rank_; ++i) { weight.PushBack(i, generate_(), true); } return weight; } private: const Generate generate_; const size_t sparse_power_rank_; }; } // namespace fst #endif // FST_SPARSE_POWER_WEIGHT_H_