You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
18 KiB

  1. // fstext/fstext-utils.h
  2. // Copyright 2009-2011 Microsoft Corporation
  3. // 2012-2013 Johns Hopkins University (Author: Daniel Povey)
  4. // 2013 Guoguo Chen
  5. // 2014 Telepoint Global Hosting Service, LLC. (Author: David
  6. // Snyder)
  7. // See ../../COPYING for clarification regarding multiple authors
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  17. // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  18. // MERCHANTABLITY OR NON-INFRINGEMENT.
  19. // See the Apache 2 License for the specific language governing permissions and
  20. // limitations under the License.
  21. #ifndef KALDI_FSTEXT_FSTEXT_UTILS_H_
  22. #define KALDI_FSTEXT_FSTEXT_UTILS_H_
  23. #include <fst/fst-decl.h>
  24. #include <fst/fstlib.h>
  25. #include <algorithm>
  26. #include <map>
  27. #include <set>
  28. #include <vector>
  29. #include "base/kaldi-common.h" // for error reporting macros.
  30. #include "fst/script/print-impl.h"
  31. #include "fstext/determinize-star.h"
  32. #include "fstext/remove-eps-local.h"
  33. #include "util/text-utils.h" // for SplitStringToVector
  34. namespace fst {
  35. /// Returns the highest numbered output symbol id of the FST (or zero
  36. /// for an empty FST.
  37. template <class Arc>
  38. typename Arc::Label HighestNumberedOutputSymbol(const Fst<Arc>& fst);
  39. /// Returns the highest numbered input symbol id of the FST (or zero
  40. /// for an empty FST.
  41. template <class Arc>
  42. typename Arc::Label HighestNumberedInputSymbol(const Fst<Arc>& fst);
  43. /// Returns the total number of arcs in an FST.
  44. template <class Arc>
  45. typename Arc::StateId NumArcs(const ExpandedFst<Arc>& fst);
  46. /// GetInputSymbols gets the list of symbols on the input of fst
  47. /// (including epsilon, if include_eps == true), as a sorted, unique
  48. /// list.
  49. template <class Arc, class I>
  50. void GetInputSymbols(const Fst<Arc>& fst, bool include_eps,
  51. std::vector<I>* symbols);
  52. /// GetOutputSymbols gets the list of symbols on the output of fst
  53. /// (including epsilon, if include_eps == true)
  54. template <class Arc, class I>
  55. void GetOutputSymbols(const Fst<Arc>& fst, bool include_eps,
  56. std::vector<I>* symbols);
  57. /// ClearSymbols sets all the symbols on the input and/or
  58. /// output side of the FST to zero, as specified.
  59. /// It does not alter the symbol tables.
  60. template <class Arc>
  61. void ClearSymbols(bool clear_input, bool clear_output, MutableFst<Arc>* fst);
  62. template <class I>
  63. void GetSymbols(const SymbolTable& symtab, bool include_eps,
  64. std::vector<I>* syms_out);
  65. inline void DeterminizeStarInLog(VectorFst<StdArc>* fst, float delta = kDelta,
  66. bool* debug_ptr = NULL, int max_states = -1);
  67. // e.g. of using this function: PushInLog<REWEIGHT_TO_INITIAL>(fst,
  68. // kPushWeights|kPushLabels);
  69. template <ReweightType rtype> // == REWEIGHT_TO_{INITIAL, FINAL}
  70. void PushInLog(VectorFst<StdArc>* fst, uint32 ptype, float delta = kDelta) {
  71. // PushInLog pushes the FST
  72. // and returns a new pushed FST (labels and weights pushed to the left).
  73. VectorFst<LogArc>* fst_log =
  74. new VectorFst<LogArc>; // Want to determinize in log semiring.
  75. Cast(*fst, fst_log);
  76. VectorFst<StdArc> tmp;
  77. *fst = tmp; // free up memory.
  78. VectorFst<LogArc>* fst_pushed_log = new VectorFst<LogArc>;
  79. Push<LogArc, rtype>(*fst_log, fst_pushed_log, ptype, delta);
  80. Cast(*fst_pushed_log, fst);
  81. delete fst_log;
  82. delete fst_pushed_log;
  83. }
  84. // Minimizes after encoding; applicable to all FSTs. It is like what you get
  85. // from the Minimize() function, except it will not push the weights, or the
  86. // symbols. This is better for our recipes, as we avoid ever pushing the
  87. // weights. However, it will only minimize optimally if your graphs are such
  88. // that the symbols are as far to the left as they can go, and the weights
  89. // in combinable paths are the same... hard to formalize this, but it's
  90. // something that is satisified by our normal FSTs.
  91. template <class Arc>
  92. void MinimizeEncoded(VectorFst<Arc>* fst, float delta = kDelta) {
  93. Map(fst, QuantizeMapper<Arc>(delta));
  94. EncodeMapper<Arc> encoder(kEncodeLabels | kEncodeWeights, ENCODE);
  95. Encode(fst, &encoder);
  96. internal::AcceptorMinimize(fst);
  97. Decode(fst, encoder);
  98. }
  99. /// GetLinearSymbolSequence gets the symbol sequence from a linear FST.
  100. /// If the FST is not just a linear sequence, it returns false. If it is
  101. /// a linear sequence (including the empty FST), it returns true. In this
  102. /// case it outputs the symbol
  103. /// sequences as "isymbols_out" and "osymbols_out" (removing epsilons), and
  104. /// the total weight as "tot_weight". The total weight will be Weight::Zero()
  105. /// if the FST is empty. If any of the output pointers are NULL, it does not
  106. /// create that output.
  107. template <class Arc, class I>
  108. bool GetLinearSymbolSequence(const Fst<Arc>& fst, std::vector<I>* isymbols_out,
  109. std::vector<I>* osymbols_out,
  110. typename Arc::Weight* tot_weight_out);
  111. /// This function converts an FST with a special structure, which is
  112. /// output by the OpenFst functions ShortestPath and RandGen, and converts
  113. /// them into a std::vector of separate FSTs. This special structure is that
  114. /// the only state that has more than one (arcs-out or final-prob) is the
  115. /// start state. fsts_out is resized to the appropriate size.
  116. template <class Arc>
  117. void ConvertNbestToVector(const Fst<Arc>& fst,
  118. std::vector<VectorFst<Arc> >* fsts_out);
  119. /// Takes the n-shortest-paths (using ShortestPath), but outputs
  120. /// the result as a vector of up to n fsts. This function will
  121. /// size the "fsts_out" vector to however many paths it got
  122. /// (which will not exceed n). n must be >= 1.
  123. template <class Arc>
  124. void NbestAsFsts(const Fst<Arc>& fst, size_t n,
  125. std::vector<VectorFst<Arc> >* fsts_out);
  126. /// Creates unweighted linear acceptor from symbol sequence.
  127. template <class Arc, class I>
  128. void MakeLinearAcceptor(const std::vector<I>& labels, MutableFst<Arc>* ofst);
  129. /// Creates an unweighted acceptor with a linear structure, with alternatives
  130. /// at each position. Epsilon is treated like a normal symbol here.
  131. /// Each position in "labels" must have at least one alternative.
  132. template <class Arc, class I>
  133. void MakeLinearAcceptorWithAlternatives(
  134. const std::vector<std::vector<I> >& labels, MutableFst<Arc>* ofst);
  135. /// Does PreDeterminize and DeterminizeStar and then removes the disambiguation
  136. /// symbols. This is a form of determinization that will never blow up. Note
  137. /// that ifst is non-const and can be considered to be destroyed by this
  138. /// operation.
  139. /// Does not do epsilon removal (RemoveEpsLocal)-- this is so it's safe to cast
  140. /// to log and do this, and maintain equivalence in tropical.
  141. template <class Arc>
  142. void SafeDeterminizeWrapper(MutableFst<Arc>* ifst, MutableFst<Arc>* ofst,
  143. float delta = kDelta);
  144. /// SafeDeterminizeMinimizeWapper is as SafeDeterminizeWrapper except that it
  145. /// also minimizes (encoded minimization, which is safe). This algorithm will
  146. /// destroy "ifst".
  147. template <class Arc>
  148. void SafeDeterminizeMinimizeWrapper(MutableFst<Arc>* ifst, VectorFst<Arc>* ofst,
  149. float delta = kDelta);
  150. /// SafeDeterminizeMinimizeWapperInLog is as SafeDeterminizeMinimizeWrapper
  151. /// except it first casts tothe log semiring.
  152. void SafeDeterminizeMinimizeWrapperInLog(VectorFst<StdArc>* ifst,
  153. VectorFst<StdArc>* ofst,
  154. float delta = kDelta);
  155. /// RemoveSomeInputSymbols removes any symbol that appears in "to_remove", from
  156. /// the input side of the FST, replacing them with epsilon.
  157. template <class Arc, class I>
  158. void RemoveSomeInputSymbols(const std::vector<I>& to_remove,
  159. MutableFst<Arc>* fst);
  160. // MapInputSymbols will replace any input symbol i that is between 0 and
  161. // symbol_map.size()-1, with symbol_map[i]. It removes the input symbol
  162. // table of the FST.
  163. template <class Arc, class I>
  164. void MapInputSymbols(const std::vector<I>& symbol_map, MutableFst<Arc>* fst);
  165. template <class Arc>
  166. void RemoveWeights(MutableFst<Arc>* fst);
  167. /// Returns true if and only if the FST is such that the input symbols
  168. /// on arcs entering any given state all have the same value.
  169. /// if "start_is_epsilon", treat start-state as an epsilon input arc
  170. /// [i.e. ensure only epsilon can enter start-state].
  171. template <class Arc>
  172. bool PrecedingInputSymbolsAreSame(bool start_is_epsilon, const Fst<Arc>& fst);
  173. /// This is as PrecedingInputSymbolsAreSame, but with a functor f that maps
  174. /// labels to classes. The function tests whether the symbols preceding any
  175. /// given state are in the same class. Formally, f is of a type F that has an
  176. /// operator of type F::Result F::operator() (F::Arg a) const; where F::Result
  177. /// is an integer type and F::Arc can be constructed from Arc::Label. this must
  178. /// apply to valid labels and also to kNoLabel (so we can have a marker for the
  179. /// invalid labels.
  180. template <class Arc, class F>
  181. bool PrecedingInputSymbolsAreSameClass(bool start_is_epsilon,
  182. const Fst<Arc>& fst, const F& f);
  183. /// Returns true if and only if the FST is such that the input symbols
  184. /// on arcs exiting any given state all have the same value.
  185. /// If end_is_epsilon, treat end-state as an epsilon output arc [i.e. ensure
  186. /// end-states cannot have non-epsilon output transitions.]
  187. template <class Arc>
  188. bool FollowingInputSymbolsAreSame(bool end_is_epsilon, const Fst<Arc>& fst);
  189. template <class Arc, class F>
  190. bool FollowingInputSymbolsAreSameClass(bool end_is_epsilon, const Fst<Arc>& fst,
  191. const F& f);
  192. /// MakePrecedingInputSymbolsSame ensures that all arcs entering any given fst
  193. /// state have the same input symbol. It does this by detecting states
  194. /// that have differing input symbols going in, and inserting, for each of
  195. /// the preceding arcs with non-epsilon input symbol, a new dummy state that
  196. /// has an epsilon link to the fst state.
  197. /// If "start_is_epsilon", ensure that start-state can have only epsilon-links
  198. /// into it.
  199. template <class Arc>
  200. void MakePrecedingInputSymbolsSame(bool start_is_epsilon, MutableFst<Arc>* fst);
  201. /// As MakePrecedingInputSymbolsSame, but takes a functor object that maps
  202. /// labels to classes.
  203. template <class Arc, class F>
  204. void MakePrecedingInputSymbolsSameClass(bool start_is_epsilon,
  205. MutableFst<Arc>* fst, const F& f);
  206. /// MakeFollowingInputSymbolsSame ensures that all arcs exiting any given fst
  207. /// state have the same input symbol. It does this by detecting states that
  208. /// have differing input symbols on arcs that exit it, and inserting, for each
  209. /// of the following arcs with non-epsilon input symbol, a new dummy state that
  210. /// has an input-epsilon link from the fst state. The output symbol and weight
  211. /// stay on the link to the dummy state (in order to keep the FST
  212. /// output-deterministic and stochastic, if it already was). If end_is_epsilon,
  213. /// treat "being a final-state" like having an epsilon output link.
  214. template <class Arc>
  215. void MakeFollowingInputSymbolsSame(bool end_is_epsilon, MutableFst<Arc>* fst);
  216. /// As MakeFollowingInputSymbolsSame, but takes a functor object that maps
  217. /// labels to classes.
  218. template <class Arc, class F>
  219. void MakeFollowingInputSymbolsSameClass(bool end_is_epsilon,
  220. MutableFst<Arc>* fst, const F& f);
  221. /// MakeLoopFst creates an FST that has a state that is both initial and
  222. /// final (weight == Weight::One()), and for each non-NULL pointer fsts[i],
  223. /// it has an arc out whose output-symbol is i and which goes to a
  224. /// sub-graph whose input language is equivalent to fsts[i], where the
  225. /// final-state becomes a transition to the loop-state. Each fst in "fsts"
  226. /// should be an acceptor. The fst MakeLoopFst returns is output-deterministic,
  227. /// but not output-epsilon free necessarily, and arcs are sorted on output
  228. /// label. Note: if some of the pointers in the input vector "fsts" have the
  229. /// same value, "MakeLoopFst" uses this to speed up the computation.
  230. /// Formally: suppose I is the set of indexes i such that fsts[i] != NULL.
  231. /// Let L[i] be the language that the acceptor fsts[i] accepts.
  232. /// Let the language K be the set of input-output pairs i:l such
  233. /// that i in I and l in L[i]. Then the FST returned by MakeLoopFst
  234. /// accepts the language K*, where * is the Kleene closure (CLOSURE_STAR)
  235. /// of K.
  236. /// We could have implemented this via a combination of "project",
  237. /// "concat", "union" and "closure". But that FST would have been
  238. /// less well optimized and would have a lot of final-states.
  239. template <class Arc>
  240. VectorFst<Arc>* MakeLoopFst(const std::vector<const ExpandedFst<Arc>*>& fsts);
  241. /// ApplyProbabilityScale is applicable to FSTs in the log or tropical semiring.
  242. /// It multiplies the arc and final weights by "scale" [this is not the Mul
  243. /// operation of the semiring, it's actual multiplication, which is equivalent
  244. /// to taking a power in the semiring].
  245. template <class Arc>
  246. void ApplyProbabilityScale(float scale, MutableFst<Arc>* fst);
  247. /// EqualAlign is similar to RandGen, but it generates a sequence with exactly
  248. /// "length" input symbols. It returns true on success, false on failure
  249. /// (failure is partly random but should never happen in practice for normal
  250. /// speech models.) It generates a random path through the input FST, finds out
  251. /// which subset of the states it visits along the way have self-loops with
  252. /// inupt symbols on them, and outputs a path with exactly enough self-loops to
  253. /// have the requested number of input symbols. Note that EqualAlign does not
  254. /// use the probabilities on the FST. It just uses equal probabilities in the
  255. /// first stage of selection (since the output will anyway not be a truly random
  256. /// sample from the FST). The input fst "ifst" must be connected or this may
  257. /// enter an infinite loop.
  258. template <class Arc>
  259. bool EqualAlign(const Fst<Arc>& ifst, typename Arc::StateId length,
  260. int rand_seed, MutableFst<Arc>* ofst, int num_retries = 10);
  261. // RemoveUselessArcs removes arcs such that there is no input symbol
  262. // sequence for which the best path through the FST would contain
  263. // those arcs [for these purposes, epsilon is not treated as a real symbol].
  264. // This is mainly geared towards decoding-graph FSTs which may contain
  265. // transitions that have less likely words on them that would never be
  266. // taken. We do not claim that this algorithm removes all such arcs;
  267. // it just does the best job it can.
  268. // Only works for tropical (not log) semiring as it uses
  269. // NaturalLess.
  270. template <class Arc>
  271. void RemoveUselessArcs(MutableFst<Arc>* fst);
  272. // PhiCompose is a version of composition where
  273. // the right hand FST (fst2) is treated as a backoff
  274. // LM, with the phi symbol (e.g. #0) treated as a
  275. // "failure transition", only taken when we don't
  276. // have a match for the requested symbol.
  277. template <class Arc>
  278. void PhiCompose(const Fst<Arc>& fst1, const Fst<Arc>& fst2,
  279. typename Arc::Label phi_label, MutableFst<Arc>* fst);
  280. // PropagateFinal propagates final-probs through
  281. // "phi" transitions (note that here, phi_label may
  282. // be epsilon if you want). If you have a backoff LM
  283. // with special symbols ("phi") on the backoff arcs
  284. // instead of epsilon, you may use PhiCompose to compose
  285. // with it, but this won't do the right thing w.r.t.
  286. // final probabilities. You should first call PropagateFinal
  287. // on the FST with phi's i it (fst2 in PhiCompose above),
  288. // to fix this. If a state does not have a final-prob,
  289. // but has a phi transition, it makes the state's final-prob
  290. // (phi-prob * final-prob-of-dest-state), and does this
  291. // recursively i.e. follows phi transitions on the dest state
  292. // first. It behaves as if there were a super-final state
  293. // with a special symbol leading to it, from each currently
  294. // final state. Note that this may not behave as desired
  295. // if there are epsilons in your FST; it might be better
  296. // to remove those before calling this function.
  297. template <class Arc>
  298. void PropagateFinal(typename Arc::Label phi_label, MutableFst<Arc>* fst);
  299. // PhiCompose is a version of composition where
  300. // the right hand FST (fst2) has speciall "rho transitions"
  301. // which are taken whenever no normal transition matches; these
  302. // transitions will be rewritten with whatever symbol was on
  303. // the first FST.
  304. template <class Arc>
  305. void RhoCompose(const Fst<Arc>& fst1, const Fst<Arc>& fst2,
  306. typename Arc::Label rho_label, MutableFst<Arc>* fst);
  307. /** This function returns true if, in the semiring of the FST, the sum (within
  308. the semiring) of all the arcs out of each state in the FST is one, to within
  309. delta. After MakeStochasticFst, this should be true (for a connected FST).
  310. @param fst [in] the FST that we are testing.
  311. @param delta [in] the tolerance to within which we test equality to 1.
  312. @param min_sum [out] if non, NULL, contents will be set to the minimum sum
  313. of weights.
  314. @param max_sum [out] if non, NULL, contents will be set to the maximum sum
  315. of weights.
  316. @return Returns true if the FST is stochastic, and false otherwise.
  317. */
  318. template <class Arc>
  319. bool IsStochasticFst(const Fst<Arc>& fst,
  320. float delta = kDelta, // kDelta = 1.0/1024.0 by default.
  321. typename Arc::Weight* min_sum = NULL,
  322. typename Arc::Weight* max_sum = NULL);
  323. // IsStochasticFstInLog makes sure it's stochastic after casting to log.
  324. inline bool IsStochasticFstInLog(
  325. const Fst<StdArc>& fst,
  326. float delta = kDelta, // kDelta = 1.0/1024.0 by default.
  327. StdArc::Weight* min_sum = NULL, StdArc::Weight* max_sum = NULL);
  328. } // end namespace fst
  329. #include "fstext/fstext-utils-inl.h"
  330. #endif // KALDI_FSTEXT_FSTEXT_UTILS_H_