22 #ifndef FST_EXTENSIONS_NGRAM_NGRAM_FST_H_ 23 #define FST_EXTENSIONS_NGRAM_NGRAM_FST_H_ 25 #include <sys/types.h> 65 typedef typename A::Label
Label;
106 SetInputSymbols(
nullptr);
107 SetOutputSymbols(
nullptr);
108 SetProperties(kStaticProperties);
116 FSTERROR() <<
"Copying NGramFst Impls is not supported, use safe = false.";
121 auto impl = std::make_unique<NGramFstImpl<A>>();
123 if (!impl->ReadHeader(strm, opts, kMinFileVersion, &hdr))
return nullptr;
124 uint64_t num_states, num_futures, num_final;
125 const size_t offset =
126 sizeof(num_states) +
sizeof(num_futures) +
sizeof(num_final);
128 strm.read(reinterpret_cast<char *>(&num_states),
sizeof(num_states));
129 strm.read(reinterpret_cast<char *>(&num_futures),
sizeof(num_futures));
130 strm.read(reinterpret_cast<char *>(&num_final),
sizeof(num_final));
131 size_t size = Storage(num_states, num_futures, num_final);
133 char *data =
static_cast<char *
>(data_region->mutable_data());
135 memcpy(data, reinterpret_cast<char *>(&num_states),
sizeof(num_states));
136 memcpy(data +
sizeof(num_states), reinterpret_cast<char *>(&num_futures),
137 sizeof(num_futures));
138 memcpy(data +
sizeof(num_states) +
sizeof(num_futures),
139 reinterpret_cast<char *>(&num_final),
sizeof(num_final));
140 strm.read(data + offset, size - offset);
141 if (strm.fail())
return nullptr;
142 impl->Init(data, std::move(data_region));
143 return impl.release();
150 WriteHeader(strm, opts, kFileVersion, &hdr);
151 strm.write(data_, StorageSize());
155 StateId
Start()
const {
return start_; }
158 if (final_index_.Get(state)) {
159 return final_probs_[final_index_.Rank1(state)];
161 return Weight::Zero();
166 if (inst ==
nullptr) {
167 const std::pair<size_t, size_t> zeros =
168 (state == 0) ? select_root_ : future_index_.Select0s(state);
169 return zeros.second - zeros.first - 1;
171 SetInstFuture(state, inst);
172 return inst->num_futures_ + ((state == 0) ? 0 : 1);
177 if (state == 0)
return 0;
188 data->
base =
nullptr;
192 static size_t Storage(uint64_t num_states, uint64_t num_futures,
193 uint64_t num_final) {
198 sizeof(num_states) +
sizeof(num_futures) +
sizeof(num_final);
203 offset += (num_states + 1) *
sizeof(label) + num_futures *
sizeof(label);
206 offset = (offset +
sizeof(weight) - 1) & ~(
sizeof(weight) - 1);
207 offset += (num_states + 1) *
sizeof(weight) + num_final *
sizeof(weight) +
208 (num_futures + 1) *
sizeof(weight);
213 if (inst->
state_ != state) {
215 const std::pair<size_t, size_t> zeros = future_index_.Select0s(state);
217 inst->
offset_ = future_index_.Rank1(zeros.first + 1);
224 inst->
node_ = context_index_.Select1(inst->
state_);
233 size_t node = inst->
node_;
235 const size_t rank1 = context_index_.Rank1(node);
236 const size_t rank0 = node - rank1;
237 inst->
context_.push_back(context_words_[rank1]);
238 node = context_index_.Select1(rank0 - 1);
244 const char *
GetData(
size_t *data_size)
const {
245 *data_size = StorageSize();
249 void Init(
const char *data,
250 std::unique_ptr<MappedFile> data_region);
253 SetInstFuture(s, inst);
254 SetInstContext(inst);
262 void GetStates(
const std::vector<Label> &context,
263 std::vector<StateId> *states)
const;
266 StateId Transition(
const std::vector<Label> &context, Label future)
const;
269 static constexpr uint64_t kStaticProperties =
275 static constexpr
int kFileVersion = 4;
277 static constexpr
int kMinFileVersion = 4;
279 std::unique_ptr<MappedFile> data_region_;
280 const char *data_ =
nullptr;
282 uint64_t num_states_ = 0;
284 uint64_t num_final_ = 0;
285 std::pair<size_t, size_t> select_root_;
286 const Label *root_children_ =
nullptr;
289 const uint64_t *future_ =
nullptr;
290 const uint64_t *final_ =
nullptr;
291 const Label *context_words_ =
nullptr;
292 const Label *future_words_ =
nullptr;
293 const Weight *backoff_ =
nullptr;
294 const Weight *final_probs_ =
nullptr;
295 const Weight *future_probs_ =
nullptr;
305 template <
typename A>
307 const std::vector<Label> &context,
308 std::vector<typename A::StateId> *states)
const {
310 states->push_back(0);
311 typename std::vector<Label>::const_reverse_iterator cit = context.rbegin();
312 const Label *children = root_children_;
313 size_t num_children = select_root_.second - 2;
314 const Label *loc = std::lower_bound(children, children + num_children, *cit);
315 if (loc == children + num_children || *loc != *cit)
return;
316 size_t node = 2 + loc - children;
317 size_t node_rank = context_index_.Rank1(node);
318 states->push_back(node_rank);
319 if (context.size() == 1)
return;
320 std::pair<size_t, size_t> zeros =
321 node_rank == 0 ? select_root_ : context_index_.Select0s(node_rank);
322 size_t first_child = zeros.first + 1;
324 if (context_index_.Get(first_child) !=
false) {
325 size_t last_child = zeros.second - 1;
326 while (cit != context.rend()) {
327 children = context_words_ + context_index_.Rank1(first_child);
328 loc = std::lower_bound(children, children + last_child - first_child + 1,
330 if (loc == children + last_child - first_child + 1 || *loc != *cit) {
334 node = first_child + loc - children;
335 node_rank = context_index_.Rank1(node);
336 states->push_back(node_rank);
338 node_rank == 0 ? select_root_ : context_index_.Select0s(node_rank);
339 first_child = zeros.first + 1;
340 if (context_index_.Get(first_child) ==
false)
break;
341 last_child = zeros.second - 1;
363 :
Base(std::make_shared<
Impl>(dst, nullptr)) {}
366 :
Base(std::make_shared<
Impl>(fst, order_out)) {}
377 GetMutableImpl()->Init(data,
nullptr);
381 const char *
GetData(
size_t *data_size)
const {
382 return GetImpl()->GetData(data_size);
386 return GetImpl()->GetContext(s, &inst_);
392 std::vector<StateId> *state)
const {
393 return GetImpl()->GetStates(context, state);
397 return GetImpl()->NumArcs(s, &inst_);
405 Impl *impl = Impl::Read(strm, opts);
406 return impl ?
new NGramFst<A>(std::shared_ptr<Impl>(impl)) :
nullptr;
410 if (!source.empty()) {
411 std::ifstream strm(source,
412 std::ios_base::in | std::ios_base::binary);
414 LOG(ERROR) <<
"NGramFst::Read: Can't open file: " << source;
424 return GetImpl()->Write(strm, opts);
427 bool Write(
const std::string &source)
const override {
432 GetImpl()->InitStateIterator(data);
435 inline void InitArcIterator(StateId s,
445 static const auto props =
451 if (!HasRequiredProps(fst)) {
454 typename A::StateId unigram = fst.
Start();
458 if (aiter.
Done() || aiter.
Value().ilabel != 0)
break;
459 unigram = aiter.
Value().nextstate;
465 const typename A::StateId &state = siter.Value();
467 if (state != unigram) {
468 if (aiter.
Done())
return false;
469 if (aiter.
Value().ilabel != 0)
return false;
471 if (!aiter.
Done() && aiter.
Value().ilabel == 0)
return false;
479 using Base::GetMutableImpl;
481 explicit NGramFst(std::shared_ptr<Impl> impl) :
Base(impl) {}
489 GetImpl()->SetInstFuture(s, &inst_);
490 GetImpl()->SetInstNode(&inst_);
491 data->
base = std::make_unique<ArcIterator<NGramFst<A>>>(*
this, s);
496 template <
typename A>
498 std::vector<StateId> *order_out) {
500 typedef typename Arc::Label
Label;
501 typedef typename Arc::Weight
Weight;
502 typedef typename Arc::StateId
StateId;
506 SetProperties(kStaticProperties);
510 FSTERROR() <<
"NGramFst only accepts OpenGrm language models as input";
516 std::vector<Label> context(num_states, 0);
520 StateId unigram = fst.
Start();
523 FSTERROR() <<
"Could not identify unigram state";
529 LOG(WARNING) <<
"Unigram state " << unigram <<
" has no arcs.";
532 if (aiter.
Value().ilabel != 0)
break;
533 unigram = aiter.
Value().nextstate;
538 std::queue<std::pair<StateId, Label>> label_queue;
539 std::vector<bool> visited(num_states);
541 label_queue.push(std::make_pair(fst.
Start(), 0));
544 std::make_pair(aiter.Value().nextstate, aiter.Value().ilabel));
547 while (!label_queue.empty()) {
548 std::pair<StateId, Label> &now = label_queue.front();
549 if (!visited[now.first]) {
550 context[now.first] = now.second;
551 visited[now.first] =
true;
554 const Arc &arc = aiter.Value();
555 if (arc.ilabel != 0) {
556 label_queue.push(std::make_pair(arc.nextstate, now.second));
567 context[fst.
Start()] = 0;
571 uint64_t num_final = 0;
572 for (
int i = 0; i < num_states; ++i) {
573 if (fst.
Final(i) != Weight::Zero()) {
581 int64_t num_context_arcs = 0;
582 int64_t num_futures = 0;
584 const StateId &state = siter.Value();
588 const Arc &arc = aiter.
Value();
591 if (arc.ilabel == 0) {
592 context_fst.
AddArc(arc.nextstate, Arc(context[state], context[state],
598 if (num_context_arcs != context_fst.
NumStates() - 1) {
599 FSTERROR() <<
"Number of contexts arcs != number of states - 1";
603 if (context_fst.
NumStates() != num_states) {
604 FSTERROR() <<
"Number of contexts != number of states";
608 int64_t context_props =
611 FSTERROR() <<
"Input Fst is not structured properly";
622 const size_t storage = Storage(num_states, num_futures, num_final);
624 char *data =
static_cast<char *
>(data_region->mutable_data());
625 memset(data, 0, storage);
627 memcpy(data + offset, reinterpret_cast<char *>(&num_states),
629 offset +=
sizeof(num_states);
630 memcpy(data + offset, reinterpret_cast<char *>(&num_futures),
631 sizeof(num_futures));
632 offset +=
sizeof(num_futures);
633 memcpy(data + offset, reinterpret_cast<char *>(&num_final),
635 offset +=
sizeof(num_final);
636 uint64_t *context_bits =
reinterpret_cast<uint64_t *
>(data + offset);
638 uint64_t *future_bits =
reinterpret_cast<uint64_t *
>(data + offset);
641 uint64_t *final_bits =
reinterpret_cast<uint64_t *
>(data + offset);
643 Label *context_words =
reinterpret_cast<Label *
>(data + offset);
644 offset += (num_states + 1) *
sizeof(label);
645 Label *future_words =
reinterpret_cast<Label *
>(data + offset);
646 offset += num_futures *
sizeof(label);
647 offset = (offset +
sizeof(weight) - 1) & ~(
sizeof(weight) - 1);
648 Weight *backoff =
reinterpret_cast<Weight *
>(data + offset);
649 offset += (num_states + 1) *
sizeof(weight);
650 Weight *final_probs =
reinterpret_cast<Weight *
>(data + offset);
651 offset += num_final *
sizeof(weight);
652 Weight *future_probs =
reinterpret_cast<Weight *
>(data + offset);
653 int64_t context_arc = 0, future_arc = 0, context_bit = 0, future_bit = 0,
659 context_words[context_arc] = label;
660 backoff[context_arc] = Weight::Zero();
666 order_out->resize(num_states);
669 std::queue<StateId> context_q;
670 context_q.push(context_fst.
Start());
671 StateId state_number = 0;
672 while (!context_q.empty()) {
673 const StateId &state = context_q.front();
675 (*order_out)[state] = state_number;
678 const Weight final_weight = context_fst.
Final(state);
679 if (final_weight != Weight::Zero()) {
681 final_probs[final_bit] = final_weight;
687 const Arc &arc = aiter.Value();
688 context_words[context_arc] = arc.ilabel;
689 backoff[context_arc] = arc.weight;
692 context_q.push(arc.nextstate);
697 const Arc &arc = aiter.Value();
698 if (arc.ilabel != 0) {
699 future_words[future_arc] = arc.ilabel;
700 future_probs[future_arc] = arc.weight;
710 if ((state_number != num_states) || (context_bit != num_states * 2 + 1) ||
711 (context_arc != num_states) || (future_arc != num_futures) ||
712 (future_bit != num_futures + num_states + 1) ||
713 (final_bit != num_final)) {
714 FSTERROR() <<
"Structure problems detected during construction";
719 Init(data, std::move(data_region));
722 template <
typename A>
724 std::unique_ptr<MappedFile> data_region) {
725 data_region_ = std::move(data_region);
728 num_states_ = *(
reinterpret_cast<const uint64_t *
>(data_ + offset));
729 offset +=
sizeof(num_states_);
730 num_futures_ = *(
reinterpret_cast<const uint64_t *
>(data_ + offset));
732 num_final_ = *(
reinterpret_cast<const uint64_t *
>(data_ + offset));
733 offset +=
sizeof(num_final_);
735 size_t context_bits = num_states_ * 2 + 1;
737 context_ =
reinterpret_cast<const uint64_t *
>(data_ + offset);
739 future_ =
reinterpret_cast<const uint64_t *
>(data_ + offset);
741 final_ =
reinterpret_cast<const uint64_t *
>(data_ + offset);
743 context_words_ =
reinterpret_cast<const Label *
>(data_ + offset);
744 offset += (num_states_ + 1) *
sizeof(*context_words_);
745 future_words_ =
reinterpret_cast<const Label *
>(data_ + offset);
747 offset = (offset +
sizeof(*backoff_) - 1) & ~(
sizeof(*backoff_) - 1);
748 backoff_ =
reinterpret_cast<const Weight *
>(data_ + offset);
749 offset += (num_states_ + 1) *
sizeof(*backoff_);
750 final_probs_ =
reinterpret_cast<const Weight *
>(data_ + offset);
751 offset += num_final_ *
sizeof(*final_probs_);
752 future_probs_ =
reinterpret_cast<const Weight *
>(data_ + offset);
754 context_index_.BuildIndex(
context_, context_bits,
757 future_index_.BuildIndex(future_, future_bits,
760 final_index_.BuildIndex(final_, num_states_);
762 select_root_ = context_index_.Select0s(0);
763 if (context_index_.Rank1(0) != 0 || select_root_.first != 1 ||
764 context_index_.Get(2) ==
false) {
769 root_children_ = context_words_ + context_index_.Rank1(2);
773 template <
typename A>
775 const std::vector<Label> &context,
Label future)
const {
776 const Label *children = root_children_;
777 size_t num_children = select_root_.second - 2;
779 std::lower_bound(children, children + num_children, future);
780 if (loc == children + num_children || *loc != future) {
781 return context_index_.Rank1(0);
783 size_t node = 2 + loc - children;
784 size_t node_rank = context_index_.Rank1(node);
785 std::pair<size_t, size_t> zeros =
786 (node_rank == 0) ? select_root_ : context_index_.Select0s(node_rank);
787 size_t first_child = zeros.first + 1;
788 if (context_index_.Get(first_child) ==
false) {
791 size_t last_child = zeros.second - 1;
792 for (
int word = context.size() - 1; word >= 0; --word) {
793 children = context_words_ + context_index_.Rank1(first_child);
794 loc = std::lower_bound(children, children + last_child - first_child + 1,
796 if (loc == children + last_child - first_child + 1 ||
797 *loc != context[word]) {
800 node = first_child + loc - children;
801 node_rank = context_index_.Rank1(node);
803 (node_rank == 0) ? select_root_ : context_index_.Select0s(node_rank);
804 first_child = zeros.first + 1;
805 if (context_index_.Get(first_child) ==
false)
break;
806 last_child = zeros.second - 1;
824 : owned_fst_(fst.Copy()),
827 match_type_(match_type),
828 current_loop_(false),
831 std::swap(loop_.ilabel, loop_.olabel);
839 match_type_(match_type),
840 current_loop_(false),
843 std::swap(loop_.ilabel, loop_.olabel);
849 : owned_fst_(matcher.fst_.Copy(safe)),
851 inst_(matcher.inst_),
852 match_type_(matcher.match_type_),
853 current_loop_(false),
856 std::swap(loop_.ilabel, loop_.olabel);
868 uint64_t
Properties(uint64_t props)
const override {
return props; }
871 fst_.GetImpl()->SetInstFuture(s, &inst_);
872 current_loop_ =
false;
878 if (label == 0 || label == nolabel) {
880 current_loop_ =
true;
881 loop_.nextstate = inst_.state_;
884 if (inst_.state_ != 0) {
885 arc_.ilabel = arc_.olabel = 0;
886 fst_.GetImpl()->SetInstNode(&inst_);
887 arc_.nextstate = fst_.GetImpl()->context_index_.Rank1(
888 fst_.GetImpl()->context_index_.Select1(
889 fst_.GetImpl()->context_index_.Rank0(inst_.node_) - 1));
890 arc_.weight = fst_.GetImpl()->backoff_[inst_.state_];
894 current_loop_ =
false;
895 const Label *start = fst_.GetImpl()->future_words_ + inst_.offset_;
896 const Label *end = start + inst_.num_futures_;
897 const Label *search = std::lower_bound(start, end, label);
898 if (search != end && *search == label) {
899 size_t state = search - start;
900 arc_.ilabel = arc_.olabel = label;
901 arc_.weight = fst_.GetImpl()->future_probs_[inst_.offset_ + state];
902 fst_.GetImpl()->SetInstContext(&inst_);
903 arc_.nextstate = fst_.GetImpl()->Transition(inst_.context_, label);
910 bool Done() const final {
return !current_loop_ && done_; }
912 const Arc &
Value() const final {
return (current_loop_) ? loop_ : arc_; }
916 current_loop_ =
false;
922 ssize_t
Priority(StateId s)
final {
return fst_.NumArcs(s); }
925 std::unique_ptr<NGramFst<A>> owned_fst_;
945 : s_(0), num_states_(fst.NumStates()) {}
947 bool Done() const final {
return s_ >= num_states_; }
973 : lazy_(~0), impl_(fst.GetImpl()), i_(0), flags_(
kArcValueFlags) {
975 impl_->SetInstFuture(state, &inst_);
976 impl_->SetInstNode(&inst_);
981 ((inst_.node_ == 0) ? inst_.num_futures_ : inst_.num_futures_ + 1);
986 bool eps = (inst_.node_ != 0 && i_ == 0);
987 StateId state = (inst_.node_ == 0) ? i_ : i_ - 1;
989 arc_.ilabel = arc_.olabel =
990 eps ? 0 : impl_->future_words_[inst_.offset_ + state];
996 impl_->context_index_.Rank1(impl_->context_index_.Select1(
997 impl_->context_index_.Rank0(inst_.node_) - 1));
999 if (lazy_ & kArcNextStateValue) {
1000 impl_->SetInstContext(&inst_);
1002 arc_.nextstate = impl_->Transition(
1003 inst_.context_, impl_->future_words_[inst_.offset_ + state]);
1005 lazy_ &= ~kArcNextStateValue;
1008 arc_.weight = eps ? impl_->backoff_[inst_.state_]
1009 : impl_->future_probs_[inst_.offset_ + state];
1010 lazy_ &= ~kArcWeightValue;
1034 uint8_t
Flags() const final {
return flags_; }
1043 mutable uint8_t lazy_;
1052 #endif // FST_EXTENSIONS_NGRAM_NGRAM_FST_H_
constexpr uint64_t kCyclic
void GetStates(const std::vector< Label > &context, std::vector< StateId > *state) const
constexpr uint64_t kNotString
NGramFst< A > * Copy(bool safe=false) const override
constexpr uint8_t kArcValueFlags
size_t NumInputEpsilons(StateId state) const
virtual uint64_t Properties(uint64_t mask, bool test) const =0
constexpr uint64_t kOEpsilons
const Arc & Value() const final
virtual size_t NumArcs(StateId) const =0
static size_t Storage(uint64_t num_states, uint64_t num_futures, uint64_t num_final)
constexpr uint64_t kCoAccessible
void SetInputSymbols(const SymbolTable *isyms) override
void SetInstContext(NGramFstInst< A > *inst) const
uint8_t Flags() const final
static void Set(uint64_t *bits, size_t index)
constexpr uint64_t kNotTopSorted
size_t Position() const final
constexpr uint64_t kError
size_t StorageSize() const
StateId Start() const override
constexpr uint64_t kInitialAcyclic
static NGramFstImpl< A > * Read(std::istream &strm, const FstReadOptions &opts)
virtual Weight Final(StateId) const =0
uint64_t Properties(uint64_t props) const override
constexpr uint8_t kArcILabelValue
constexpr uint64_t kEpsilons
Weight Final(StateId s) const override
constexpr uint64_t kODeterministic
const Arc & Value() const final
NGramFstMatcher< A > * Copy(bool safe=false) const override
const Arc & Value() const
uint64_t Properties(uint64_t mask, bool test) const override
NGramFstMatcher(const NGramFstMatcher< A > &matcher, bool safe=false)
static MappedFile * Allocate(size_t size, size_t align=kArchAlignment)
void InitArcIterator(StateId s, ArcIteratorData< A > *data) const override
NGramFst(const Fst< A > &fst, std::vector< StateId > *order_out)
const Fst< A > & GetFst() const override
virtual size_t NumInputEpsilons(StateId) const =0
NGramFst(const Fst< A > &dst)
size_t NumArcs(StateId state, NGramFstInst< A > *inst=nullptr) const
const std::vector< Label > & GetContext(StateId s, NGramFstInst< A > *inst) const
static size_t StorageSize(size_t num_bits)
NGramFst(const NGramFst< A > &fst, bool safe=false)
ssize_t NumInputEpsilons(const ExpandedFst< Arc > &fst, typename Arc::StateId s)
const char * GetData(size_t *data_size) const
void ArcSort(MutableFst< Arc > *fst, Compare comp)
constexpr uint64_t kOLabelSorted
void SetInstNode(NGramFstInst< A > *inst) const
void SetFlags(uint8_t flags, uint8_t mask) final
static NGramFst< A > * Read(std::istream &strm, const FstReadOptions &opts)
std::vector< Label > context_
MatcherBase< A > * InitMatcher(MatchType match_type) const override
bool Write(const std::string &source) const override
StateId NumStates() const override
StateId Value() const final
NGramFstMatcher(const NGramFst< A > &fst, MatchType match_type)
constexpr uint64_t kAccessible
constexpr uint8_t kArcOLabelValue
const char * GetData(size_t *data_size) const
MatchType Type(bool test) const override
size_t NumArcs(StateId s) const override
void SetInstFuture(StateId state, NGramFstInst< A > *inst) const
virtual StateId Start() const =0
std::unique_ptr< StateIteratorBase< Arc > > base
constexpr uint64_t kIDeterministic
void SetState(StateId s) final
NGramFstImpl(const Fst< A > &fst)
std::unique_ptr< ArcIteratorBase< Arc > > base
const std::vector< Label > GetContext(StateId s) const
constexpr uint64_t kIEpsilons
void Seek(size_t a) final
StateId AddState() override
void AddArc(StateId s, const Arc &arc) override
void SetOutputSymbols(const SymbolTable *osyms) override
bool WriteFile(const std::string &source) const
StateId NumStates() const
constexpr uint8_t kArcWeightValue
size_t StorageSize() const
constexpr uint64_t kILabelSorted
void SetFinal(StateId s, Weight weight=Weight::One()) override
bool Write(std::ostream &strm, const FstWriteOptions &opts) const override
virtual const SymbolTable * InputSymbols() const =0
Arc::StateId CountStates(const Fst< Arc > &fst)
constexpr uint8_t kArcNextStateValue
ssize_t Priority(StateId s) final
ArcIterator(const NGramFst< A > &fst, StateId state)
size_t NumOutputEpsilons(StateId state) const
NGramFstImpl(const NGramFstImpl &other)
NGramFstMatcher(const NGramFst< A > *fst, MatchType match_type)
NGramFst(const char *data)
void InitStateIterator(StateIteratorData< A > *data) const override
Weight Final(StateId state) const
void InitStateIterator(StateIteratorData< A > *data) const
bool Write(std::ostream &strm, const FstWriteOptions &opts) const
constexpr uint64_t kWeighted
bool Find(Label label) final
constexpr uint64_t kExpanded
static bool HasRequiredStructure(const Fst< A > &fst)
StateIterator(const NGramFst< A > &fst)
static NGramFst< A > * Read(const std::string &source)
static bool HasRequiredProps(const Fst< A > &fst)
void SetStart(StateId s) override
constexpr uint64_t kAcceptor
virtual const SymbolTable * OutputSymbols() const =0