// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Weights consisting of sets (of integral Labels) and // associated semiring operation definitions using intersect // and union. #ifndef FST_SET_WEIGHT_H_ #define FST_SET_WEIGHT_H_ #include #include #include #include #include #include #include namespace fst { constexpr int kSetEmpty = 0; // Label for the empty set. constexpr int kSetUniv = -1; // Label for the universal set. constexpr int kSetBad = -2; // Label for a non-set. constexpr char kSetSeparator = '_'; // Label separator in sets. // Determines whether to use (intersect, union) or (union, intersect) // as (+, *) for the semiring. SET_INTERSECT_UNION_RESTRICTED is a // restricted version of (intersect, union) that requires summed // arguments to be equal (or an error is signalled), useful for // algorithms that require a unique labelled path weight. SET_BOOLEAN // treats all non-Zero() elements as equivalent (with Zero() == // UnivSet()), useful for algorithms that don't really depend on the // detailed sets. enum SetType { SET_INTERSECT_UNION = 0, SET_UNION_INTERSECT = 1, SET_INTERSECT_UNION_RESTRICT = 2, SET_BOOLEAN = 3 }; template class SetWeightIterator; // Set semiring of integral labels. template class SetWeight { public: using Label = Label_; using ReverseWeight = SetWeight; using Iterator = SetWeightIterator; friend class SetWeightIterator; // Allow type-converting copy and move constructors private access. template friend class SetWeight; SetWeight() {} // Input should be positive, sorted and unique. template SetWeight(const Iterator &begin, const Iterator &end) { for (auto iter = begin; iter != end; ++iter) PushBack(*iter); } // Input should be positive. (Non-positive value has // special internal meaning w.r.t. integral constants above.) explicit SetWeight(Label label) { PushBack(label); } template explicit SetWeight(const SetWeight &w) : first_(w.first_), rest_(w.rest_) {} template explicit SetWeight(SetWeight &&w) : first_(w.first_), rest_(std::move(w.rest_)) { w.Clear(); } template SetWeight &operator=(const SetWeight &w) { first_ = w.first_; rest_ = w.rest_; return *this; } template SetWeight &operator=(SetWeight &&w) { first_ = w.first_; rest_ = std::move(w.rest_); w.Clear(); return *this; } static const SetWeight &Zero() { return S == SET_UNION_INTERSECT ? EmptySet() : UnivSet(); } static const SetWeight &One() { return S == SET_UNION_INTERSECT ? UnivSet() : EmptySet(); } static const SetWeight &NoWeight() { static const auto *const no_weight = new SetWeight(Label(kSetBad)); return *no_weight; } static const string &Type() { static const string *const type = new string( S == SET_UNION_INTERSECT ? "union_intersect_set" : (S == SET_INTERSECT_UNION ? "intersect_union_set" : (S == SET_INTERSECT_UNION_RESTRICT ? "restricted_set_intersect_union" : "boolean_set"))); return *type; } bool Member() const; std::istream &Read(std::istream &strm); std::ostream &Write(std::ostream &strm) const; size_t Hash() const; SetWeight Quantize(float delta = kDelta) const { return *this; } ReverseWeight Reverse() const; static constexpr uint64 Properties() { return kIdempotent | kLeftSemiring | kRightSemiring | kCommutative; } // These operations combined with the SetWeightIterator // provide the access and mutation of the set internal elements. // The empty set. static const SetWeight &EmptySet() { static const auto *const empty = new SetWeight(Label(kSetEmpty)); return *empty; } // The univeral set. static const SetWeight &UnivSet() { static const auto *const univ = new SetWeight(Label(kSetUniv)); return *univ; } // Clear existing SetWeight. void Clear() { first_ = kSetEmpty; rest_.clear(); } size_t Size() const { return first_ == kSetEmpty ? 0 : rest_.size() + 1; } Label Back() { if (rest_.empty()) { return first_; } else { return rest_.back(); } } // Caller must add in sort order and be unique (or error signalled). // Input should also be positive. Non-positive value (for the first // push) has special internal meaning w.r.t. integral constants above. void PushBack(Label label) { if (first_ == kSetEmpty) { first_ = label; } else { if (label <= Back() || label <= 0) { FSTERROR() << "SetWeight: labels must be positive, added" << " in sort order and be unique."; rest_.push_back(Label(kSetBad)); } rest_.push_back(label); } } private: Label first_ = kSetEmpty; // First label in set (kSetEmpty if empty). std::list