|
// Copyright 2005-2024 Google LLC
|
|
//
|
|
// 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.
|
|
//
|
|
// See www.openfst.org for extensive documentation on this weighted
|
|
// finite-state transducer library.
|
|
//
|
|
// Classes for filtering the composition matches, e.g. for correct epsilon
|
|
// handling.
|
|
|
|
#ifndef FST_COMPOSE_FILTER_H_
|
|
#define FST_COMPOSE_FILTER_H_
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
|
|
#include <fst/filter-state.h>
|
|
#include <fst/fst-decl.h> // For optional argument declarations
|
|
#include <fst/fst.h>
|
|
#include <fst/matcher.h>
|
|
#include <fst/properties.h>
|
|
|
|
namespace fst {
|
|
|
|
// Composition filters determine which matches are allowed to proceed. The
|
|
// filter's state is represeted by the type ComposeFilter::FilterState.
|
|
// The basic filters handle correct epsilon matching. Their interface is:
|
|
//
|
|
// template <class M1, class M2>
|
|
// class ComposeFilter {
|
|
// public:
|
|
// using Matcher1 = ...;
|
|
// using Matcher2 = ...;
|
|
// using FST1 = typename M1::FST;
|
|
// using FST2 = typename M2::FST;
|
|
// using FilterState = ...;
|
|
//
|
|
// using Arc = typename FST1::Arc;
|
|
// using StateId = typename Arc::StateId;
|
|
// using Weight = typename Arc::Weight;
|
|
//
|
|
// // Required constructor.
|
|
// ComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
// M1 *matcher1 = nullptr, M2 *matcher2 = nullptr);
|
|
//
|
|
// // If safe=true, the copy is thread-safe. See Fst<>::Copy()
|
|
// // for further doc.
|
|
// ComposeFilter(const ComposeFilter<M1, M2> &filter,
|
|
// bool safe = false);
|
|
//
|
|
// // Return start state of filter.
|
|
// FilterState Start() const;
|
|
//
|
|
// // Specifies current composition state.
|
|
// void SetState(StateId s1, StateId s2, const FilterState &fs);
|
|
//
|
|
// // Apply filter at current composition state to these transitions. If an
|
|
// // arc label to be matched is kNolabel, then that side does not consume a
|
|
// // symbol. Returns the new filter state or, if disallowed,
|
|
// // FilterState::NoState(). The filter is permitted to modify its inputs
|
|
// // (e.g. for optimization reasons).
|
|
// FilterState FilterArc(Arc *arc1, Arc *arc2) const;
|
|
|
|
// // Apply filter at current composition state to these final weights
|
|
// // (cf. superfinal transitions). The filter may modify its inputs
|
|
// // (e.g. for optimization reasons).
|
|
// void FilterFinal(Weight *w1, Weight *w2) const;
|
|
//
|
|
// // Return the respective matchers. Ownership stays with filter. These
|
|
// // methods allow the filter to access and possibly modify the compositio
|
|
// // matchers (useful, e.g., with lookahead).
|
|
//
|
|
// Matcher1 *GetMatcher1();
|
|
//
|
|
// Matcher2 *GetMatcher2();
|
|
//
|
|
// // This specifies how the filter affects the composition result properties.
|
|
// It takes as argument the properties that would apply with a trivial
|
|
// // composition filter.
|
|
// uint64_t Properties(uint64_t props) const;
|
|
// };
|
|
//
|
|
// This filter allows only exact matching of symbols from FST1 with on FST2;
|
|
// e.g., no special interpretation of epsilons.
|
|
template <class M1, class M2 /* = M1 */>
|
|
class NullComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = TrivialFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
NullComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr, Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
NullComposeFilter(const NullComposeFilter &filter, bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
FilterState Start() const { return FilterState(true); }
|
|
|
|
void SetState(StateId, StateId, const FilterState &) {}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
return (arc1->olabel == kNoLabel || arc2->ilabel == kNoLabel)
|
|
? FilterState::NoState()
|
|
: FilterState(true);
|
|
}
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST1 &fst1_;
|
|
const FST2 &fst2_;
|
|
};
|
|
|
|
// This filter allows all epsilon matches, potentially resulting in redundant
|
|
// epsilon paths. The use of this filter gives correct results iff one of the
|
|
// following conditions hold:
|
|
//
|
|
// (1) The semiring is idempotent,
|
|
// (2) the first FST is output-epsilon free, or
|
|
// (3) the second FST is input-epsilon free.
|
|
//
|
|
// For (1), redundant epsilon paths may be created but won't hurt correctness.
|
|
// For (2) and (3), no redundant paths are created.
|
|
template <class M1, class M2 /* = M1 */>
|
|
class TrivialComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = TrivialFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
TrivialComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr,
|
|
Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
TrivialComposeFilter(const TrivialComposeFilter<Matcher1, Matcher2> &filter,
|
|
bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
FilterState Start() const { return FilterState(true); }
|
|
|
|
void SetState(StateId, StateId, const FilterState &) {}
|
|
|
|
FilterState FilterArc(Arc *, Arc *) const { return FilterState(true); }
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST1 &fst1_;
|
|
const FST2 &fst2_;
|
|
};
|
|
|
|
// This filter requires epsilons on FST1 to be read before epsilons on FST2.
|
|
template <class M1, class M2 /* = M1 */>
|
|
class SequenceComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = CharFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
SequenceComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr,
|
|
Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst1_(matcher1_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
SequenceComposeFilter(const SequenceComposeFilter<Matcher1, Matcher2> &filter,
|
|
bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst1_(matcher1_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
FilterState Start() const { return FilterState(0); }
|
|
|
|
void SetState(StateId s1, StateId s2, const FilterState &fs) {
|
|
if (s1_ == s1 && s2_ == s2 && fs == fs_) return;
|
|
s1_ = s1;
|
|
s2_ = s2;
|
|
fs_ = fs;
|
|
const auto na1 = internal::NumArcs(fst1_, s1);
|
|
const auto ne1 = internal::NumOutputEpsilons(fst1_, s1);
|
|
const bool fin1 = internal::Final(fst1_, s1) != Weight::Zero();
|
|
alleps1_ = na1 == ne1 && !fin1;
|
|
noeps1_ = ne1 == 0;
|
|
}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
if (arc1->olabel == kNoLabel) {
|
|
return alleps1_ ? FilterState::NoState()
|
|
: noeps1_ ? FilterState(0)
|
|
: FilterState(1);
|
|
} else if (arc2->ilabel == kNoLabel) {
|
|
return fs_ != FilterState(0) ? FilterState::NoState() : FilterState(0);
|
|
} else {
|
|
return arc1->olabel == 0 ? FilterState::NoState() : FilterState(0);
|
|
}
|
|
}
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST1 &fst1_;
|
|
StateId s1_; // Current fst1_ state.
|
|
StateId s2_; // Current fst2_ state.
|
|
FilterState fs_; // Current filter state.
|
|
bool alleps1_; // Only epsilons (and non-final) leaving s1_?
|
|
bool noeps1_; // No epsilons leaving s1_?
|
|
};
|
|
|
|
// This filter requires epsilons on FST2 to be read before epsilons on FST1.
|
|
template <class M1, class M2 /* = M1 */>
|
|
class AltSequenceComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = CharFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
AltSequenceComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr,
|
|
Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst2_(matcher2_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
AltSequenceComposeFilter(
|
|
const AltSequenceComposeFilter<Matcher1, Matcher2> &filter,
|
|
bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst2_(matcher2_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
FilterState Start() const { return FilterState(0); }
|
|
|
|
void SetState(StateId s1, StateId s2, const FilterState &fs) {
|
|
if (s1_ == s1 && s2_ == s2 && fs == fs_) return;
|
|
s1_ = s1;
|
|
s2_ = s2;
|
|
fs_ = fs;
|
|
const auto na2 = internal::NumArcs(fst2_, s2);
|
|
const auto ne2 = internal::NumInputEpsilons(fst2_, s2);
|
|
const bool fin2 = internal::Final(fst2_, s2) != Weight::Zero();
|
|
alleps2_ = na2 == ne2 && !fin2;
|
|
noeps2_ = ne2 == 0;
|
|
}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
if (arc2->ilabel == kNoLabel) {
|
|
return alleps2_ ? FilterState::NoState()
|
|
: noeps2_ ? FilterState(0)
|
|
: FilterState(1);
|
|
} else if (arc1->olabel == kNoLabel) {
|
|
return fs_ == FilterState(1) ? FilterState::NoState() : FilterState(0);
|
|
} else {
|
|
return arc1->olabel == 0 ? FilterState::NoState() : FilterState(0);
|
|
}
|
|
}
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST2 &fst2_;
|
|
StateId s1_; // Current fst1_ state.
|
|
StateId s2_; // Current fst2_ state.
|
|
FilterState fs_; // Current filter state.
|
|
bool alleps2_; // Only epsilons (and non-final) leaving s2_?
|
|
bool noeps2_; // No epsilons leaving s2_?
|
|
};
|
|
|
|
// This filter requires epsilons on FST1 to be matched with epsilons on FST2
|
|
// whenever possible. (Template arg default declared in fst-decl.h.)
|
|
template <class M1, class M2 /* = M1 */>
|
|
class MatchComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = CharFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
MatchComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr, Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
MatchComposeFilter(const MatchComposeFilter<Matcher1, Matcher2> &filter,
|
|
bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()),
|
|
s1_(kNoStateId),
|
|
s2_(kNoStateId),
|
|
fs_(kNoStateId) {}
|
|
|
|
FilterState Start() const { return FilterState(0); }
|
|
|
|
void SetState(StateId s1, StateId s2, const FilterState &fs) {
|
|
if (s1_ == s1 && s2_ == s2 && fs == fs_) return;
|
|
s1_ = s1;
|
|
s2_ = s2;
|
|
fs_ = fs;
|
|
size_t na1 = internal::NumArcs(fst1_, s1);
|
|
size_t ne1 = internal::NumOutputEpsilons(fst1_, s1);
|
|
bool f1 = internal::Final(fst1_, s1) != Weight::Zero();
|
|
alleps1_ = na1 == ne1 && !f1;
|
|
noeps1_ = ne1 == 0;
|
|
size_t na2 = internal::NumArcs(fst2_, s2);
|
|
size_t ne2 = internal::NumInputEpsilons(fst2_, s2);
|
|
bool f2 = internal::Final(fst2_, s2) != Weight::Zero();
|
|
alleps2_ = na2 == ne2 && !f2;
|
|
noeps2_ = ne2 == 0;
|
|
}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
if (arc2->ilabel == kNoLabel) { // Epsilon in FST1.
|
|
return fs_ == FilterState(0)
|
|
? (noeps2_
|
|
? FilterState(0)
|
|
: (alleps2_ ? FilterState::NoState() : FilterState(1)))
|
|
: (fs_ == FilterState(1) ? FilterState(1)
|
|
: FilterState::NoState());
|
|
} else if (arc1->olabel == kNoLabel) { // Epsilon in FST2.
|
|
return fs_ == FilterState(0)
|
|
? (noeps1_
|
|
? FilterState(0)
|
|
: (alleps1_ ? FilterState::NoState() : FilterState(2)))
|
|
: (fs_ == FilterState(2) ? FilterState(2)
|
|
: FilterState::NoState());
|
|
} else if (arc1->olabel == 0) { // Epsilon in both.
|
|
return fs_ == FilterState(0) ? FilterState(0) : FilterState::NoState();
|
|
} else { // Both are non-epsilons.
|
|
return FilterState(0);
|
|
}
|
|
}
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST1 &fst1_;
|
|
const FST2 &fst2_;
|
|
StateId s1_; // Current fst1_ state.
|
|
StateId s2_; // Current fst2_ state.
|
|
FilterState fs_; // Current filter state ID.
|
|
bool alleps1_; // Only epsilson (and non-final) leaving s1?
|
|
bool alleps2_; // Only epsilons (and non-final) leaving s2?
|
|
bool noeps1_; // No epsilons leaving s1?
|
|
bool noeps2_; // No epsilons leaving s2?
|
|
};
|
|
|
|
// This filter disallows matching epsilons on FST1 with epsilons on FST2,
|
|
// but allows all other matches, potentially resulting in redundant
|
|
// epsilon paths. The use of this filter gives correct results iff one of the
|
|
// following conditions hold:
|
|
//
|
|
// (1) The semiring is idempotent,
|
|
// (2) the first FST is output-epsilon free, or
|
|
// (3) the second FST is input-epsilon free.
|
|
//
|
|
// For (1), redundant epsilon paths may be created but won't hurt correctness.
|
|
// For (2) and (3), no redundant paths are created.
|
|
template <class M1, class M2 /* = M1 */>
|
|
class NoMatchComposeFilter {
|
|
public:
|
|
using Matcher1 = M1;
|
|
using Matcher2 = M2;
|
|
using FST1 = typename M1::FST;
|
|
using FST2 = typename M2::FST;
|
|
using FilterState = TrivialFilterState;
|
|
|
|
using Arc = typename FST1::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
NoMatchComposeFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr,
|
|
Matcher2 *matcher2 = nullptr)
|
|
: matcher1_(matcher1 ? matcher1 : new Matcher1(fst1, MATCH_OUTPUT)),
|
|
matcher2_(matcher2 ? matcher2 : new Matcher2(fst2, MATCH_INPUT)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
NoMatchComposeFilter(const NoMatchComposeFilter<Matcher1, Matcher2> &filter,
|
|
bool safe = false)
|
|
: matcher1_(filter.matcher1_->Copy(safe)),
|
|
matcher2_(filter.matcher2_->Copy(safe)),
|
|
fst1_(matcher1_->GetFst()),
|
|
fst2_(matcher2_->GetFst()) {}
|
|
|
|
FilterState Start() const { return FilterState(true); }
|
|
|
|
void SetState(StateId, StateId, const FilterState &) {}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
return FilterState(arc1->olabel != 0 || arc2->ilabel != 0);
|
|
}
|
|
|
|
void FilterFinal(Weight *, Weight *) const {}
|
|
|
|
Matcher1 *GetMatcher1() { return matcher1_.get(); }
|
|
|
|
Matcher2 *GetMatcher2() { return matcher2_.get(); }
|
|
|
|
uint64_t Properties(uint64_t props) const { return props; }
|
|
|
|
private:
|
|
std::unique_ptr<Matcher1> matcher1_;
|
|
std::unique_ptr<Matcher2> matcher2_;
|
|
const FST1 &fst1_;
|
|
const FST2 &fst2_;
|
|
};
|
|
|
|
// This filter works with the MultiEpsMatcher to determine if multi-epsilons are
|
|
// preserved in the composition output (rather than rewritten as 0) and
|
|
// ensures correct properties.
|
|
template <class Filter>
|
|
class MultiEpsFilter {
|
|
public:
|
|
using Matcher1 = typename Filter::Matcher1;
|
|
using Matcher2 = typename Filter::Matcher2;
|
|
using FST1 = typename Filter::FST1;
|
|
using FST2 = typename Filter::FST2;
|
|
using FilterState = typename Filter::FilterState;
|
|
|
|
using Arc = typename Filter::Arc;
|
|
using Label = typename Arc::Label;
|
|
using StateId = typename Arc::StateId;
|
|
using Weight = typename Arc::Weight;
|
|
|
|
MultiEpsFilter(const FST1 &fst1, const FST2 &fst2,
|
|
Matcher1 *matcher1 = nullptr, Matcher2 *matcher2 = nullptr,
|
|
bool keep_multi_eps = false)
|
|
: filter_(fst1, fst2, matcher1, matcher2),
|
|
keep_multi_eps_(keep_multi_eps) {}
|
|
|
|
MultiEpsFilter(const MultiEpsFilter &filter, bool safe = false)
|
|
: filter_(filter.filter_, safe),
|
|
keep_multi_eps_(filter.keep_multi_eps_) {}
|
|
|
|
FilterState Start() const { return filter_.Start(); }
|
|
|
|
void SetState(StateId s1, StateId s2, const FilterState &fs) {
|
|
return filter_.SetState(s1, s2, fs);
|
|
}
|
|
|
|
FilterState FilterArc(Arc *arc1, Arc *arc2) const {
|
|
const auto fs = filter_.FilterArc(arc1, arc2);
|
|
if (keep_multi_eps_) {
|
|
if (arc1->olabel == kNoLabel) arc1->ilabel = arc2->ilabel;
|
|
if (arc2->ilabel == kNoLabel) arc2->olabel = arc1->olabel;
|
|
}
|
|
return fs;
|
|
}
|
|
|
|
void FilterFinal(Weight *w1, Weight *w2) const {
|
|
return filter_.FilterFinal(w1, w2);
|
|
}
|
|
|
|
Matcher1 *GetMatcher1() { return filter_.GetMatcher1(); }
|
|
|
|
Matcher2 *GetMatcher2() { return filter_.GetMatcher2(); }
|
|
|
|
uint64_t Properties(uint64_t iprops) const {
|
|
const auto oprops = filter_.Properties(iprops);
|
|
return oprops & kILabelInvariantProperties & kOLabelInvariantProperties;
|
|
}
|
|
|
|
private:
|
|
Filter filter_;
|
|
bool keep_multi_eps_;
|
|
};
|
|
|
|
} // namespace fst
|
|
|
|
#endif // FST_COMPOSE_FILTER_H_
|