blob: e11c1bbd177a5e3b334c2a8d4299f86cc5b334e6 [file] [log] [blame]
// lookahead-filter.h
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2005-2010 Google, Inc.
// Author: riley@google.com (Michael Riley)
//
// \file
// Composition filters to support lookahead matchers, useful for improving
// composition efficiency with certain inputs.
#ifndef FST_LIB_LOOKAHEAD_FILTER_H__
#define FST_LIB_LOOKAHEAD_FILTER_H__
#include <vector>
using std::vector;
#include <fst/fst.h>
#include <fst/lookahead-matcher.h>
namespace fst {
// Identifies and verifies the capabilities of the matcher to be used for
// lookahead with the composition filters below. This version is passed
// the matchers.
template <class M1, class M2>
MatchType LookAheadMatchType(const M1 &m1, const M2 &m2) {
MatchType type1 = m1.Type(false);
MatchType type2 = m2.Type(false);
if (type1 == MATCH_OUTPUT &&
m1.Flags() & kOutputLookAheadMatcher)
return MATCH_OUTPUT;
else if (type2 == MATCH_INPUT &&
m2.Flags() & kInputLookAheadMatcher)
return MATCH_INPUT;
else if (m1.Flags() & kOutputLookAheadMatcher &&
m1.Type(true) == MATCH_OUTPUT)
return MATCH_OUTPUT;
else if (m2.Flags() & kInputLookAheadMatcher &&
m2.Type(true) == MATCH_INPUT)
return MATCH_INPUT;
else
return MATCH_NONE;
}
// Identifies and verifies the capabilities of the matcher to be used for
// lookahead with the composition filters below. This version uses the
// Fst's default matchers.
template <class Arc>
MatchType LookAheadMatchType(const Fst<Arc> &fst1, const Fst<Arc> &fst2) {
LookAheadMatcher< Fst <Arc> > matcher1(fst1, MATCH_OUTPUT);
LookAheadMatcher< Fst <Arc> > matcher2(fst2, MATCH_INPUT);
return LookAheadMatchType(matcher1, matcher2);
}
//
// LookAheadSelector - a helper class for selecting among possibly
// distinct FST and matcher types w/o using a common base class. This
// lets us avoid virtual function calls.
//
// Stores and returns the appropriate FST and matcher for lookahead.
// It is templated on the matcher types. General case has no methods
// since not currently supported.
template <class M1, class M2, MatchType MT>
class LookAheadSelector {
};
// Stores and returns the appropriate FST and matcher for lookahead.
// Specialized for two matchers of same type with the (match) 'type'
// arg determining which is used for lookahead.
template <class M, MatchType MT>
class LookAheadSelector<M, M, MT> {
public:
typedef typename M::Arc Arc;
typedef typename M::FST F;
LookAheadSelector(M *lmatcher1, M *lmatcher2, MatchType type)
: lmatcher1_(lmatcher1->Copy()),
lmatcher2_(lmatcher2->Copy()),
type_(type) {}
LookAheadSelector(const LookAheadSelector<M, M, MT> &selector)
: lmatcher1_(selector.lmatcher1_->Copy()),
lmatcher2_(selector.lmatcher2_->Copy()),
type_(selector.type_) {}
~LookAheadSelector() {
delete lmatcher1_;
delete lmatcher2_;
}
const F &GetFst() const {
return type_ == MATCH_OUTPUT ? lmatcher2_->GetFst() :
lmatcher1_->GetFst();
}
M *GetMatcher() const {
return type_ == MATCH_OUTPUT ? lmatcher1_ : lmatcher2_;
}
private:
M *lmatcher1_;
M *lmatcher2_;
MatchType type_;
void operator=(const LookAheadSelector<M, M, MT> &); // disallow
};
// Stores and returns the appropriate FST and matcher for lookahead.
// Specialized for lookahead on input labels.
template <class M1, class M2>
class LookAheadSelector<M1, M2, MATCH_INPUT> {
public:
typedef typename M1::FST F1;
LookAheadSelector(M1 *lmatcher1, M2 *lmatcher2, MatchType)
: fst_(lmatcher1->GetFst().Copy()),
lmatcher_(lmatcher2->Copy()) {}
LookAheadSelector(const LookAheadSelector<M1, M2, MATCH_INPUT> &selector)
: fst_(selector.fst_->Copy()),
lmatcher_(selector.lmatcher_->Copy()) {}
~LookAheadSelector() {
delete lmatcher_;
delete fst_;
}
const F1 &GetFst() const { return *fst_; }
M2 *GetMatcher() const { return lmatcher_; }
private:
const F1 *fst_;
M2 *lmatcher_;
void operator=(const LookAheadSelector<M1, M2, MATCH_INPUT> &); // disallow
};
// Stores and returns the appropriate FST and matcher for lookahead.
// Specialized for lookahead on output labels.
template <class M1, class M2>
class LookAheadSelector<M1, M2, MATCH_OUTPUT> {
public:
typedef typename M2::FST F2;
LookAheadSelector(M1 *lmatcher1, M2 *lmatcher2, MatchType)
: fst_(lmatcher2->GetFst().Copy()),
lmatcher_(lmatcher1->Copy()) {}
LookAheadSelector(const LookAheadSelector<M1, M2, MATCH_OUTPUT> &selector)
: fst_(selector.fst_->Copy()),
lmatcher_(selector.lmatcher_->Copy()) {}
~LookAheadSelector() {
delete lmatcher_;
delete fst_;
}
const F2 &GetFst() const { return *fst_; }
M1 *GetMatcher() const { return lmatcher_; }
private:
const F2 *fst_;
M1 *lmatcher_;
void operator=(const LookAheadSelector<M1, M2, MATCH_OUTPUT> &); // disallow
};
// This filter uses a lookahead matcher in FilterArc(arc1, arc2) to
// examine the future of the composition state (arc1.nextstate,
// arc2.nextstate), blocking moving forward when its determined to be
// non-coaccessible. It is templated on an underlying filter,
// typically the epsilon filter. Which matcher is the lookahead
// matcher is determined by the template argument MT unless it is
// MATCH_BOTH. In that case, both matcher arguments must be lookahead
// matchers of the same type and one will be selected by
// LookAheadMatchType() based on their capability.
template <class F,
class M1 = LookAheadMatcher<typename F::FST1>,
class M2 = M1,
MatchType MT = MATCH_BOTH>
class LookAheadComposeFilter {
public:
typedef typename F::FST1 FST1;
typedef typename F::FST2 FST2;
typedef typename F::Arc Arc;
typedef typename F::Matcher1 Matcher1;
typedef typename F::Matcher2 Matcher2;
typedef typename F::FilterState FilterState;
typedef LookAheadComposeFilter<F, M1, M2, MT> Filter;
typedef typename Arc::StateId StateId;
typedef typename Arc::Label Label;
typedef typename Arc::Weight Weight;
LookAheadComposeFilter(const FST1 &fst1, const FST2 &fst2,
M1 *matcher1, M2 *matcher2)
: filter_(fst1, fst2, matcher1, matcher2),
lookahead_type_(MT == MATCH_BOTH ?
LookAheadMatchType(*filter_.GetMatcher1(),
*filter_.GetMatcher2()) : MT),
selector_(filter_.GetMatcher1(), filter_.GetMatcher2(),
lookahead_type_),
flags_(lookahead_type_ == MATCH_OUTPUT ?
filter_.GetMatcher1()->Flags() :
filter_.GetMatcher2()->Flags()) {
if (lookahead_type_ == MATCH_NONE) {
FSTERROR() << "LookAheadComposeFilter: 1st argument cannot "
<< "match/look-ahead on output labels and 2nd argument "
<< "cannot match/look-ahead on input labels.";
}
selector_.GetMatcher()->InitLookAheadFst(selector_.GetFst());
}
LookAheadComposeFilter(const LookAheadComposeFilter<F, M1, M2, MT> &filter,
bool safe = false)
: filter_(filter.filter_, safe),
lookahead_type_(filter.lookahead_type_),
selector_(filter_.GetMatcher1(), filter_.GetMatcher2(),
lookahead_type_),
flags_(filter.flags_) {
selector_.GetMatcher()->InitLookAheadFst(selector_.GetFst(), true);
}
FilterState Start() const {
return filter_.Start();
}
void SetState(StateId s1, StateId s2, const FilterState &f) {
filter_.SetState(s1, s2, f);
}
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
lookahead_arc_ = false;
const FilterState &f = filter_.FilterArc(arc1, arc2);
if (f == FilterState::NoState())
return FilterState::NoState();
return LookAheadOutput() ? LookAheadFilterArc(arc1, arc2, f) :
LookAheadFilterArc(arc2, arc1, f);
}
void FilterFinal(Weight *weight1, Weight *weight2) const {
filter_.FilterFinal(weight1, weight2);
}
// Return resp matchers. Ownership stays with filter.
Matcher1 *GetMatcher1() { return filter_.GetMatcher1(); }
Matcher2 *GetMatcher2() { return filter_.GetMatcher2(); }
const LookAheadSelector<Matcher1, Matcher2, MT> &Selector() const {
return selector_;
}
uint64 Properties(uint64 inprops) const {
uint64 outprops = filter_.Properties(inprops);
if (lookahead_type_ == MATCH_NONE)
outprops |= kError;
return outprops;
}
uint32 LookAheadFlags() const { return flags_; }
bool LookAheadArc() const { return lookahead_arc_; }
bool LookAheadOutput() const {
if (MT == MATCH_OUTPUT)
return true;
else if (MT == MATCH_INPUT)
return false;
else if (lookahead_type_ == MATCH_OUTPUT)
return true;
else
return false;
}
private:
FilterState LookAheadFilterArc(Arc *arca, Arc *arcb,
const FilterState &f) const {
Label &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
if (labela != 0 && !(flags_ & kLookAheadNonEpsilons))
return f;
if (labela == 0 && !(flags_ & kLookAheadEpsilons))
return f;
lookahead_arc_ = true;
selector_.GetMatcher()->SetState(arca->nextstate);
return selector_.GetMatcher()->LookAheadFst(selector_.GetFst(),
arcb->nextstate) ? f :
FilterState::NoState();
}
F filter_; // Underlying filter
MatchType lookahead_type_; // Lookahead match type
LookAheadSelector<Matcher1, Matcher2, MT> selector_;
uint32 flags_; // Lookahead flags
mutable bool lookahead_arc_; // Look-ahead performed at last FilterArc()?
void operator=(const LookAheadComposeFilter<F, M1, M2> &); // disallow
};
// This filter adds weight-pushing to a lookahead composition filter
// using the LookAheadWeight() method of matcher argument. It is
// templated on an underlying lookahead filter, typically the basic
// lookahead filter. Weight-pushing in composition brings weights
// forward as much as possible based on the lookahead information.
template <class F,
class M1 = LookAheadMatcher<typename F::FST1>,
class M2 = M1,
MatchType MT = MATCH_BOTH>
class PushWeightsComposeFilter {
public:
typedef typename F::FST1 FST1;
typedef typename F::FST2 FST2;
typedef typename F::Arc Arc;
typedef typename F::Matcher1 Matcher1;
typedef typename F::Matcher2 Matcher2;
typedef typename F::FilterState FilterState1;
typedef WeightFilterState<typename Arc::Weight> FilterState2;
typedef PairFilterState<FilterState1, FilterState2> FilterState;
typedef typename Arc::StateId StateId;
typedef typename Arc::Label Label;
typedef typename Arc::Weight Weight;
PushWeightsComposeFilter(const FST1 &fst1, const FST2 &fst2,
M1 *matcher1, M2 *matcher2)
: filter_(fst1, fst2, matcher1, matcher2),
f_(FilterState::NoState()) {}
PushWeightsComposeFilter(const PushWeightsComposeFilter<F, M1, M2, MT>
&filter,
bool safe = false)
: filter_(filter.filter_, safe),
f_(FilterState::NoState()) {}
FilterState Start() const {
return FilterState(filter_.Start(), FilterState2(Weight::One()));
}
void SetState(StateId s1, StateId s2, const FilterState &f) {
f_ = f;
filter_.SetState(s1, s2, f.GetState1());
}
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
const FilterState1 &f1 = filter_.FilterArc(arc1, arc2);
if (f1 == FilterState1::NoState())
return FilterState::NoState();
if (!(LookAheadFlags() & kLookAheadWeight))
return FilterState(f1, FilterState2(Weight::One()));
const Weight &lweight = filter_.LookAheadArc() ?
Selector().GetMatcher()->LookAheadWeight() : Weight::One();
const FilterState2 &f2 = f_.GetState2();
const Weight &fweight = f2.GetWeight();
arc2->weight = Divide(Times(arc2->weight, lweight), fweight);
return FilterState(f1, FilterState2(lweight));
}
void FilterFinal(Weight *weight1, Weight *weight2) const {
filter_.FilterFinal(weight1, weight2);
if (!(LookAheadFlags() & kLookAheadWeight) || *weight1 == Weight::Zero())
return;
const FilterState2 &f2 = f_.GetState2();
const Weight &fweight = f2.GetWeight();
*weight1 = Divide(*weight1, fweight);
}
// Return resp matchers. Ownership states with filter.
Matcher1 *GetMatcher1() { return filter_.GetMatcher1(); }
Matcher2 *GetMatcher2() { return filter_.GetMatcher2(); }
const LookAheadSelector<Matcher1, Matcher2, MT> &Selector() const {
return filter_.Selector();
}
uint32 LookAheadFlags() const { return filter_.LookAheadFlags(); }
bool LookAheadArc() const { return filter_.LookAheadArc(); }
bool LookAheadOutput() const { return filter_.LookAheadOutput(); }
uint64 Properties(uint64 props) const {
return filter_.Properties(props) & kWeightInvariantProperties;
}
private:
F filter_; // Underlying filter
FilterState f_; // Current filter state
void operator=(const PushWeightsComposeFilter<F, M1, M2, MT> &); // disallow
};
// This filter adds label-pushing to a lookahead composition filter
// using the LookAheadPrefix() method of the matcher argument. It is
// templated on an underlying filter, typically the basic lookahead
// or weight-pushing lookahead filter. Label-pushing in composition
// matches labels as early as possible based on the lookahead
// information.
template <class F,
class M1 = LookAheadMatcher<typename F::FST1>,
class M2 = M1,
MatchType MT = MATCH_BOTH>
class PushLabelsComposeFilter {
public:
typedef typename F::FST1 FST1;
typedef typename F::FST2 FST2;
typedef typename F::Arc Arc;
typedef typename Arc::StateId StateId;
typedef typename Arc::Label Label;
typedef typename Arc::Weight Weight;
typedef MultiEpsMatcher<typename F::Matcher1> Matcher1;
typedef MultiEpsMatcher<typename F::Matcher2> Matcher2;
typedef typename F::FilterState FilterState1;
typedef IntegerFilterState<typename Arc::Label> FilterState2;
typedef PairFilterState<FilterState1, FilterState2> FilterState;
PushLabelsComposeFilter(const FST1 &fst1, const FST2 &fst2,
M1 *matcher1, M2 *matcher2)
: filter_(fst1, fst2, matcher1, matcher2),
f_(FilterState::NoState()),
fst1_(filter_.GetMatcher1()->GetFst()),
fst2_(filter_.GetMatcher2()->GetFst()),
matcher1_(fst1_, MATCH_OUTPUT,
filter_.LookAheadOutput() ? kMultiEpsList : kMultiEpsLoop,
filter_.GetMatcher1(),
false),
matcher2_(fst2_, MATCH_INPUT,
filter_.LookAheadOutput() ? kMultiEpsLoop : kMultiEpsList,
filter_.GetMatcher2(),
false) {}
PushLabelsComposeFilter(const PushLabelsComposeFilter<F, M1, M2, MT> &filter,
bool safe = false)
: filter_(filter.filter_, safe),
f_(FilterState::NoState()),
fst1_(filter_.GetMatcher1()->GetFst()),
fst2_(filter_.GetMatcher2()->GetFst()),
matcher1_(fst1_, MATCH_OUTPUT,
filter_.LookAheadOutput() ? kMultiEpsList : kMultiEpsLoop,
filter_.GetMatcher1(),
false),
matcher2_(fst2_, MATCH_INPUT,
filter_.LookAheadOutput() ? kMultiEpsLoop : kMultiEpsList,
filter_.GetMatcher2(),
false) {
}
FilterState Start() const {
return FilterState(filter_.Start(), FilterState2(kNoLabel));
}
void SetState(StateId s1, StateId s2, const FilterState &f) {
f_ = f;
filter_.SetState(s1, s2, f.GetState1());
if (!(LookAheadFlags() & kLookAheadPrefix))
return;
narcsa_ = LookAheadOutput() ? internal::NumArcs(fst1_, s1)
: internal::NumArcs(fst2_, s2);
const FilterState2 &f2 = f_.GetState2();
const Label &flabel = f2.GetState();
GetMatcher1()->ClearMultiEpsLabels();
GetMatcher2()->ClearMultiEpsLabels();
if (flabel != kNoLabel) { // Have a lookahead label?
GetMatcher1()->AddMultiEpsLabel(flabel); // Yes, make it a multi-epsilon
GetMatcher2()->AddMultiEpsLabel(flabel); // label so that it matches the
} // implicit epsilon arc to be
} // modified below when pushing.
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
if (!(LookAheadFlags() & kLookAheadPrefix))
return FilterState(filter_.FilterArc(arc1, arc2),
FilterState2(kNoLabel));
const FilterState2 &f2 = f_.GetState2();
const Label &flabel = f2.GetState();
if (flabel != kNoLabel) // Have a lookahead label?
return LookAheadOutput() ? PushedLabelFilterArc(arc1, arc2, flabel) :
PushedLabelFilterArc(arc2, arc1, flabel);
const FilterState1 &f1 = filter_.FilterArc(arc1, arc2);
if (f1 == FilterState1::NoState())
return FilterState::NoState();
if (!filter_.LookAheadArc())
return FilterState(f1, FilterState2(kNoLabel));
return LookAheadOutput() ? PushLabelFilterArc(arc1, arc2, f1) :
PushLabelFilterArc(arc2, arc1, f1);
}
void FilterFinal(Weight *weight1, Weight *weight2) const {
filter_.FilterFinal(weight1, weight2);
if (!(LookAheadFlags() & kLookAheadPrefix) ||
*weight1 == Weight::Zero())
return;
const FilterState2 &f2 = f_.GetState2();
const Label &flabel = f2.GetState();
if (flabel != kNoLabel)
*weight1 = Weight::Zero();
}
// Return resp matchers. Ownership states with filter.
Matcher1 *GetMatcher1() { return &matcher1_; }
Matcher2 *GetMatcher2() { return &matcher2_; }
uint64 Properties(uint64 iprops) const {
uint64 oprops = filter_.Properties(iprops);
if (LookAheadOutput())
return oprops & kOLabelInvariantProperties;
else
return oprops & kILabelInvariantProperties;
}
private:
const LookAheadSelector<typename F::Matcher1, typename F::Matcher2, MT>
&Selector() const {
return filter_.Selector();
}
// Consumes an already pushed label.
FilterState PushedLabelFilterArc(Arc *arca, Arc *arcb,
Label flabel) const {
Label &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
const Label &labelb = LookAheadOutput() ? arcb->ilabel : arcb->olabel;
if (labelb != kNoLabel) {
return FilterState::NoState(); // Block non- (multi-) epsilon label
} else if (labela == flabel) {
labela = 0; // Convert match to multi-eps to eps
return Start();
} else if (labela == 0) {
if (narcsa_ == 1)
return f_; // Take eps; keep state w/ label
Selector().GetMatcher()->SetState(arca->nextstate);
if (Selector().GetMatcher()->LookAheadLabel(flabel))
return f_; // Take eps; keep state w/ label
else
return FilterState::NoState(); // Block non-coaccessible path
} else {
return FilterState::NoState(); // Block mismatch to multi-eps label
}
}
// Pushes a label forward when possible.
FilterState PushLabelFilterArc(Arc *arca, Arc *arcb,
const FilterState1 &f1) const {
Label &labela = LookAheadOutput() ? arca->olabel : arca->ilabel;
const Label &labelb = LookAheadOutput() ? arcb->olabel : arcb->ilabel;
if (labelb != 0) // No place to push.
return FilterState(f1, FilterState2(kNoLabel));
if (labela != 0 && // Wrong lookahead prefix type?
LookAheadFlags() & kLookAheadNonEpsilonPrefix)
return FilterState(f1, FilterState2(kNoLabel));
Arc larc(kNoLabel, kNoLabel, Weight::Zero(), kNoStateId);
if (Selector().GetMatcher()->LookAheadPrefix(&larc)) { // Have prefix arc?
labela = LookAheadOutput() ? larc.ilabel : larc.olabel;
arcb->ilabel = larc.ilabel; // Yes, go forward on that arc,
arcb->olabel = larc.olabel; // thus pushing the label.
arcb->weight = Times(arcb->weight, larc.weight);
arcb->nextstate = larc.nextstate;
return FilterState(f1, FilterState2(labela));
} else {
return FilterState(f1, FilterState2(kNoLabel));
}
}
uint32 LookAheadFlags() const { return filter_.LookAheadFlags(); }
bool LookAheadArc() const { return filter_.LookAheadArc(); }
bool LookAheadOutput() const { return filter_.LookAheadOutput(); }
F filter_; // Underlying filter
FilterState f_ ; // Current filter state
const FST1 &fst1_;
const FST2 &fst2_;
Matcher1 matcher1_; // Multi-epsilon matcher for fst1
Matcher2 matcher2_; // Multi-epsilon matcher for fst2
ssize_t narcsa_; // Number of arcs leaving look-ahead match FST
void operator=(const PushLabelsComposeFilter<F, M1, M2, MT> &); // disallow
};
//
// CONVENIENCE CLASS useful for setting up composition with a default
// look-ahead matcher and filter.
//
template <class A, MatchType type> // MATCH_NONE
class DefaultLookAhead {
public:
typedef Matcher< Fst<A> > M;
typedef SequenceComposeFilter<M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for MATCH_INPUT to allow lookahead.
template <class A>
class DefaultLookAhead<A, MATCH_INPUT> {
public:
typedef LookAheadMatcher< Fst<A> > M;
typedef SequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for MATCH_OUTPUT to allow lookahead.
template <class A>
class DefaultLookAhead<A, MATCH_OUTPUT> {
public:
typedef LookAheadMatcher< Fst<A> > M;
typedef AltSequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for StdArc to allow weight and label pushing.
template <>
class DefaultLookAhead<StdArc, MATCH_INPUT> {
public:
typedef StdArc A;
typedef LookAheadMatcher< Fst<A> > M;
typedef SequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> LF;
typedef PushWeightsComposeFilter<LF, M> WF;
typedef PushLabelsComposeFilter<WF, M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for StdArc to allow weight and label pushing.
template <>
class DefaultLookAhead<StdArc, MATCH_OUTPUT> {
public:
typedef StdArc A;
typedef LookAheadMatcher< Fst<A> > M;
typedef AltSequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> LF;
typedef PushWeightsComposeFilter<LF, M> WF;
typedef PushLabelsComposeFilter<WF, M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for LogArc to allow weight and label pushing.
template <>
class DefaultLookAhead<LogArc, MATCH_INPUT> {
public:
typedef LogArc A;
typedef LookAheadMatcher< Fst<A> > M;
typedef SequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> LF;
typedef PushWeightsComposeFilter<LF, M> WF;
typedef PushLabelsComposeFilter<WF, M> ComposeFilter;
typedef M FstMatcher;
};
// Specializes for LogArc to allow weight and label pushing.
template <>
class DefaultLookAhead<LogArc, MATCH_OUTPUT> {
public:
typedef LogArc A;
typedef LookAheadMatcher< Fst<A> > M;
typedef AltSequenceComposeFilter<M> SF;
typedef LookAheadComposeFilter<SF, M> LF;
typedef PushWeightsComposeFilter<LF, M> WF;
typedef PushLabelsComposeFilter<WF, M> ComposeFilter;
typedef M FstMatcher;
};
} // namespace fst
#endif // FST_LIB_LOOKAHEAD_FILTER_H__