You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

612 lines
23 KiB

  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. // Class to determine if a non-epsilon label can be read as the first
  19. // non-epsilon symbol along some path from a given state.
  20. #ifndef FST_LABEL_REACHABLE_H_
  21. #define FST_LABEL_REACHABLE_H_
  22. #include <sys/types.h>
  23. #include <cstddef>
  24. #include <istream>
  25. #include <memory>
  26. #include <ostream>
  27. #include <utility>
  28. #include <vector>
  29. #include <fst/log.h>
  30. #include <fst/accumulator.h>
  31. #include <fst/arcsort.h>
  32. #include <fst/fst.h>
  33. #include <fst/interval-set.h>
  34. #include <fst/mutable-fst.h>
  35. #include <fst/properties.h>
  36. #include <fst/state-reachable.h>
  37. #include <fst/util.h>
  38. #include <fst/vector-fst.h>
  39. #include <unordered_map>
  40. namespace fst {
  41. // Stores shareable data for label reachable class copies.
  42. template <typename Label>
  43. class LabelReachableData {
  44. public:
  45. using LabelIntervalSet = IntervalSet<Label>;
  46. using Interval = typename LabelIntervalSet::Interval;
  47. explicit LabelReachableData(bool reach_input, bool keep_relabel_data = true)
  48. : reach_input_(reach_input),
  49. keep_relabel_data_(keep_relabel_data),
  50. have_relabel_data_(true),
  51. final_label_(kNoLabel) {}
  52. ~LabelReachableData() = default;
  53. bool ReachInput() const { return reach_input_; }
  54. std::vector<LabelIntervalSet> *MutableIntervalSets() {
  55. return &interval_sets_;
  56. }
  57. const LabelIntervalSet &GetIntervalSet(int s) const {
  58. return interval_sets_[s];
  59. }
  60. int NumIntervalSets() const { return interval_sets_.size(); }
  61. std::unordered_map<Label, Label> *MutableLabel2Index() {
  62. if (!have_relabel_data_) {
  63. FSTERROR() << "LabelReachableData: No relabeling data";
  64. }
  65. return &label2index_;
  66. }
  67. const std::unordered_map<Label, Label> *Label2Index() const {
  68. if (!have_relabel_data_) {
  69. FSTERROR() << "LabelReachableData: No relabeling data";
  70. }
  71. return &label2index_;
  72. }
  73. void SetFinalLabel(Label final_label) { final_label_ = final_label; }
  74. Label FinalLabel() const { return final_label_; }
  75. static LabelReachableData *Read(std::istream &istrm,
  76. const FstReadOptions &opts) {
  77. // NB: Using `new` to access private constructor.
  78. auto data = fst::WrapUnique(new LabelReachableData());
  79. ReadType(istrm, &data->reach_input_);
  80. ReadType(istrm, &data->keep_relabel_data_);
  81. data->have_relabel_data_ = data->keep_relabel_data_;
  82. if (data->keep_relabel_data_) ReadType(istrm, &data->label2index_);
  83. ReadType(istrm, &data->final_label_);
  84. ReadType(istrm, &data->interval_sets_);
  85. return data.release();
  86. }
  87. bool Write(std::ostream &ostrm, const FstWriteOptions &opts) const {
  88. WriteType(ostrm, reach_input_);
  89. WriteType(ostrm, keep_relabel_data_);
  90. if (keep_relabel_data_) WriteType(ostrm, label2index_);
  91. WriteType(ostrm, FinalLabel());
  92. WriteType(ostrm, interval_sets_);
  93. return true;
  94. }
  95. private:
  96. LabelReachableData() = default;
  97. bool reach_input_; // Input labels considered?
  98. bool keep_relabel_data_; // Save label2index_ to file?
  99. bool have_relabel_data_; // Using label2index_?
  100. Label final_label_; // Final label.
  101. std::unordered_map<Label, Label> label2index_; // Finds index for a label.
  102. std::vector<LabelIntervalSet> interval_sets_; // Interval sets per state.
  103. };
  104. // Apply a new state order to a vector of LabelIntervalSets. order[i] gives
  105. // the StateId after sorting that corresponds to the StateId i before
  106. // sorting; it must therefore be a permutation of the input FST's StateId
  107. // sequence.
  108. template <typename Label, typename StateId>
  109. bool StateSort(std::vector<IntervalSet<Label>> *interval_sets,
  110. const std::vector<StateId> &order) {
  111. if (order.size() != interval_sets->size()) {
  112. FSTERROR() << "StateSort: Bad order vector size: " << order.size()
  113. << ", expected: " << interval_sets->size();
  114. return false;
  115. }
  116. std::vector<IntervalSet<Label>> reordered_interval_sets(
  117. interval_sets->size());
  118. // TODO(jrosenstock): Use storage-efficient cycle-following algorithm
  119. // from StateSort(MutableFst *, order).
  120. for (StateId s = 0; s < order.size(); ++s) {
  121. reordered_interval_sets[order[s]] = std::move((*interval_sets)[s]);
  122. }
  123. *interval_sets = std::move(reordered_interval_sets);
  124. return true;
  125. }
  126. // Apply a new state order to LabelReachableData.
  127. template <typename Label, typename StateId>
  128. bool StateSort(LabelReachableData<Label> *data,
  129. const std::vector<StateId> &order) {
  130. return StateSort(data->MutableIntervalSets(), order);
  131. }
  132. // Functor to find the LowerBound of a Label using an ArcIterator.
  133. // Used by LabelReachable. Other, more efficient implementations of
  134. // this interface specialized to certain FST types may be used instead.
  135. template <class Arc>
  136. class LabelLowerBound {
  137. public:
  138. using Label = typename Arc::Label;
  139. using StateId = typename Arc::StateId;
  140. // Initializes with the FST that will later supply the ArcIterator for
  141. // `operator()`. `reach_input` specified whether `operator()` will search
  142. // input or output labels. If `is_copy == true`, then `fst` is a copy
  143. // of the one previously passed to `Init`, so any expensive initialization
  144. // can be skipped.
  145. template <class FST>
  146. void Init(const FST &fst, bool reach_input, bool is_copy) {
  147. reach_input_ = reach_input;
  148. }
  149. // Sets state that will be searched by `operator()`.
  150. void SetState(StateId aiter_s) {}
  151. // Positions `aiter` at the first Arc with `label >= match_label` in the
  152. // half-open interval `[aiter_begin, aiter_end)`. Returns the position
  153. // of `aiter`. `aiter` must be an iterator of the FST that was passed to
  154. // `Init`.
  155. template <class ArcIterator>
  156. ssize_t operator()(ArcIterator *aiter, ssize_t aiter_begin, ssize_t aiter_end,
  157. Label match_label) const {
  158. // Only needs to compute the ilabel or olabel of arcs when performing the
  159. // binary search.
  160. aiter->SetFlags(reach_input_ ? kArcILabelValue : kArcOLabelValue,
  161. kArcValueFlags);
  162. ssize_t low = aiter_begin;
  163. ssize_t high = aiter_end;
  164. while (low < high) {
  165. const ssize_t mid = low + (high - low) / 2;
  166. aiter->Seek(mid);
  167. auto label = reach_input_ ? aiter->Value().ilabel : aiter->Value().olabel;
  168. if (label < match_label) {
  169. low = mid + 1;
  170. } else {
  171. high = mid;
  172. }
  173. }
  174. aiter->Seek(low);
  175. aiter->SetFlags(kArcValueFlags, kArcValueFlags);
  176. return low;
  177. }
  178. private:
  179. bool reach_input_ = false;
  180. };
  181. // Tests reachability of labels from a given state. If reach_input is true, then
  182. // input labels are considered, o.w. output labels are considered. To test for
  183. // reachability from a state s, first do SetState(s), then a label l can be
  184. // reached from state s of FST f iff Reach(r) is true where r = Relabel(l). The
  185. // relabeling is required to ensure the consecutive ones property (C1P); this
  186. // allows a compact representation of the reachable labels. See Section 2.3.3 of
  187. // "A Generalized Composition Algorithm for Weighted Finite-State Transducers",
  188. // Cyril Allauzen, Michael Riley, Johan Schalkwyk, Interspeech 2009.
  189. // https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/35539.pdf
  190. // The whole FST can be relabeled instead with Relabel(&f, reach_input) so that
  191. // the test Reach(r) applies directly to the labels of the transformed FST f.
  192. // The relabeled FST will also be sorted appropriately for composition.
  193. //
  194. // Reachablity of a final state from state s (via an epsilon path) can be
  195. // tested with ReachFinal().
  196. //
  197. // Reachability can also be tested on the set of labels specified by an arc
  198. // iterator, useful for FST composition. In particular, Reach(aiter, ...) is
  199. // true if labels on the input (output) side of the transitions of the arc
  200. // iterator, when iter_input is true (false), can be reached from the state s.
  201. // The iterator labels must have already been relabeled.
  202. //
  203. // With the arc iterator test of reachability, the begin position, end position
  204. // and accumulated arc weight of the matches can be returned. The optional
  205. // template argument controls how reachable arc weights are accumulated. The
  206. // default uses semiring Plus(). Alternative ones can be used to distribute the
  207. // weights in composition in various ways.
  208. template <class Arc, class Accumulator = DefaultAccumulator<Arc>,
  209. class D = LabelReachableData<typename Arc::Label>,
  210. class LB = LabelLowerBound<Arc>>
  211. class LabelReachable {
  212. public:
  213. using Label = typename Arc::Label;
  214. using StateId = typename Arc::StateId;
  215. using Weight = typename Arc::Weight;
  216. using Data = D;
  217. using LowerBound = LB;
  218. using LabelIntervalSet = typename Data::LabelIntervalSet;
  219. using Interval = typename LabelIntervalSet::Interval;
  220. LabelReachable(const Fst<Arc> &fst, bool reach_input,
  221. std::unique_ptr<Accumulator> accumulator = nullptr,
  222. bool keep_relabel_data = true)
  223. : fst_(std::make_unique<VectorFst<Arc>>(fst)),
  224. s_(kNoStateId),
  225. data_(std::make_shared<Data>(reach_input, keep_relabel_data)),
  226. accumulator_(accumulator ? std::move(accumulator)
  227. : std::make_unique<Accumulator>()) {
  228. const auto ins = fst_->NumStates();
  229. TransformFst();
  230. FindIntervals(ins);
  231. fst_.reset();
  232. }
  233. explicit LabelReachable(std::shared_ptr<Data> data,
  234. std::unique_ptr<Accumulator> accumulator = nullptr)
  235. : s_(kNoStateId),
  236. data_(std::move(data)),
  237. accumulator_(accumulator ? std::move(accumulator)
  238. : std::make_unique<Accumulator>()) {}
  239. LabelReachable(const LabelReachable &reachable, bool safe = false)
  240. : s_(kNoStateId),
  241. data_(reachable.data_),
  242. accumulator_(
  243. std::make_unique<Accumulator>(*reachable.accumulator_, safe)),
  244. lower_bound_(reachable.lower_bound_),
  245. reach_fst_input_(reachable.reach_fst_input_),
  246. error_(reachable.error_) {}
  247. ~LabelReachable() {
  248. if (ncalls_ > 0) {
  249. VLOG(2) << "# of calls: " << ncalls_;
  250. VLOG(2) << "# of intervals/call: " << (nintervals_ / ncalls_);
  251. }
  252. }
  253. // Relabels w.r.t labels that give compact label sets.
  254. Label Relabel(Label label) {
  255. if (label == 0 || error_) return label;
  256. const auto &label2index = *data_->Label2Index();
  257. if (auto iter = label2index.find(label); iter != label2index.end()) {
  258. return iter->second;
  259. }
  260. auto &relabel = oov_label2index_[label];
  261. if (!relabel) {
  262. // Adds new label.
  263. relabel = label2index.size() + oov_label2index_.size() + 1;
  264. }
  265. return relabel;
  266. }
  267. // Relabels FST w.r.t to labels that give compact label sets.
  268. void Relabel(MutableFst<Arc> *fst, bool relabel_input) {
  269. for (StateIterator<MutableFst<Arc>> siter(*fst); !siter.Done();
  270. siter.Next()) {
  271. for (MutableArcIterator<MutableFst<Arc>> aiter(fst, siter.Value());
  272. !aiter.Done(); aiter.Next()) {
  273. auto arc = aiter.Value();
  274. if (relabel_input) {
  275. arc.ilabel = Relabel(arc.ilabel);
  276. } else {
  277. arc.olabel = Relabel(arc.olabel);
  278. }
  279. aiter.SetValue(arc);
  280. }
  281. }
  282. if (relabel_input) {
  283. ArcSort(fst, ILabelCompare<Arc>());
  284. fst->SetInputSymbols(nullptr);
  285. } else {
  286. ArcSort(fst, OLabelCompare<Arc>());
  287. fst->SetOutputSymbols(nullptr);
  288. }
  289. }
  290. // Returns relabeling pairs (cf. relabel.h::Relabel()). If avoid_collisions is
  291. // true, extra pairs are added to ensure no collisions when relabeling
  292. // automata that have labels unseen here.
  293. void RelabelPairs(std::vector<std::pair<Label, Label>> *pairs,
  294. bool avoid_collisions = false) {
  295. pairs->clear();
  296. const auto &label2index = *data_->Label2Index();
  297. // Maps labels to their new values in [1, label2index().size()].
  298. for (const auto &kv : label2index) {
  299. if (kv.second != data_->FinalLabel()) {
  300. pairs->emplace_back(kv);
  301. }
  302. }
  303. // Maps oov labels to their values > label2index().size().
  304. pairs->insert(pairs->end(), oov_label2index_.begin(),
  305. oov_label2index_.end());
  306. if (avoid_collisions) {
  307. // Ensures any label in [1, label2index().size()] is mapped either
  308. // by the above steps or to label2index() + 1 (to avoid collisions).
  309. for (size_t i = 1; i <= label2index.size(); ++i) {
  310. const auto it = label2index.find(i);
  311. bool unmapped = it == label2index.end();
  312. if (unmapped) unmapped = oov_label2index_.count(i) == 0;
  313. if (unmapped || it->second == data_->FinalLabel()) {
  314. pairs->emplace_back(i, label2index.size() + 1);
  315. }
  316. }
  317. }
  318. }
  319. // Set current state. Optionally set state associated
  320. // with arc iterator to be passed to Reach.
  321. void SetState(StateId s, StateId aiter_s = kNoStateId) {
  322. s_ = s;
  323. if (aiter_s != kNoStateId) {
  324. accumulator_->SetState(aiter_s);
  325. if (accumulator_->Error()) error_ = true;
  326. lower_bound_.SetState(aiter_s);
  327. }
  328. }
  329. // Can reach this label from current state?
  330. // Original labels must be transformed by the Relabel methods above.
  331. bool Reach(Label label) const {
  332. if (label == 0 || error_) return false;
  333. return data_->GetIntervalSet(s_).Member(label);
  334. }
  335. // Can reach final state (via epsilon transitions) from this state?
  336. bool ReachFinal() const {
  337. if (error_) return false;
  338. return data_->GetIntervalSet(s_).Member(data_->FinalLabel());
  339. }
  340. // Initialize with secondary FST to be used with Reach(Iterator,...).
  341. // If reach_input = true, then arc input labels are considered in
  342. // Reach(aiter, ...), o.w. output labels are considered. If copy is true, then
  343. // the FST is a copy of the FST used in the previous call to this method
  344. // (useful to avoid unnecessary updates).
  345. template <class FST>
  346. void ReachInit(const FST &fst, bool reach_input, bool copy = false) {
  347. reach_fst_input_ = reach_input;
  348. if (!fst.Properties(reach_fst_input_ ? kILabelSorted : kOLabelSorted,
  349. true)) {
  350. FSTERROR() << "LabelReachable::ReachInit: Fst is not sorted";
  351. error_ = true;
  352. }
  353. accumulator_->Init(fst, copy);
  354. if (accumulator_->Error()) error_ = true;
  355. lower_bound_.Init(fst, /*reach_input=*/reach_input, /*is_copy=*/copy);
  356. }
  357. // Can reach any arc iterator label between iterator positions
  358. // aiter_begin and aiter_end?
  359. // Arc iterator labels must be transformed by the Relabel methods
  360. // above. If compute_weight is true, user may call ReachWeight().
  361. template <class Iterator>
  362. bool Reach(Iterator *aiter, ssize_t aiter_begin, ssize_t aiter_end,
  363. bool compute_weight) {
  364. if (error_) return false;
  365. const auto &interval_set = data_->GetIntervalSet(s_);
  366. ++ncalls_;
  367. nintervals_ += interval_set.Size();
  368. reach_begin_ = -1;
  369. reach_end_ = -1;
  370. reach_weight_ = Weight::Zero();
  371. const auto flags = aiter->Flags(); // Save flags to restore them on exit.
  372. aiter->SetFlags(kArcNoCache, kArcNoCache); // Makes caching optional.
  373. aiter->Seek(aiter_begin);
  374. if (2 * (aiter_end - aiter_begin) < interval_set.Size()) {
  375. // Checks each arc against intervals, setting arc iterator flags to only
  376. // compute the ilabel or olabel values, since they are the only values
  377. // required for most of the arcs processed.
  378. aiter->SetFlags(reach_fst_input_ ? kArcILabelValue : kArcOLabelValue,
  379. kArcValueFlags);
  380. Label reach_label = kNoLabel;
  381. for (auto aiter_pos = aiter_begin; aiter_pos < aiter_end;
  382. aiter->Next(), ++aiter_pos) {
  383. const auto &arc = aiter->Value();
  384. const auto label = reach_fst_input_ ? arc.ilabel : arc.olabel;
  385. if (label == reach_label || Reach(label)) {
  386. reach_label = label;
  387. if (reach_begin_ < 0) reach_begin_ = aiter_pos;
  388. reach_end_ = aiter_pos + 1;
  389. if (compute_weight) {
  390. if (!(aiter->Flags() & kArcWeightValue)) {
  391. // If arc.weight wasn't computed by the call to aiter->Value()
  392. // above, we need to call aiter->Value() again after having set
  393. // the arc iterator flags to compute the arc weight value.
  394. aiter->SetFlags(kArcWeightValue, kArcValueFlags);
  395. const auto &arcb = aiter->Value();
  396. // Call the accumulator.
  397. reach_weight_ = accumulator_->Sum(reach_weight_, arcb.weight);
  398. // Only ilabel or olabel required to process the following arcs.
  399. aiter->SetFlags(
  400. reach_fst_input_ ? kArcILabelValue : kArcOLabelValue,
  401. kArcValueFlags);
  402. } else {
  403. // Calls the accumulator.
  404. reach_weight_ = accumulator_->Sum(reach_weight_, arc.weight);
  405. }
  406. }
  407. }
  408. }
  409. } else {
  410. // Checks each interval against arcs.
  411. auto begin_low = aiter_begin;
  412. auto end_low = aiter_begin;
  413. for (const auto &interval : interval_set) {
  414. begin_low = lower_bound_(aiter, end_low, aiter_end, interval.begin);
  415. end_low = lower_bound_(aiter, begin_low, aiter_end, interval.end);
  416. if (end_low - begin_low > 0) {
  417. if (reach_begin_ < 0) reach_begin_ = begin_low;
  418. reach_end_ = end_low;
  419. if (compute_weight) {
  420. aiter->SetFlags(kArcWeightValue, kArcValueFlags);
  421. reach_weight_ =
  422. accumulator_->Sum(reach_weight_, aiter, begin_low, end_low);
  423. }
  424. }
  425. }
  426. }
  427. aiter->SetFlags(flags, kArcFlags); // Restores original flag values.
  428. return reach_begin_ >= 0;
  429. }
  430. // Returns iterator position of first matching arc.
  431. ssize_t ReachBegin() const { return reach_begin_; }
  432. // Returns iterator position one past last matching arc.
  433. ssize_t ReachEnd() const { return reach_end_; }
  434. // Return the sum of the weights for matching arcs. Valid only if
  435. // compute_weight was true in Reach() call.
  436. Weight ReachWeight() const { return reach_weight_; }
  437. // Access to the relabeling map. Excludes epsilon (0) label but
  438. // includes kNoLabel that is used internally for super-final
  439. // transitions.
  440. const std::unordered_map<Label, Label> &Label2Index() const {
  441. return *data_->Label2Index();
  442. }
  443. const Data *GetData() const { return data_.get(); }
  444. std::shared_ptr<Data> GetSharedData() const { return data_; }
  445. bool Error() const { return error_ || accumulator_->Error(); }
  446. private:
  447. // Redirects labeled arcs (input or output labels determined by ReachInput())
  448. // to new label-specific final states. Each original final state is
  449. // redirected via a transition labeled with kNoLabel to a new
  450. // kNoLabel-specific final state. Creates super-initial state for all states
  451. // with zero in-degree.
  452. void TransformFst() {
  453. auto ins = fst_->NumStates();
  454. auto ons = ins;
  455. std::vector<ssize_t> indeg(ins, 0);
  456. // Redirects labeled arcs to new final states.
  457. for (StateId s = 0; s < ins; ++s) {
  458. for (MutableArcIterator<VectorFst<Arc>> aiter(fst_.get(), s);
  459. !aiter.Done(); aiter.Next()) {
  460. auto arc = aiter.Value();
  461. const auto label = data_->ReachInput() ? arc.ilabel : arc.olabel;
  462. if (label) {
  463. if (auto insert_result = label2state_.emplace(label, ons);
  464. insert_result.second) {
  465. indeg.push_back(0);
  466. ++ons;
  467. }
  468. arc.nextstate = label2state_[label];
  469. aiter.SetValue(arc);
  470. }
  471. ++indeg[arc.nextstate]; // Finds in-degrees for next step.
  472. }
  473. // Redirects final weights to new final state.
  474. auto final_weight = fst_->Final(s);
  475. if (final_weight != Weight::Zero()) {
  476. if (auto insert_result = label2state_.emplace(kNoLabel, ons);
  477. insert_result.second) {
  478. indeg.push_back(0);
  479. ++ons;
  480. }
  481. const auto nextstate = label2state_[kNoLabel];
  482. fst_->EmplaceArc(s, kNoLabel, kNoLabel, std::move(final_weight),
  483. nextstate);
  484. ++indeg[nextstate]; // Finds in-degrees for next step.
  485. fst_->SetFinal(s, Weight::Zero());
  486. }
  487. }
  488. // Adds new final states to the FST.
  489. while (fst_->NumStates() < ons) {
  490. StateId s = fst_->AddState();
  491. fst_->SetFinal(s);
  492. }
  493. // Creates a super-initial state for all states with zero in-degree.
  494. const auto start = fst_->AddState();
  495. fst_->SetStart(start);
  496. for (StateId s = 0; s < start; ++s) {
  497. if (indeg[s] == 0) fst_->EmplaceArc(start, 0, 0, s);
  498. }
  499. }
  500. void FindIntervals(StateId ins) {
  501. StateReachable<Arc, Label, LabelIntervalSet> state_reachable(*fst_);
  502. if (state_reachable.Error()) {
  503. error_ = true;
  504. return;
  505. }
  506. auto &state2index = state_reachable.State2Index();
  507. auto &interval_sets = *data_->MutableIntervalSets();
  508. interval_sets = state_reachable.IntervalSets();
  509. interval_sets.resize(ins);
  510. auto &label2index = *data_->MutableLabel2Index();
  511. for (const auto &kv : label2state_) {
  512. Label i = state2index[kv.second];
  513. label2index[kv.first] = i;
  514. if (kv.first == kNoLabel) data_->SetFinalLabel(i);
  515. }
  516. label2state_.clear();
  517. double nintervals = 0;
  518. ssize_t non_intervals = 0;
  519. for (StateId s = 0; s < ins; ++s) {
  520. nintervals += interval_sets[s].Size();
  521. if (interval_sets[s].Size() > 1) {
  522. ++non_intervals;
  523. VLOG(3) << "state: " << s
  524. << " # of intervals: " << interval_sets[s].Size();
  525. }
  526. }
  527. VLOG(2) << "# of states: " << ins;
  528. VLOG(2) << "# of intervals: " << nintervals;
  529. VLOG(2) << "# of intervals/state: " << nintervals / ins;
  530. VLOG(2) << "# of non-interval states: " << non_intervals;
  531. }
  532. std::unique_ptr<VectorFst<Arc>> fst_;
  533. // Current state
  534. StateId s_;
  535. // Finds final state for a label
  536. std::unordered_map<Label, StateId> label2state_;
  537. // Iterator position of first match.
  538. ssize_t reach_begin_;
  539. // Iterator position after last match.
  540. ssize_t reach_end_;
  541. // Gives weight sum of arc iterator arcs with reachable labels.
  542. Weight reach_weight_;
  543. // Shareable data between copies.
  544. std::shared_ptr<Data> data_;
  545. // Sums arc weights.
  546. std::unique_ptr<Accumulator> accumulator_;
  547. // Functor for computing LowerBound(Iterator*, begin, end, label).
  548. LowerBound lower_bound_;
  549. // Relabeling map for OOV labels.
  550. std::unordered_map<Label, Label> oov_label2index_;
  551. double ncalls_ = 0;
  552. double nintervals_ = 0;
  553. bool reach_fst_input_ = false;
  554. bool error_ = false;
  555. };
  556. } // namespace fst
  557. #endif // FST_LABEL_REACHABLE_H_