// See www.openfst.org for extensive documentation on this weighted // finite-state transducer library. // // Utility classes for the recursive replacement of FSTs (RTNs). #ifndef FST_REPLACE_UTIL_H_ #define FST_REPLACE_UTIL_H_ #include #include #include #include #include #include #include #include #include namespace fst { // This specifies what labels to output on the call or return arc. Note that // REPLACE_LABEL_INPUT and REPLACE_LABEL_OUTPUT will produce transducers when // applied to acceptors. enum ReplaceLabelType { // Epsilon labels on both input and output. REPLACE_LABEL_NEITHER = 1, // Non-epsilon labels on input and epsilon on output. REPLACE_LABEL_INPUT = 2, // Epsilon on input and non-epsilon on output. REPLACE_LABEL_OUTPUT = 3, // Non-epsilon labels on both input and output. REPLACE_LABEL_BOTH = 4 }; // By default ReplaceUtil will copy the input label of the replace arc. // The call_label_type and return_label_type options specify how to manage // the labels of the call arc and the return arc of the replace FST struct ReplaceUtilOptions { int64 root; // Root rule for expansion. ReplaceLabelType call_label_type; // How to label call arc. ReplaceLabelType return_label_type; // How to label return arc. int64 return_label; // Label to put on return arc. explicit ReplaceUtilOptions( int64 root = kNoLabel, ReplaceLabelType call_label_type = REPLACE_LABEL_INPUT, ReplaceLabelType return_label_type = REPLACE_LABEL_NEITHER, int64 return_label = 0) : root(root), call_label_type(call_label_type), return_label_type(return_label_type), return_label(return_label) {} // For backwards compatibility. ReplaceUtilOptions(int64 root, bool epsilon_replace_arc) : ReplaceUtilOptions(root, epsilon_replace_arc ? REPLACE_LABEL_NEITHER : REPLACE_LABEL_INPUT) {} }; // Every non-terminal on a path appears as the first label on that path in every // FST associated with a given SCC of the replace dependency graph. This would // be true if the SCC were formed from left-linear grammar rules. constexpr uint8 kReplaceSCCLeftLinear = 0x01; // Every non-terminal on a path appears as the final label on that path in every // FST associated with a given SCC of the replace dependency graph. This would // be true if the SCC were formed from right-linear grammar rules. constexpr uint8 kReplaceSCCRightLinear = 0x02; // The SCC in the replace dependency graph has more than one state or a // self-loop. constexpr uint8 kReplaceSCCNonTrivial = 0x04; // Defined in replace.h. template void Replace( const std::vector *>> &, MutableFst *, const ReplaceUtilOptions &); // Utility class for the recursive replacement of FSTs (RTNs). The user provides // a set of label/FST pairs at construction. These are used by methods for // testing cyclic dependencies and connectedness and doing RTN connection and // specific FST replacement by label or for various optimization properties. The // modified results can be obtained with the GetFstPairs() or // GetMutableFstPairs() methods. template class ReplaceUtil { public: using Label = typename Arc::Label; using StateId = typename Arc::StateId; using Weight = typename Arc::Weight; using FstPair = std::pair *>; using MutableFstPair = std::pair *>; using NonTerminalHash = std::unordered_map; // Constructs from mutable FSTs; FST ownership is given to ReplaceUtil. ReplaceUtil(const std::vector &fst_pairs, const ReplaceUtilOptions &opts); // Constructs from FSTs; FST ownership is retained by caller. ReplaceUtil(const std::vector &fst_pairs, const ReplaceUtilOptions &opts); // Constructs from ReplaceFst internals; FST ownership is retained by caller. ReplaceUtil(const std::vector>> &fst_array, const NonTerminalHash &nonterminal_hash, const ReplaceUtilOptions &opts); ~ReplaceUtil() { for (Label i = 0; i < fst_array_.size(); ++i) delete fst_array_[i]; } // True if the non-terminal dependencies are cyclic. Cyclic dependencies will // result in an unexpandable FST. bool CyclicDependencies() const { GetDependencies(false); return depprops_ & kCyclic; } // Returns the strongly-connected component ID in the dependency graph of the // replace FSTS. StateId SCC(Label label) const { GetDependencies(false); const auto it = nonterminal_hash_.find(label); if (it == nonterminal_hash_.end()) return kNoStateId; return depscc_[it->second]; } // Returns properties for the strongly-connected component in the dependency // graph of the replace FSTs. If the SCC is kReplaceSCCLeftLinear or // kReplaceSCCRightLinear, that SCC can be represented as finite-state despite // any cyclic dependencies, but not by the usual replacement operation (see // fst/extensions/pdt/replace.h). uint8 SCCProperties(StateId scc_id) { GetSCCProperties(); return depsccprops_[scc_id]; } // Returns true if no useless FSTs, states or transitions are present in the // RTN. bool Connected() const { GetDependencies(false); uint64 props = kAccessible | kCoAccessible; for (Label i = 0; i < fst_array_.size(); ++i) { if (!fst_array_[i]) continue; if (fst_array_[i]->Properties(props, true) != props || !depaccess_[i]) { return false; } } return true; } // Removes useless FSTs, states and transitions from the RTN. void Connect(); // Replaces FSTs specified by labels, unless there are cyclic dependencies. void ReplaceLabels(const std::vector