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.

643 lines
24 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. // Composition filters to support lookahead matchers, useful for improving
  19. // composition efficiency with certain inputs.
  20. #ifndef FST_LOOKAHEAD_FILTER_H_
  21. #define FST_LOOKAHEAD_FILTER_H_
  22. #include <sys/types.h>
  23. #include <cstdint>
  24. #include <memory>
  25. #include <vector>
  26. #include <fst/log.h>
  27. #include <fst/arc.h>
  28. #include <fst/filter-state.h>
  29. #include <fst/fst-decl.h>
  30. #include <fst/fst.h>
  31. #include <fst/lookahead-matcher.h>
  32. #include <fst/matcher.h>
  33. #include <fst/properties.h>
  34. #include <fst/util.h>
  35. namespace fst {
  36. // Identifies and verifies the capabilities of the matcher to be used for
  37. // lookahead with the composition filters below. This version is passed two
  38. // matchers.
  39. template <class Matcher1, class Matcher2>
  40. MatchType LookAheadMatchType(const Matcher1 &m1, const Matcher2 &m2) {
  41. const auto type1 = m1.Type(false);
  42. const auto type2 = m2.Type(false);
  43. if (type1 == MATCH_OUTPUT && m1.Flags() & kOutputLookAheadMatcher) {
  44. return MATCH_OUTPUT;
  45. } else if (type2 == MATCH_INPUT && m2.Flags() & kInputLookAheadMatcher) {
  46. return MATCH_INPUT;
  47. } else if (m1.Flags() & kOutputLookAheadMatcher &&
  48. m1.Type(true) == MATCH_OUTPUT) {
  49. return MATCH_OUTPUT;
  50. } else if (m2.Flags() & kInputLookAheadMatcher &&
  51. m2.Type(true) == MATCH_INPUT) {
  52. return MATCH_INPUT;
  53. } else {
  54. return MATCH_NONE;
  55. }
  56. }
  57. // Identifies and verifies the capabilities of the matcher to be used for
  58. // lookahead with the composition filters below. This version uses the FST's
  59. // default matchers.
  60. template <class Arc>
  61. MatchType LookAheadMatchType(const Fst<Arc> &fst1, const Fst<Arc> &fst2) {
  62. LookAheadMatcher<Fst<Arc>> matcher1(fst1, MATCH_OUTPUT);
  63. LookAheadMatcher<Fst<Arc>> matcher2(fst2, MATCH_INPUT);
  64. return LookAheadMatchType(matcher1, matcher2);
  65. }
  66. // LookAheadSelector is a helper class for selecting among possibly distinct
  67. // FST and matcher types without using a common base class. This lets us avoid
  68. // virtual function calls. It stores and returns the appropriate FSTs and
  69. // matcher for lookahead. It is templated on the matcher types. General case
  70. // has no methods.
  71. template <class Matcher1, class Matcher2, MatchType MT>
  72. class LookAheadSelector {};
  73. // Stores and returns the appropriate FST and matcher for lookahead. Specialized
  74. // for two matchers of same type with the (match) type argument determining
  75. // which is used for lookahead.
  76. template <class Matcher, MatchType MT>
  77. class LookAheadSelector<Matcher, Matcher, MT> {
  78. public:
  79. using FST = typename Matcher::FST;
  80. LookAheadSelector(Matcher *lmatcher1, Matcher *lmatcher2, MatchType type)
  81. : lmatcher1_(lmatcher1->Copy()),
  82. lmatcher2_(lmatcher2->Copy()),
  83. type_(type) {}
  84. LookAheadSelector(const LookAheadSelector<Matcher, Matcher, MT> &selector)
  85. : lmatcher1_(selector.lmatcher1_->Copy()),
  86. lmatcher2_(selector.lmatcher2_->Copy()),
  87. type_(selector.type_) {}
  88. const FST &GetFst() const {
  89. return type_ == MATCH_OUTPUT ? lmatcher2_->GetFst() : lmatcher1_->GetFst();
  90. }
  91. Matcher *GetMatcher() const {
  92. return type_ == MATCH_OUTPUT ? lmatcher1_.get() : lmatcher2_.get();
  93. }
  94. private:
  95. std::unique_ptr<Matcher> lmatcher1_;
  96. std::unique_ptr<Matcher> lmatcher2_;
  97. MatchType type_;
  98. };
  99. // Stores and returns the appropriate FST and matcher for lookahead.
  100. // Specialized for lookahead on input labels.
  101. template <class Matcher1, class Matcher2>
  102. class LookAheadSelector<Matcher1, Matcher2, MATCH_INPUT> {
  103. public:
  104. using FST1 = typename Matcher1::FST;
  105. LookAheadSelector(Matcher1 *lmatcher1, Matcher2 *lmatcher2, MatchType)
  106. : fst_(lmatcher1->GetFst().Copy()), lmatcher_(lmatcher2->Copy()) {}
  107. LookAheadSelector(
  108. const LookAheadSelector<Matcher1, Matcher2, MATCH_INPUT> &selector)
  109. : fst_(selector.fst_->Copy()), lmatcher_(selector.lmatcher_->Copy()) {}
  110. const FST1 &GetFst() const { return *fst_; }
  111. Matcher2 *GetMatcher() const { return lmatcher_.get(); }
  112. private:
  113. std::unique_ptr<const FST1> fst_;
  114. std::unique_ptr<Matcher2> lmatcher_;
  115. };
  116. // Stores and returns the appropriate FST and matcher for lookahead.
  117. // Specialized for lookahead on output labels.
  118. template <class Matcher1, class Matcher2>
  119. class LookAheadSelector<Matcher1, Matcher2, MATCH_OUTPUT> {
  120. public:
  121. using FST2 = typename Matcher2::FST;
  122. LookAheadSelector(Matcher1 *lmatcher1, Matcher2 *lmatcher2, MatchType)
  123. : fst_(lmatcher2->GetFst().Copy()), lmatcher_(lmatcher1->Copy()) {}
  124. LookAheadSelector(
  125. const LookAheadSelector<Matcher1, Matcher2, MATCH_OUTPUT> &selector)
  126. : fst_(selector.fst_->Copy()), lmatcher_(selector.lmatcher_->Copy()) {}
  127. const FST2 &GetFst() const { return *fst_; }
  128. Matcher1 *GetMatcher() const { return lmatcher_.get(); }
  129. private:
  130. std::unique_ptr<const FST2> fst_;
  131. std::unique_ptr<Matcher1> lmatcher_;
  132. };
  133. // This filter uses a lookahead matcher in FilterArc(arc1, arc2) to examine the
  134. // future of the composition state (arc1.nextstate, arc2.nextstate), blocking
  135. // moving forward when its determined to be
  136. // non-coaccessible. It is templated on an underlying filter, typically the
  137. // epsilon filter. Which matcher is the lookahead matcher is determined by the
  138. // template argument MT unless it is MATCH_BOTH. In that case, both matcher
  139. // arguments must be lookahead matchers of the same type and one will be
  140. // selected by LookAheadMatchType() based on their capability.
  141. template <class Filter, class M1 = LookAheadMatcher<typename Filter::FST1>,
  142. class M2 = M1, MatchType MT = MATCH_BOTH>
  143. class LookAheadComposeFilter {
  144. public:
  145. using Arc = typename Filter::Arc;
  146. using StateId = typename Arc::StateId;
  147. using Weight = typename Arc::Weight;
  148. using FST1 = typename Filter::FST1;
  149. using FST2 = typename Filter::FST2;
  150. using Matcher1 = typename Filter::Matcher1;
  151. using Matcher2 = typename Filter::Matcher2;
  152. using FilterState = typename Filter::FilterState;
  153. LookAheadComposeFilter(const FST1 &fst1, const FST2 &fst2, M1 *matcher1,
  154. M2 *matcher2)
  155. : filter_(fst1, fst2, matcher1, matcher2),
  156. lookahead_type_(MT == MATCH_BOTH
  157. ? LookAheadMatchType(*filter_.GetMatcher1(),
  158. *filter_.GetMatcher2())
  159. : MT),
  160. selector_(filter_.GetMatcher1(), filter_.GetMatcher2(),
  161. lookahead_type_),
  162. flags_(lookahead_type_ == MATCH_OUTPUT
  163. ? filter_.GetMatcher1()->Flags()
  164. : filter_.GetMatcher2()->Flags()) {
  165. if (lookahead_type_ == MATCH_NONE) {
  166. FSTERROR() << "LookAheadComposeFilter: 1st argument cannot "
  167. << "match/look-ahead on output labels and 2nd argument "
  168. << "cannot match/look-ahead on input labels";
  169. }
  170. selector_.GetMatcher()->InitLookAheadFst(selector_.GetFst());
  171. }
  172. LookAheadComposeFilter(
  173. const LookAheadComposeFilter<Filter, M1, M2, MT> &filter,
  174. bool safe = false)
  175. : filter_(filter.filter_, safe),
  176. lookahead_type_(filter.lookahead_type_),
  177. selector_(filter_.GetMatcher1(), filter_.GetMatcher2(),
  178. lookahead_type_),
  179. flags_(filter.flags_) {
  180. selector_.GetMatcher()->InitLookAheadFst(selector_.GetFst(), true);
  181. }
  182. FilterState Start() const { return filter_.Start(); }
  183. void SetState(StateId s1, StateId s2, const FilterState &fs) {
  184. filter_.SetState(s1, s2, fs);
  185. }
  186. FilterState FilterArc(Arc *arc1, Arc *arc2) const {
  187. lookahead_arc_ = false;
  188. const FilterState &fs = filter_.FilterArc(arc1, arc2);
  189. if (fs == FilterState::NoState()) return FilterState::NoState();
  190. return LookAheadOutput() ? LookAheadFilterArc(arc1, arc2, fs)
  191. : LookAheadFilterArc(arc2, arc1, fs);
  192. }
  193. void FilterFinal(Weight *weight1, Weight *weight2) const {
  194. filter_.FilterFinal(weight1, weight2);
  195. }
  196. // Returns matchers; ownership stays with filter.
  197. Matcher1 *GetMatcher1() { return filter_.GetMatcher1(); }
  198. Matcher2 *GetMatcher2() { return filter_.GetMatcher2(); }
  199. const LookAheadSelector<Matcher1, Matcher2, MT> &Selector() const {
  200. return selector_;
  201. }
  202. uint64_t Properties(uint64_t inprops) const {
  203. auto outprops = filter_.Properties(inprops);
  204. if (lookahead_type_ == MATCH_NONE) outprops |= kError;
  205. return outprops;
  206. }
  207. uint32_t LookAheadFlags() const { return flags_; }
  208. bool LookAheadArc() const { return lookahead_arc_; }
  209. bool LookAheadOutput() const {
  210. if (MT == MATCH_OUTPUT) {
  211. return true;
  212. } else if (MT == MATCH_INPUT) {
  213. return false;
  214. } else if (lookahead_type_ == MATCH_OUTPUT) {
  215. return true;
  216. } else {
  217. return false;
  218. }
  219. }
  220. private:
  221. FilterState LookAheadFilterArc(Arc *arca, Arc *arcb,
  222. const FilterState &fs) const {
  223. auto &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
  224. if (labela != 0 && !(flags_ & kLookAheadNonEpsilons)) return fs;
  225. if (labela == 0 && !(flags_ & kLookAheadEpsilons)) return fs;
  226. lookahead_arc_ = true;
  227. selector_.GetMatcher()->SetState(arca->nextstate);
  228. return selector_.GetMatcher()->LookAheadFst(selector_.GetFst(),
  229. arcb->nextstate)
  230. ? fs
  231. : FilterState::NoState();
  232. }
  233. Filter filter_; // Underlying filter.
  234. MatchType lookahead_type_; // Lookahead match type.
  235. LookAheadSelector<Matcher1, Matcher2, MT> selector_;
  236. uint32_t flags_; // Lookahead flags.
  237. mutable bool lookahead_arc_; // Look-ahead performed at last FilterArc()?
  238. LookAheadComposeFilter &operator=(const LookAheadComposeFilter &) = delete;
  239. };
  240. // This filter adds weight-pushing to a lookahead composition filter using the
  241. // LookAheadWeight() method of matcher argument. It is templated on an
  242. // underlying lookahead filter, typically the basic lookahead filter.
  243. // Weight-pushing in composition brings weights forward as much as possible
  244. // based on the lookahead information.
  245. template <class Filter, class M1 = LookAheadMatcher<typename Filter::FST1>,
  246. class M2 = M1, MatchType MT = MATCH_BOTH>
  247. class PushWeightsComposeFilter {
  248. public:
  249. using Arc = typename Filter::Arc;
  250. using StateId = typename Filter::StateId;
  251. using Weight = typename Filter::Weight;
  252. using FST1 = typename Filter::FST1;
  253. using FST2 = typename Filter::FST2;
  254. using Matcher1 = typename Filter::Matcher1;
  255. using Matcher2 = typename Filter::Matcher2;
  256. using FilterState1 = typename Filter::FilterState;
  257. using FilterState2 = WeightFilterState<Weight>;
  258. using FilterState = PairFilterState<FilterState1, FilterState2>;
  259. PushWeightsComposeFilter(const FST1 &fst1, const FST2 &fst2, M1 *matcher1,
  260. M2 *matcher2)
  261. : filter_(fst1, fst2, matcher1, matcher2), fs_(FilterState::NoState()) {}
  262. PushWeightsComposeFilter(
  263. const PushWeightsComposeFilter<Filter, M1, M2, MT> &filter,
  264. bool safe = false)
  265. : filter_(filter.filter_, safe), fs_(FilterState::NoState()) {}
  266. FilterState Start() const {
  267. return FilterState(filter_.Start(), FilterState2(Weight::One()));
  268. }
  269. void SetState(StateId s1, StateId s2, const FilterState &fs) {
  270. fs_ = fs;
  271. filter_.SetState(s1, s2, fs.GetState1());
  272. }
  273. FilterState FilterArc(Arc *arc1, Arc *arc2) const {
  274. const auto &fs1 = filter_.FilterArc(arc1, arc2);
  275. if (fs1 == FilterState1::NoState()) return FilterState::NoState();
  276. if (!(LookAheadFlags() & kLookAheadWeight)) {
  277. return FilterState(fs1, FilterState2(Weight::One()));
  278. }
  279. const auto &lweight = LookAheadArc()
  280. ? Selector().GetMatcher()->LookAheadWeight()
  281. : Weight::One();
  282. const auto &fs2 = fs_.GetState2();
  283. const auto &fweight = fs2.GetWeight();
  284. // Disallows Zero() weight futures.
  285. if (lweight == Weight::Zero()) return FilterState::NoState();
  286. arc2->weight = Divide(Times(arc2->weight, lweight), fweight);
  287. return FilterState(fs1, FilterState2(lweight.Quantize()));
  288. }
  289. void FilterFinal(Weight *weight1, Weight *weight2) const {
  290. filter_.FilterFinal(weight1, weight2);
  291. if (!(LookAheadFlags() & kLookAheadWeight) || *weight1 == Weight::Zero()) {
  292. return;
  293. }
  294. const auto &fs2 = fs_.GetState2();
  295. const auto &fweight = fs2.GetWeight();
  296. *weight1 = Divide(*weight1, fweight);
  297. }
  298. // Returns matchers; ownership states with filter.
  299. Matcher1 *GetMatcher1() { return filter_.GetMatcher1(); }
  300. Matcher2 *GetMatcher2() { return filter_.GetMatcher2(); }
  301. const LookAheadSelector<Matcher1, Matcher2, MT> &Selector() const {
  302. return filter_.Selector();
  303. }
  304. uint32_t LookAheadFlags() const { return filter_.LookAheadFlags(); }
  305. bool LookAheadArc() const { return filter_.LookAheadArc(); }
  306. bool LookAheadOutput() const { return filter_.LookAheadOutput(); }
  307. uint64_t Properties(uint64_t props) const {
  308. return filter_.Properties(props) & kWeightInvariantProperties;
  309. }
  310. private:
  311. Filter filter_; // Underlying filter.
  312. FilterState fs_; // Current filter state.
  313. PushWeightsComposeFilter &operator=(const PushWeightsComposeFilter &) =
  314. delete;
  315. };
  316. // This filter adds label-pushing to a lookahead composition filter using the
  317. // LookAheadPrefix() method of the matcher argument. It is templated on an
  318. // underlying filter, typically the basic lookahead or weight-pushing lookahead
  319. // filter. Label-pushing in composition matches labels as early as possible
  320. // based on the lookahead information.
  321. template <class Filter, class M1 = LookAheadMatcher<typename Filter::FST1>,
  322. class M2 = M1, MatchType MT = MATCH_BOTH>
  323. class PushLabelsComposeFilter {
  324. public:
  325. using Arc = typename Filter::Arc;
  326. using Label = typename Arc::Label;
  327. using StateId = typename Arc::StateId;
  328. using Weight = typename Arc::Weight;
  329. using FST1 = typename Filter::FST1;
  330. using FST2 = typename Filter::FST2;
  331. using Matcher1 = MultiEpsMatcher<typename Filter::Matcher1>;
  332. using Matcher2 = MultiEpsMatcher<typename Filter::Matcher2>;
  333. using FilterState1 = typename Filter::FilterState;
  334. using FilterState2 = IntegerFilterState<Label>;
  335. using FilterState = PairFilterState<FilterState1, FilterState2>;
  336. PushLabelsComposeFilter(const FST1 &fst1, const FST2 &fst2, M1 *matcher1,
  337. M2 *matcher2)
  338. : filter_(fst1, fst2, matcher1, matcher2),
  339. fs_(FilterState::NoState()),
  340. fst1_(filter_.GetMatcher1()->GetFst()),
  341. fst2_(filter_.GetMatcher2()->GetFst()),
  342. matcher1_(fst1_, MATCH_OUTPUT,
  343. filter_.LookAheadOutput() ? kMultiEpsList : kMultiEpsLoop,
  344. filter_.GetMatcher1(), /*own_matcher=*/false),
  345. matcher2_(fst2_, MATCH_INPUT,
  346. filter_.LookAheadOutput() ? kMultiEpsLoop : kMultiEpsList,
  347. filter_.GetMatcher2(), /*own_matcher=*/false) {}
  348. PushLabelsComposeFilter(
  349. const PushLabelsComposeFilter<Filter, M1, M2, MT> &filter,
  350. bool safe = false)
  351. : filter_(filter.filter_, safe),
  352. fs_(FilterState::NoState()),
  353. fst1_(filter_.GetMatcher1()->GetFst()),
  354. fst2_(filter_.GetMatcher2()->GetFst()),
  355. matcher1_(fst1_, MATCH_OUTPUT,
  356. filter_.LookAheadOutput() ? kMultiEpsList : kMultiEpsLoop,
  357. filter_.GetMatcher1(), /*own_matcher=*/false),
  358. matcher2_(fst2_, MATCH_INPUT,
  359. filter_.LookAheadOutput() ? kMultiEpsLoop : kMultiEpsList,
  360. filter_.GetMatcher2(), /*own_matcher=*/false) {}
  361. FilterState Start() const {
  362. return FilterState(filter_.Start(), FilterState2(kNoLabel));
  363. }
  364. void SetState(StateId s1, StateId s2, const FilterState &fs) {
  365. fs_ = fs;
  366. filter_.SetState(s1, s2, fs.GetState1());
  367. if (!(LookAheadFlags() & kLookAheadPrefix)) return;
  368. narcsa_ = LookAheadOutput() ? internal::NumArcs(fst1_, s1)
  369. : internal::NumArcs(fst2_, s2);
  370. const auto &fs2 = fs_.GetState2();
  371. const auto &flabel = fs2.GetState();
  372. GetMatcher1()->ClearMultiEpsLabels();
  373. GetMatcher2()->ClearMultiEpsLabels();
  374. if (flabel != kNoLabel) { // Have a lookahead label?
  375. GetMatcher1()->AddMultiEpsLabel(flabel); // Yes, make it a multi-epsilon
  376. GetMatcher2()->AddMultiEpsLabel(flabel); // label so that it matches the
  377. } // implicit epsilon arc to be
  378. } // modified below when pushing.
  379. FilterState FilterArc(Arc *arc1, Arc *arc2) const {
  380. if (!(LookAheadFlags() & kLookAheadPrefix)) {
  381. return FilterState(filter_.FilterArc(arc1, arc2), FilterState2(kNoLabel));
  382. }
  383. const auto &fs2 = fs_.GetState2();
  384. const auto &flabel = fs2.GetState();
  385. if (flabel != kNoLabel) { // Have a lookahead label?
  386. return LookAheadOutput() ? PushedLabelFilterArc(arc1, arc2, flabel)
  387. : PushedLabelFilterArc(arc2, arc1, flabel);
  388. }
  389. const auto &fs1 = filter_.FilterArc(arc1, arc2);
  390. if (fs1 == FilterState1::NoState()) return FilterState::NoState();
  391. if (!LookAheadArc()) return FilterState(fs1, FilterState2(kNoLabel));
  392. return LookAheadOutput() ? PushLabelFilterArc(arc1, arc2, fs1)
  393. : PushLabelFilterArc(arc2, arc1, fs1);
  394. }
  395. void FilterFinal(Weight *weight1, Weight *weight2) const {
  396. filter_.FilterFinal(weight1, weight2);
  397. if (!(LookAheadFlags() & kLookAheadPrefix) || *weight1 == Weight::Zero()) {
  398. return;
  399. }
  400. const auto &fs2 = fs_.GetState2();
  401. const auto &flabel = fs2.GetState();
  402. if (flabel != kNoLabel) *weight1 = Weight::Zero();
  403. }
  404. // Returns matchers; ownership states with filter.
  405. Matcher1 *GetMatcher1() { return &matcher1_; }
  406. Matcher2 *GetMatcher2() { return &matcher2_; }
  407. uint64_t Properties(uint64_t iprops) const {
  408. const auto oprops = filter_.Properties(iprops);
  409. if (LookAheadOutput()) {
  410. return oprops & kOLabelInvariantProperties;
  411. } else {
  412. return oprops & kILabelInvariantProperties;
  413. }
  414. }
  415. private:
  416. const LookAheadSelector<typename Filter::Matcher1, typename Filter::Matcher2,
  417. MT>
  418. &Selector() const {
  419. return filter_.Selector();
  420. }
  421. // Consumes an already pushed label.
  422. FilterState PushedLabelFilterArc(Arc *arca, Arc *arcb, Label flabel) const {
  423. auto &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
  424. const auto &labelb = LookAheadOutput() ? arcb->ilabel : arcb->olabel;
  425. if (labelb != kNoLabel) {
  426. return FilterState::NoState(); // Blocks non-(multi-)epsilon label
  427. } else if (labela == flabel) {
  428. labela = 0; // Converts match to multi-epsilon to epsilon.
  429. return Start();
  430. } else if (labela == 0) {
  431. if (narcsa_ == 1) return fs_; // Takes epsilon, keeping state with label.
  432. Selector().GetMatcher()->SetState(arca->nextstate);
  433. if (Selector().GetMatcher()->LookAheadLabel(flabel)) {
  434. return fs_; // Takes epsilon, keeping state with label.
  435. } else {
  436. return FilterState::NoState(); // Blocks non-coaccessible path.
  437. }
  438. } else {
  439. return FilterState::NoState(); // Blocks mismatch to multi-epsilon label.
  440. }
  441. }
  442. // Pushes a label forward when possible.
  443. FilterState PushLabelFilterArc(Arc *arca, Arc *arcb,
  444. const FilterState1 &fs1) const {
  445. auto &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
  446. const auto &labelb = LookAheadOutput() ? arcb->olabel : arcb->ilabel;
  447. if (labelb != 0) { // No place to push.
  448. return FilterState(fs1, FilterState2(kNoLabel));
  449. }
  450. if (labela != 0 && // Wrong lookahead prefix type?
  451. LookAheadFlags() & kLookAheadNonEpsilonPrefix) {
  452. return FilterState(fs1, FilterState2(kNoLabel));
  453. }
  454. Arc larc(kNoLabel, kNoLabel, Weight::Zero(), kNoStateId);
  455. if (Selector().GetMatcher()->LookAheadPrefix(&larc)) { // Have prefix arc?
  456. labela = LookAheadOutput() ? larc.ilabel : larc.olabel;
  457. arcb->ilabel = larc.ilabel; // Goes forward on that arc,
  458. arcb->olabel = larc.olabel; // thus pushing the label.
  459. arcb->weight = Times(arcb->weight, larc.weight);
  460. arcb->nextstate = larc.nextstate;
  461. return FilterState(fs1, FilterState2(labela));
  462. } else {
  463. return FilterState(fs1, FilterState2(kNoLabel));
  464. }
  465. }
  466. uint32_t LookAheadFlags() const { return filter_.LookAheadFlags(); }
  467. bool LookAheadArc() const { return filter_.LookAheadArc(); }
  468. bool LookAheadOutput() const { return filter_.LookAheadOutput(); }
  469. Filter filter_; // Underlying filter.
  470. FilterState fs_; // Current filter state.
  471. const FST1 &fst1_;
  472. const FST2 &fst2_;
  473. Matcher1 matcher1_; // Multi-epsilon matcher for fst1_.
  474. Matcher2 matcher2_; // Multi-epsilon matcher for fst2_.
  475. ssize_t narcsa_; // Number of arcs leaving look-ahead match FST.
  476. PushLabelsComposeFilter &operator=(const PushLabelsComposeFilter &) = delete;
  477. };
  478. // Convenience class for setting up composition with a default lookahead matcher
  479. // and filter.
  480. template <class Arc, MatchType type>
  481. class DefaultLookAhead {
  482. public:
  483. using M = Matcher<Fst<Arc>>;
  484. using ComposeFilter = SequenceComposeFilter<M>;
  485. using FstMatcher = M;
  486. };
  487. // Specializes for MATCH_INPUT to allow lookahead.
  488. template <class Arc>
  489. class DefaultLookAhead<Arc, MATCH_INPUT> {
  490. public:
  491. using M = LookAheadMatcher<Fst<Arc>>;
  492. using SF = SequenceComposeFilter<M>;
  493. using ComposeFilter = LookAheadComposeFilter<SF, M>;
  494. using FstMatcher = M;
  495. };
  496. // Specializes for MATCH_OUTPUT to allow lookahead.
  497. template <class Arc>
  498. class DefaultLookAhead<Arc, MATCH_OUTPUT> {
  499. public:
  500. using M = LookAheadMatcher<Fst<Arc>>;
  501. using SF = AltSequenceComposeFilter<M>;
  502. using ComposeFilter = LookAheadComposeFilter<SF, M>;
  503. using FstMatcher = M;
  504. };
  505. // Specializes for StdArc to allow weight and label pushing.
  506. template <>
  507. class DefaultLookAhead<StdArc, MATCH_INPUT> {
  508. public:
  509. using M = LookAheadMatcher<Fst<StdArc>>;
  510. using SF = SequenceComposeFilter<M>;
  511. using LF = LookAheadComposeFilter<SF, M>;
  512. using WF = PushWeightsComposeFilter<LF, M>;
  513. using ComposeFilter = PushLabelsComposeFilter<WF, M>;
  514. using FstMatcher = M;
  515. };
  516. // Specializes for StdArc to allow weight and label pushing.
  517. template <>
  518. class DefaultLookAhead<StdArc, MATCH_OUTPUT> {
  519. public:
  520. using M = LookAheadMatcher<Fst<StdArc>>;
  521. using SF = AltSequenceComposeFilter<M>;
  522. using LF = LookAheadComposeFilter<SF, M>;
  523. using WF = PushWeightsComposeFilter<LF, M>;
  524. using ComposeFilter = PushLabelsComposeFilter<WF, M>;
  525. using FstMatcher = M;
  526. };
  527. // Specializes for LogArc to allow weight and label pushing.
  528. template <>
  529. class DefaultLookAhead<LogArc, MATCH_INPUT> {
  530. public:
  531. using M = LookAheadMatcher<Fst<LogArc>>;
  532. using SF = SequenceComposeFilter<M>;
  533. using LF = LookAheadComposeFilter<SF, M>;
  534. using WF = PushWeightsComposeFilter<LF, M>;
  535. using ComposeFilter = PushLabelsComposeFilter<WF, M>;
  536. using FstMatcher = M;
  537. };
  538. // Specializes for LogArc to allow weight and label pushing.
  539. template <>
  540. class DefaultLookAhead<LogArc, MATCH_OUTPUT> {
  541. public:
  542. using M = LookAheadMatcher<Fst<LogArc>>;
  543. using SF = AltSequenceComposeFilter<M>;
  544. using LF = LookAheadComposeFilter<SF, M>;
  545. using WF = PushWeightsComposeFilter<LF, M>;
  546. using ComposeFilter = PushLabelsComposeFilter<WF, M>;
  547. using FstMatcher = M;
  548. };
  549. } // namespace fst
  550. #endif // FST_LOOKAHEAD_FILTER_H_