FST  openfst-1.8.3
OpenFst Library
linear-fst.h
Go to the documentation of this file.
1 // Copyright 2005-2024 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 // Classes for building, storing and representing log-linear models as FSTs.
19 
20 #ifndef FST_EXTENSIONS_LINEAR_LINEAR_FST_H_
21 #define FST_EXTENSIONS_LINEAR_LINEAR_FST_H_
22 
23 #include <sys/types.h>
24 
25 #include <algorithm>
26 #include <cstddef>
27 #include <cstdint>
28 #include <functional>
29 #include <ios>
30 #include <iostream>
31 #include <istream>
32 #include <memory>
33 #include <ostream>
34 #include <string>
35 #include <utility>
36 #include <vector>
37 
38 #include <fst/compat.h>
39 #include <fst/log.h>
43 #include <fst/bi-table.h>
44 #include <fst/cache.h>
45 #include <fstream>
46 #include <fst/fst.h>
47 #include <fst/impl-to-fst.h>
48 #include <fst/matcher.h>
49 #include <fst/properties.h>
50 #include <fst/symbol-table.h>
51 #include <fst/util.h>
52 
53 namespace fst {
54 
55 // Forward declaration of the specialized matcher for both
56 // LinearTaggerFst and LinearClassifierFst.
57 template <class F>
59 
60 namespace internal {
61 
62 // Implementation class for on-the-fly generated LinearTaggerFst with
63 // special optimization in matching.
64 template <class A>
65 class LinearTaggerFstImpl : public CacheImpl<A> {
66  public:
67  using FstImpl<A>::SetType;
72 
80 
81  typedef A Arc;
82  typedef typename A::Label Label;
83  typedef typename A::Weight Weight;
84  typedef typename A::StateId StateId;
86 
87  // Constructs an empty FST by default.
89  : CacheImpl<A>(CacheOptions()),
90  data_(std::make_shared<LinearFstData<A>>()),
91  delay_(0) {
92  SetType("linear-tagger");
93  }
94 
95  // Constructs the FST with given data storage and symbol
96  // tables.
97  //
98  // TODO(wuke): when there is no constraint on output we can delay
99  // less than `data->MaxFutureSize` positions.
101  const SymbolTable *osyms, CacheOptions opts)
102  : CacheImpl<A>(opts), data_(data), delay_(data->MaxFutureSize()) {
103  SetType("linear-tagger");
105  SetInputSymbols(isyms);
106  SetOutputSymbols(osyms);
107  ReserveStubSpace();
108  }
109 
110  // Copy by sharing the underlying data storage.
112  : CacheImpl<A>(impl), data_(impl.data_), delay_(impl.delay_) {
113  SetType("linear-tagger");
117  ReserveStubSpace();
118  }
119 
120  StateId Start() {
121  if (!HasStart()) {
122  StateId start = FindStartState();
123  SetStart(start);
124  }
125  return CacheImpl<A>::Start();
126  }
127 
128  Weight Final(StateId s) {
129  if (!HasFinal(s)) {
130  state_stub_.clear();
131  FillState(s, &state_stub_);
132  if (CanBeFinal(state_stub_))
133  SetFinal(s, data_->FinalWeight(InternalBegin(state_stub_),
134  InternalEnd(state_stub_)));
135  else
136  SetFinal(s, Weight::Zero());
137  }
138  return CacheImpl<A>::Final(s);
139  }
140 
141  size_t NumArcs(StateId s) {
142  if (!HasArcs(s)) Expand(s);
143  return CacheImpl<A>::NumArcs(s);
144  }
145 
146  size_t NumInputEpsilons(StateId s) {
147  if (!HasArcs(s)) Expand(s);
149  }
150 
151  size_t NumOutputEpsilons(StateId s) {
152  if (!HasArcs(s)) Expand(s);
154  }
155 
156  void InitArcIterator(StateId s, ArcIteratorData<A> *data) {
157  if (!HasArcs(s)) Expand(s);
159  }
160 
161  // Computes the outgoing transitions from a state, creating new
162  // destination states as needed.
163  void Expand(StateId s);
164 
165  // Appends to `arcs` all out-going arcs from state `s` that matches `label` as
166  // the input label.
167  void MatchInput(StateId s, Label ilabel, std::vector<Arc> *arcs);
168 
169  static LinearTaggerFstImpl *Read(std::istream &strm,
170  const FstReadOptions &opts);
171 
172  bool Write(std::ostream &strm, const FstWriteOptions &opts) const {
173  FstHeader header;
174  header.SetStart(kNoStateId);
175  WriteHeader(strm, opts, kFileVersion, &header);
176  data_->Write(strm);
177  if (!strm) {
178  LOG(ERROR) << "LinearTaggerFst::Write: Write failed: " << opts.source;
179  return false;
180  }
181  return true;
182  }
183 
184  private:
185  static constexpr int kMinFileVersion = 1;
186  static constexpr int kFileVersion = 1;
187 
188  // A collection of functions to access parts of the state tuple. A
189  // state tuple is a vector of `Label`s with two parts:
190  // [buffer] [internal].
191  //
192  // - [buffer] is a buffer of observed input labels with length
193  // `delay_`. `LinearFstData<A>::kStartOfSentence`
194  // (resp. `LinearFstData<A>::kEndOfSentence`) are used as
195  // paddings when the buffer has fewer than `delay_` elements, which
196  // can only appear as the prefix (resp. suffix) of the buffer.
197  //
198  // - [internal] is the internal state tuple for `LinearFstData`
199  typename std::vector<Label>::const_iterator BufferBegin(
200  const std::vector<Label> &state) const {
201  return state.begin();
202  }
203 
204  typename std::vector<Label>::const_iterator BufferEnd(
205  const std::vector<Label> &state) const {
206  return state.begin() + delay_;
207  }
208 
209  typename std::vector<Label>::const_iterator InternalBegin(
210  const std::vector<Label> &state) const {
211  return state.begin() + delay_;
212  }
213 
214  typename std::vector<Label>::const_iterator InternalEnd(
215  const std::vector<Label> &state) const {
216  return state.end();
217  }
218 
219  // The size of state tuples are fixed, reserve them in stubs
220  void ReserveStubSpace() {
221  state_stub_.reserve(delay_ + data_->NumGroups());
222  next_stub_.reserve(delay_ + data_->NumGroups());
223  }
224 
225  // Computes the start state tuple and maps it to the start state id.
226  StateId FindStartState() {
227  // Empty buffer with start-of-sentence paddings
228  state_stub_.clear();
229  state_stub_.resize(delay_, LinearFstData<A>::kStartOfSentence);
230  // Append internal states
231  data_->EncodeStartState(&state_stub_);
232  return FindState(state_stub_);
233  }
234 
235  // Tests whether the buffer in `(begin, end)` is empty.
236  bool IsEmptyBuffer(typename std::vector<Label>::const_iterator begin,
237  typename std::vector<Label>::const_iterator end) const {
238  // The following is guanranteed by `ShiftBuffer()`:
239  // - buffer[i] == LinearFstData<A>::kEndOfSentence =>
240  // buffer[i+x] == LinearFstData<A>::kEndOfSentence
241  // - buffer[i] == LinearFstData<A>::kStartOfSentence =>
242  // buffer[i-x] == LinearFstData<A>::kStartOfSentence
243  return delay_ == 0 || *(end - 1) == LinearFstData<A>::kStartOfSentence ||
245  }
246 
247  // Tests whether the given state tuple can be a final state. A state
248  // is final iff there is no observed input in the buffer.
249  bool CanBeFinal(const std::vector<Label> &state) {
250  return IsEmptyBuffer(BufferBegin(state), BufferEnd(state));
251  }
252 
253  // Finds state corresponding to an n-gram. Creates new state if n-gram not
254  // found.
255  StateId FindState(const std::vector<Label> &ngram) {
256  StateId sparse = ngrams_.FindId(ngram, true);
257  StateId dense = condensed_.FindId(sparse, true);
258  return dense;
259  }
260 
261  // Appends after `output` the state tuple corresponding to the state id. The
262  // state id must exist.
263  void FillState(StateId s, std::vector<Label> *output) {
264  s = condensed_.FindEntry(s);
265  for (NGramIterator it = ngrams_.FindSet(s); !it.Done(); it.Next()) {
266  Label label = it.Element();
267  output->push_back(label);
268  }
269  }
270 
271  // Shifts the buffer in `state` by appending `ilabel` and popping
272  // the one in the front as the return value. `next_stub_` is a
273  // shifted buffer of size `delay_` where the first `delay_ - 1`
274  // elements are the last `delay_ - 1` elements in the buffer of
275  // `state`. The last (if any) element in `next_stub_` will be
276  // `ilabel` after the call returns.
277  Label ShiftBuffer(const std::vector<Label> &state, Label ilabel,
278  std::vector<Label> *next_stub_);
279 
280  // Builds an arc from state tuple `state` consuming `ilabel` and
281  // `olabel`. `next_stub_` is the buffer filled in `ShiftBuffer`.
282  Arc MakeArc(const std::vector<Label> &state, Label ilabel, Label olabel,
283  std::vector<Label> *next_stub_);
284 
285  // Expands arcs from state `s`, equivalent to state tuple `state`,
286  // with input `ilabel`. `next_stub_` is the buffer filled in
287  // `ShiftBuffer`.
288  void ExpandArcs(StateId s, const std::vector<Label> &state, Label ilabel,
289  std::vector<Label> *next_stub_);
290 
291  // Appends arcs from state `s`, equivalent to state tuple `state`,
292  // with input `ilabel` to `arcs`. `next_stub_` is the buffer filled
293  // in `ShiftBuffer`.
294  void AppendArcs(StateId s, const std::vector<Label> &state, Label ilabel,
295  std::vector<Label> *next_stub_, std::vector<Arc> *arcs);
296 
297  std::shared_ptr<const LinearFstData<A>> data_;
298  size_t delay_;
299  // Mapping from internal state tuple to *non-consecutive* IDs.
301  // Mapping from non-consecutive id to actual state ID.
303  // Two frequently used vectors, reuse to avoid repeated heap allocation.
304  std::vector<Label> state_stub_;
305  std::vector<Label> next_stub_;
306 
307  LinearTaggerFstImpl &operator=(const LinearTaggerFstImpl &) = delete;
308 };
309 
310 template <class A>
311 inline typename A::Label LinearTaggerFstImpl<A>::ShiftBuffer(
312  const std::vector<Label> &state, Label ilabel,
313  std::vector<Label> *next_stub_) {
314  DCHECK(ilabel > 0 || ilabel == LinearFstData<A>::kEndOfSentence);
315  if (delay_ == 0) {
316  DCHECK_GT(ilabel, 0);
317  return ilabel;
318  } else {
319  (*next_stub_)[BufferEnd(*next_stub_) - next_stub_->begin() - 1] = ilabel;
320  return *BufferBegin(state);
321  }
322 }
323 
324 template <class A>
325 inline A LinearTaggerFstImpl<A>::MakeArc(const std::vector<Label> &state,
326  Label ilabel, Label olabel,
327  std::vector<Label> *next_stub_) {
328  DCHECK(ilabel > 0 || ilabel == LinearFstData<A>::kEndOfSentence);
329  DCHECK(olabel > 0 || olabel == LinearFstData<A>::kStartOfSentence);
330  Weight weight(Weight::One());
331  data_->TakeTransition(BufferEnd(state), InternalBegin(state),
332  InternalEnd(state), ilabel, olabel, next_stub_,
333  &weight);
334  StateId nextstate = FindState(*next_stub_);
335  // Restore `next_stub_` to its size before the call
336  next_stub_->resize(delay_);
337  // In the actual arc, we use epsilons instead of boundaries.
338  return A(ilabel == LinearFstData<A>::kEndOfSentence ? 0 : ilabel,
339  olabel == LinearFstData<A>::kStartOfSentence ? 0 : olabel, weight,
340  nextstate);
341 }
342 
343 template <class A>
345  const std::vector<Label> &state,
346  Label ilabel,
347  std::vector<Label> *next_stub_) {
348  // Input label to constrain the output with, observed `delay_` steps
349  // back. `ilabel` is the input label to be put on the arc, which
350  // fires features.
351  Label obs_ilabel = ShiftBuffer(state, ilabel, next_stub_);
352  if (obs_ilabel == LinearFstData<A>::kStartOfSentence) {
353  // This happens when input is shorter than `delay_`.
354  PushArc(s, MakeArc(state, ilabel, LinearFstData<A>::kStartOfSentence,
355  next_stub_));
356  } else {
357  std::pair<typename std::vector<typename A::Label>::const_iterator,
358  typename std::vector<typename A::Label>::const_iterator>
359  range = data_->PossibleOutputLabels(obs_ilabel);
360  for (typename std::vector<typename A::Label>::const_iterator it =
361  range.first;
362  it != range.second; ++it)
363  PushArc(s, MakeArc(state, ilabel, *it, next_stub_));
364  }
365 }
366 
367 // TODO(wuke): this has much in duplicate with `ExpandArcs()`
368 template <class A>
370  const std::vector<Label> &state,
371  Label ilabel,
372  std::vector<Label> *next_stub_,
373  std::vector<Arc> *arcs) {
374  // Input label to constrain the output with, observed `delay_` steps
375  // back. `ilabel` is the input label to be put on the arc, which
376  // fires features.
377  Label obs_ilabel = ShiftBuffer(state, ilabel, next_stub_);
378  if (obs_ilabel == LinearFstData<A>::kStartOfSentence) {
379  // This happens when input is shorter than `delay_`.
380  arcs->push_back(
381  MakeArc(state, ilabel, LinearFstData<A>::kStartOfSentence, next_stub_));
382  } else {
383  std::pair<typename std::vector<typename A::Label>::const_iterator,
384  typename std::vector<typename A::Label>::const_iterator>
385  range = data_->PossibleOutputLabels(obs_ilabel);
386  for (typename std::vector<typename A::Label>::const_iterator it =
387  range.first;
388  it != range.second; ++it)
389  arcs->push_back(MakeArc(state, ilabel, *it, next_stub_));
390  }
391 }
392 
393 template <class A>
395  VLOG(3) << "Expand " << s;
396  state_stub_.clear();
397  FillState(s, &state_stub_);
398 
399  // Precompute the first `delay_ - 1` elements in the buffer of
400  // next states, which are identical for different input/output.
401  next_stub_.clear();
402  next_stub_.resize(delay_);
403  if (delay_ > 0)
404  std::copy(BufferBegin(state_stub_) + 1, BufferEnd(state_stub_),
405  next_stub_.begin());
406 
407  // Epsilon transition for flushing out the next observed input
408  if (!IsEmptyBuffer(BufferBegin(state_stub_), BufferEnd(state_stub_)))
409  ExpandArcs(s, state_stub_, LinearFstData<A>::kEndOfSentence, &next_stub_);
410 
411  // Non-epsilon input when we haven't flushed
412  if (delay_ == 0 ||
413  *(BufferEnd(state_stub_) - 1) != LinearFstData<A>::kEndOfSentence) {
414  for (Label ilabel = data_->MinInputLabel();
415  ilabel <= data_->MaxInputLabel(); ++ilabel) {
416  ExpandArcs(s, state_stub_, ilabel, &next_stub_);
417  }
418  }
419 
420  SetArcs(s);
421 }
422 
423 template <class A>
425  std::vector<Arc> *arcs) {
426  state_stub_.clear();
427  FillState(s, &state_stub_);
428 
429  // Precompute the first `delay_ - 1` elements in the buffer of
430  // next states, which are identical for different input/output.
431  next_stub_.clear();
432  next_stub_.resize(delay_);
433  if (delay_ > 0)
434  std::copy(BufferBegin(state_stub_) + 1, BufferEnd(state_stub_),
435  next_stub_.begin());
436 
437  if (ilabel == 0) {
438  // Epsilon transition for flushing out the next observed input
439  if (!IsEmptyBuffer(BufferBegin(state_stub_), BufferEnd(state_stub_)))
440  AppendArcs(s, state_stub_, LinearFstData<A>::kEndOfSentence, &next_stub_,
441  arcs);
442  } else {
443  // Non-epsilon input when we haven't flushed
444  if (delay_ == 0 ||
445  *(BufferEnd(state_stub_) - 1) != LinearFstData<A>::kEndOfSentence)
446  AppendArcs(s, state_stub_, ilabel, &next_stub_, arcs);
447  }
448 }
449 
450 template <class A>
452  std::istream &strm, const FstReadOptions &opts) {
453  std::unique_ptr<LinearTaggerFstImpl<A>> impl(new LinearTaggerFstImpl<A>());
454  FstHeader header;
455  if (!impl->ReadHeader(strm, opts, kMinFileVersion, &header)) {
456  return nullptr;
457  }
458  impl->data_ = std::shared_ptr<LinearFstData<A>>(LinearFstData<A>::Read(strm));
459  if (!impl->data_) {
460  return nullptr;
461  }
462  impl->delay_ = impl->data_->MaxFutureSize();
463  impl->ReserveStubSpace();
464  return impl.release();
465 }
466 
467 } // namespace internal
468 
469 // This class attaches interface to implementation and handles
470 // reference counting, delegating most methods to ImplToFst.
471 template <class A>
472 class LinearTaggerFst : public ImplToFst<internal::LinearTaggerFstImpl<A>> {
473  public:
474  friend class ArcIterator<LinearTaggerFst<A>>;
475  friend class StateIterator<LinearTaggerFst<A>>;
477 
478  typedef A Arc;
479  typedef typename A::Label Label;
480  typedef typename A::Weight Weight;
481  typedef typename A::StateId StateId;
483  typedef typename Store::State State;
485 
486  LinearTaggerFst() : ImplToFst<Impl>(std::make_shared<Impl>()) {}
487 
489  const SymbolTable *isyms = nullptr,
490  const SymbolTable *osyms = nullptr,
491  CacheOptions opts = CacheOptions())
492  : ImplToFst<Impl>(std::make_shared<Impl>(data, isyms, osyms, opts)) {}
493 
494  explicit LinearTaggerFst(const Fst<A> &fst)
495  : ImplToFst<Impl>(std::make_shared<Impl>()) {
496  LOG(FATAL) << "LinearTaggerFst: no constructor from arbitrary FST.";
497  }
498 
499  // See Fst<>::Copy() for doc.
500  LinearTaggerFst(const LinearTaggerFst<A> &fst, bool safe = false)
501  : ImplToFst<Impl>(fst, safe) {}
502 
503  // Get a copy of this LinearTaggerFst. See Fst<>::Copy() for further doc.
504  LinearTaggerFst<A> *Copy(bool safe = false) const override {
505  return new LinearTaggerFst<A>(*this, safe);
506  }
507 
508  inline void InitStateIterator(StateIteratorData<A> *data) const override;
509 
510  void InitArcIterator(StateId s, ArcIteratorData<A> *data) const override {
511  GetMutableImpl()->InitArcIterator(s, data);
512  }
513 
514  MatcherBase<A> *InitMatcher(MatchType match_type) const override {
515  return new LinearFstMatcherTpl<LinearTaggerFst<A>>(this, match_type);
516  }
517 
518  static LinearTaggerFst<A> *Read(const std::string &source) {
519  if (!source.empty()) {
520  std::ifstream strm(source,
521  std::ios_base::in | std::ios_base::binary);
522  if (!strm) {
523  LOG(ERROR) << "LinearTaggerFst::Read: Can't open file: " << source;
524  return nullptr;
525  }
526  return Read(strm, FstReadOptions(source));
527  } else {
528  return Read(std::cin, FstReadOptions("standard input"));
529  }
530  }
531 
532  static LinearTaggerFst<A> *Read(std::istream &in,
533  const FstReadOptions &opts) {
534  auto *impl = Impl::Read(in, opts);
535  return impl ? new LinearTaggerFst<A>(std::shared_ptr<Impl>(impl)) : nullptr;
536  }
537 
538  bool Write(const std::string &source) const override {
539  if (!source.empty()) {
540  std::ofstream strm(source,
541  std::ios_base::out | std::ios_base::binary);
542  if (!strm) {
543  LOG(ERROR) << "LinearTaggerFst::Write: Can't open file: " << source;
544  return false;
545  }
546  return Write(strm, FstWriteOptions(source));
547  } else {
548  return Write(std::cout, FstWriteOptions("standard output"));
549  }
550  }
551 
552  bool Write(std::ostream &strm, const FstWriteOptions &opts) const override {
553  return GetImpl()->Write(strm, opts);
554  }
555 
556  private:
559 
560  explicit LinearTaggerFst(std::shared_ptr<Impl> impl)
561  : ImplToFst<Impl>(impl) {}
562 
563  void operator=(const LinearTaggerFst<A> &fst) = delete;
564 };
565 
566 // Specialization for LinearTaggerFst.
567 template <class Arc>
569  : public CacheStateIterator<LinearTaggerFst<Arc>> {
570  public:
572  : CacheStateIterator<LinearTaggerFst<Arc>>(fst, fst.GetMutableImpl()) {}
573 };
574 
575 // Specialization for LinearTaggerFst.
576 template <class Arc>
578  : public CacheArcIterator<LinearTaggerFst<Arc>> {
579  public:
580  using StateId = typename Arc::StateId;
581 
583  : CacheArcIterator<LinearTaggerFst<Arc>>(fst.GetMutableImpl(), s) {
584  if (!fst.GetImpl()->HasArcs(s)) fst.GetMutableImpl()->Expand(s);
585  }
586 };
587 
588 template <class Arc>
590  StateIteratorData<Arc> *data) const {
591  data->base = std::make_unique<StateIterator<LinearTaggerFst<Arc>>>(*this);
592 }
593 
594 namespace internal {
595 
596 // Implementation class for on-the-fly generated LinearClassifierFst with
597 // special optimization in matching.
598 template <class A>
600  public:
601  using FstImpl<A>::SetType;
606 
614 
615  typedef A Arc;
616  typedef typename A::Label Label;
617  typedef typename A::Weight Weight;
618  typedef typename A::StateId StateId;
620 
621  // Constructs an empty FST by default.
623  : CacheImpl<A>(CacheOptions()),
624  data_(std::make_shared<LinearFstData<A>>()) {
625  SetType("linear-classifier");
626  num_classes_ = 0;
627  num_groups_ = 0;
628  }
629 
630  // Constructs the FST with given data storage, number of classes and
631  // symbol tables.
632  LinearClassifierFstImpl(const LinearFstData<Arc> *data, size_t num_classes,
633  const SymbolTable *isyms, const SymbolTable *osyms,
634  CacheOptions opts)
635  : CacheImpl<A>(opts),
636  data_(data),
637  num_classes_(num_classes),
638  num_groups_(data_->NumGroups() / num_classes_) {
639  SetType("linear-classifier");
641  SetInputSymbols(isyms);
642  SetOutputSymbols(osyms);
643  ReserveStubSpace();
644  }
645 
646  // Copy by sharing the underlying data storage.
648  : CacheImpl<A>(impl),
649  data_(impl.data_),
650  num_classes_(impl.num_classes_),
651  num_groups_(impl.num_groups_) {
652  SetType("linear-classifier");
656  ReserveStubSpace();
657  }
658 
659  StateId Start() {
660  if (!HasStart()) {
661  StateId start = FindStartState();
662  SetStart(start);
663  }
664  return CacheImpl<A>::Start();
665  }
666 
667  Weight Final(StateId s) {
668  if (!HasFinal(s)) {
669  state_stub_.clear();
670  FillState(s, &state_stub_);
671  SetFinal(s, FinalWeight(state_stub_));
672  }
673  return CacheImpl<A>::Final(s);
674  }
675 
676  size_t NumArcs(StateId s) {
677  if (!HasArcs(s)) Expand(s);
678  return CacheImpl<A>::NumArcs(s);
679  }
680 
681  size_t NumInputEpsilons(StateId s) {
682  if (!HasArcs(s)) Expand(s);
684  }
685 
686  size_t NumOutputEpsilons(StateId s) {
687  if (!HasArcs(s)) Expand(s);
689  }
690 
691  void InitArcIterator(StateId s, ArcIteratorData<A> *data) {
692  if (!HasArcs(s)) Expand(s);
694  }
695 
696  // Computes the outgoing transitions from a state, creating new
697  // destination states as needed.
698  void Expand(StateId s);
699 
700  // Appends to `arcs` all out-going arcs from state `s` that matches
701  // `label` as the input label.
702  void MatchInput(StateId s, Label ilabel, std::vector<Arc> *arcs);
703 
704  static LinearClassifierFstImpl<A> *Read(std::istream &strm,
705  const FstReadOptions &opts);
706 
707  bool Write(std::ostream &strm, const FstWriteOptions &opts) const {
708  FstHeader header;
709  header.SetStart(kNoStateId);
710  WriteHeader(strm, opts, kFileVersion, &header);
711  data_->Write(strm);
712  WriteType(strm, num_classes_);
713  if (!strm) {
714  LOG(ERROR) << "LinearClassifierFst::Write: Write failed: " << opts.source;
715  return false;
716  }
717  return true;
718  }
719 
720  private:
721  static constexpr int kMinFileVersion = 0;
722  static constexpr int kFileVersion = 0;
723 
724  // A collection of functions to access parts of the state tuple. A
725  // state tuple is a vector of `Label`s with two parts:
726  // [prediction] [internal].
727  //
728  // - [prediction] is a single label of the predicted class. A state
729  // must have a positive class label, unless it is the start state.
730  //
731  // - [internal] is the internal state tuple for `LinearFstData` of
732  // the given class; or kNoTrieNodeId's if in start state.
733  Label &Prediction(std::vector<Label> &state) { return state[0]; }
734  Label Prediction(const std::vector<Label> &state) const { return state[0]; }
735 
736  Label &InternalAt(std::vector<Label> &state, int index) {
737  return state[index + 1];
738  }
739  Label InternalAt(const std::vector<Label> &state, int index) const {
740  return state[index + 1];
741  }
742 
743  // The size of state tuples are fixed, reserve them in stubs
744  void ReserveStubSpace() {
745  size_t size = 1 + num_groups_;
746  state_stub_.reserve(size);
747  next_stub_.reserve(size);
748  }
749 
750  // Computes the start state tuple and maps it to the start state id.
751  StateId FindStartState() {
752  // A start state tuple has no prediction
753  state_stub_.clear();
754  state_stub_.push_back(kNoLabel);
755  // For a start state, we don't yet know where we are in the tries.
756  for (size_t i = 0; i < num_groups_; ++i)
757  state_stub_.push_back(kNoTrieNodeId);
758  return FindState(state_stub_);
759  }
760 
761  // Tests if the state tuple represents the start state.
762  bool IsStartState(const std::vector<Label> &state) const {
763  return state[0] == kNoLabel;
764  }
765 
766  // Computes the actual group id in the data storage.
767  int GroupId(Label pred, int group) const {
768  return group * num_classes_ + pred - 1;
769  }
770 
771  // Finds out the final weight of the given state. A state is final
772  // iff it is not the start.
773  Weight FinalWeight(const std::vector<Label> &state) const {
774  if (IsStartState(state)) {
775  return Weight::Zero();
776  }
777  Label pred = Prediction(state);
778  DCHECK_GT(pred, 0);
779  DCHECK_LE(pred, num_classes_);
780  Weight final_weight = Weight::One();
781  for (size_t group = 0; group < num_groups_; ++group) {
782  int group_id = GroupId(pred, group);
783  int trie_state = InternalAt(state, group);
784  final_weight =
785  Times(final_weight, data_->GroupFinalWeight(group_id, trie_state));
786  }
787  return final_weight;
788  }
789 
790  // Finds state corresponding to an n-gram. Creates new state if n-gram not
791  // found.
792  StateId FindState(const std::vector<Label> &ngram) {
793  StateId sparse = ngrams_.FindId(ngram, true);
794  StateId dense = condensed_.FindId(sparse, true);
795  return dense;
796  }
797 
798  // Appends after `output` the state tuple corresponding to the state id. The
799  // state id must exist.
800  void FillState(StateId s, std::vector<Label> *output) {
801  s = condensed_.FindEntry(s);
802  for (NGramIterator it = ngrams_.FindSet(s); !it.Done(); it.Next()) {
803  output->emplace_back(it.Element());
804  }
805  }
806 
807  std::shared_ptr<const LinearFstData<A>> data_;
808  // Division of groups in `data_`; num_classes_ * num_groups_ ==
809  // data_->NumGroups().
810  size_t num_classes_;
811  size_t num_groups_;
812  // Mapping from internal state tuple to *non-consecutive* IDs.
814  // Mapping from non-consecutive id to actual state ID.
816  // Two frequently used vectors, reuse to avoid repeated heap allocation.
817  std::vector<Label> state_stub_;
818  std::vector<Label> next_stub_;
819 
820  void operator=(const LinearClassifierFstImpl<A> &) = delete;
821 };
822 
823 template <class A>
825  VLOG(3) << "Expand " << s;
826  state_stub_.clear();
827  FillState(s, &state_stub_);
828  next_stub_.clear();
829  next_stub_.resize(1 + num_groups_);
830 
831  if (IsStartState(state_stub_)) {
832  // Make prediction
833  for (Label pred = 1; pred <= num_classes_; ++pred) {
834  Prediction(next_stub_) = pred;
835  for (int i = 0; i < num_groups_; ++i)
836  InternalAt(next_stub_, i) = data_->GroupStartState(GroupId(pred, i));
837  PushArc(s, A(0, pred, Weight::One(), FindState(next_stub_)));
838  }
839  } else {
840  Label pred = Prediction(state_stub_);
841  DCHECK_GT(pred, 0);
842  DCHECK_LE(pred, num_classes_);
843  for (Label ilabel = data_->MinInputLabel();
844  ilabel <= data_->MaxInputLabel(); ++ilabel) {
845  Prediction(next_stub_) = pred;
846  Weight weight = Weight::One();
847  for (int i = 0; i < num_groups_; ++i)
848  InternalAt(next_stub_, i) =
849  data_->GroupTransition(GroupId(pred, i), InternalAt(state_stub_, i),
850  ilabel, pred, &weight);
851  PushArc(s, A(ilabel, 0, weight, FindState(next_stub_)));
852  }
853  }
854 
855  SetArcs(s);
856 }
857 
858 template <class A>
859 void LinearClassifierFstImpl<A>::MatchInput(StateId s, Label ilabel,
860  std::vector<Arc> *arcs) {
861  state_stub_.clear();
862  FillState(s, &state_stub_);
863  next_stub_.clear();
864  next_stub_.resize(1 + num_groups_);
865 
866  if (IsStartState(state_stub_)) {
867  // Make prediction if `ilabel` is epsilon.
868  if (ilabel == 0) {
869  for (Label pred = 1; pred <= num_classes_; ++pred) {
870  Prediction(next_stub_) = pred;
871  for (int i = 0; i < num_groups_; ++i)
872  InternalAt(next_stub_, i) = data_->GroupStartState(GroupId(pred, i));
873  arcs->push_back(A(0, pred, Weight::One(), FindState(next_stub_)));
874  }
875  }
876  } else if (ilabel != 0) {
877  Label pred = Prediction(state_stub_);
878  Weight weight = Weight::One();
879  Prediction(next_stub_) = pred;
880  for (int i = 0; i < num_groups_; ++i)
881  InternalAt(next_stub_, i) = data_->GroupTransition(
882  GroupId(pred, i), InternalAt(state_stub_, i), ilabel, pred, &weight);
883  arcs->push_back(A(ilabel, 0, weight, FindState(next_stub_)));
884  }
885 }
886 
887 template <class A>
889  std::istream &strm, const FstReadOptions &opts) {
890  std::unique_ptr<LinearClassifierFstImpl<A>> impl(
892  FstHeader header;
893  if (!impl->ReadHeader(strm, opts, kMinFileVersion, &header)) {
894  return nullptr;
895  }
896  impl->data_ = std::shared_ptr<LinearFstData<A>>(LinearFstData<A>::Read(strm));
897  if (!impl->data_) {
898  return nullptr;
899  }
900  ReadType(strm, &impl->num_classes_);
901  if (!strm) {
902  return nullptr;
903  }
904  impl->num_groups_ = impl->data_->NumGroups() / impl->num_classes_;
905  if (impl->num_groups_ * impl->num_classes_ != impl->data_->NumGroups()) {
906  FSTERROR() << "Total number of feature groups is not a multiple of the "
907  "number of classes: num groups = "
908  << impl->data_->NumGroups()
909  << ", num classes = " << impl->num_classes_;
910  return nullptr;
911  }
912  impl->ReserveStubSpace();
913  return impl.release();
914 }
915 
916 } // namespace internal
917 
918 // This class attaches interface to implementation and handles
919 // reference counting, delegating most methods to ImplToFst.
920 template <class A>
922  : public ImplToFst<internal::LinearClassifierFstImpl<A>> {
923  public:
927 
928  typedef A Arc;
929  typedef typename A::Label Label;
930  typedef typename A::Weight Weight;
931  typedef typename A::StateId StateId;
933  typedef typename Store::State State;
935 
936  LinearClassifierFst() : ImplToFst<Impl>(std::make_shared<Impl>()) {}
937 
938  explicit LinearClassifierFst(LinearFstData<A> *data, size_t num_classes,
939  const SymbolTable *isyms = nullptr,
940  const SymbolTable *osyms = nullptr,
941  CacheOptions opts = CacheOptions())
942  : ImplToFst<Impl>(
943  std::make_shared<Impl>(data, num_classes, isyms, osyms, opts)) {}
944 
945  explicit LinearClassifierFst(const Fst<A> &fst)
946  : ImplToFst<Impl>(std::make_shared<Impl>()) {
947  LOG(FATAL) << "LinearClassifierFst: no constructor from arbitrary FST.";
948  }
949 
950  // See Fst<>::Copy() for doc.
951  LinearClassifierFst(const LinearClassifierFst<A> &fst, bool safe = false)
952  : ImplToFst<Impl>(fst, safe) {}
953 
954  // Get a copy of this LinearClassifierFst. See Fst<>::Copy() for further doc.
955  LinearClassifierFst<A> *Copy(bool safe = false) const override {
956  return new LinearClassifierFst<A>(*this, safe);
957  }
958 
959  inline void InitStateIterator(StateIteratorData<A> *data) const override;
960 
961  void InitArcIterator(StateId s, ArcIteratorData<A> *data) const override {
962  GetMutableImpl()->InitArcIterator(s, data);
963  }
964 
965  MatcherBase<A> *InitMatcher(MatchType match_type) const override {
966  return new LinearFstMatcherTpl<LinearClassifierFst<A>>(this, match_type);
967  }
968 
969  static LinearClassifierFst<A> *Read(const std::string &source) {
970  if (!source.empty()) {
971  std::ifstream strm(source,
972  std::ios_base::in | std::ios_base::binary);
973  if (!strm) {
974  LOG(ERROR) << "LinearClassifierFst::Read: Can't open file: " << source;
975  return nullptr;
976  }
977  return Read(strm, FstReadOptions(source));
978  } else {
979  return Read(std::cin, FstReadOptions("standard input"));
980  }
981  }
982 
983  static LinearClassifierFst<A> *Read(std::istream &in,
984  const FstReadOptions &opts) {
985  auto *impl = Impl::Read(in, opts);
986  return impl ? new LinearClassifierFst<A>(std::shared_ptr<Impl>(impl))
987  : nullptr;
988  }
989 
990  bool Write(const std::string &source) const override {
991  if (!source.empty()) {
992  std::ofstream strm(source,
993  std::ios_base::out | std::ios_base::binary);
994  if (!strm) {
995  LOG(ERROR) << "ProdLmFst::Write: Can't open file: " << source;
996  return false;
997  }
998  return Write(strm, FstWriteOptions(source));
999  } else {
1000  return Write(std::cout, FstWriteOptions("standard output"));
1001  }
1002  }
1003 
1004  bool Write(std::ostream &strm, const FstWriteOptions &opts) const override {
1005  return GetImpl()->Write(strm, opts);
1006  }
1007 
1008  private:
1011 
1012  explicit LinearClassifierFst(std::shared_ptr<Impl> impl)
1013  : ImplToFst<Impl>(impl) {}
1014 
1015  void operator=(const LinearClassifierFst<A> &fst) = delete;
1016 };
1017 
1018 // Specialization for LinearClassifierFst.
1019 template <class Arc>
1021  : public CacheStateIterator<LinearClassifierFst<Arc>> {
1022  public:
1025  fst.GetMutableImpl()) {}
1026 };
1027 
1028 // Specialization for LinearClassifierFst.
1029 template <class Arc>
1031  : public CacheArcIterator<LinearClassifierFst<Arc>> {
1032  public:
1033  using StateId = typename Arc::StateId;
1034 
1036  : CacheArcIterator<LinearClassifierFst<Arc>>(fst.GetMutableImpl(), s) {
1037  if (!fst.GetImpl()->HasArcs(s)) fst.GetMutableImpl()->Expand(s);
1038  }
1039 };
1040 
1041 template <class Arc>
1043  StateIteratorData<Arc> *data) const {
1044  data->base = std::make_unique<StateIterator<LinearClassifierFst<Arc>>>(*this);
1045 }
1046 
1047 // Specialized Matcher for LinearFsts. This matcher only supports
1048 // matching from the input side. This is intentional because comparing
1049 // the scores of different input sequences with the same output
1050 // sequence is meaningless in a discriminative model.
1051 template <class F>
1052 class LinearFstMatcherTpl : public MatcherBase<typename F::Arc> {
1053  public:
1054  typedef typename F::Arc Arc;
1055  typedef typename Arc::Label Label;
1056  typedef typename Arc::Weight Weight;
1057  typedef typename Arc::StateId StateId;
1058  typedef F FST;
1059 
1060  // This makes a copy of the FST.
1061  LinearFstMatcherTpl(const FST &fst, MatchType match_type)
1062  : owned_fst_(fst.Copy()),
1063  fst_(*owned_fst_),
1064  match_type_(match_type),
1065  s_(kNoStateId),
1066  current_loop_(false),
1067  loop_(kNoLabel, 0, Weight::One(), kNoStateId),
1068  cur_arc_(0),
1069  error_(false) {
1070  switch (match_type_) {
1071  case MATCH_INPUT:
1072  case MATCH_OUTPUT:
1073  case MATCH_NONE:
1074  break;
1075  default:
1076  FSTERROR() << "LinearFstMatcherTpl: Bad match type";
1077  match_type_ = MATCH_NONE;
1078  error_ = true;
1079  }
1080  }
1081 
1082  // This doesn't copy the FST.
1083  LinearFstMatcherTpl(const FST *fst, MatchType match_type)
1084  : fst_(*fst),
1085  match_type_(match_type),
1086  s_(kNoStateId),
1087  current_loop_(false),
1088  loop_(kNoLabel, 0, Weight::One(), kNoStateId),
1089  cur_arc_(0),
1090  error_(false) {
1091  switch (match_type_) {
1092  case MATCH_INPUT:
1093  case MATCH_OUTPUT:
1094  case MATCH_NONE:
1095  break;
1096  default:
1097  FSTERROR() << "LinearFstMatcherTpl: Bad match type";
1098  match_type_ = MATCH_NONE;
1099  error_ = true;
1100  }
1101  }
1102 
1103  // This makes a copy of the FST.
1104  LinearFstMatcherTpl(const LinearFstMatcherTpl<F> &matcher, bool safe = false)
1105  : owned_fst_(matcher.fst_.Copy(safe)),
1106  fst_(*owned_fst_),
1107  match_type_(matcher.match_type_),
1108  s_(kNoStateId),
1109  current_loop_(false),
1110  loop_(matcher.loop_),
1111  cur_arc_(0),
1112  error_(matcher.error_) {}
1113 
1114  LinearFstMatcherTpl<F> *Copy(bool safe = false) const override {
1115  return new LinearFstMatcherTpl<F>(*this, safe);
1116  }
1117 
1118  MatchType Type(bool /*test*/) const override {
1119  // `MATCH_INPUT` is the only valid type
1120  return match_type_ == MATCH_INPUT ? match_type_ : MATCH_NONE;
1121  }
1122 
1123  void SetState(StateId s) final {
1124  if (s_ == s) return;
1125  s_ = s;
1126  // `MATCH_INPUT` is the only valid type
1127  if (match_type_ != MATCH_INPUT) {
1128  FSTERROR() << "LinearFstMatcherTpl: Bad match type";
1129  error_ = true;
1130  }
1131  loop_.nextstate = s;
1132  }
1133 
1134  bool Find(Label label) final {
1135  if (error_) {
1136  current_loop_ = false;
1137  return false;
1138  }
1139  current_loop_ = label == 0;
1140  if (label == kNoLabel) label = 0;
1141  arcs_.clear();
1142  cur_arc_ = 0;
1143  fst_.GetMutableImpl()->MatchInput(s_, label, &arcs_);
1144  return current_loop_ || !arcs_.empty();
1145  }
1146 
1147  bool Done() const final {
1148  return !(current_loop_ || cur_arc_ < arcs_.size());
1149  }
1150 
1151  const Arc &Value() const final {
1152  return current_loop_ ? loop_ : arcs_[cur_arc_];
1153  }
1154 
1155  void Next() final {
1156  if (current_loop_)
1157  current_loop_ = false;
1158  else
1159  ++cur_arc_;
1160  }
1161 
1162  ssize_t Priority(StateId s) final { return kRequirePriority; }
1163 
1164  const FST &GetFst() const override { return fst_; }
1165 
1166  uint64_t Properties(uint64_t props) const override {
1167  if (error_) props |= kError;
1168  return props;
1169  }
1170 
1171  uint32_t Flags() const override { return kRequireMatch; }
1172 
1173  private:
1174  std::unique_ptr<const FST> owned_fst_;
1175  const FST &fst_;
1176  MatchType match_type_; // Type of match to perform.
1177  StateId s_; // Current state.
1178  bool current_loop_; // Current arc is the implicit loop.
1179  Arc loop_; // For non-consuming symbols.
1180  // All out-going arcs matching the label in last Find() call.
1181  std::vector<Arc> arcs_;
1182  size_t cur_arc_; // Index to the arc that `Value()` should return.
1183  bool error_; // Error encountered.
1184 };
1185 
1186 } // namespace fst
1187 
1188 #endif // FST_EXTENSIONS_LINEAR_LINEAR_FST_H_
void InitStateIterator(StateIteratorData< A > *data) const override
Definition: linear-fst.h:589
void InitArcIterator(StateId s, ArcIteratorData< A > *data) const override
Definition: linear-fst.h:961
LinearClassifierFst(const Fst< A > &fst)
Definition: linear-fst.h:945
Store::State State
Definition: linear-fst.h:483
constexpr ssize_t kRequirePriority
Definition: matcher.h:135
LinearTaggerFstImpl(const LinearFstData< Arc > *data, const SymbolTable *isyms, const SymbolTable *osyms, CacheOptions opts)
Definition: linear-fst.h:100
constexpr int kNoLabel
Definition: fst.h:195
I FindId(const std::vector< T > &set, bool insert=true)
Definition: collection.h:87
SetIterator FindSet(I id)
Definition: collection.h:99
bool Write(std::ostream &strm, const FstWriteOptions &opts) const
Definition: linear-fst.h:707
DefaultCacheStore< A > Store
Definition: linear-fst.h:932
DefaultCacheStore< A > Store
Definition: linear-fst.h:482
void SetFinal(StateId s, Weight weight=Weight::One())
Definition: cache.h:930
LinearFstMatcherTpl(const FST *fst, MatchType match_type)
Definition: linear-fst.h:1083
uint64_t Properties(uint64_t props) const override
Definition: linear-fst.h:1166
const SymbolTable * OutputSymbols() const
Definition: fst.h:761
MatchType
Definition: fst.h:187
ErrorWeight Times(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:64
constexpr uint64_t kError
Definition: properties.h:52
const T & FindEntry(I s) const
Definition: bi-table.h:181
bool Find(Label label) final
Definition: linear-fst.h:1134
static LinearClassifierFst< A > * Read(std::istream &in, const FstReadOptions &opts)
Definition: linear-fst.h:983
LinearClassifierFstImpl(const LinearFstData< Arc > *data, size_t num_classes, const SymbolTable *isyms, const SymbolTable *osyms, CacheOptions opts)
Definition: linear-fst.h:632
LinearFstMatcherTpl(const LinearFstMatcherTpl< F > &matcher, bool safe=false)
Definition: linear-fst.h:1104
#define LOG(type)
Definition: log.h:53
uint32_t Flags() const override
Definition: linear-fst.h:1171
void SetState(StateId s) final
Definition: linear-fst.h:1123
void MatchInput(StateId s, Label ilabel, std::vector< Arc > *arcs)
Definition: linear-fst.h:424
void InitArcIterator(StateId s, ArcIteratorData< A > *data) const override
Definition: linear-fst.h:510
void SetOutputSymbols(const SymbolTable *osyms)
Definition: fst.h:771
LinearClassifierFst(LinearFstData< A > *data, size_t num_classes, const SymbolTable *isyms=nullptr, const SymbolTable *osyms=nullptr, CacheOptions opts=CacheOptions())
Definition: linear-fst.h:938
Collection< StateId, Label >::SetIterator NGramIterator
Definition: linear-fst.h:619
#define DCHECK_GT(x, y)
Definition: log.h:77
LinearTaggerFst(LinearFstData< A > *data, const SymbolTable *isyms=nullptr, const SymbolTable *osyms=nullptr, CacheOptions opts=CacheOptions())
Definition: linear-fst.h:488
constexpr int kNoStateId
Definition: fst.h:196
MatcherBase< A > * InitMatcher(MatchType match_type) const override
Definition: linear-fst.h:965
LinearClassifierFst(const LinearClassifierFst< A > &fst, bool safe=false)
Definition: linear-fst.h:951
bool Done() const final
Definition: linear-fst.h:1147
static LinearTaggerFstImpl * Read(std::istream &strm, const FstReadOptions &opts)
Definition: linear-fst.h:451
std::ostream & WriteType(std::ostream &strm, const T t)
Definition: util.h:228
std::string source
Definition: fst.h:102
#define FSTERROR()
Definition: util.h:56
ssize_t Priority(StateId s) final
Definition: linear-fst.h:1162
static LinearClassifierFst< A > * Read(const std::string &source)
Definition: linear-fst.h:969
StateIterator(const LinearTaggerFst< Arc > &fst)
Definition: linear-fst.h:571
size_t NumOutputEpsilons(StateId s)
Definition: linear-fst.h:151
virtual uint64_t Properties() const
Definition: fst.h:701
LinearTaggerFst(const LinearTaggerFst< A > &fst, bool safe=false)
Definition: linear-fst.h:500
const FST & GetFst() const override
Definition: linear-fst.h:1164
LinearTaggerFst(const Fst< A > &fst)
Definition: linear-fst.h:494
constexpr uint64_t kCopyProperties
Definition: properties.h:163
MatchType Type(bool) const override
Definition: linear-fst.h:1118
typename FirstCacheStore< VectorCacheStore< CacheState< Arc > > >::State State
Definition: cache.h:673
bool Write(const std::string &source) const override
Definition: linear-fst.h:538
LinearClassifierFst< A > * Copy(bool safe=false) const override
Definition: linear-fst.h:955
StateIterator(const LinearClassifierFst< Arc > &fst)
Definition: linear-fst.h:1023
ArcIterator(const LinearClassifierFst< Arc > &fst, StateId s)
Definition: linear-fst.h:1035
MatcherBase< A > * InitMatcher(MatchType match_type) const override
Definition: linear-fst.h:514
#define VLOG(level)
Definition: log.h:54
constexpr int kNoTrieNodeId
Definition: trie.h:35
static LinearTaggerFst< A > * Read(const std::string &source)
Definition: linear-fst.h:518
void WriteHeader(std::ostream &strm, const FstWriteOptions &opts, int version, FstHeader *hdr) const
Definition: fst.h:785
bool Write(std::ostream &strm, const FstWriteOptions &opts) const
Definition: linear-fst.h:172
void InitArcIterator(StateId s, ArcIteratorData< A > *data)
Definition: linear-fst.h:691
ArcIterator(const LinearTaggerFst< Arc > &fst, StateId s)
Definition: linear-fst.h:582
std::unique_ptr< StateIteratorBase< Arc > > base
Definition: fst.h:382
void InitArcIterator(StateId s, ArcIteratorData< Arc > *data) const
Definition: cache.h:1049
LinearFstMatcherTpl(const FST &fst, MatchType match_type)
Definition: linear-fst.h:1061
static LinearFstData< A > * Read(std::istream &strm)
void SetInputSymbols(const SymbolTable *isyms)
Definition: fst.h:767
A::StateId StateId
Definition: linear-fst.h:481
bool Write(std::ostream &strm, const FstWriteOptions &opts) const override
Definition: linear-fst.h:1004
constexpr uint64_t kILabelSorted
Definition: properties.h:94
constexpr uint64_t kFstProperties
Definition: properties.h:326
LinearClassifierFstImpl(const LinearClassifierFstImpl &impl)
Definition: linear-fst.h:647
#define DCHECK_LE(x, y)
Definition: log.h:78
void PushArc(StateId s, const Arc &arc)
Definition: cache.h:940
const SymbolTable * InputSymbols() const
Definition: fst.h:759
void InitArcIterator(StateId s, ArcIteratorData< A > *data)
Definition: linear-fst.h:156
void SetType(std::string_view type)
Definition: fst.h:699
Collection< StateId, Label >::SetIterator NGramIterator
Definition: linear-fst.h:85
void SetStart(int64_t start)
Definition: fst.h:162
void MatchInput(StateId s, Label ilabel, std::vector< Arc > *arcs)
Definition: linear-fst.h:859
LinearTaggerFstImpl(const LinearTaggerFstImpl &impl)
Definition: linear-fst.h:111
LinearTaggerFst< A > * Copy(bool safe=false) const override
Definition: linear-fst.h:504
std::istream & ReadType(std::istream &strm, T *t)
Definition: util.h:80
size_t NumInputEpsilons(StateId s)
Definition: linear-fst.h:146
#define DCHECK(x)
Definition: log.h:74
Impl * GetMutableImpl() const
Definition: impl-to-fst.h:125
I FindId(const T &entry, bool insert=true)
Definition: bi-table.h:165
LinearFstMatcherTpl< F > * Copy(bool safe=false) const override
Definition: linear-fst.h:1114
static LinearClassifierFstImpl< A > * Read(std::istream &strm, const FstReadOptions &opts)
Definition: linear-fst.h:888
void InitStateIterator(StateIteratorData< A > *data) const override
Definition: linear-fst.h:1042
const Arc & Value() const final
Definition: linear-fst.h:1151
bool Write(const std::string &source) const override
Definition: linear-fst.h:990
static LinearTaggerFst< A > * Read(std::istream &in, const FstReadOptions &opts)
Definition: linear-fst.h:532
const Impl * GetImpl() const
Definition: impl-to-fst.h:123
constexpr uint32_t kRequireMatch
Definition: matcher.h:129
bool Write(std::ostream &strm, const FstWriteOptions &opts) const override
Definition: linear-fst.h:552