1 // complement.h
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 //
16 // \file
17 // Class to complement an Fst.
18
19 #ifndef FST_LIB_COMPLEMENT_H__
20 #define FST_LIB_COMPLEMENT_H__
21
22 #include <algorithm>
23
24 #include "fst/lib/fst.h"
25 #include "fst/lib/test-properties.h"
26
27 namespace fst {
28
29 template <class A> class ComplementFst;
30
31 // Implementation of delayed ComplementFst. The algorithm used
32 // completes the (deterministic) FSA and then exchanges final and
33 // non-final states. Completion, i.e. ensuring that all labels can be
34 // read from every state, is accomplished by using RHO labels, which
35 // match all labels that are otherwise not found leaving a state. The
36 // first state in the output is reserved to be a new state that is the
37 // destination of all RHO labels. Each remaining output state s
38 // corresponds to input state s - 1. The first arc in the output at
39 // these states is the rho label, the remaining arcs correspond to the
40 // input arcs.
41 template<class A>
42 class ComplementFstImpl : public FstImpl<A> {
43 public:
44 using FstImpl<A>::SetType;
45 using FstImpl<A>::SetProperties;
46 using FstImpl<A>::Properties;
47 using FstImpl<A>::SetInputSymbols;
48 using FstImpl<A>::SetOutputSymbols;
49
50 friend class StateIterator< ComplementFst<A> >;
51 friend class ArcIterator< ComplementFst<A> >;
52
53 typedef typename A::Label Label;
54 typedef typename A::Weight Weight;
55 typedef typename A::StateId StateId;
56
ComplementFstImpl(const Fst<A> & fst)57 explicit ComplementFstImpl(const Fst<A> &fst) : fst_(fst.Copy()) {
58 SetType("complement");
59 uint64 props = fst.Properties(kILabelSorted, false);
60 SetProperties(ComplementProperties(props), kCopyProperties);
61 SetInputSymbols(fst.InputSymbols());
62 SetOutputSymbols(fst.OutputSymbols());
63 }
64
~ComplementFstImpl()65 ~ComplementFstImpl() { delete fst_; }
66
Start()67 StateId Start() const {
68 StateId start = fst_->Start();
69 if (start != kNoStateId)
70 return start + 1;
71 else
72 return 0;
73 }
74
75 // Exchange final and non-final states; make rho destination state final.
Final(StateId s)76 Weight Final(StateId s) const {
77 if (s == 0 || fst_->Final(s - 1) == Weight::Zero())
78 return Weight::One();
79 else
80 return Weight::Zero();
81 }
82
NumArcs(StateId s)83 size_t NumArcs(StateId s) const {
84 if (s == 0)
85 return 1;
86 else
87 return fst_->NumArcs(s - 1) + 1;
88 }
89
NumInputEpsilons(StateId s)90 size_t NumInputEpsilons(StateId s) const {
91 return s == 0 ? 0 : fst_->NumInputEpsilons(s - 1);
92 }
93
NumOutputEpsilons(StateId s)94 size_t NumOutputEpsilons(StateId s) const {
95 return s == 0 ? 0 : fst_->NumOutputEpsilons(s - 1);
96 }
97
98 private:
99 const Fst<A> *fst_;
100
101 DISALLOW_EVIL_CONSTRUCTORS(ComplementFstImpl);
102 };
103
104
105 // Complements an automaton; this is a library-internal operation
106 // that introduces the rho label. This version is a delayed Fst.
107 template <class A>
108 class ComplementFst : public Fst<A> {
109 public:
110 friend class StateIterator< ComplementFst<A> >;
111 friend class ArcIterator< ComplementFst<A> >;
112
113 typedef A Arc;
114 typedef typename A::Label Label;
115 typedef typename A::Weight Weight;
116 typedef typename A::StateId StateId;
117
ComplementFst(const Fst<A> & fst)118 explicit ComplementFst(const Fst<A> &fst)
119 : impl_(new ComplementFstImpl<A>(fst)) {
120 uint64 props = kUnweighted | kNoEpsilons | kIDeterministic | kAcceptor;
121 if (fst.Properties(props, true) != props)
122 LOG(FATAL) << "ComplementFst: argument not an unweighted"
123 << " epsilon-free deterministic acceptor";
124 }
125
ComplementFst(const ComplementFst<A> & fst)126 ComplementFst(const ComplementFst<A> &fst) : impl_(fst.impl_) {
127 impl_->IncrRefCount();
128 }
129
~ComplementFst()130 virtual ~ComplementFst() { if (!impl_->DecrRefCount()) { delete impl_; }}
131
Start()132 virtual StateId Start() const { return impl_->Start(); }
133
Final(StateId s)134 virtual Weight Final(StateId s) const { return impl_->Final(s); }
135
Properties(uint64 mask,bool test)136 virtual uint64 Properties(uint64 mask, bool test) const {
137 if (test) {
138 uint64 known, test = TestProperties(*this, mask, &known);
139 impl_->SetProperties(test, known);
140 return test & mask;
141 } else {
142 return impl_->Properties(mask);
143 }
144 }
145
Type()146 virtual const string& Type() const { return impl_->Type(); }
147
Copy()148 virtual ComplementFst<A> *Copy() const {
149 return new ComplementFst<A>(*this);
150 }
151
InputSymbols()152 virtual const SymbolTable* InputSymbols() const {
153 return impl_->InputSymbols();
154 }
155
OutputSymbols()156 virtual const SymbolTable* OutputSymbols() const {
157 return impl_->OutputSymbols();
158 }
159
NumArcs(StateId s)160 virtual size_t NumArcs(StateId s) const { return impl_->NumArcs(s); }
161
NumInputEpsilons(StateId s)162 virtual size_t NumInputEpsilons(StateId s) const {
163 return impl_->NumInputEpsilons(s);
164 }
165
NumOutputEpsilons(StateId s)166 virtual size_t NumOutputEpsilons(StateId s) const {
167 return impl_->NumOutputEpsilons(s);
168 }
169
170 virtual inline void InitStateIterator(StateIteratorData<A> *data) const;
171
172 virtual inline void InitArcIterator(StateId s,
173 ArcIteratorData<A> *data) const;
174
175 private:
176 ComplementFstImpl<A> *impl_;
177
178 void operator=(const ComplementFst<A> &fst); // disallow
179 };
180
181
182 // Specialization for ComplementFst.
183 template <class A>
184 class StateIterator< ComplementFst<A> > : public StateIteratorBase<A> {
185 public:
186 typedef typename A::StateId StateId;
187 typedef typename A::Label Label;
188
StateIterator(const ComplementFst<A> & fst)189 explicit StateIterator(const ComplementFst<A> &fst)
190 : siter_(*fst.impl_->fst_), s_(0) {
191 }
192
Done()193 virtual bool Done() const { return s_ > 0 && siter_.Done(); }
Value()194 virtual StateId Value() const { return s_; }
Next()195 virtual void Next() {
196 if (s_ != 0)
197 siter_.Next();
198 ++s_;
199 }
Reset()200 virtual void Reset() {
201 siter_.Reset();
202 s_ = 0;
203 }
204
205 private:
206 StateIterator< Fst<A> > siter_;
207 StateId s_;
208
209 DISALLOW_EVIL_CONSTRUCTORS(StateIterator);
210 };
211
212
213 // Specialization for ComplementFst.
214 template <class A>
215 class ArcIterator< ComplementFst<A> > : public ArcIteratorBase<A> {
216 public:
217 typedef typename A::StateId StateId;
218 typedef typename A::Label Label;
219 typedef typename A::Weight Weight;
220
ArcIterator(const ComplementFst<A> & fst,StateId s)221 ArcIterator(const ComplementFst<A> &fst, StateId s)
222 : aiter_(0), s_(s), pos_(0) {
223 if (s_ != 0)
224 aiter_ = new ArcIterator< Fst<A> >(*fst.impl_->fst_, s - 1);
225 }
~ArcIterator()226 virtual ~ArcIterator() { delete aiter_; }
227
Done()228 virtual bool Done() const {
229 if (s_ != 0)
230 return pos_ > 0 && aiter_->Done();
231 else
232 return pos_ > 0;
233 }
234
235 // Adds the rho label to the rho destination state.
Value()236 virtual const A& Value() const {
237 if (pos_ == 0) {
238 arc_.ilabel = arc_.olabel = kRhoLabel;
239 arc_.weight = Weight::One();
240 arc_.nextstate = 0;
241 } else {
242 arc_ = aiter_->Value();
243 ++arc_.nextstate;
244 }
245 return arc_;
246 }
Next()247 virtual void Next() {
248 if (s_ != 0 && pos_ > 0)
249 aiter_->Next();
250 ++pos_;
251 }
Reset()252 virtual void Reset() {
253 if (s_ != 0)
254 aiter_->Reset();
255 pos_ = 0;
256 }
Seek(size_t a)257 virtual void Seek(size_t a) {
258 if (s_ != 0) {
259 if (a == 0) {
260 aiter_->Reset();
261 } else {
262 aiter_->Seek(a - 1);
263 }
264 }
265 pos_ = a;
266 }
267
268 private:
269 ArcIterator< Fst<A> > *aiter_;
270 StateId s_;
271 size_t pos_;
272 mutable A arc_;
273 DISALLOW_EVIL_CONSTRUCTORS(ArcIterator);
274 };
275
276
277 template <class A> inline void
InitStateIterator(StateIteratorData<A> * data)278 ComplementFst<A>::InitStateIterator(StateIteratorData<A> *data) const {
279 data->base = new StateIterator< ComplementFst<A> >(*this);
280 }
281
282 template <class A> inline void
InitArcIterator(StateId s,ArcIteratorData<A> * data)283 ComplementFst<A>::InitArcIterator(StateId s, ArcIteratorData<A> *data) const {
284 data->base = new ArcIterator< ComplementFst<A> >(*this, s);
285 }
286
287
288 // Useful alias when using StdArc.
289 typedef ComplementFst<StdArc> StdComplementFst;
290
291 } // namespace fst
292
293 #endif // FST_LIB_COMPLEMENT_H__
294