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.

135 lines
4.9 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. // Functions and classes to sort arcs in an FST.
  19. #ifndef FST_REVERSE_H_
  20. #define FST_REVERSE_H_
  21. #include <algorithm>
  22. #include <cstdint>
  23. #include <vector>
  24. #include <fst/cache.h>
  25. #include <fst/cc-visitors.h>
  26. #include <fst/dfs-visit.h>
  27. #include <fst/expanded-fst.h>
  28. #include <fst/fst.h>
  29. #include <fst/mutable-fst.h>
  30. #include <fst/properties.h>
  31. namespace fst {
  32. // Reverses an FST. The reversed result is written to an output mutable FST.
  33. // If A transduces string x to y with weight a, then the reverse of A
  34. // transduces the reverse of x to the reverse of y with weight a.Reverse().
  35. //
  36. // Typically, a = a.Reverse() and an arc is its own reverse (e.g., for
  37. // TropicalWeight or LogWeight). In general, e.g., when the weights only form a
  38. // left or right semiring, the output arc type must match the input arc type
  39. // except having the reversed Weight type.
  40. //
  41. // When require_superinitial is false, a superinitial state is not created in
  42. // the reversed FST iff the input FST has exactly one final state (which becomes
  43. // the initial state of the reversed FST) with a final weight of semiring One,
  44. // or if it does not belong to any cycle. When require_superinitial is true, a
  45. // superinitial state is always created.
  46. template <class FromArc, class ToArc>
  47. void Reverse(const Fst<FromArc> &ifst, MutableFst<ToArc> *ofst,
  48. bool require_superinitial = true) {
  49. using StateId = typename FromArc::StateId;
  50. using Weight = typename FromArc::Weight;
  51. ofst->DeleteStates();
  52. ofst->SetInputSymbols(ifst.InputSymbols());
  53. ofst->SetOutputSymbols(ifst.OutputSymbols());
  54. if (std::optional<StateId> num_states = ifst.NumStatesIfKnown()) {
  55. ofst->ReserveStates(*num_states + 1);
  56. }
  57. StateId istart = ifst.Start();
  58. StateId ostart = kNoStateId;
  59. StateId offset = 0;
  60. uint64_t dfs_iprops = 0;
  61. uint64_t dfs_oprops = 0;
  62. if (!require_superinitial) {
  63. for (StateIterator<Fst<FromArc>> siter(ifst); !siter.Done(); siter.Next()) {
  64. const auto s = siter.Value();
  65. if (ifst.Final(s) == Weight::Zero()) continue;
  66. if (ostart != kNoStateId) {
  67. ostart = kNoStateId;
  68. break;
  69. } else {
  70. ostart = s;
  71. }
  72. }
  73. if (ostart != kNoStateId && ifst.Final(ostart) != Weight::One()) {
  74. std::vector<StateId> scc;
  75. SccVisitor<FromArc> scc_visitor(&scc, nullptr, nullptr, &dfs_iprops);
  76. DfsVisit(ifst, &scc_visitor);
  77. if (std::count(scc.begin(), scc.end(), scc[ostart]) > 1) {
  78. ostart = kNoStateId;
  79. } else {
  80. for (ArcIterator<Fst<FromArc>> aiter(ifst, ostart); !aiter.Done();
  81. aiter.Next()) {
  82. if (aiter.Value().nextstate == ostart) {
  83. ostart = kNoStateId;
  84. break;
  85. }
  86. }
  87. }
  88. if (ostart != kNoStateId) dfs_oprops = kInitialAcyclic;
  89. }
  90. }
  91. if (ostart == kNoStateId) { // Super-initial requested or needed.
  92. ostart = ofst->AddState();
  93. offset = 1;
  94. }
  95. for (StateIterator<Fst<FromArc>> siter(ifst); !siter.Done(); siter.Next()) {
  96. const auto is = siter.Value();
  97. const auto os = is + offset;
  98. while (ofst->NumStates() <= os) ofst->AddState();
  99. if (is == istart) ofst->SetFinal(os);
  100. const auto weight = ifst.Final(is);
  101. if ((weight != Weight::Zero()) && (offset == 1)) {
  102. const ToArc oarc(0, 0, weight.Reverse(), os);
  103. ofst->AddArc(0, oarc);
  104. }
  105. for (ArcIterator<Fst<FromArc>> aiter(ifst, is); !aiter.Done();
  106. aiter.Next()) {
  107. const auto &iarc = aiter.Value();
  108. const auto nos = iarc.nextstate + offset;
  109. auto weight = iarc.weight.Reverse();
  110. if (!offset && (nos == ostart)) {
  111. weight = Times(ifst.Final(ostart).Reverse(), weight);
  112. }
  113. const ToArc oarc(iarc.ilabel, iarc.olabel, weight, os);
  114. while (ofst->NumStates() <= nos) ofst->AddState();
  115. ofst->AddArc(nos, oarc);
  116. }
  117. }
  118. ofst->SetStart(ostart);
  119. if (offset == 0 && ostart == istart) {
  120. ofst->SetFinal(ostart, ifst.Final(ostart).Reverse());
  121. }
  122. const auto iprops = ifst.Properties(kCopyProperties, false) | dfs_iprops;
  123. const auto oprops = ofst->Properties(kFstProperties, false) | dfs_oprops;
  124. ofst->SetProperties(ReverseProperties(iprops, offset == 1) | oprops,
  125. kFstProperties);
  126. }
  127. } // namespace fst
  128. #endif // FST_REVERSE_H_