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