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.

144 lines
7.3 KiB

  1. // fstext/determinize-lattice.h
  2. // Copyright 2009-2011 Microsoft Corporation
  3. // See ../../COPYING for clarification regarding multiple authors
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  12. // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  13. // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  14. // MERCHANTABLITY OR NON-INFRINGEMENT.
  15. // See the Apache 2 License for the specific language governing permissions and
  16. // limitations under the License.
  17. #ifndef KALDI_FSTEXT_DETERMINIZE_LATTICE_H_
  18. #define KALDI_FSTEXT_DETERMINIZE_LATTICE_H_
  19. #include <fst/fst-decl.h>
  20. //#include <fst/fstlib.h>
  21. #include <algorithm>
  22. #include <map>
  23. #include <set>
  24. #include <vector>
  25. #include "fstext/lattice-weight.h"
  26. namespace fst {
  27. /// \addtogroup fst_extensions
  28. /// @{
  29. // For example of usage, see test-determinize-lattice.cc
  30. /*
  31. DeterminizeLattice implements a special form of determinization
  32. with epsilon removal, optimized for a phase of lattice generation.
  33. Its input is an FST with weight-type BaseWeightType (usually a pair of
  34. floats, with a lexicographical type of order, such as
  35. LatticeWeightTpl<float>). Typically this would be a state-level lattice, with
  36. input symbols equal to words, and output-symbols equal to p.d.f's (so like
  37. the inverse of HCLG). Imagine representing this as an acceptor of type
  38. CompactLatticeWeightTpl<float>, in which the input/output symbols are words,
  39. and the weights contain the original weights together with strings (with zero
  40. or one symbol in them) containing the original output labels (the p.d.f.'s).
  41. We determinize this using acceptor determinization with epsilon removal.
  42. Remember (from lattice-weight.h) that CompactLatticeWeightTpl has a special
  43. kind of semiring where we always take the string corresponding to the best
  44. cost (of type BaseWeightType), and discard the other. This corresponds to
  45. taking the best output-label sequence (of p.d.f.'s) for each input-label
  46. sequence (of words). We couldn't use the Gallic weight for this, or it would
  47. die as soon as it detected that the input FST was non-functional. In our
  48. case, any acyclic FST (and many cyclic ones) can be determinized. We assume
  49. that there is a function Compare(const BaseWeightType &a, const
  50. BaseWeightType &b) that returns (-1, 0, 1) according to whether (a < b, a ==
  51. b, a > b) in the total order on the BaseWeightType... this information should
  52. be the same as NaturalLess would give, but it's more efficient to do it this
  53. way. You can define this for things like TropicalWeight if you need to
  54. instantiate this class for that weight type.
  55. We implement this determinization in a special way to make it efficient for
  56. the types of FSTs that we will apply it to. One issue is that if we
  57. explicitly represent the strings (in CompactLatticeWeightTpl) as vectors of
  58. type vector<IntType>, the algorithm takes time quadratic in the length of
  59. words (in states), because propagating each arc involves copying a whole
  60. vector (of integers representing p.d.f.'s). Instead we use a hash structure
  61. where each string is a pointer (Entry*), and uses a hash from (Entry*,
  62. IntType), to the successor string (and a way to get the latest IntType and
  63. the ancestor Entry*). [this is the class LatticeStringRepository].
  64. Another issue is that rather than representing a determinized-state as a
  65. collection of (state, weight), we represent it in a couple of reduced forms.
  66. Suppose a determinized-state is a collection of (state, weight) pairs; call
  67. this the "canonical representation". Note: these collections are always
  68. normalized to remove any common weight and string part. Define end-states as
  69. the subset of states that have an arc out of them with a label on, or are
  70. final. If we represent a determinized-state a the set of just its
  71. (end-state, weight) pairs, this will be a valid and more compact
  72. representation, and will lead to a smaller set of determinized states (like
  73. early minimization). Call this collection of (end-state, weight) pairs the
  74. "minimal representation". As a mechanism to reduce compute, we can also
  75. consider another representation. In the determinization algorithm, we start
  76. off with a set of (begin-state, weight) pairs (where the "begin-states" are
  77. initial or have a label on the transition into them), and the "canonical
  78. representation" consists of the epsilon-closure of this set (i.e. follow
  79. epsilons). Call this set of (begin-state, weight) pairs, appropriately
  80. normalized, the "initial representation". If two initial representations are
  81. the same, the "canonical representation" and hence the "minimal
  82. representation" will be the same. We can use this to reduce compute. Note
  83. that if two initial representations are different, this does not preclude the
  84. other representations from being the same.
  85. */
  86. struct DeterminizeLatticeOptions {
  87. float delta; // A small offset used to measure equality of weights.
  88. int max_mem; // If >0, determinization will fail and return false
  89. // when the algorithm's (approximate) memory consumption crosses this
  90. // threshold.
  91. int max_loop; // If >0, can be used to detect non-determinizable input
  92. // (a case that wouldn't be caught by max_mem).
  93. DeterminizeLatticeOptions() : delta(kDelta), max_mem(-1), max_loop(-1) {}
  94. };
  95. /**
  96. This function implements the normal version of DeterminizeLattice, in which
  97. the output strings are represented using sequences of arcs, where all but
  98. the first one has an epsilon on the input side. The debug_ptr argument is
  99. an optional pointer to a bool that, if it becomes true while the algorithm
  100. is executing, the algorithm will print a traceback and terminate (used in
  101. fstdeterminizestar.cc debug non-terminating determinization). More
  102. efficient if ifst is arc-sorted on input label. If the number of arcs gets
  103. more than max_states, it will throw std::runtime_error (otherwise this code
  104. does not use exceptions). This is mainly useful for debug. */
  105. template <class Weight, class IntType>
  106. bool DeterminizeLattice(
  107. const Fst<ArcTpl<Weight> >& ifst, MutableFst<ArcTpl<Weight> >* ofst,
  108. DeterminizeLatticeOptions opts = DeterminizeLatticeOptions(),
  109. bool* debug_ptr = NULL);
  110. /* This is a version of DeterminizeLattice with a slightly more "natural"
  111. output format, where the output sequences are encoded using the
  112. CompactLatticeArcTpl template (i.e. the sequences of output symbols are
  113. represented directly as strings) More efficient if ifst is arc-sorted on
  114. input label. If the #arcs gets more than max_arcs, it will throw
  115. std::runtime_error (otherwise this code does not use exceptions). This is
  116. mainly useful for debug.
  117. */
  118. template <class Weight, class IntType>
  119. bool DeterminizeLattice(
  120. const Fst<ArcTpl<Weight> >& ifst,
  121. MutableFst<ArcTpl<CompactLatticeWeightTpl<Weight, IntType> > >* ofst,
  122. DeterminizeLatticeOptions opts = DeterminizeLatticeOptions(),
  123. bool* debug_ptr = NULL);
  124. /// @} end "addtogroup fst_extensions"
  125. } // end namespace fst
  126. #include "fstext/determinize-lattice-inl.h"
  127. #endif // KALDI_FSTEXT_DETERMINIZE_LATTICE_H_