00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <fst/fstlib.h>
00022 #include <fst/random-weight.h>
00023
00024
00025
00026
00027
00028 #define TEST_TROPICAL
00029 #define TEST_LOG
00030
00031
00032
00033
00034
00035
00036
00037 DEFINE_int32(seed, -1, "random seed");
00038 DEFINE_int32(repeat, 25, "number of test repetitions");
00039
00040 namespace fst {
00041
00042
00043
00044 template <class A>
00045 class EpsMapper {
00046 public:
00047 EpsMapper() {}
00048
00049 A operator()(const A &arc) const {
00050 return A(0, 0, arc.weight, arc.nextstate);
00051 }
00052
00053 uint64 Properties(uint64 props) const {
00054 props &= ~kNotAcceptor;
00055 props |= kAcceptor;
00056 props &= ~kNoIEpsilons & ~kNoOEpsilons & ~kNoEpsilons;
00057 props |= kIEpsilons | kOEpsilons | kEpsilons;
00058 props &= ~kNotILabelSorted & ~kNotOLabelSorted;
00059 props |= kILabelSorted | kOLabelSorted;
00060 return props;
00061 }
00062
00063 MapFinalAction FinalAction() const { return MAP_NO_SUPERFINAL; }
00064
00065
00066 MapSymbolsAction InputSymbolsAction() const { return MAP_COPY_SYMBOLS;}
00067
00068 MapSymbolsAction OutputSymbolsAction() const { return MAP_COPY_SYMBOLS;}
00069 };
00070
00071
00072
00073 template <class Arc, class WeightGenerator>
00074 class WeightedTester {
00075 public:
00076 typedef typename Arc::Label Label;
00077 typedef typename Arc::StateId StateId;
00078 typedef typename Arc::Weight Weight;
00079
00080 WeightedTester(int seed, const Fst<Arc> &zero_fst, const Fst<Arc> &one_fst,
00081 const Fst<Arc> &univ_fst, WeightGenerator *weight_generator)
00082 : seed_(seed), zero_fst_(zero_fst), one_fst_(one_fst),
00083 univ_fst_(univ_fst), weight_generator_(weight_generator) {}
00084
00085 void Test(const Fst<Arc> &T1, const Fst<Arc> &T2, const Fst<Arc> &T3) {
00086 TestRational(T1, T2, T3);
00087 TestMap(T1);
00088 TestCompose(T1, T2, T3);
00089 TestSort(T1);
00090 TestOptimize(T1);
00091 TestSearch(T1);
00092 }
00093
00094 private:
00095
00096 void TestRational(const Fst<Arc> &T1, const Fst<Arc> &T2,
00097 const Fst<Arc> &T3) {
00098
00099 {
00100 VLOG(1) << "Check destructive and delayed union are equivalent.";
00101 VectorFst<Arc> U1(T1);
00102 Union(&U1, T2);
00103 UnionFst<Arc> U2(T1, T2);
00104 CHECK(Equiv(U1, U2));
00105 }
00106
00107
00108 {
00109 VLOG(1) << "Check destructive and delayed concatenation are equivalent.";
00110 VectorFst<Arc> C1(T1);
00111 Concat(&C1, T2);
00112 ConcatFst<Arc> C2(T1, T2);
00113 CHECK(Equiv(C1, C2));
00114 VectorFst<Arc> C3(T2);
00115 Concat(T1, &C3);
00116 CHECK(Equiv(C3, C2));
00117 }
00118
00119 {
00120 VLOG(1) << "Check destructive and delayed closure* are equivalent.";
00121 VectorFst<Arc> C1(T1);
00122 Closure(&C1, CLOSURE_STAR);
00123 ClosureFst<Arc> C2(T1, CLOSURE_STAR);
00124 CHECK(Equiv(C1, C2));
00125 }
00126
00127 {
00128 VLOG(1) << "Check destructive and delayed closure+ are equivalent.";
00129 VectorFst<Arc> C1(T1);
00130 Closure(&C1, CLOSURE_PLUS);
00131 ClosureFst<Arc> C2(T1, CLOSURE_PLUS);
00132 CHECK(Equiv(C1, C2));
00133 }
00134
00135 {
00136 VLOG(1) << "Check union is associative (destructive).";
00137 VectorFst<Arc> U1(T1);
00138 Union(&U1, T2);
00139 Union(&U1, T3);
00140
00141 VectorFst<Arc> U3(T2);
00142 Union(&U3, T3);
00143 VectorFst<Arc> U4(T1);
00144 Union(&U4, U3);
00145
00146 CHECK(Equiv(U1, U4));
00147 }
00148
00149 {
00150 VLOG(1) << "Check union is associative (delayed).";
00151 UnionFst<Arc> U1(T1, T2);
00152 UnionFst<Arc> U2(U1, T3);
00153
00154 UnionFst<Arc> U3(T2, T3);
00155 UnionFst<Arc> U4(T1, U3);
00156
00157 CHECK(Equiv(U2, U4));
00158 }
00159
00160
00161 {
00162 VLOG(1) << "Check union is associative (destructive delayed).";
00163 UnionFst<Arc> U1(T1, T2);
00164 Union(&U1, T3);
00165
00166 UnionFst<Arc> U3(T2, T3);
00167 UnionFst<Arc> U4(T1, U3);
00168
00169 CHECK(Equiv(U1, U4));
00170 }
00171
00172 {
00173 VLOG(1) << "Check concatenation is associative (destructive).";
00174 VectorFst<Arc> C1(T1);
00175 Concat(&C1, T2);
00176 Concat(&C1, T3);
00177
00178 VectorFst<Arc> C3(T2);
00179 Concat(&C3, T3);
00180 VectorFst<Arc> C4(T1);
00181 Concat(&C4, C3);
00182
00183 CHECK(Equiv(C1, C4));
00184 }
00185
00186 {
00187 VLOG(1) << "Check concatenation is associative (delayed).";
00188 ConcatFst<Arc> C1(T1, T2);
00189 ConcatFst<Arc> C2(C1, T3);
00190
00191 ConcatFst<Arc> C3(T2, T3);
00192 ConcatFst<Arc> C4(T1, C3);
00193
00194 CHECK(Equiv(C2, C4));
00195 }
00196
00197 {
00198 VLOG(1) << "Check concatenation is associative (destructive delayed).";
00199 ConcatFst<Arc> C1(T1, T2);
00200 Concat(&C1, T3);
00201
00202 ConcatFst<Arc> C3(T2, T3);
00203 ConcatFst<Arc> C4(T1, C3);
00204
00205 CHECK(Equiv(C1, C4));
00206 }
00207
00208 if (Weight::Properties() & kLeftSemiring) {
00209 VLOG(1) << "Check concatenation left distributes"
00210 << " over union (destructive).";
00211
00212 VectorFst<Arc> U1(T1);
00213 Union(&U1, T2);
00214 VectorFst<Arc> C1(T3);
00215 Concat(&C1, U1);
00216
00217 VectorFst<Arc> C2(T3);
00218 Concat(&C2, T1);
00219 VectorFst<Arc> C3(T3);
00220 Concat(&C3, T2);
00221 VectorFst<Arc> U2(C2);
00222 Union(&U2, C3);
00223
00224 CHECK(Equiv(C1, U2));
00225 }
00226
00227 if (Weight::Properties() & kRightSemiring) {
00228 VLOG(1) << "Check concatenation right distributes"
00229 << " over union (destructive).";
00230 VectorFst<Arc> U1(T1);
00231 Union(&U1, T2);
00232 VectorFst<Arc> C1(U1);
00233 Concat(&C1, T3);
00234
00235 VectorFst<Arc> C2(T1);
00236 Concat(&C2, T3);
00237 VectorFst<Arc> C3(T2);
00238 Concat(&C3, T3);
00239 VectorFst<Arc> U2(C2);
00240 Union(&U2, C3);
00241
00242 CHECK(Equiv(C1, U2));
00243 }
00244
00245 if (Weight::Properties() & kLeftSemiring) {
00246 VLOG(1) << "Check concatenation left distributes over union (delayed).";
00247 UnionFst<Arc> U1(T1, T2);
00248 ConcatFst<Arc> C1(T3, U1);
00249
00250 ConcatFst<Arc> C2(T3, T1);
00251 ConcatFst<Arc> C3(T3, T2);
00252 UnionFst<Arc> U2(C2, C3);
00253
00254 CHECK(Equiv(C1, U2));
00255 }
00256
00257 if (Weight::Properties() & kRightSemiring) {
00258 VLOG(1) << "Check concatenation right distributes over union (delayed).";
00259 UnionFst<Arc> U1(T1, T2);
00260 ConcatFst<Arc> C1(U1, T3);
00261
00262 ConcatFst<Arc> C2(T1, T3);
00263 ConcatFst<Arc> C3(T2, T3);
00264 UnionFst<Arc> U2(C2, C3);
00265
00266 CHECK(Equiv(C1, U2));
00267 }
00268
00269
00270 if (Weight::Properties() & kLeftSemiring) {
00271 VLOG(1) << "Check T T* == T+ (destructive).";
00272 VectorFst<Arc> S(T1);
00273 Closure(&S, CLOSURE_STAR);
00274 VectorFst<Arc> C(T1);
00275 Concat(&C, S);
00276
00277 VectorFst<Arc> P(T1);
00278 Closure(&P, CLOSURE_PLUS);
00279
00280 CHECK(Equiv(C, P));
00281 }
00282
00283
00284 if (Weight::Properties() & kRightSemiring) {
00285 VLOG(1) << "Check T* T == T+ (destructive).";
00286 VectorFst<Arc> S(T1);
00287 Closure(&S, CLOSURE_STAR);
00288 VectorFst<Arc> C(S);
00289 Concat(&C, T1);
00290
00291 VectorFst<Arc> P(T1);
00292 Closure(&P, CLOSURE_PLUS);
00293
00294 CHECK(Equiv(C, P));
00295 }
00296
00297 if (Weight::Properties() & kLeftSemiring) {
00298 VLOG(1) << "Check T T* == T+ (delayed).";
00299 ClosureFst<Arc> S(T1, CLOSURE_STAR);
00300 ConcatFst<Arc> C(T1, S);
00301
00302 ClosureFst<Arc> P(T1, CLOSURE_PLUS);
00303
00304 CHECK(Equiv(C, P));
00305 }
00306
00307 if (Weight::Properties() & kRightSemiring) {
00308 VLOG(1) << "Check T* T == T+ (delayed).";
00309 ClosureFst<Arc> S(T1, CLOSURE_STAR);
00310 ConcatFst<Arc> C(S, T1);
00311
00312 ClosureFst<Arc> P(T1, CLOSURE_PLUS);
00313
00314 CHECK(Equiv(C, P));
00315 }
00316 }
00317
00318
00319 void TestMap(const Fst<Arc> &T) {
00320
00321 {
00322 VLOG(1) << "Check destructive and delayed projection are equivalent.";
00323 VectorFst<Arc> P1(T);
00324 Project(&P1, PROJECT_INPUT);
00325 ProjectFst<Arc> P2(T, PROJECT_INPUT);
00326 CHECK(Equiv(P1, P2));
00327 }
00328
00329
00330 {
00331 VLOG(1) << "Check destructive and delayed inversion are equivalent.";
00332 VectorFst<Arc> I1(T);
00333 Invert(&I1);
00334 InvertFst<Arc> I2(T);
00335 CHECK(Equiv(I1, I2));
00336 }
00337
00338 {
00339 VLOG(1) << "Check Pi_1(T) = Pi_2(T^-1) (destructive).";
00340 VectorFst<Arc> P1(T);
00341 VectorFst<Arc> I1(T);
00342 Project(&P1, PROJECT_INPUT);
00343 Invert(&I1);
00344 Project(&I1, PROJECT_OUTPUT);
00345 CHECK(Equiv(P1, I1));
00346 }
00347
00348 {
00349 VLOG(1) << "Check Pi_2(T) = Pi_1(T^-1) (destructive).";
00350 VectorFst<Arc> P1(T);
00351 VectorFst<Arc> I1(T);
00352 Project(&P1, PROJECT_OUTPUT);
00353 Invert(&I1);
00354 Project(&I1, PROJECT_INPUT);
00355 CHECK(Equiv(P1, I1));
00356 }
00357
00358 {
00359 VLOG(1) << "Check Pi_1(T) = Pi_2(T^-1) (delayed).";
00360 ProjectFst<Arc> P1(T, PROJECT_INPUT);
00361 InvertFst<Arc> I1(T);
00362 ProjectFst<Arc> P2(I1, PROJECT_OUTPUT);
00363 CHECK(Equiv(P1, P2));
00364 }
00365
00366
00367 {
00368 VLOG(1) << "Check Pi_2(T) = Pi_1(T^-1) (delayed).";
00369 ProjectFst<Arc> P1(T, PROJECT_OUTPUT);
00370 InvertFst<Arc> I1(T);
00371 ProjectFst<Arc> P2(I1, PROJECT_INPUT);
00372 CHECK(Equiv(P1, P2));
00373 }
00374
00375
00376 {
00377 VLOG(1) << "Check destructive relabeling";
00378 static const int kNumLabels = 10;
00379
00380 vector<Label> labelset(kNumLabels);
00381 for (size_t i = 0; i < kNumLabels; ++i) labelset[i] = i;
00382 for (size_t i = 0; i < kNumLabels; ++i) {
00383 swap(labelset[i], labelset[rand() % kNumLabels]);
00384 }
00385
00386 vector<pair<Label, Label> > ipairs1(kNumLabels);
00387 vector<pair<Label, Label> > opairs1(kNumLabels);
00388 for (size_t i = 0; i < kNumLabels; ++i) {
00389 ipairs1[i] = make_pair(i, labelset[i]);
00390 opairs1[i] = make_pair(labelset[i], i);
00391 }
00392 VectorFst<Arc> R(T);
00393 Relabel(&R, ipairs1, opairs1);
00394
00395 vector<pair<Label, Label> > ipairs2(kNumLabels);
00396 vector<pair<Label, Label> > opairs2(kNumLabels);
00397 for (size_t i = 0; i < kNumLabels; ++i) {
00398 ipairs2[i] = make_pair(labelset[i], i);
00399 opairs2[i] = make_pair(i, labelset[i]);
00400 }
00401 Relabel(&R, ipairs2, opairs2);
00402 CHECK(Equiv(R, T));
00403
00404 VLOG(1) << "Check on-the-fly relabeling";
00405 RelabelFst<Arc> Rdelay(T, ipairs1, opairs1);
00406
00407 RelabelFst<Arc> RRdelay(Rdelay, ipairs2, opairs2);
00408 CHECK(Equiv(RRdelay, T));
00409 }
00410
00411 {
00412 VLOG(1) << "Check encoding/decoding (destructive).";
00413 VectorFst<Arc> D(T);
00414 uint32 encode_props = 0;
00415 if (rand() % 2)
00416 encode_props |= kEncodeLabels;
00417 if (rand() % 2)
00418 encode_props |= kEncodeWeights;
00419 EncodeMapper<Arc> encoder(encode_props, ENCODE);
00420 Encode(&D, &encoder);
00421 Decode(&D, encoder);
00422 CHECK(Equiv(D, T));
00423 }
00424
00425 {
00426 VLOG(1) << "Check encoding/decoding (delayed).";
00427 uint32 encode_props = 0;
00428 if (rand() % 2)
00429 encode_props |= kEncodeLabels;
00430 if (rand() % 2)
00431 encode_props |= kEncodeWeights;
00432 EncodeMapper<Arc> encoder(encode_props, ENCODE);
00433 EncodeFst<Arc> E(T, &encoder);
00434 VectorFst<Arc> Encoded(E);
00435 DecodeFst<Arc> D(Encoded, encoder);
00436 CHECK(Equiv(D, T));
00437 }
00438
00439 {
00440 VLOG(1) << "Check gallic mappers (constructive).";
00441 ToGallicMapper<Arc> to_mapper;
00442 FromGallicMapper<Arc> from_mapper;
00443 VectorFst< GallicArc<Arc> > G;
00444 VectorFst<Arc> F;
00445 Map(T, &G, to_mapper);
00446 Map(G, &F, from_mapper);
00447 CHECK(Equiv(T, F));
00448 }
00449
00450 {
00451 VLOG(1) << "Check gallic mappers (delayed).";
00452 ToGallicMapper<Arc> to_mapper;
00453 FromGallicMapper<Arc> from_mapper;
00454 MapFst<Arc, GallicArc<Arc>, ToGallicMapper<Arc> >
00455 G(T, to_mapper);
00456 MapFst<GallicArc<Arc>, Arc, FromGallicMapper<Arc> >
00457 F(G, from_mapper);
00458 CHECK(Equiv(T, F));
00459 }
00460 }
00461
00462
00463 void TestCompose(const Fst<Arc> &T1, const Fst<Arc> &T2,
00464 const Fst<Arc> &T3) {
00465 if (!(Weight::Properties() & kCommutative))
00466 return;
00467
00468 VectorFst<Arc> S1(T1);
00469 VectorFst<Arc> S2(T2);
00470 VectorFst<Arc> S3(T3);
00471
00472 ILabelCompare<Arc> icomp;
00473 OLabelCompare<Arc> ocomp;
00474
00475 ArcSort(&S1, ocomp);
00476 ArcSort(&S2, ocomp);
00477 ArcSort(&S3, icomp);
00478
00479 {
00480 VLOG(1) << "Check composition is associative.";
00481 ComposeFst<Arc> C1(S1, S2);
00482
00483 ComposeFst<Arc> C2(C1, S3);
00484 ComposeFst<Arc> C3(S2, S3);
00485 ComposeFst<Arc> C4(S1, C3);
00486
00487 CHECK(Equiv(C2, C4));
00488 }
00489
00490 {
00491 VLOG(1) << "Check composition left distributes over union.";
00492 UnionFst<Arc> U1(S2, S3);
00493 ComposeFst<Arc> C1(S1, U1);
00494
00495 ComposeFst<Arc> C2(S1, S2);
00496 ComposeFst<Arc> C3(S1, S3);
00497 UnionFst<Arc> U2(C2, C3);
00498
00499 CHECK(Equiv(C1, U2));
00500 }
00501
00502 {
00503 VLOG(1) << "Check composition right distributes over union.";
00504 UnionFst<Arc> U1(S1, S2);
00505 ComposeFst<Arc> C1(U1, S3);
00506
00507 ComposeFst<Arc> C2(S1, S3);
00508 ComposeFst<Arc> C3(S2, S3);
00509 UnionFst<Arc> U2(C2, C3);
00510
00511 CHECK(Equiv(C1, U2));
00512 }
00513
00514 VectorFst<Arc> A1(S1);
00515 VectorFst<Arc> A2(S2);
00516 VectorFst<Arc> A3(S3);
00517 Project(&A1, PROJECT_OUTPUT);
00518 Project(&A2, PROJECT_INPUT);
00519 Project(&A3, PROJECT_INPUT);
00520
00521 {
00522 VLOG(1) << "Check intersection is commutative.";
00523 IntersectFst<Arc> I1(A1, A2);
00524 IntersectFst<Arc> I2(A2, A1);
00525 CHECK(Equiv(I1, I2));
00526 }
00527
00528 {
00529 VLOG(1) << "Check all epsilon filters leads to equivalent results.";
00530 typedef Matcher< Fst<Arc> > M;
00531 ComposeFst<Arc> C1(S1, S2);
00532 ComposeFst<Arc> C2(
00533 S1, S2,
00534 ComposeFstOptions<Arc, M, AltSequenceComposeFilter<M> >());
00535 ComposeFst<Arc> C3(
00536 S1, S2,
00537 ComposeFstOptions<Arc, M, MatchComposeFilter<M> >());
00538
00539 CHECK(Equiv(C1, C2));
00540 CHECK(Equiv(C1, C3));
00541 }
00542 }
00543
00544
00545 void TestSort(const Fst<Arc> &T) {
00546 ILabelCompare<Arc> icomp;
00547 OLabelCompare<Arc> ocomp;
00548
00549 {
00550 VLOG(1) << "Check arc sorted Fst is equivalent to its input.";
00551 VectorFst<Arc> S1(T);
00552 ArcSort(&S1, icomp);
00553 CHECK(Equiv(T, S1));
00554 }
00555
00556 {
00557 VLOG(1) << "Check destructive and delayed arcsort are equivalent.";
00558 VectorFst<Arc> S1(T);
00559 ArcSort(&S1, icomp);
00560 ArcSortFst< Arc, ILabelCompare<Arc> > S2(T, icomp);
00561 CHECK(Equiv(S1, S2));
00562 }
00563
00564 {
00565 VLOG(1) << "Check ilabel sorting vs. olabel sorting with inversions.";
00566 VectorFst<Arc> S1(T);
00567 VectorFst<Arc> S2(T);
00568 ArcSort(&S1, icomp);
00569 Invert(&S2);
00570 ArcSort(&S2, ocomp);
00571 Invert(&S2);
00572 CHECK(Equiv(S1, S2));
00573 }
00574
00575 {
00576 VLOG(1) << "Check topologically sorted Fst is equivalent to its input.";
00577 VectorFst<Arc> S1(T);
00578 TopSort(&S1);
00579 CHECK(Equiv(T, S1));
00580 }
00581
00582 {
00583 VLOG(1) << "Check reverse(reverse(T)) = T";
00584 VectorFst< ReverseArc<Arc> > R1;
00585 VectorFst<Arc> R2;
00586 Reverse(T, &R1);
00587 Reverse(R1, &R2);
00588 CHECK(Equiv(T, R2));
00589 }
00590 }
00591
00592
00593 void TestOptimize(const Fst<Arc> &T) {
00594 uint64 tprops = T.Properties(kFstProperties, true);
00595 uint64 wprops = Weight::Properties();
00596
00597 VectorFst<Arc> A(T);
00598 Project(&A, PROJECT_INPUT);
00599
00600 {
00601 VLOG(1) << "Check connected FST is equivalent to its input.";
00602 VectorFst<Arc> C1(T);
00603 Connect(&C1);
00604 CHECK(Equiv(T, C1));
00605 }
00606
00607 if ((wprops & kSemiring) == kSemiring &&
00608 (tprops & kAcyclic || wprops & kIdempotent)) {
00609 VLOG(1) << "Check epsilon-removed FST is equivalent to its input.";
00610 VectorFst<Arc> R1(T);
00611 RmEpsilon(&R1);
00612 CHECK(Equiv(T, R1));
00613
00614 VLOG(1) << "Check destructive and delayed epsilon removal"
00615 << "are equivalent.";
00616 RmEpsilonFst<Arc> R2(T);
00617 CHECK(Equiv(R1, R2));
00618
00619 VLOG(1) << "Check an FST with a large proportion"
00620 << " of epsilon transitions:";
00621
00622
00623 VectorFst<Arc> U;
00624 Map(T, &U, EpsMapper<Arc>());
00625 VectorFst<Arc> V;
00626 V.SetStart(V.AddState());
00627 Arc arc(1, 1, Weight::One(), V.AddState());
00628 V.AddArc(V.Start(), arc);
00629 V.SetFinal(arc.nextstate, Weight::One());
00630 Concat(&U, V);
00631
00632
00633 vector<Weight> d;
00634 ShortestDistance(U, &d, true);
00635 Weight w = U.Start() < d.size() ? d[U.Start()] : Weight::Zero();
00636 VectorFst<Arc> U1(U);
00637 RmEpsilon(&U1);
00638 ShortestDistance(U1, &d, true);
00639 Weight w1 = U1.Start() < d.size() ? d[U1.Start()] : Weight::Zero();
00640 CHECK(ApproxEqual(w, w1, kTestDelta));
00641 RmEpsilonFst<Arc> U2(U);
00642 ShortestDistance(U2, &d, true);
00643 Weight w2 = U2.Start() < d.size() ? d[U2.Start()] : Weight::Zero();
00644 CHECK(ApproxEqual(w, w2, kTestDelta));
00645 }
00646
00647 if ((wprops & kSemiring) == kSemiring && tprops & kAcyclic) {
00648 VLOG(1) << "Check determinized FSA is equivalent to its input.";
00649 DeterminizeFst<Arc> D(A);
00650 CHECK(Equiv(A, D));
00651
00652
00653 int n;
00654 {
00655 VLOG(1) << "Check size(min(det(A))) <= size(det(A))"
00656 << " and min(det(A)) equiv det(A)";
00657 VectorFst<Arc> M(D);
00658 n = M.NumStates();
00659 Minimize(&M);
00660 CHECK(Equiv(D, M));
00661 CHECK(M.NumStates() <= n);
00662 n = M.NumStates();
00663 }
00664
00665 if (n && (wprops & kIdempotent) == kIdempotent &&
00666 A.Properties(kNoEpsilons, true)) {
00667 VLOG(1) << "Check that Revuz's algorithm leads to the"
00668 << " same number of states as Brozozowski's algorithm";
00669
00670
00671
00672
00673 VectorFst<Arc> R;
00674 Reverse(A, &R);
00675 RmEpsilon(&R);
00676 DeterminizeFst<Arc> DR(R);
00677 VectorFst<Arc> RD;
00678 Reverse(DR, &RD);
00679 DeterminizeFst<Arc> DRD(RD);
00680 VectorFst<Arc> M(DRD);
00681 CHECK_EQ(n + 1, M.NumStates());
00682
00683 }
00684 }
00685
00686 if (Arc::Type() == LogArc::Type() || Arc::Type() == StdArc::Type()) {
00687 VLOG(1) << "Check reweight(T) equiv T";
00688 vector<Weight> potential;
00689 VectorFst<Arc> RI(T);
00690 VectorFst<Arc> RF(T);
00691 while (potential.size() < RI.NumStates())
00692 potential.push_back((*weight_generator_)());
00693
00694 Reweight(&RI, potential, REWEIGHT_TO_INITIAL);
00695 CHECK(Equiv(T, RI));
00696
00697 Reweight(&RF, potential, REWEIGHT_TO_FINAL);
00698 CHECK(Equiv(T, RF));
00699 }
00700
00701 if ((wprops & kIdempotent) || (tprops & kAcyclic)) {
00702 VLOG(1) << "Check pushed FST is equivalent to input FST.";
00703
00704 if (wprops & kRightSemiring) {
00705 VectorFst<Arc> P1;
00706 Push<Arc, REWEIGHT_TO_FINAL>(T, &P1, kPushLabels);
00707 CHECK(Equiv(T, P1));
00708
00709 VectorFst<Arc> P2;
00710 Push<Arc, REWEIGHT_TO_FINAL>(T, &P2, kPushWeights);
00711 CHECK(Equiv(T, P2));
00712
00713 VectorFst<Arc> P3;
00714 Push<Arc, REWEIGHT_TO_FINAL>(T, &P3, kPushLabels | kPushWeights);
00715 CHECK(Equiv(T, P3));
00716 }
00717
00718
00719 if (wprops & kLeftSemiring) {
00720 VectorFst<Arc> P1;
00721 Push<Arc, REWEIGHT_TO_INITIAL>(T, &P1, kPushLabels);
00722 CHECK(Equiv(T, P1));
00723
00724 VectorFst<Arc> P2;
00725 Push<Arc, REWEIGHT_TO_INITIAL>(T, &P2, kPushWeights);
00726 CHECK(Equiv(T, P2));
00727 VectorFst<Arc> P3;
00728 Push<Arc, REWEIGHT_TO_INITIAL>(T, &P3, kPushLabels | kPushWeights);
00729 CHECK(Equiv(T, P3));
00730 }
00731 }
00732
00733 if ((wprops & (kPath | kCommutative)) == (kPath | kCommutative)) {
00734 VLOG(1) << "Check pruning algorithm";
00735 {
00736 VLOG(1) << "Check equiv. of constructive and destructive algorithms";
00737 Weight thresold = (*weight_generator_)();
00738 VectorFst<Arc> P1(T);
00739 Prune(&P1, thresold);
00740 VectorFst<Arc> P2;
00741 Prune(T, &P2, thresold);
00742 CHECK(Equiv(P1,P2));
00743 }
00744
00745 {
00746 VLOG(1) << "Check prune(reverse) equiv reverse(prune)";
00747 Weight thresold = (*weight_generator_)();
00748 VectorFst< ReverseArc<Arc> > R;
00749 VectorFst<Arc> P1(T);
00750 VectorFst<Arc> P2;
00751 Prune(&P1, thresold);
00752 Reverse(T, &R);
00753 Prune(&R, thresold.Reverse());
00754 Reverse(R, &P2);
00755 CHECK(Equiv(P1, P2));
00756 }
00757 {
00758 VLOG(1) << "Check: ShortestDistance(T- prune(T))"
00759 << " > ShortestDistance(T) times Thresold";
00760 Weight thresold = (*weight_generator_)();
00761 VectorFst<Arc> P;
00762 Prune(A, &P, thresold);
00763 DifferenceFst<Arc> C(A, DeterminizeFst<Arc>
00764 (RmEpsilonFst<Arc>
00765 (MapFst<Arc, Arc,
00766 RmWeightMapper<Arc> >
00767 (P, RmWeightMapper<Arc>()))));
00768 Weight sum1 = Times(ShortestDistance(A), thresold);
00769 Weight sum2 = ShortestDistance(C);
00770 CHECK(Plus(sum1, sum2) == sum1);
00771 }
00772 }
00773 if (tprops & kAcyclic) {
00774 VLOG(1) << "Check synchronize(T) equiv T";
00775 SynchronizeFst<Arc> S(T);
00776 CHECK(Equiv(T, S));
00777 }
00778 }
00779
00780
00781 void TestSearch(const Fst<Arc> &T) {
00782 uint64 wprops = Weight::Properties();
00783
00784 VectorFst<Arc> A(T);
00785 Project(&A, PROJECT_INPUT);
00786
00787 if ((wprops & (kPath | kRightSemiring)) == (kPath | kRightSemiring)) {
00788 VLOG(1) << "Check 1-best weight.";
00789 VectorFst<Arc> path;
00790 ShortestPath(T, &path);
00791 Weight tsum = ShortestDistance(T);
00792 Weight psum = ShortestDistance(path);
00793 CHECK(ApproxEqual(tsum, psum, kTestDelta));
00794 }
00795
00796 if ((wprops & (kPath | kSemiring)) == (kPath | kSemiring)) {
00797 VLOG(1) << "Check n-best weights";
00798 VectorFst<Arc> R(A);
00799 RmEpsilon(&R);
00800 int nshortest = rand() % kNumRandomShortestPaths + 2;
00801 VectorFst<Arc> paths;
00802 ShortestPath(R, &paths, nshortest, true, false,
00803 Weight::Zero(), kNumShortestStates);
00804 vector<Weight> distance;
00805 ShortestDistance(paths, &distance, true);
00806 StateId pstart = paths.Start();
00807 if (pstart != kNoStateId) {
00808 ArcIterator< Fst<Arc> > piter(paths, pstart);
00809 for (; !piter.Done(); piter.Next()) {
00810 StateId s = piter.Value().nextstate;
00811 Weight nsum = s < distance.size() ?
00812 Times(piter.Value().weight, distance[s]) : Weight::Zero();
00813 VectorFst<Arc> path;
00814 ShortestPath(R, &path);
00815 Weight dsum = ShortestDistance(path);
00816 CHECK(ApproxEqual(nsum, dsum, kTestDelta));
00817 Map(&path, RmWeightMapper<Arc>());
00818 VectorFst<Arc> S;
00819 Difference(R, path, &S);
00820 R = S;
00821 }
00822 }
00823 }
00824 }
00825
00826
00827
00828 bool Equiv(const Fst<Arc> &fst1, const Fst<Arc> &fst2) {
00829 VLOG(1) << "Check FSTs for sanity (including property bits).";
00830 CHECK(Verify(fst1));
00831 CHECK(Verify(fst2));
00832
00833 UniformArcSelector<Arc> uniform_selector(seed_);
00834 RandGenOptions< UniformArcSelector<Arc> >
00835 opts(uniform_selector, kRandomPathLength);
00836 return RandEquivalent(fst1, fst2, kNumRandomPaths, kTestDelta, opts);
00837 }
00838
00839
00840 int seed_;
00841
00842
00843 VectorFst<Arc> zero_fst_;
00844
00845
00846 VectorFst<Arc> one_fst_;
00847
00848
00849 VectorFst<Arc> univ_fst_;
00850
00851
00852 WeightGenerator *weight_generator_;
00853
00854
00855 static const int kRandomPathLength;
00856
00857
00858 static const int kNumRandomPaths;
00859
00860
00861 static const int kNumRandomShortestPaths;
00862
00863
00864 static const int kNumShortestStates;
00865
00866
00867 static const float kTestDelta;
00868
00869 DISALLOW_COPY_AND_ASSIGN(WeightedTester);
00870 };
00871
00872
00873 template <class A, class WG>
00874 const int WeightedTester<A, WG>::kRandomPathLength = 25;
00875
00876 template <class A, class WG>
00877 const int WeightedTester<A, WG>::kNumRandomPaths = 100;
00878
00879 template <class A, class WG>
00880 const int WeightedTester<A, WG>::kNumRandomShortestPaths = 100;
00881
00882 template <class A, class WG>
00883 const int WeightedTester<A, WG>::kNumShortestStates = 10000;
00884
00885 template <class A, class WG>
00886 const float WeightedTester<A, WG>::kTestDelta = .05;
00887
00888
00889
00890
00891 template <class Arc>
00892 class UnweightedTester {
00893 public:
00894 UnweightedTester(const Fst<Arc> &zero_fsa, const Fst<Arc> &one_fsa,
00895 const Fst<Arc> &univ_fsa) {}
00896
00897 void Test(const Fst<Arc> &A1, const Fst<Arc> &A2, const Fst<Arc> &A3) {}
00898 };
00899
00900
00901
00902
00903
00904 template <>
00905 class UnweightedTester<StdArc> {
00906 public:
00907 typedef StdArc Arc;
00908 typedef Arc::Label Label;
00909 typedef Arc::StateId StateId;
00910 typedef Arc::Weight Weight;
00911
00912 UnweightedTester(const Fst<Arc> &zero_fsa, const Fst<Arc> &one_fsa,
00913 const Fst<Arc> &univ_fsa)
00914 : zero_fsa_(zero_fsa), one_fsa_(one_fsa), univ_fsa_(univ_fsa) {}
00915
00916 void Test(const Fst<Arc> &A1, const Fst<Arc> &A2, const Fst<Arc> &A3) {
00917 TestRational(A1, A2, A3);
00918 TestIntersect(A1, A2, A3);
00919 TestOptimize(A1);
00920 }
00921
00922 private:
00923
00924 void TestRational(const Fst<Arc> &A1, const Fst<Arc> &A2,
00925 const Fst<Arc> &A3) {
00926
00927 {
00928 VLOG(1) << "Check the union contains its arguments (destructive).";
00929 VectorFst<Arc> U(A1);
00930 Union(&U, A2);
00931
00932 CHECK(Subset(A1, U));
00933 CHECK(Subset(A2, U));
00934 }
00935
00936 {
00937 VLOG(1) << "Check the union contains its arguments (delayed).";
00938 UnionFst<Arc> U(A1, A2);
00939
00940 CHECK(Subset(A1, U));
00941 CHECK(Subset(A2, U));
00942 }
00943
00944 {
00945 VLOG(1) << "Check if A^n c A* (destructive).";
00946 VectorFst<Arc> C(one_fsa_);
00947 int n = rand() % 5;
00948 for (int i = 0; i < n; ++i)
00949 Concat(&C, A1);
00950
00951 VectorFst<Arc> S(A1);
00952 Closure(&S, CLOSURE_STAR);
00953 CHECK(Subset(C, S));
00954 }
00955
00956 {
00957 VLOG(1) << "Check if A^n c A* (delayed).";
00958 int n = rand() % 5;
00959 Fst<Arc> *C = new VectorFst<Arc>(one_fsa_);
00960 for (int i = 0; i < n; ++i) {
00961 ConcatFst<Arc> *F = new ConcatFst<Arc>(*C, A1);
00962 delete C;
00963 C = F;
00964 }
00965 ClosureFst<Arc> S(A1, CLOSURE_STAR);
00966 CHECK(Subset(*C, S));
00967 delete C;
00968 }
00969 }
00970
00971
00972 void TestIntersect(const Fst<Arc> &A1, const Fst<Arc> &A2,
00973 const Fst<Arc> &A3) {
00974 VectorFst<Arc> S1(A1);
00975 VectorFst<Arc> S2(A2);
00976 VectorFst<Arc> S3(A3);
00977
00978 ILabelCompare<Arc> comp;
00979
00980 ArcSort(&S1, comp);
00981 ArcSort(&S2, comp);
00982 ArcSort(&S3, comp);
00983
00984 {
00985 VLOG(1) << "Check the intersection is contained in its arguments.";
00986 IntersectFst<Arc> I1(S1, S2);
00987 CHECK(Subset(I1, S1));
00988 CHECK(Subset(I1, S2));
00989 }
00990
00991 {
00992 VLOG(1) << "Check union distributes over intersection.";
00993 IntersectFst<Arc> I1(S1, S2);
00994 UnionFst<Arc> U1(I1, S3);
00995
00996 UnionFst<Arc> U2(S1, S3);
00997 UnionFst<Arc> U3(S2, S3);
00998 ArcSortFst< Arc, ILabelCompare<Arc> > S4(U3, comp);
00999 IntersectFst<Arc> I2(U2, S4);
01000
01001 CHECK(Equiv(U1, I2));
01002 }
01003
01004 VectorFst<Arc> C1;
01005 VectorFst<Arc> C2;
01006 Complement(S1, &C1);
01007 Complement(S2, &C2);
01008 ArcSort(&C1, comp);
01009 ArcSort(&C2, comp);
01010
01011
01012 {
01013 VLOG(1) << "Check S U S' = Sigma*";
01014 UnionFst<Arc> U(S1, C1);
01015 CHECK(Equiv(U, univ_fsa_));
01016 }
01017
01018 {
01019 VLOG(1) << "Check S n S' = {}";
01020 IntersectFst<Arc> I(S1, C1);
01021 CHECK(Equiv(I, zero_fsa_));
01022 }
01023
01024 {
01025 VLOG(1) << "Check (S1' U S2') == (S1 n S2)'";
01026 UnionFst<Arc> U(C1, C2);
01027
01028 IntersectFst<Arc> I(S1, S2);
01029 VectorFst<Arc> C3;
01030 Complement(I, &C3);
01031 CHECK(Equiv(U, C3));
01032 }
01033
01034 {
01035 VLOG(1) << "Check (S1' n S2') == (S1 U S2)'";
01036 IntersectFst<Arc> I(C1, C2);
01037
01038 UnionFst<Arc> U(S1, S2);
01039 VectorFst<Arc> C3;
01040 Complement(U, &C3);
01041 CHECK(Equiv(I, C3));
01042 }
01043 }
01044
01045
01046 void TestOptimize(const Fst<Arc> &A) {
01047 {
01048 VLOG(1) << "Check determinized FSA is equivalent to its input.";
01049 DeterminizeFst<Arc> D(A);
01050 CHECK(Equiv(A, D));
01051 }
01052
01053 {
01054 VLOG(1) << "Check minimized FSA is equivalent to its input.";
01055 int n;
01056 {
01057 RmEpsilonFst<Arc> R(A);
01058 DeterminizeFst<Arc> D(R);
01059 VectorFst<Arc> M(D);
01060 Minimize(&M);
01061 CHECK(Equiv(A, M));
01062 n = M.NumStates();
01063 }
01064
01065 if (n) {
01066 VLOG(1) << "Check that Hopcroft's and Revuz's algorithms lead to the"
01067 << " same number of states as Brozozowski's algorithm";
01068 VectorFst<Arc> R;
01069 Reverse(A, &R);
01070 RmEpsilon(&R);
01071 DeterminizeFst<Arc> DR(R);
01072 VectorFst<Arc> RD;
01073 Reverse(DR, &RD);
01074 DeterminizeFst<Arc> DRD(RD);
01075 VectorFst<Arc> M(DRD);
01076 CHECK_EQ(n + 1, M.NumStates());
01077
01078 }
01079 }
01080 }
01081
01082
01083 bool Equiv(const Fst<Arc> &fsa1, const Fst<Arc> &fsa2) {
01084 VLOG(1) << "Check FSAs for sanity (including property bits).";
01085 CHECK(Verify(fsa1));
01086 CHECK(Verify(fsa2));
01087
01088 VectorFst<Arc> vfsa1(fsa1);
01089 VectorFst<Arc> vfsa2(fsa2);
01090 RmEpsilon(&vfsa1);
01091 RmEpsilon(&vfsa2);
01092 DeterminizeFst<Arc> dfa1(vfsa1);
01093 DeterminizeFst<Arc> dfa2(vfsa2);
01094
01095
01096 bool equiv1 = Equivalent(dfa1, dfa2);
01097
01098
01099 ILabelCompare<Arc> comp;
01100 VectorFst<Arc> sdfa1(dfa1);
01101 ArcSort(&sdfa1, comp);
01102 VectorFst<Arc> sdfa2(dfa2);
01103 ArcSort(&sdfa2, comp);
01104
01105 DifferenceFst<Arc> dfsa1(sdfa1, sdfa2);
01106 DifferenceFst<Arc> dfsa2(sdfa2, sdfa1);
01107
01108 VectorFst<Arc> ufsa(dfsa1);
01109 Union(&ufsa, dfsa2);
01110 Connect(&ufsa);
01111 bool equiv2 = ufsa.NumStates() == 0;
01112
01113
01114 CHECK((equiv1 && equiv2) || (!equiv1 && !equiv2));
01115
01116 return equiv1;
01117 }
01118
01119
01120 bool Subset(const Fst<Arc> &fsa1, const Fst<Arc> &fsa2) {
01121 VLOG(1) << "Check FSAs (incl. property bits) for sanity";
01122 CHECK(Verify(fsa1));
01123 CHECK(Verify(fsa2));
01124
01125 VectorFst<StdArc> vfsa1;
01126 VectorFst<StdArc> vfsa2;
01127 RmEpsilon(&vfsa1);
01128 RmEpsilon(&vfsa2);
01129 ILabelCompare<StdArc> comp;
01130 ArcSort(&vfsa1, comp);
01131 ArcSort(&vfsa2, comp);
01132 IntersectFst<StdArc> ifsa(vfsa1, vfsa2);
01133 DeterminizeFst<StdArc> dfa1(vfsa1);
01134 DeterminizeFst<StdArc> dfa2(ifsa);
01135 return Equivalent(dfa1, dfa2);
01136 }
01137
01138
01139 void Complement(const Fst<Arc> &ifsa, MutableFst<Arc> *ofsa) {
01140 RmEpsilonFst<Arc> rfsa(ifsa);
01141 DeterminizeFst<Arc> dfa(rfsa);
01142 DifferenceFst<Arc> cfsa(univ_fsa_, dfa);
01143 *ofsa = cfsa;
01144 }
01145
01146
01147 VectorFst<Arc> zero_fsa_;
01148
01149
01150 VectorFst<Arc> one_fsa_;
01151
01152
01153 VectorFst<Arc> univ_fsa_;
01154
01155 DISALLOW_COPY_AND_ASSIGN(UnweightedTester);
01156 };
01157
01158
01159
01160
01161
01162
01163 template <class Arc, class WeightGenerator>
01164 class AlgoTester {
01165 public:
01166 typedef typename Arc::Label Label;
01167 typedef typename Arc::StateId StateId;
01168 typedef typename Arc::Weight Weight;
01169
01170 AlgoTester(WeightGenerator generator, int seed) :
01171 weight_generator_(generator), seed_(seed) {
01172 one_fst_.AddState();
01173 one_fst_.SetStart(0);
01174 one_fst_.SetFinal(0, Weight::One());
01175
01176 univ_fst_.AddState();
01177 univ_fst_.SetStart(0);
01178 univ_fst_.SetFinal(0, Weight::One());
01179 for (int i = 0; i < kNumRandomLabels; ++i)
01180 univ_fst_.AddArc(0, Arc(i, i, Weight::One(), 0));
01181 }
01182
01183 void Test() {
01184 VLOG(1) << "weight type = " << Weight::Type();
01185
01186 for (int i = 0; i < FLAGS_repeat; ++i) {
01187
01188 VectorFst<Arc> T1;
01189 VectorFst<Arc> T2;
01190 VectorFst<Arc> T3;
01191 RandFst(&T1);
01192 RandFst(&T2);
01193 RandFst(&T3);
01194 WeightedTester<Arc, WeightGenerator>
01195 weighted_tester(seed_, zero_fst_, one_fst_,
01196 univ_fst_, &weight_generator_);
01197 weighted_tester.Test(T1, T2, T3);
01198
01199 VectorFst<Arc> A1(T1);
01200 VectorFst<Arc> A2(T2);
01201 VectorFst<Arc> A3(T3);
01202 Project(&A1, PROJECT_OUTPUT);
01203 Project(&A2, PROJECT_INPUT);
01204 Project(&A3, PROJECT_INPUT);
01205 Map(&A1, rm_weight_mapper);
01206 Map(&A2, rm_weight_mapper);
01207 Map(&A3, rm_weight_mapper);
01208 UnweightedTester<Arc> unweighted_tester(zero_fst_, one_fst_, univ_fst_);
01209 unweighted_tester.Test(A1, A2, A3);
01210 }
01211 }
01212
01213 private:
01214
01215 void RandFst(MutableFst<Arc> *fst) {
01216
01217
01218 enum ArcDirection { ANY_DIRECTION = 0, FORWARD_DIRECTION = 1,
01219 REVERSE_DIRECTION = 2, NUM_DIRECTIONS = 3 };
01220
01221 ArcDirection arc_direction = ANY_DIRECTION;
01222 if (rand()/(RAND_MAX + 1.0) < kAcyclicProb)
01223 arc_direction = rand() % 2 ? FORWARD_DIRECTION : REVERSE_DIRECTION;
01224
01225 fst->DeleteStates();
01226 StateId ns = rand() % kNumRandomStates;
01227
01228 if (ns == 0)
01229 return;
01230 for (StateId s = 0; s < ns; ++s)
01231 fst->AddState();
01232
01233 StateId start = rand() % ns;
01234 fst->SetStart(start);
01235
01236 size_t na = rand() % kNumRandomArcs;
01237 for (size_t n = 0; n < na; ++n) {
01238 StateId s = rand() % ns;
01239 Arc arc;
01240 arc.ilabel = rand() % kNumRandomLabels;
01241 arc.olabel = rand() % kNumRandomLabels;
01242 arc.weight = weight_generator_();
01243 arc.nextstate = rand() % ns;
01244
01245 if (arc_direction == ANY_DIRECTION ||
01246 (arc_direction == FORWARD_DIRECTION && arc.ilabel > arc.olabel) ||
01247 (arc_direction == REVERSE_DIRECTION && arc.ilabel < arc.olabel))
01248 fst->AddArc(s, arc);
01249 }
01250
01251 StateId nf = rand() % (ns + 1);
01252 for (StateId n = 0; n < nf; ++n) {
01253 StateId s = rand() % ns;
01254 Weight final = weight_generator_();
01255 fst->SetFinal(s, final);
01256 }
01257 VLOG(1) << "Check FST for sanity (including property bits).";
01258 CHECK(Verify(*fst));
01259
01260
01261 uint64 props = fst->Properties(kFstProperties, true);
01262
01263
01264 uint64 mask = 0;
01265 for (int n = 0; n < 8; ++n) {
01266 mask |= rand() & 0xff;
01267 mask <<= 8;
01268 }
01269 mask &= ~kTrinaryProperties;
01270 fst->SetProperties(props & ~mask, mask);
01271 }
01272
01273
01274 WeightGenerator weight_generator_;
01275
01276
01277 int seed_;
01278
01279
01280 VectorFst<Arc> zero_fst_;
01281
01282
01283 VectorFst<Arc> one_fst_;
01284
01285
01286 VectorFst<Arc> univ_fst_;
01287
01288
01289 RmWeightMapper<Arc> rm_weight_mapper;
01290
01291
01292 static const int kNumRandomStates;
01293
01294
01295 static const int kNumRandomArcs;
01296
01297
01298 static const int kNumRandomLabels;
01299
01300
01301 static const float kAcyclicProb;
01302
01303
01304 static const int kRandomPathLength;
01305
01306
01307 static const int kNumRandomPaths;
01308
01309 DISALLOW_COPY_AND_ASSIGN(AlgoTester);
01310 };
01311
01312 template <class A, class G> const int AlgoTester<A, G>::kNumRandomStates = 10;
01313
01314 template <class A, class G> const int AlgoTester<A, G>::kNumRandomArcs = 25;
01315
01316 template <class A, class G> const int AlgoTester<A, G>::kNumRandomLabels = 5;
01317
01318 template <class A, class G> const float AlgoTester<A, G>::kAcyclicProb = .25;
01319
01320 template <class A, class G> const int AlgoTester<A, G>::kRandomPathLength = 25;
01321
01322 template <class A, class G> const int AlgoTester<A, G>::kNumRandomPaths = 100;
01323
01324 }
01325
01326
01327 using fst::StdArc;
01328 using fst::TropicalWeightGenerator;
01329
01330 using fst::LogArc;
01331 using fst::LogWeightGenerator;
01332
01333 using fst::MinMaxArc;
01334 using fst::MinMaxWeightGenerator;
01335
01336 using fst::StringArc;
01337 using fst::StringWeightGenerator;
01338 using fst::STRING_LEFT;
01339 using fst::STRING_RIGHT;
01340
01341 using fst::GallicArc;
01342 using fst::GallicWeightGenerator;
01343
01344 using fst::LexicographicArc;
01345 using fst::TropicalWeight;
01346 using fst::LexicographicWeightGenerator;
01347
01348 using fst::ArcTpl;
01349 using fst::PowerWeight;
01350 using fst::PowerWeightGenerator;
01351
01352 using fst::AlgoTester;
01353
01354 int main(int argc, char **argv) {
01355 FLAGS_fst_verify_properties = true;
01356 std::set_new_handler(FailedNewHandler);
01357 SetFlags(argv[0], &argc, &argv, true);
01358
01359 static const int kCacheGcLimit = 20;
01360
01361 int seed = FLAGS_seed >= 0 ? FLAGS_seed : time(0);
01362 srand(seed);
01363 LOG(INFO) << "Seed = " << seed;
01364
01365 FLAGS_fst_default_cache_gc = rand() % 2;
01366 FLAGS_fst_default_cache_gc_limit = rand() % kCacheGcLimit;
01367 VLOG(1) << "default_cache_gc:" << FLAGS_fst_default_cache_gc;
01368 VLOG(1) << "default_cache_gc_limit:" << FLAGS_fst_default_cache_gc_limit;
01369
01370 #ifdef TEST_TROPICAL
01371 TropicalWeightGenerator tropical_generator(seed, false);
01372 AlgoTester<StdArc, TropicalWeightGenerator>
01373 tropical_tester(tropical_generator, seed);
01374 tropical_tester.Test();
01375 #endif /// TEST_TROPICAL
01376
01377 #ifdef TEST_LOG
01378 LogWeightGenerator log_generator(seed, false);
01379 AlgoTester<LogArc, LogWeightGenerator>
01380 log_tester(log_generator, seed);
01381 log_tester.Test();
01382 #endif /// TEST_LOG
01383
01384 #ifdef TEST_MINMAX
01385 MinMaxWeightGenerator minmax_generator(seed, false);
01386 AlgoTester<MinMaxArc, MinMaxWeightGenerator>
01387 minmax_tester(minmax_generator, seed);
01388 minmax_tester.Test();
01389 #endif
01390
01391 #ifdef TEST_LEFT_STRING
01392 StringWeightGenerator<int> left_string_generator(seed, false);
01393 AlgoTester<StringArc<>, StringWeightGenerator<int> >
01394 left_string_tester(left_string_generator, seed);
01395 left_string_tester.Test();
01396 #endif /// TEST_LEFT_STRING
01397
01398 #ifdef TEST_RIGHT_STRING
01399 StringWeightGenerator<int, STRING_RIGHT> right_string_generator(seed, false);
01400 AlgoTester<StringArc<STRING_RIGHT>,
01401 StringWeightGenerator<int, STRING_RIGHT> >
01402 right_string_tester(right_string_generator, seed);
01403 right_string_tester.Test();
01404 #endif /// TEST_RIGHT_STRING
01405
01406 #ifdef TEST_GALLIC
01407 typedef GallicArc<StdArc> StdGallicArc;
01408 typedef GallicWeightGenerator<int, TropicalWeightGenerator>
01409 TropicalGallicWeightGenerator;
01410
01411 TropicalGallicWeightGenerator tropical_gallic_generator(seed, false);
01412 AlgoTester<StdGallicArc, TropicalGallicWeightGenerator>
01413 gallic_tester(tropical_gallic_generator, seed);
01414 gallic_tester.Test();
01415 #endif /// TEST_GALLIC
01416
01417 #ifdef TEST_LEXICOGRAPHIC
01418 typedef LexicographicArc<TropicalWeight, TropicalWeight>
01419 TropicalLexicographicArc;
01420 typedef LexicographicWeightGenerator<TropicalWeightGenerator,
01421 TropicalWeightGenerator> TropicalLexicographicWeightGenerator;
01422 TropicalLexicographicWeightGenerator lexicographic_generator(seed, false);
01423 AlgoTester<TropicalLexicographicArc, TropicalLexicographicWeightGenerator>
01424 lexicographic_tester(lexicographic_generator, seed);
01425 lexicographic_tester.Test();
01426 #endif /// TEST_LEXICOGRAPHIC
01427
01428 #ifdef TEST_POWER
01429 typedef PowerWeight<TropicalWeight, 3> TropicalCubeWeight;
01430 typedef ArcTpl<TropicalCubeWeight> TropicalCubeArc;
01431 typedef PowerWeightGenerator<TropicalWeightGenerator, 3>
01432 TropicalCubeWeightGenerator;
01433
01434 TropicalCubeWeightGenerator tropical_cube_generator(seed, false);
01435 AlgoTester<TropicalCubeArc, TropicalCubeWeightGenerator>
01436 tropical_cube_tester(tropical_cube_generator, seed);
01437 tropical_cube_tester.Test();
01438 #endif /// TEST_POWER
01439
01440 cout << "PASS" << endl;
01441
01442 return 0;
01443 }
01444