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.

107 lines
3.1 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. // Topological sort of FSTs.
  19. #ifndef FST_TOPSORT_H_
  20. #define FST_TOPSORT_H_
  21. #include <vector>
  22. #include <fst/dfs-visit.h>
  23. #include <fst/fst.h>
  24. #include <fst/mutable-fst.h>
  25. #include <fst/properties.h>
  26. #include <fst/statesort.h>
  27. namespace fst {
  28. // DFS visitor class to return topological ordering.
  29. template <class Arc>
  30. class TopOrderVisitor {
  31. public:
  32. using StateId = typename Arc::StateId;
  33. // If acyclic, order[i] gives the topological position of StateId i;
  34. // otherwise it is unchanged. acyclic_ will be true iff the FST has no
  35. // cycles. The caller retains ownership of the state order vector.
  36. TopOrderVisitor(std::vector<StateId> *order, bool *acyclic)
  37. : order_(order), acyclic_(acyclic) {}
  38. void InitVisit(const Fst<Arc> &fst) {
  39. finish_.clear();
  40. *acyclic_ = true;
  41. }
  42. constexpr bool InitState(StateId, StateId) const { return true; }
  43. constexpr bool TreeArc(StateId, const Arc &) const { return true; }
  44. bool BackArc(StateId, const Arc &) { return (*acyclic_ = false); }
  45. constexpr bool ForwardOrCrossArc(StateId, const Arc &) const { return true; }
  46. void FinishState(StateId s, StateId, const Arc *) { finish_.push_back(s); }
  47. void FinishVisit() {
  48. if (*acyclic_) {
  49. order_->clear();
  50. for (StateId s = 0; s < finish_.size(); ++s) {
  51. order_->push_back(kNoStateId);
  52. }
  53. for (StateId s = 0; s < finish_.size(); ++s) {
  54. (*order_)[finish_[finish_.size() - s - 1]] = s;
  55. }
  56. }
  57. }
  58. private:
  59. std::vector<StateId> *order_;
  60. bool *acyclic_;
  61. // States in finish-time order.
  62. std::vector<StateId> finish_;
  63. };
  64. // Topologically sorts its input if acyclic, modifying it. Otherwise, the input
  65. // is unchanged. When sorted, all transitions are from lower to higher state
  66. // IDs.
  67. //
  68. // Complexity:
  69. //
  70. // Time: O(V + E)
  71. // Space: O(V + E)
  72. //
  73. // where V is the number of states and E is the number of arcs.
  74. template <class Arc>
  75. bool TopSort(MutableFst<Arc> *fst) {
  76. std::vector<typename Arc::StateId> order;
  77. bool acyclic;
  78. TopOrderVisitor<Arc> top_order_visitor(&order, &acyclic);
  79. DfsVisit(*fst, &top_order_visitor);
  80. if (acyclic) {
  81. StateSort(fst, order);
  82. fst->SetProperties(kAcyclic | kInitialAcyclic | kTopSorted,
  83. kAcyclic | kInitialAcyclic | kTopSorted);
  84. } else {
  85. fst->SetProperties(kCyclic | kNotTopSorted, kCyclic | kNotTopSorted);
  86. }
  87. return acyclic;
  88. }
  89. } // namespace fst
  90. #endif // FST_TOPSORT_H_