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