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.

97 lines
3.2 KiB

  1. // Copyright 2005-2024 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the 'License');
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an 'AS IS' BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // See www.openfst.org for extensive documentation on this weighted
  16. // finite-state transducer library.
  17. //
  18. // Function to remove of final states that have epsilon-only input arcs.
  19. #ifndef FST_RMFINALEPSILON_H_
  20. #define FST_RMFINALEPSILON_H_
  21. #include <cstdint>
  22. #include <vector>
  23. #include <fst/cc-visitors.h>
  24. #include <fst/connect.h>
  25. #include <fst/dfs-visit.h>
  26. #include <fst/fst.h>
  27. #include <fst/mutable-fst.h>
  28. #include <unordered_set>
  29. namespace fst {
  30. // Removes final states that have epsilon-only input arcs.
  31. template <class Arc>
  32. void RmFinalEpsilon(MutableFst<Arc> *fst) {
  33. using StateId = typename Arc::StateId;
  34. using Weight = typename Arc::Weight;
  35. // Determines the coaccesibility of states.
  36. std::vector<bool> access;
  37. std::vector<bool> coaccess;
  38. uint64_t props = 0;
  39. SccVisitor<Arc> scc_visitor(nullptr, &access, &coaccess, &props);
  40. DfsVisit(*fst, &scc_visitor);
  41. // Finds potential list of removable final states. These are final states that
  42. // have no outgoing transitions or final states that have a non-coaccessible
  43. // future.
  44. std::unordered_set<StateId> finals;
  45. for (StateIterator<Fst<Arc>> siter(*fst); !siter.Done(); siter.Next()) {
  46. const auto s = siter.Value();
  47. if (fst->Final(s) != Weight::Zero()) {
  48. bool future_coaccess = false;
  49. for (ArcIterator<Fst<Arc>> aiter(*fst, s); !aiter.Done(); aiter.Next()) {
  50. const auto &arc = aiter.Value();
  51. if (coaccess[arc.nextstate]) {
  52. future_coaccess = true;
  53. break;
  54. }
  55. }
  56. if (!future_coaccess) finals.insert(s);
  57. }
  58. }
  59. // Moves the final weight.
  60. std::vector<Arc> arcs;
  61. for (StateIterator<Fst<Arc>> siter(*fst); !siter.Done(); siter.Next()) {
  62. const auto s = siter.Value();
  63. auto weight = fst->Final(s);
  64. arcs.clear();
  65. for (ArcIterator<Fst<Arc>> aiter(*fst, s); !aiter.Done(); aiter.Next()) {
  66. const auto &arc = aiter.Value();
  67. // Next state is in the list of finals.
  68. if (finals.find(arc.nextstate) != finals.end()) {
  69. // Sums up all epsilon arcs.
  70. if (arc.ilabel == 0 && arc.olabel == 0) {
  71. weight = Plus(Times(fst->Final(arc.nextstate), arc.weight), weight);
  72. } else {
  73. arcs.push_back(arc);
  74. }
  75. } else {
  76. arcs.push_back(arc);
  77. }
  78. }
  79. // If some arcs (epsilon arcs) were deleted, delete all arcs and add back
  80. // only the non-epsilon arcs.
  81. if (arcs.size() < fst->NumArcs(s)) {
  82. fst->DeleteArcs(s);
  83. fst->SetFinal(s, weight);
  84. for (const auto &arc : arcs) fst->AddArc(s, arc);
  85. }
  86. }
  87. Connect(fst);
  88. }
  89. } // namespace fst
  90. #endif // FST_RMFINALEPSILON_H_