// fstext/lattice-utils-test.cc // Copyright 2011 Microsoft Corporation // See ../../COPYING for clarification regarding multiple authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, // MERCHANTABLITY OR NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing permissions and // limitations under the License. #include "fstext/lattice-utils.h" #include "fstext/fst-test-utils.h" #include "base/kaldi-math.h" namespace fst { template void TestConvert(bool invert) { typedef ArcTpl Arc; typedef ArcTpl > CompactArc; for(int i = 0; i < 5; i++) { VectorFst *fst = RandFst(); std::cout << "FST before converting to compact-arc is:\n"; { FstPrinter fstprinter(*fst, NULL, NULL, NULL, false, true, "\t"); fstprinter.Print(&std::cout, "standard output"); } VectorFst ofst; ConvertLattice(*fst, &ofst, invert); std::cout << "FST after converting is:\n"; { FstPrinter fstprinter(ofst, NULL, NULL, NULL, false, true, "\t"); fstprinter.Print(&std::cout, "standard output"); } VectorFst origfst; ConvertLattice(ofst, &origfst, invert); std::cout << "FST after back conversion is:\n"; { FstPrinter fstprinter(origfst, NULL, NULL, NULL, false, true, "\t"); fstprinter.Print(&std::cout, "standard output"); } assert(RandEquivalent(*fst, origfst, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst; } } // This tests the ShortestPath algorithm, and by proxy, tests the // NaturalLess template etc. template void TestShortestPath() { for (int p = 0; p < 10; p++) { typedef ArcTpl Arc; typedef ArcTpl > CompactArc; for(int i = 0; i < 5; i++) { VectorFst *fst = RandPairFst(); std::cout << "Testing shortest path\n"; std::cout << "FST before converting to compact-arc is:\n"; { FstPrinter fstprinter(*fst, NULL, NULL, NULL, false, true, "\t"); fstprinter.Print(&std::cout, "standard output"); } VectorFst cfst; ConvertLattice(*fst, &cfst, false); // invert == false { VectorFst nbest_fst_1; ShortestPath(*fst, &nbest_fst_1, 1); VectorFst nbest_fst_2; ShortestPath(*fst, &nbest_fst_2, 3); VectorFst nbest_fst_1b; ShortestPath(nbest_fst_2, &nbest_fst_1b, 1); assert(ApproxEqual(ShortestDistance(nbest_fst_1), ShortestDistance(nbest_fst_1b))); // since semiring is idempotent, this should succeed too. assert(ApproxEqual(ShortestDistance(*fst), ShortestDistance(nbest_fst_1b))); } { VectorFst nbest_fst_1; ShortestPath(cfst, &nbest_fst_1, 1); VectorFst nbest_fst_2; ShortestPath(cfst, &nbest_fst_2, 3); VectorFst nbest_fst_1b; ShortestPath(nbest_fst_2, &nbest_fst_1b, 1); assert(ApproxEqual(ShortestDistance(nbest_fst_1), ShortestDistance(nbest_fst_1b))); // since semiring is idempotent, this should succeed too. assert(ApproxEqual(ShortestDistance(cfst), ShortestDistance(nbest_fst_1b))); } delete fst; } } } template void TestConvert2() { typedef ArcTpl > ArcF; typedef ArcTpl > ArcD; typedef ArcTpl, Int> > CArcF; typedef ArcTpl, Int> > CArcD; for(int i = 0; i < 2; i++) { { VectorFst *fst1 = RandPairFst(); VectorFst fst2; VectorFst fst3; ConvertLattice(*fst1, &fst2); ConvertLattice(fst2, &fst3); assert(RandEquivalent(*fst1, fst3, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1, cfst3; ConvertLattice(*fst1, &cfst1); VectorFst cfst2; ConvertLattice(cfst1, &cfst2); ConvertLattice(cfst2, &cfst3); assert(RandEquivalent(cfst1, cfst3, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1, cfst3; ConvertLattice(*fst1, &cfst1); VectorFst cfst2; ConvertLattice(cfst1, &cfst2); ConvertLattice(cfst2, &cfst3); assert(RandEquivalent(cfst1, cfst3, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1, cfst3; ConvertLattice(*fst1, &cfst1); VectorFst cfst2; ConvertLattice(cfst1, &cfst2); ConvertLattice(cfst2, &cfst3); assert(RandEquivalent(cfst1, cfst3, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1; ConvertLattice(*fst1, &cfst1); VectorFst fst2; ConvertLattice(cfst1, &fst2); assert(RandEquivalent(*fst1, fst2, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1; ConvertLattice(*fst1, &cfst1); VectorFst fst2; ConvertLattice(cfst1, &fst2); assert(RandEquivalent(*fst1, fst2, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } { VectorFst *fst1 = RandPairFst(); VectorFst cfst1; ConvertLattice(*fst1, &cfst1); VectorFst fst2; ConvertLattice(cfst1, &fst2); assert(RandEquivalent(*fst1, fst2, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst1; } } } // use TestConvertPair when the Weight can be constructed from // a pair of floats. template void TestConvertPair(bool invert) { typedef ArcTpl Arc; typedef ArcTpl > CompactArc; for(int i = 0; i < 2; i++) { VectorFst *fst = RandPairFst(); /*std::cout << "FST before converting to compact-arc is:\n"; { FstPrinter fstprinter(*fst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ VectorFst ofst; ConvertLattice(*fst, &ofst, invert); /*std::cout << "FST after converting is:\n"; { FstPrinter fstprinter(ofst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ VectorFst origfst; ConvertLattice(ofst, &origfst, invert); /*std::cout << "FST after back conversion is:\n"; { FstPrinter fstprinter(origfst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ assert(RandEquivalent(*fst, origfst, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)); delete fst; } } // use TestConvertPair when the Weight can be constructed from // a pair of floats. template void TestScalePair(bool invert) { vector > scale1 = DefaultLatticeScale(), scale2 = DefaultLatticeScale(); // important that all these numbers exactly representable as floats.. // exact floating-point comparisons are used in LatticeWeight, and // this exactness is being tested here.. this test will fail for // other types of number. if (kaldi::Rand() % 4 == 0) { scale1[0][0] = 2.0; scale2[0][0] = 0.5; scale1[1][1] = 4.0; scale2[1][1] = 0.25; } else if (kaldi::Rand() % 3 == 0) { // use that [1 0.25; 0 1] [ 1 -0.25; 0 1] is the unit matrix. scale1[0][1] = 0.25; scale2[0][1] = -0.25; } else if (kaldi::Rand() % 2 == 0) { scale1[1][0] = 0.25; scale2[1][0] = -0.25; } typedef ArcTpl Arc; typedef ArcTpl > CompactArc; for(int i = 0; i < 2; i++) { VectorFst *fst = RandPairFst(); /*std::cout << "FST before converting to compact-arc is:\n"; { FstPrinter fstprinter(*fst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ VectorFst ofst; ConvertLattice(*fst, &ofst, invert); ScaleLattice(scale1, &ofst); /*std::cout << "FST after converting and scaling is:\n"; { FstPrinter fstprinter(ofst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ VectorFst origfst; ConvertLattice(ofst, &origfst, invert); ScaleLattice(scale2, &origfst); /*std::cout << "FST after back conversion and scaling is:\n"; { FstPrinter fstprinter(origfst, NULL, NULL, NULL, false, true); fstprinter.Print(&std::cout, "standard output"); }*/ // If RandEquivalent doesn't work, it could be due to a nasty issue related to the use // of exact floating-point comparisons in the Plus function of LatticeWeight. if (!RandEquivalent(*fst, origfst, 5/*paths*/, 0.01/*delta*/, kaldi::Rand()/*seed*/, 100/*path length-- max?*/)) { std::cerr << "Warn, randequivalent returned false. Checking equivalence another way.\n"; assert(Equal(*fst, origfst)); } delete fst; } } } // end namespace fst int main() { using namespace fst; typedef ::int64 int64; typedef ::uint64 uint64; typedef ::int32 int32; typedef ::uint32 uint32; { typedef LatticeWeightTpl LatticeWeight; for(int i = 0; i < 2; i++) { bool invert = (i % 2); TestConvert(invert); TestConvertPair(invert); TestConvertPair(invert); TestConvertPair, size_t>(invert); TestScalePair(invert); TestScalePair(invert); TestScalePair, size_t>(invert); } } { typedef LatticeWeightTpl LatticeWeight; TestShortestPath(); TestConvert2(); for(int i = 0; i < 2; i++) { bool invert = (i % 2); TestConvertPair(invert); TestConvertPair(invert); TestConvertPair, size_t>(invert); TestScalePair(invert); TestScalePair(invert); TestScalePair, size_t>(invert); } } std::cout << "Tests succeeded\n"; }