FST  openfst-1.8.3
OpenFst Library
fst_test.h
Go to the documentation of this file.
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 // Regression test for FST classes.
19 
20 #ifndef FST_TEST_FST_TEST_H_
21 #define FST_TEST_FST_TEST_H_
22 
23 #include <cstddef>
24 #include <memory>
25 #include <string>
26 
27 #include <fst/log.h>
28 #include <fst/equal.h>
29 #include <fst/expanded-fst.h>
30 #include <fstream>
31 #include <fst/fst.h>
32 #include <fst/matcher.h>
33 #include <fst/mutable-fst.h>
34 #include <fst/properties.h>
35 #include <fst/vector-fst.h>
36 #include <fst/verify.h>
37 
38 namespace fst {
39 
40 // This tests an Fst F that is assumed to have a copy method from an
41 // arbitrary Fst. Some test functions make further assumptions mostly
42 // obvious from their name. These tests are written as member temple
43 // functions that take a test fst as its argument so that different
44 // Fsts in the interface hierarchy can be tested separately and so
45 // that we can instantiate only those tests that make sense for a
46 // particular Fst.
47 template <class F>
48 class FstTester {
49  public:
50  using Arc = typename F::Arc;
51  using StateId = typename Arc::StateId;
52  using Weight = typename Arc::Weight;
53  using Label = typename Arc::Label;
54 
55  explicit FstTester(size_t num_states = 128, bool weighted = true)
56  : num_states_(num_states), weighted_(weighted) {
57  VectorFst<Arc> vfst;
58  InitFst(&vfst, num_states);
59  testfst_ = std::make_unique<F>(vfst);
60  }
61 
62  // This verifies the contents described in InitFst() using
63  // methods defined in a generic Fst.
64  template <class G>
65  void TestBase(const G &fst) const {
66  StateId ns = 0;
67  StateIterator<G> siter(fst);
68  Matcher<G> matcher(fst, MATCH_INPUT);
69  MatchType match_type = matcher.Type(true);
70  bool has_states = false;
71  for (; !siter.Done(); siter.Next()) {
72  has_states = true;
73  }
74  CHECK_EQ(fst.Start(), has_states ? 0 : kNoStateId);
75  for (siter.Reset(); !siter.Done(); siter.Next()) {
76  StateId s = siter.Value();
77  matcher.SetState(s);
78  CHECK_EQ(fst.Final(s), NthWeight(s));
79  size_t na = 0;
80  ArcIterator<G> aiter(fst, s);
81  for (; !aiter.Done(); aiter.Next()) {
82  }
83  for (aiter.Reset(); !aiter.Done(); aiter.Next()) {
84  ++na;
85  const Arc &arc = aiter.Value();
86  CHECK_EQ(arc.ilabel, na);
87  CHECK_EQ(arc.olabel, 0);
88  CHECK_EQ(arc.weight, NthWeight(na));
89  if (na == ns + 1) {
90  CHECK_EQ(arc.nextstate, s == num_states_ - 1 ? 0 : s + 1);
91  } else {
92  CHECK_EQ(arc.nextstate, s);
93  }
94  if (match_type == MATCH_INPUT) {
95  CHECK(matcher.Find(arc.ilabel));
96  CHECK_EQ(matcher.Value().ilabel, arc.ilabel);
97  }
98  }
99  CHECK_EQ(na, s + 1);
100  CHECK_EQ(na, aiter.Position());
101  CHECK_EQ(fst.NumArcs(s), s + 1);
102  CHECK_EQ(fst.NumInputEpsilons(s), 0);
103  CHECK_EQ(fst.NumOutputEpsilons(s), s + 1);
104  CHECK(!matcher.Find(s + 2)); // out-of-range
105  CHECK(!matcher.Find(kNoLabel)); // no explicit input epsilons
106  CHECK(matcher.Find(0));
107  CHECK_EQ(matcher.Value().ilabel, kNoLabel); // implicit epsilon loop
108  ++ns;
109  }
110  CHECK_EQ(num_states_, ns);
111  CHECK(Verify(fst));
112  CHECK(fst.Properties(ns > 0 ? kNotAcceptor : kAcceptor, true));
113  CHECK(fst.Properties(ns > 0 ? kOEpsilons : kNoOEpsilons, true));
114  }
115 
116  void TestBase() const { TestBase(*testfst_); }
117 
118  // This verifies methods specfic to an ExpandedFst.
119  template <class G>
120  void TestExpanded(const G &fst) const {
121  CHECK_EQ(fst.NumStates(), num_states_);
122  StateId ns = 0;
123  for (StateIterator<G> siter(fst); !siter.Done(); siter.Next()) {
124  ++ns;
125  }
126  CHECK_EQ(fst.NumStates(), ns);
127  CHECK(fst.Properties(kExpanded, false));
128  }
129 
130  void TestExpanded() const { TestExpanded(*testfst_); }
131 
132  // This verifies methods specific to a MutableFst.
133  template <class G>
134  void TestMutable(G *fst) const {
135  for (StateIterator<G> siter(*fst); !siter.Done(); siter.Next()) {
136  StateId s = siter.Value();
137  size_t na = 0;
138  size_t ni = fst->NumInputEpsilons(s);
139  MutableArcIterator<G> aiter(fst, s);
140  for (; !aiter.Done(); aiter.Next()) {
141  }
142  for (aiter.Reset(); !aiter.Done(); aiter.Next()) {
143  ++na;
144  Arc arc = aiter.Value();
145  arc.ilabel = 0;
146  aiter.SetValue(arc);
147  arc = aiter.Value();
148  CHECK_EQ(arc.ilabel, 0);
149  CHECK_EQ(fst->NumInputEpsilons(s), ni + 1);
150  arc.ilabel = na;
151  aiter.SetValue(arc);
152  CHECK_EQ(fst->NumInputEpsilons(s), ni);
153  }
154  }
155 
156  {
157  std::unique_ptr<G> cfst1(fst->Copy());
158  cfst1->DeleteStates();
159  CHECK_EQ(cfst1->NumStates(), 0);
160  }
161 
162  std::unique_ptr<G> cfst2(fst->Copy());
163  for (StateIterator<G> siter(*cfst2); !siter.Done(); siter.Next()) {
164  StateId s = siter.Value();
165  cfst2->DeleteArcs(s);
166  CHECK_EQ(cfst2->NumArcs(s), 0);
167  CHECK_EQ(cfst2->NumInputEpsilons(s), 0);
168  CHECK_EQ(cfst2->NumOutputEpsilons(s), 0);
169  }
170  }
171 
172  void TestMutable() { TestMutable(testfst_.get()); }
173 
174  // This verifies operator=
175  template <class G>
176  void TestAssign(const G &fst) const {
177  // Assignment from G
178  G afst1;
179  afst1 = fst;
180  CHECK(Equal(fst, afst1));
181 
182  // Assignment from Fst
183  G afst2;
184  afst2 = static_cast<const Fst<Arc> &>(fst);
185  CHECK(Equal(fst, afst2));
186 
187  // Assignment from self
188  afst2.operator=(afst2);
189  CHECK(Equal(fst, afst2));
190  }
191 
192  void TestAssign() { TestAssign(*testfst_); }
193 
194  // This verifies the copy constructor and Copy method.
195  template <class G>
196  void TestCopy(const G &fst) const {
197  // Copy from G
198  G c1fst(fst);
199  TestBase(c1fst);
200 
201  // Copy from Fst
202  const G c2fst(static_cast<const Fst<Arc> &>(fst));
203  TestBase(c2fst);
204 
205  // Copy from self
206  std::unique_ptr<const G> c3fst(fst.Copy());
207  TestBase(*c3fst);
208  }
209 
210  void TestCopy() const { TestCopy(*testfst_); }
211 
212  // This verifies the read/write methods.
213  template <class G>
214  void TestIO(const G &fst) const {
215  const std::string filename = FST_FLAGS_tmpdir + "/test.fst";
216  const std::string aligned =
217  FST_FLAGS_tmpdir + "/aligned.fst";
218  {
219  // write/read
220  CHECK(fst.Write(filename));
221  auto ffst = fst::WrapUnique(G::Read(filename));
222  CHECK(ffst);
223  TestBase(*ffst);
224  }
225 
226  {
227  // generic read/cast/test
228  auto gfst = fst::WrapUnique(Fst<Arc>::Read(filename));
229  CHECK(gfst);
230  G *dfst = down_cast<G *>(gfst.get());
231  TestBase(*dfst);
232 
233  // generic write/read/test
234  CHECK(gfst->Write(filename));
235  auto hfst = fst::WrapUnique(Fst<Arc>::Read(filename));
236  CHECK(hfst);
237  TestBase(*hfst);
238  }
239 
240  {
241  // check mmaping by first writing the file with the aligned attribute set
242  {
243  std::ofstream ostr(aligned);
244  FstWriteOptions opts;
245  opts.source = aligned;
246  opts.align = true;
247  CHECK(fst.Write(ostr, opts));
248  }
249  std::ifstream istr(aligned);
250  FstReadOptions opts;
251  opts.mode = FstReadOptions::ReadMode("map");
252  opts.source = aligned;
253  auto gfst = fst::WrapUnique(G::Read(istr, opts));
254  CHECK(gfst);
255  TestBase(*gfst);
256  }
257 
258  // check mmaping of unaligned files to make sure it does not fail.
259  {
260  {
261  std::ofstream ostr(aligned);
262  FstWriteOptions opts;
263  opts.source = aligned;
264  opts.align = false;
265  CHECK(fst.Write(ostr, opts));
266  }
267  std::ifstream istr(aligned);
268  FstReadOptions opts;
269  opts.mode = FstReadOptions::ReadMode("map");
270  opts.source = aligned;
271  auto gfst = fst::WrapUnique(G::Read(istr, opts));
272  CHECK(gfst);
273  TestBase(*gfst);
274  }
275 
276  // expanded write/read/test
277  if (fst.Properties(kExpanded, false)) {
278  auto efst = fst::WrapUnique(ExpandedFst<Arc>::Read(filename));
279  CHECK(efst);
280  TestBase(*efst);
281  TestExpanded(*efst);
282  }
283 
284  // mutable write/read/test
285  if (fst.Properties(kMutable, false)) {
286  auto mfst = fst::WrapUnique(MutableFst<Arc>::Read(filename));
287  CHECK(mfst);
288  TestBase(*mfst);
289  TestExpanded(*mfst);
290  TestMutable(mfst.get());
291  }
292  }
293 
294  void TestIO() const { TestIO(*testfst_); }
295 
296  private:
297  // This constructs test FSTs. Given a mutable FST, will leave
298  // the FST as follows:
299  // (I) NumStates() = nstates
300  // (II) Start() = 0
301  // (III) Final(s) = NthWeight(s)
302  // (IV) For state s:
303  // (a) NumArcs(s) == s + 1
304  // (b) For ith arc (i: 1 to s) of s:
305  // (1) ilabel = i
306  // (2) olabel = 0
307  // (3) weight = NthWeight(i)
308  // (4) nextstate = s
309  // (c) s+1st arc of s:
310  // (1) ilabel = s + 1
311  // (2) olabel = 0
312  // (3) weight = NthWeight(s + 1)
313  // (4) nextstate = s + 1 if s < nstates - 1
314  // 0 if s == nstates - 1
315  void InitFst(MutableFst<Arc> *fst, size_t nstates) const {
316  fst->DeleteStates();
317 
318  for (StateId s = 0; s < nstates; ++s) {
319  fst->AddState();
320  fst->SetFinal(s, NthWeight(s));
321  for (size_t i = 1; i <= s; ++i) {
322  Arc arc(i, 0, NthWeight(i), s);
323  fst->AddArc(s, arc);
324  }
325  fst->AddArc(
326  s, Arc(s + 1, 0, NthWeight(s + 1), s == nstates - 1 ? 0 : s + 1));
327  }
328 
329  if (nstates > 0) fst->SetStart(0);
330  }
331 
332  // Generates One() + ... + One() (n times) if weighted_,
333  // otherwise One().
334  Weight NthWeight(int n) const {
335  if (!weighted_) return Weight::One();
336  Weight w = Weight::Zero();
337  for (int i = 0; i < n; ++i) w = Plus(w, Weight::One());
338  return w;
339  }
340 
341  size_t num_states_ = 0;
342  bool weighted_ = true;
343  std::unique_ptr<F> testfst_; // what we're testing
344 };
345 
346 } // namespace fst
347 
348 #endif // FST_TEST_FST_TEST_H_
void TestExpanded(const G &fst) const
Definition: fst_test.h:120
size_t Position() const
Definition: fst.h:564
MatchType Type(bool test) const
Definition: matcher.h:1553
constexpr uint64_t kMutable
Definition: properties.h:49
constexpr int kNoLabel
Definition: fst.h:195
void TestBase() const
Definition: fst_test.h:116
constexpr uint64_t kOEpsilons
Definition: properties.h:89
void Reset()
Definition: fst.h:548
ErrorWeight Plus(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:61
void TestIO(const G &fst) const
Definition: fst_test.h:214
FstTester(size_t num_states=128, bool weighted=true)
Definition: fst_test.h:55
std::string source
Definition: fst.h:73
MatchType
Definition: fst.h:187
virtual void SetStart(StateId)=0
void TestAssign(const G &fst) const
Definition: fst_test.h:176
void SetValue(const Arc &arc)
Definition: mutable-fst.h:246
To down_cast(From *f)
Definition: compat.h:50
std::unique_ptr< T > WrapUnique(T *ptr)
Definition: compat.h:132
constexpr int kNoStateId
Definition: fst.h:196
const Arc & Value() const
Definition: fst.h:536
const Arc & Value() const
Definition: mutable-fst.h:236
std::string source
Definition: fst.h:102
void TestCopy(const G &fst) const
Definition: fst_test.h:196
void TestIO() const
Definition: fst_test.h:294
void TestCopy() const
Definition: fst_test.h:210
constexpr uint64_t kNoOEpsilons
Definition: properties.h:91
constexpr uint64_t kNotAcceptor
Definition: properties.h:66
typename Arc::Weight Weight
Definition: fst_test.h:52
void TestExpanded() const
Definition: fst_test.h:130
StateId Value() const
Definition: fst.h:419
bool Done() const
Definition: fst.h:532
bool Equal(const Fst< Arc > &fst1, const Fst< Arc > &fst2, WeightEqual weight_equal, uint8_t etype=kEqualFsts)
Definition: equal.h:63
bool Find(Label label)
Definition: matcher.h:1557
void TestAssign()
Definition: fst_test.h:192
bool Verify(const Fst< Arc > &fst, bool allow_negative_labels=false)
Definition: verify.h:36
static FileReadMode ReadMode(std::string_view mode)
Definition: fst.cc:126
typename F::Arc Arc
Definition: fst_test.h:50
void SetState(StateId s)
Definition: matcher.h:1555
virtual void AddArc(StateId, const Arc &)=0
void Next()
Definition: fst.h:421
#define CHECK_EQ(x, y)
Definition: log.h:66
void TestMutable(G *fst) const
Definition: fst_test.h:134
bool Done() const
Definition: fst.h:415
virtual StateId AddState()=0
virtual void SetFinal(StateId s, Weight weight=Weight::One())=0
FileReadMode mode
Definition: fst.h:80
virtual void DeleteStates(const std::vector< StateId > &)=0
void TestMutable()
Definition: fst_test.h:172
typename Arc::StateId StateId
Definition: fst_test.h:51
#define CHECK(x)
Definition: log.h:65
const Arc & Value() const
Definition: matcher.h:1561
void Reset()
Definition: fst.h:429
void TestBase(const G &fst) const
Definition: fst_test.h:65
typename Arc::Label Label
Definition: fst_test.h:53
constexpr uint64_t kExpanded
Definition: properties.h:46
constexpr uint64_t kAcceptor
Definition: properties.h:64
void Next()
Definition: fst.h:540