1 // Copyright 2005-2020 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 // Function to verify an FST's contents. 19 20 #ifndef FST_VERIFY_H_ 21 #define FST_VERIFY_H_ 22 23 #include <fst/types.h> 24 #include <fst/log.h> 25 26 #include <fst/fst.h> 27 #include <fst/test-properties.h> 28 29 30 namespace fst { 31 32 // Verifies that an Fst's contents are sane. 33 template <class Arc> 34 bool Verify(const Fst<Arc> &fst, bool allow_negative_labels = false) { 35 const auto start = fst.Start(); 36 const auto *isyms = fst.InputSymbols(); 37 const auto *osyms = fst.OutputSymbols(); 38 const auto ns = CountStates(fst); 39 if (start == kNoStateId && ns > 0) { 40 LOG(ERROR) << "Verify: FST start state ID not set"; 41 return false; 42 } else if (start >= ns) { 43 LOG(ERROR) << "Verify: FST start state ID exceeds number of states"; 44 return false; 45 } 46 for (StateIterator<Fst<Arc>> siter(fst); !siter.Done(); siter.Next()) { 47 auto state = siter.Value(); 48 size_t na = 0; 49 for (ArcIterator<Fst<Arc>> aiter(fst, state); !aiter.Done(); aiter.Next()) { 50 const auto &arc = aiter.Value(); 51 if (!allow_negative_labels && arc.ilabel < 0) { 52 LOG(ERROR) << "Verify: FST input label ID of arc at position " << na 53 << " of state " << state << " is negative"; 54 return false; 55 } else if (isyms && !isyms->Member(arc.ilabel)) { 56 LOG(ERROR) << "Verify: FST input label ID " << arc.ilabel 57 << " of arc at position " << na << " of state " << state 58 << " is missing from input symbol table \"" << isyms->Name() 59 << "\""; 60 return false; 61 } else if (!allow_negative_labels && arc.olabel < 0) { 62 LOG(ERROR) << "Verify: FST output label ID of arc at position " << na 63 << " of state " << state << " is negative"; 64 return false; 65 } else if (osyms && !osyms->Member(arc.olabel)) { 66 LOG(ERROR) << "Verify: FST output label ID " << arc.olabel 67 << " of arc at position " << na << " of state " << state 68 << " is missing from output symbol table \"" << osyms->Name() 69 << "\""; 70 return false; 71 } else if (!arc.weight.Member()) { 72 LOG(ERROR) << "Verify: FST weight of arc at position " << na 73 << " of state " << state << " is invalid"; 74 return false; 75 } else if (arc.nextstate < 0) { 76 LOG(ERROR) << "Verify: FST destination state ID of arc at position " 77 << na << " of state " << state << " is negative"; 78 return false; 79 } else if (arc.nextstate >= ns) { 80 LOG(ERROR) << "Verify: FST destination state ID of arc at position " 81 << na << " of state " << state 82 << " exceeds number of states"; 83 return false; 84 } 85 ++na; 86 } 87 if (!fst.Final(state).Member()) { 88 LOG(ERROR) << "Verify: FST final weight of state " << state 89 << " is invalid"; 90 return false; 91 } 92 } 93 const auto fst_props = fst.Properties(kFstProperties, /*test=*/false); 94 if (fst_props & kError) { 95 LOG(ERROR) << "Verify: FST error property is set"; 96 return false; 97 } 98 uint64 known_props; 99 uint64 test_props = 100 internal::ComputeProperties(fst, kFstProperties, &known_props); 101 if (!internal::CompatProperties(fst_props, test_props)) { 102 LOG(ERROR) << "Verify: Stored FST properties incorrect " 103 << "(props1 = stored props, props2 = tested)"; 104 return false; 105 } else { 106 return true; 107 } 108 } 109 110 } // namespace fst 111 112 #endif // FST_VERIFY_H_ 113