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.

295 lines
8.3 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. // Class to complement an FST.
  19. #ifndef FST_COMPLEMENT_H_
  20. #define FST_COMPLEMENT_H_
  21. #include <algorithm>
  22. #include <cstddef>
  23. #include <cstdint>
  24. #include <memory>
  25. #include <string>
  26. #include <vector>
  27. #include <fst/log.h>
  28. #include <fst/arc.h>
  29. #include <fst/float-weight.h>
  30. #include <fst/fst.h>
  31. #include <fst/impl-to-fst.h>
  32. #include <fst/properties.h>
  33. #include <fst/util.h>
  34. namespace fst {
  35. template <class Arc>
  36. class ComplementFst;
  37. namespace internal {
  38. // Implementation of delayed ComplementFst. The algorithm used completes the
  39. // (deterministic) FSA and then exchanges final and non-final states.
  40. // Completion, i.e. ensuring that all labels can be read from every state, is
  41. // accomplished by using ρ-labels, which match all labels that are otherwise
  42. // not found leaving a state. The first state in the output is reserved to be a
  43. // new state that is the destination of all ρ-labels. Each remaining output
  44. // state s corresponds to input state s - 1. The first arc in the output at
  45. // these states is the ρ-label, the remaining arcs correspond to the input
  46. // arcs.
  47. template <class A>
  48. class ComplementFstImpl : public FstImpl<A> {
  49. public:
  50. using Arc = A;
  51. using Label = typename Arc::Label;
  52. using StateId = typename Arc::StateId;
  53. using Weight = typename Arc::Weight;
  54. using FstImpl<A>::SetType;
  55. using FstImpl<A>::SetProperties;
  56. using FstImpl<A>::SetInputSymbols;
  57. using FstImpl<A>::SetOutputSymbols;
  58. friend class StateIterator<ComplementFst<Arc>>;
  59. friend class ArcIterator<ComplementFst<Arc>>;
  60. explicit ComplementFstImpl(const Fst<Arc> &fst) : fst_(fst.Copy()) {
  61. SetType("complement");
  62. const auto props = fst.Properties(kILabelSorted, false);
  63. SetProperties(ComplementProperties(props), kCopyProperties);
  64. SetInputSymbols(fst.InputSymbols());
  65. SetOutputSymbols(fst.OutputSymbols());
  66. }
  67. ComplementFstImpl(const ComplementFstImpl<Arc> &impl)
  68. : fst_(impl.fst_->Copy()) {
  69. SetType("complement");
  70. SetProperties(impl.Properties(), kCopyProperties);
  71. SetInputSymbols(impl.InputSymbols());
  72. SetOutputSymbols(impl.OutputSymbols());
  73. }
  74. StateId Start() const {
  75. if (Properties(kError)) return kNoStateId;
  76. const auto start = fst_->Start();
  77. return start != kNoStateId ? start + 1 : 0;
  78. }
  79. // Exchange final and non-final states; makes ρ-destination state final.
  80. Weight Final(StateId s) const {
  81. if (s == 0 || fst_->Final(s - 1) == Weight::Zero()) {
  82. return Weight::One();
  83. } else {
  84. return Weight::Zero();
  85. }
  86. }
  87. size_t NumArcs(StateId s) const {
  88. return s == 0 ? 1 : fst_->NumArcs(s - 1) + 1;
  89. }
  90. size_t NumInputEpsilons(StateId s) const {
  91. return s == 0 ? 0 : fst_->NumInputEpsilons(s - 1);
  92. }
  93. size_t NumOutputEpsilons(StateId s) const {
  94. return s == 0 ? 0 : fst_->NumOutputEpsilons(s - 1);
  95. }
  96. uint64_t Properties() const override { return Properties(kFstProperties); }
  97. // Sets error if found, and returns other FST impl properties.
  98. uint64_t Properties(uint64_t mask) const override {
  99. if ((mask & kError) && fst_->Properties(kError, false)) {
  100. SetProperties(kError, kError);
  101. }
  102. return FstImpl<Arc>::Properties(mask);
  103. }
  104. private:
  105. std::unique_ptr<const Fst<Arc>> fst_;
  106. };
  107. } // namespace internal
  108. // Complements an automaton. This is a library-internal operation that
  109. // introduces a (negative) ρ-label; use Difference/DifferenceFst in user code,
  110. // which will not see this label. This version is a delayed FST.
  111. //
  112. // This class attaches interface to implementation and handles
  113. // reference counting, delegating most methods to ImplToFst.
  114. template <class A>
  115. class ComplementFst : public ImplToFst<internal::ComplementFstImpl<A>> {
  116. public:
  117. using Arc = A;
  118. using Label = typename Arc::Label;
  119. using StateId = typename Arc::StateId;
  120. using Impl = internal::ComplementFstImpl<Arc>;
  121. friend class StateIterator<ComplementFst<Arc>>;
  122. friend class ArcIterator<ComplementFst<Arc>>;
  123. explicit ComplementFst(const Fst<Arc> &fst)
  124. : ImplToFst<Impl>(std::make_shared<Impl>(fst)) {
  125. static constexpr auto props =
  126. kUnweighted | kNoEpsilons | kIDeterministic | kAcceptor;
  127. if (fst.Properties(props, true) != props) {
  128. FSTERROR() << "ComplementFst: Argument not an unweighted "
  129. << "epsilon-free deterministic acceptor";
  130. GetImpl()->SetProperties(kError, kError);
  131. }
  132. }
  133. // See Fst<>::Copy() for doc.
  134. ComplementFst(const ComplementFst &fst, bool safe = false)
  135. : ImplToFst<Impl>(fst, safe) {}
  136. // Gets a copy of this FST. See Fst<>::Copy() for further doc.
  137. ComplementFst *Copy(bool safe = false) const override {
  138. return new ComplementFst(*this, safe);
  139. }
  140. inline void InitStateIterator(StateIteratorData<Arc> *data) const override;
  141. inline void InitArcIterator(StateId s,
  142. ArcIteratorData<Arc> *data) const override;
  143. // Label that represents the ρ-transition; we use a negative value private to
  144. // the library and which will preserve FST label sort order.
  145. static constexpr Label kRhoLabel = -2;
  146. private:
  147. using ImplToFst<Impl>::GetImpl;
  148. ComplementFst &operator=(const ComplementFst &) = delete;
  149. };
  150. // Specialization for ComplementFst.
  151. template <class Arc>
  152. class StateIterator<ComplementFst<Arc>> : public StateIteratorBase<Arc> {
  153. public:
  154. using StateId = typename Arc::StateId;
  155. explicit StateIterator(const ComplementFst<Arc> &fst)
  156. : siter_(*fst.GetImpl()->fst_), s_(0) {}
  157. bool Done() const final { return s_ > 0 && siter_.Done(); }
  158. StateId Value() const final { return s_; }
  159. void Next() final {
  160. if (s_ != 0) siter_.Next();
  161. ++s_;
  162. }
  163. void Reset() final {
  164. siter_.Reset();
  165. s_ = 0;
  166. }
  167. private:
  168. StateIterator<Fst<Arc>> siter_;
  169. StateId s_;
  170. };
  171. // Specialization for ComplementFst.
  172. template <class Arc>
  173. class ArcIterator<ComplementFst<Arc>> : public ArcIteratorBase<Arc> {
  174. public:
  175. using StateId = typename Arc::StateId;
  176. using Weight = typename Arc::Weight;
  177. ArcIterator(const ComplementFst<Arc> &fst, StateId s) : s_(s), pos_(0) {
  178. if (s_ != 0) {
  179. aiter_ =
  180. std::make_unique<ArcIterator<Fst<Arc>>>(*fst.GetImpl()->fst_, s - 1);
  181. }
  182. }
  183. bool Done() const final {
  184. if (s_ != 0) {
  185. return pos_ > 0 && aiter_->Done();
  186. } else {
  187. return pos_ > 0;
  188. }
  189. }
  190. // Adds the ρ-label to the ρ destination state.
  191. const Arc &Value() const final {
  192. if (pos_ == 0) {
  193. arc_.ilabel = arc_.olabel = ComplementFst<Arc>::kRhoLabel;
  194. arc_.weight = Weight::One();
  195. arc_.nextstate = 0;
  196. } else {
  197. arc_ = aiter_->Value();
  198. ++arc_.nextstate;
  199. }
  200. return arc_;
  201. }
  202. void Next() final {
  203. if (s_ != 0 && pos_ > 0) aiter_->Next();
  204. ++pos_;
  205. }
  206. size_t Position() const final { return pos_; }
  207. void Reset() final {
  208. if (s_ != 0) aiter_->Reset();
  209. pos_ = 0;
  210. }
  211. void Seek(size_t a) final {
  212. if (s_ != 0) {
  213. if (a == 0) {
  214. aiter_->Reset();
  215. } else {
  216. aiter_->Seek(a - 1);
  217. }
  218. }
  219. pos_ = a;
  220. }
  221. uint8_t Flags() const final { return kArcValueFlags; }
  222. void SetFlags(uint8_t, uint8_t) final {}
  223. private:
  224. std::unique_ptr<ArcIterator<Fst<Arc>>> aiter_;
  225. StateId s_;
  226. size_t pos_;
  227. mutable Arc arc_;
  228. };
  229. template <class Arc>
  230. inline void ComplementFst<Arc>::InitStateIterator(
  231. StateIteratorData<Arc> *data) const {
  232. data->base = std::make_unique<StateIterator<ComplementFst<Arc>>>(*this);
  233. }
  234. template <class Arc>
  235. inline void ComplementFst<Arc>::InitArcIterator(
  236. StateId s, ArcIteratorData<Arc> *data) const {
  237. data->base = std::make_unique<ArcIterator<ComplementFst<Arc>>>(*this, s);
  238. }
  239. // Useful alias when using StdArc.
  240. using StdComplementFst = ComplementFst<StdArc>;
  241. } // namespace fst
  242. #endif // FST_COMPLEMENT_H_