FST  openfst-1.8.4
OpenFst Library
state-reachable.h
Go to the documentation of this file.
1 // Copyright 2005-2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the 'License');
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an 'AS IS' BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // See www.openfst.org for extensive documentation on this weighted
16 // finite-state transducer library.
17 //
18 // Class to determine whether a given (final) state can be reached from some
19 // other given state.
20 
21 #ifndef FST_STATE_REACHABLE_H_
22 #define FST_STATE_REACHABLE_H_
23 
24 #include <cstddef>
25 #include <cstdlib>
26 #include <vector>
27 
28 #include <fst/log.h>
29 #include <fst/connect.h>
30 #include <fst/dfs-visit.h>
31 #include <fst/fst.h>
32 #include <fst/interval-set.h>
33 #include <fst/properties.h>
34 #include <fst/util.h>
35 #include <fst/vector-fst.h>
36 
37 namespace fst {
38 
39 // Computes the (final) states reachable from a given state in an FST. After
40 // this visitor has been called, a final state f can be reached from a state
41 // s iff (*isets)[s].Member(state2index[f]) is true, where (*isets[s]) is a
42 // set of half-open interval of final state indices and state2index[f] maps from
43 // a final state to its index. If state2index is empty, it is filled-in with
44 // suitable indices. If it is non-empty, those indices are used; in this case,
45 // the final states must have out-degree 0.
46 template <class Arc, class I = typename Arc::StateId, class S = IntervalSet<I>>
48  public:
49  using Label = typename Arc::Label;
50  using StateId = typename Arc::StateId;
51  using Weight = typename Arc::Weight;
52 
53  using Index = I;
54  using ISet = S;
55  using Interval = typename ISet::Interval;
56 
57  IntervalReachVisitor(const Fst<Arc> &fst, std::vector<S> *isets,
58  std::vector<Index> *state2index)
59  : fst_(fst),
60  isets_(isets),
61  state2index_(state2index),
62  index_(state2index->empty() ? 1 : -1),
63  error_(false) {
64  isets_->clear();
65  }
66 
67  void InitVisit(const Fst<Arc> &) { error_ = false; }
68 
69  bool InitState(StateId s, StateId r) {
70  while (isets_->size() <= s) isets_->push_back(S());
71  while (state2index_->size() <= s) state2index_->push_back(-1);
72  if (fst_.Final(s) != Weight::Zero()) {
73  // Create tree interval.
74  auto *intervals = (*isets_)[s].MutableIntervals();
75  if (index_ < 0) { // Uses state2index_ map to set index.
76  if (fst_.NumArcs(s) > 0) {
77  FSTERROR() << "IntervalReachVisitor: state2index map must be empty "
78  << "for this FST";
79  error_ = true;
80  return false;
81  }
82  const auto index = (*state2index_)[s];
83  if (index < 0) {
84  FSTERROR() << "IntervalReachVisitor: state2index map incomplete";
85  error_ = true;
86  return false;
87  }
88  intervals->push_back(Interval(index, index + 1));
89  } else { // Use pre-order index.
90  intervals->push_back(Interval(index_, index_ + 1));
91  (*state2index_)[s] = index_++;
92  }
93  }
94  return true;
95  }
96 
97  constexpr bool TreeArc(StateId, const Arc &) const { return true; }
98 
99  bool BackArc(StateId s, const Arc &arc) {
100  FSTERROR() << "IntervalReachVisitor: Cyclic input";
101  error_ = true;
102  return false;
103  }
104 
105  bool ForwardOrCrossArc(StateId s, const Arc &arc) {
106  // Non-tree interval.
107  (*isets_)[s].Union((*isets_)[arc.nextstate]);
108  return true;
109  }
110 
111  void FinishState(StateId s, StateId p, const Arc *) {
112  if (index_ >= 0 && fst_.Final(s) != Weight::Zero()) {
113  auto *intervals = (*isets_)[s].MutableIntervals();
114  (*intervals)[0].end = index_; // Updates tree interval end.
115  }
116  (*isets_)[s].Normalize();
117  if (p != kNoStateId) {
118  (*isets_)[p].Union((*isets_)[s]); // Propagates intervals to parent.
119  }
120  }
121 
122  void FinishVisit() {}
123 
124  bool Error() const { return error_; }
125 
126  private:
127  const Fst<Arc> &fst_;
128  std::vector<ISet> *isets_;
129  std::vector<Index> *state2index_;
130  Index index_;
131  bool error_;
132 };
133 
134 // Tests reachability of final states from a given state. To test for
135 // reachability from a state s, first do SetState(s). Then a final state f can
136 // be reached from state s of FST iff Reach(f) is true. The input can be cyclic,
137 // but no cycle may contain a final state.
138 template <class Arc, class I = typename Arc::StateId, class S = IntervalSet<I>>
140  public:
141  using Label = typename Arc::Label;
142  using StateId = typename Arc::StateId;
143  using Weight = typename Arc::Weight;
144 
145  using Index = I;
146  using ISet = S;
147  using Interval = typename ISet::Interval;
148 
149  explicit StateReachable(const Fst<Arc> &fst) : error_(false) {
150  if (fst.Properties(kAcyclic, true)) {
151  AcyclicStateReachable(fst);
152  } else {
153  CyclicStateReachable(fst);
154  }
155  }
156 
157  explicit StateReachable(const StateReachable<Arc> &reachable) {
158  FSTERROR() << "Copy constructor for state reachable class "
159  << "not implemented.";
160  error_ = true;
161  }
162 
163  // Sets current state.
164  void SetState(StateId s) { s_ = s; }
165 
166  // Can reach this final state from current state?
167  bool Reach(StateId s) {
168  if (s >= state2index_.size()) return false;
169  const auto i = state2index_[s];
170  if (i < 0) {
171  FSTERROR() << "StateReachable: State non-final: " << s;
172  error_ = true;
173  return false;
174  }
175  return isets_[s_].Member(i);
176  }
177 
178  // Access to the state-to-index mapping. Unassigned states have index -1.
179  std::vector<Index> &State2Index() { return state2index_; }
180 
181  // Access to the interval sets. These specify the reachability to the final
182  // states as intervals of the final state indices.
183  const std::vector<ISet> &IntervalSets() { return isets_; }
184 
185  bool Error() const { return error_; }
186 
187  private:
188  void AcyclicStateReachable(const Fst<Arc> &fst) {
189  IntervalReachVisitor<Arc, StateId, ISet> reach_visitor(fst, &isets_,
190  &state2index_);
191  DfsVisit(fst, &reach_visitor);
192  if (reach_visitor.Error()) error_ = true;
193  }
194 
195  void CyclicStateReachable(const Fst<Arc> &fst) {
196  // Finds state reachability on the acyclic condensation FST.
197  VectorFst<Arc> cfst;
198  std::vector<StateId> scc;
199  Condense(fst, &cfst, &scc);
200  StateReachable reachable(cfst);
201  if (reachable.Error()) {
202  error_ = true;
203  return;
204  }
205  // Gets the number of states per SCC.
206  std::vector<size_t> nscc;
207  for (StateId s = 0; s < scc.size(); ++s) {
208  const auto c = scc[s];
209  while (c >= nscc.size()) nscc.push_back(0);
210  ++nscc[c];
211  }
212  // Constructs the interval sets and state index mapping for the original
213  // FST from the condensation FST.
214  state2index_.resize(scc.size(), -1);
215  isets_.resize(scc.size());
216  for (StateId s = 0; s < scc.size(); ++s) {
217  const auto c = scc[s];
218  isets_[s] = reachable.IntervalSets()[c];
219  state2index_[s] = reachable.State2Index()[c];
220  // Checks that each final state in an input FST is not contained in a
221  // cycle (i.e., not in a non-trivial SCC).
222  if (cfst.Final(c) != Weight::Zero() && nscc[c] > 1) {
223  FSTERROR() << "StateReachable: Final state contained in a cycle";
224  error_ = true;
225  return;
226  }
227  }
228  }
229 
230  StateId s_; // Current state.
231  std::vector<ISet> isets_; // Interval sets per state.
232  std::vector<Index> state2index_; // Finds index for a final state.
233  bool error_;
234 
235  StateReachable &operator=(const StateReachable &) = delete;
236 };
237 
238 } // namespace fst
239 
240 #endif // FST_STATE_REACHABLE_H_
bool InitState(StateId s, StateId r)
IntervalReachVisitor(const Fst< Arc > &fst, std::vector< S > *isets, std::vector< Index > *state2index)
void InitVisit(const Fst< Arc > &)
const std::vector< ISet > & IntervalSets()
virtual uint64_t Properties(uint64_t mask, bool test) const =0
StateReachable(const StateReachable< Arc > &reachable)
bool ForwardOrCrossArc(StateId s, const Arc &arc)
std::vector< Index > & State2Index()
virtual size_t NumArcs(StateId) const =0
bool BackArc(StateId s, const Arc &arc)
typename Arc::StateId StateId
void DfsVisit(const FST &fst, Visitor *visitor, ArcFilter filter, bool access_only=false)
Definition: dfs-visit.h:112
virtual Weight Final(StateId) const =0
typename ISet::Interval Interval
Weight Final(StateId s) const override
Definition: impl-to-fst.h:50
typename Arc::Weight Weight
constexpr int kNoStateId
Definition: fst.h:195
typename Arc::StateId StateId
constexpr bool TreeArc(StateId, const Arc &) const
#define FSTERROR()
Definition: util.h:57
typename ISet::Interval Interval
constexpr uint64_t kAcyclic
Definition: properties.h:111
typename Arc::Weight Weight
typename Arc::Label Label
void SetState(StateId s)
typename Arc::Label Label
bool Reach(StateId s)
void Condense(const Fst< Arc > &ifst, MutableFst< Arc > *ofst, std::vector< typename Arc::StateId > *scc)
Definition: connect.h:67
StateReachable(const Fst< Arc > &fst)
void FinishState(StateId s, StateId p, const Arc *)