FST  openfst-1.8.3
OpenFst Library
minimize.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 // Functions and classes to minimize an FST.
19 
20 #ifndef FST_MINIMIZE_H_
21 #define FST_MINIMIZE_H_
22 
23 #include <algorithm>
24 #include <cmath>
25 #include <cstddef>
26 #include <map>
27 #include <memory>
28 #include <queue>
29 #include <utility>
30 #include <vector>
31 
32 #include <fst/log.h>
33 #include <fst/arc-map.h>
34 #include <fst/arc.h>
35 #include <fst/arcsort.h>
36 #include <fst/connect.h>
37 #include <fst/dfs-visit.h>
38 #include <fst/encode.h>
39 #include <fst/expanded-fst.h>
40 #include <fst/factor-weight.h>
41 #include <fst/fst.h>
42 #include <fst/mutable-fst.h>
43 #include <fst/partition.h>
44 #include <fst/properties.h>
45 #include <fst/push.h>
46 #include <fst/queue.h>
47 #include <fst/reverse.h>
48 #include <fst/reweight.h>
49 #include <fst/shortest-distance.h>
50 #include <fst/state-map.h>
51 #include <fst/string-weight.h>
52 #include <fst/symbol-table.h>
53 #include <fst/util.h>
54 #include <fst/vector-fst.h>
55 #include <fst/weight.h>
56 #include <unordered_map>
57 
58 namespace fst {
59 namespace internal {
60 
61 // Comparator for creating partition.
62 template <class Arc>
64  public:
65  using StateId = typename Arc::StateId;
66  using Weight = typename Arc::Weight;
67 
68  StateComparator(const Fst<Arc> &fst, const Partition<StateId> &partition)
69  : fst_(fst), partition_(partition) {}
70 
71  // Compares state x with state y based on sort criteria.
72  bool operator()(const StateId x, const StateId y) const {
73  // Checks for final state equivalence.
74  const auto xfinal = fst_.Final(x).Hash();
75  const auto yfinal = fst_.Final(y).Hash();
76  if (xfinal < yfinal) {
77  return true;
78  } else if (xfinal > yfinal) {
79  return false;
80  }
81  // Checks for number of arcs.
82  if (fst_.NumArcs(x) < fst_.NumArcs(y)) return true;
83  if (fst_.NumArcs(x) > fst_.NumArcs(y)) return false;
84  // If the number of arcs are equal, checks for arc match.
85  for (ArcIterator<Fst<Arc>> aiter1(fst_, x), aiter2(fst_, y);
86  !aiter1.Done() && !aiter2.Done(); aiter1.Next(), aiter2.Next()) {
87  const auto &arc1 = aiter1.Value();
88  const auto &arc2 = aiter2.Value();
89  if (arc1.ilabel < arc2.ilabel) return true;
90  if (arc1.ilabel > arc2.ilabel) return false;
91  if (partition_.ClassId(arc1.nextstate) <
92  partition_.ClassId(arc2.nextstate))
93  return true;
94  if (partition_.ClassId(arc1.nextstate) >
95  partition_.ClassId(arc2.nextstate))
96  return false;
97  }
98  return false;
99  }
100 
101  private:
102  const Fst<Arc> &fst_;
103  const Partition<StateId> &partition_;
104 };
105 
106 // Computes equivalence classes for cyclic unweighted acceptors. For cyclic
107 // minimization we use the classic Hopcroft minimization algorithm, which has
108 // complexity O(E log V) where E is the number of arcs and V is the number of
109 // states.
110 //
111 // For more information, see:
112 //
113 // Hopcroft, J. 1971. An n Log n algorithm for minimizing states in a finite
114 // automaton. Ms, Stanford University.
115 //
116 // Note: the original presentation of the paper was for a finite automaton (==
117 // deterministic, unweighted acceptor), but we also apply it to the
118 // nondeterministic case, where it is also applicable as long as the semiring is
119 // idempotent (if the semiring is not idempotent, there are some complexities
120 // in keeping track of the weight when there are multiple arcs to states that
121 // will be merged, and we don't deal with this).
122 template <class Arc, class Queue>
124  public:
125  using Label = typename Arc::Label;
126  using StateId = typename Arc::StateId;
127  using ClassId = typename Arc::StateId;
128  using Weight = typename Arc::Weight;
131  // TODO(wolfsonkin): Consider storing ArcIterator<> directly rather than in
132  // unique_ptr when ArcIterator<Fst<>> is made movable.
133  using RevArcIterPtr = std::unique_ptr<RevArcIter>;
134 
136  Initialize(fst);
137  Compute(fst);
138  }
139 
140  const Partition<StateId> &GetPartition() const { return P_; }
141 
142  private:
143  // StateILabelHasher is a hashing object that computes a hash-function
144  // of an FST state that depends only on the set of ilabels on arcs leaving
145  // the state [note: it assumes that the arcs are ilabel-sorted].
146  // In order to work correctly for non-deterministic automata, multiple
147  // instances of the same ilabel count the same as a single instance.
148  class StateILabelHasher {
149  public:
150  explicit StateILabelHasher(const Fst<Arc> &fst) : fst_(fst) {}
151 
152  using Label = typename Arc::Label;
153  using StateId = typename Arc::StateId;
154 
155  size_t operator()(const StateId s) {
156  const size_t p1 = 7603;
157  const size_t p2 = 433024223;
158  size_t result = p2;
159  size_t current_ilabel = kNoLabel;
160  for (ArcIterator<Fst<Arc>> aiter(fst_, s); !aiter.Done(); aiter.Next()) {
161  const Label this_ilabel = aiter.Value().ilabel;
162  if (this_ilabel != current_ilabel) { // Ignores repeats.
163  result = p1 * result + this_ilabel;
164  current_ilabel = this_ilabel;
165  }
166  }
167  return result;
168  }
169 
170  private:
171  const Fst<Arc> &fst_;
172  };
173 
174  class ArcIterCompare {
175  public:
176  // Compares two iterators based on their input labels.
177  bool operator()(const RevArcIterPtr &x, const RevArcIterPtr &y) const {
178  const auto &xarc = x->Value();
179  const auto &yarc = y->Value();
180  return xarc.ilabel > yarc.ilabel;
181  }
182  };
183 
184  using ArcIterQueue =
185  std::priority_queue<RevArcIterPtr, std::vector<RevArcIterPtr>,
186  ArcIterCompare>;
187 
188  private:
189  // Prepartitions the space into equivalence classes. We ensure that final and
190  // non-final states always go into different equivalence classes, and we use
191  // class StateILabelHasher to make sure that most of the time, states with
192  // different sets of ilabels on arcs leaving them, go to different partitions.
193  // Note: for the O(n) guarantees we don't rely on the goodness of this
194  // hashing function---it just provides a bonus speedup.
195  void PrePartition(const ExpandedFst<Arc> &fst) {
196  VLOG(5) << "PrePartition";
197  StateId next_class = 0;
198  auto num_states = fst.NumStates();
199  // Allocates a temporary vector to store the initial class mappings, so that
200  // we can allocate the classes all at once.
201  std::vector<StateId> state_to_initial_class(num_states);
202  {
203  // We maintain two maps from hash-value to class---one for final states
204  // (final-prob == One()) and one for non-final states
205  // (final-prob == Zero()). We are processing unweighted acceptors, so the
206  // are the only two possible values.
207  using HashToClassMap = std::unordered_map<size_t, StateId>;
208  HashToClassMap hash_to_class_nonfinal;
209  HashToClassMap hash_to_class_final;
210  StateILabelHasher hasher(fst);
211  for (StateId s = 0; s < num_states; ++s) {
212  size_t hash = hasher(s);
213  HashToClassMap &this_map =
214  (fst.Final(s) != Weight::Zero() ? hash_to_class_final
215  : hash_to_class_nonfinal);
216  // Avoids two map lookups by using 'insert' instead of 'find'.
217  auto p = this_map.emplace(hash, next_class);
218  state_to_initial_class[s] = p.second ? next_class++ : p.first->second;
219  }
220  // Lets the maps go out of scope before we allocate the classes,
221  // to reduce the maximum amount of memory used.
222  }
223  P_.AllocateClasses(next_class);
224  for (StateId s = 0; s < num_states; ++s) {
225  P_.Add(s, state_to_initial_class[s]);
226  }
227  for (StateId c = 0; c < next_class; ++c) L_.Enqueue(c);
228  VLOG(5) << "Initial Partition: " << P_.NumClasses();
229  }
230 
231  // Creates inverse transition Tr_ = rev(fst), loops over states in FST and
232  // splits on final, creating two blocks in the partition corresponding to
233  // final, non-final.
234  void Initialize(const ExpandedFst<Arc> &fst) {
235  // Constructs Tr.
236  Reverse(fst, &Tr_);
237  static const ILabelCompare<RevArc> icomp;
238  ArcSort(&Tr_, icomp);
239  // Tells the partition how many elements to allocate. The first state in
240  // Tr_ is super-final state.
241  P_.Initialize(Tr_.NumStates() - 1);
242  // Prepares initial partition.
243  PrePartition(fst);
244  // Allocates arc iterator queue.
245  aiter_queue_ = std::make_unique<ArcIterQueue>();
246  }
247  // Partitions all classes with destination C.
248  void Split(ClassId C) {
249  // Prepares priority queue: opens arc iterator for each state in C, and
250  // inserts into priority queue.
251  for (PartitionIterator<StateId> siter(P_, C); !siter.Done(); siter.Next()) {
252  const auto s = siter.Value();
253  if (Tr_.NumArcs(s + 1)) {
254  aiter_queue_->push(std::make_unique<RevArcIter>(Tr_, s + 1));
255  }
256  }
257  // Now pops arc iterator from queue, splits entering equivalence class, and
258  // re-inserts updated iterator into queue.
259  Label prev_label = -1;
260  while (!aiter_queue_->empty()) {
261  // NB: There is no way to "move" out of a std::priority_queue given that
262  // the `top` accessor is a const ref. We const-cast to move out the
263  // unique_ptr out of the priority queue. This is fine and doesn't cause an
264  // issue with the invariants of the pqueue since we immediately pop after.
265  RevArcIterPtr aiter =
266  std::move(const_cast<RevArcIterPtr &>(aiter_queue_->top()));
267  aiter_queue_->pop();
268  if (aiter->Done()) continue;
269  const auto &arc = aiter->Value();
270  auto from_state = aiter->Value().nextstate - 1;
271  auto from_label = arc.ilabel;
272  if (prev_label != from_label) P_.FinalizeSplit(&L_);
273  auto from_class = P_.ClassId(from_state);
274  if (P_.ClassSize(from_class) > 1) P_.SplitOn(from_state);
275  prev_label = from_label;
276  aiter->Next();
277  if (!aiter->Done()) aiter_queue_->push(std::move(aiter));
278  }
279  P_.FinalizeSplit(&L_);
280  }
281 
282  // Main loop for Hopcroft minimization.
283  void Compute(const Fst<Arc> &fst) {
284  // Processes active classes (FIFO, or FILO).
285  while (!L_.Empty()) {
286  const auto C = L_.Head();
287  L_.Dequeue();
288  Split(C); // Splits on C, all labels in C.
289  }
290  }
291 
292  private:
293  // Partioning of states into equivalence classes.
295  // Set of active classes to be processed in partition P.
296  Queue L_;
297  // Reverses transition function.
298  VectorFst<RevArc> Tr_;
299  // Priority queue of open arc iterators for all states in the splitter
300  // equivalence class.
301  std::unique_ptr<ArcIterQueue> aiter_queue_;
302 };
303 
304 // Computes equivalence classes for acyclic FST.
305 //
306 // Complexity:
307 //
308 // O(E)
309 //
310 // where E is the number of arcs.
311 //
312 // For more information, see:
313 //
314 // Revuz, D. 1992. Minimization of acyclic deterministic automata in linear
315 // time. Theoretical Computer Science 92(1): 181-189.
316 template <class Arc>
318  public:
319  using Label = typename Arc::Label;
320  using StateId = typename Arc::StateId;
321  using ClassId = typename Arc::StateId;
322  using Weight = typename Arc::Weight;
323 
325  Initialize(fst);
326  Refine(fst);
327  }
328 
329  const Partition<StateId> &GetPartition() { return partition_; }
330 
331  private:
332  // DFS visitor to compute the height (distance) to final state.
333  class HeightVisitor {
334  public:
335  HeightVisitor() : max_height_(0), num_states_(0) {}
336 
337  // Invoked before DFS visit.
338  void InitVisit(const Fst<Arc> &fst) {}
339 
340  // Invoked when state is discovered (2nd arg is DFS tree root).
341  bool InitState(StateId s, StateId root) {
342  // Extends height array and initialize height (distance) to 0.
343  for (StateId i = height_.size(); i <= s; ++i) height_.push_back(-1);
344  if (s >= num_states_) num_states_ = s + 1;
345  return true;
346  }
347 
348  // Invoked when tree arc examined (to undiscovered state).
349  bool TreeArc(StateId s, const Arc &arc) { return true; }
350 
351  // Invoked when back arc examined (to unfinished state).
352  bool BackArc(StateId s, const Arc &arc) { return true; }
353 
354  // Invoked when forward or cross arc examined (to finished state).
355  bool ForwardOrCrossArc(StateId s, const Arc &arc) {
356  if (height_[arc.nextstate] + 1 > height_[s]) {
357  height_[s] = height_[arc.nextstate] + 1;
358  }
359  return true;
360  }
361 
362  // Invoked when state finished (parent is kNoStateId for tree root).
363  void FinishState(StateId s, StateId parent, const Arc *parent_arc) {
364  if (height_[s] == -1) height_[s] = 0;
365  const auto h = height_[s] + 1;
366  if (parent >= 0) {
367  if (h > height_[parent]) height_[parent] = h;
368  if (h > max_height_) max_height_ = h;
369  }
370  }
371 
372  // Invoked after DFS visit.
373  void FinishVisit() {}
374 
375  size_t max_height() const { return max_height_; }
376 
377  const std::vector<StateId> &height() const { return height_; }
378 
379  size_t num_states() const { return num_states_; }
380 
381  private:
382  std::vector<StateId> height_;
383  size_t max_height_;
384  size_t num_states_;
385  };
386 
387  private:
388  // Cluster states according to height (distance to final state)
389  void Initialize(const Fst<Arc> &fst) {
390  // Computes height (distance to final state).
391  HeightVisitor hvisitor;
392  DfsVisit(fst, &hvisitor);
393  // Creates initial partition based on height.
394  partition_.Initialize(hvisitor.num_states());
395  partition_.AllocateClasses(hvisitor.max_height() + 1);
396  const auto &hstates = hvisitor.height();
397  for (StateId s = 0; s < hstates.size(); ++s) partition_.Add(s, hstates[s]);
398  }
399 
400  // Refines states based on arc sort (out degree, arc equivalence).
401  void Refine(const Fst<Arc> &fst) {
402  using EquivalenceMap = std::map<StateId, StateId, StateComparator<Arc>>;
403  StateComparator<Arc> comp(fst, partition_);
404  // Starts with tail (height = 0).
405  auto height = partition_.NumClasses();
406  for (StateId h = 0; h < height; ++h) {
407  EquivalenceMap equiv_classes(comp);
408  // Sorts states within equivalence class.
409  PartitionIterator<StateId> siter(partition_, h);
410  equiv_classes[siter.Value()] = h;
411  for (siter.Next(); !siter.Done(); siter.Next()) {
412  auto insert_result = equiv_classes.emplace(siter.Value(), kNoStateId);
413  if (insert_result.second) {
414  insert_result.first->second = partition_.AddClass();
415  }
416  }
417  // Creates refined partition.
418  for (siter.Reset(); !siter.Done();) {
419  const auto s = siter.Value();
420  const auto old_class = partition_.ClassId(s);
421  const auto new_class = equiv_classes[s];
422  // A move operation can invalidate the iterator, so we first update
423  // the iterator to the next element before we move the current element
424  // out of the list.
425  siter.Next();
426  if (old_class != new_class) partition_.Move(s, new_class);
427  }
428  }
429  }
430 
431  private:
432  Partition<StateId> partition_;
433 };
434 
435 // Given a partition and a Mutable FST, merges states of Fst in place (i.e.,
436 // destructively). Merging works by taking the first state in a class of the
437 // partition to be the representative state for the class. Each arc is then
438 // reconnected to this state. All states in the class are merged by adding
439 // their arcs to the representative state.
440 template <class Arc>
442  MutableFst<Arc> *fst) {
443  using StateId = typename Arc::StateId;
444  std::vector<StateId> state_map(partition.NumClasses());
445  for (StateId i = 0; i < partition.NumClasses(); ++i) {
446  PartitionIterator<StateId> siter(partition, i);
447  state_map[i] = siter.Value(); // First state in partition.
448  }
449  // Relabels destination states.
450  for (StateId c = 0; c < partition.NumClasses(); ++c) {
451  for (PartitionIterator<StateId> siter(partition, c); !siter.Done();
452  siter.Next()) {
453  const auto s = siter.Value();
454  for (MutableArcIterator<MutableFst<Arc>> aiter(fst, s); !aiter.Done();
455  aiter.Next()) {
456  auto arc = aiter.Value();
457  arc.nextstate = state_map[partition.ClassId(arc.nextstate)];
458  if (s == state_map[c]) { // For the first state, just sets destination.
459  aiter.SetValue(arc);
460  } else {
461  fst->AddArc(state_map[c], std::move(arc));
462  }
463  }
464  }
465  }
466  fst->SetStart(state_map[partition.ClassId(fst->Start())]);
467  Connect(fst);
468 }
469 
470 template <class Arc>
472  // Connects FST before minimization, handles disconnected states.
473  Connect(fst);
474  if (fst->Start() == kNoStateId) return;
475  // The Revuz acyclic algorithm won't work for nondeterministic inputs, so if
476  // the input is nondeterministic, we force the use of the Hopcroft cyclic
477  // algorithm instead.
478  static constexpr auto revuz_props = kAcyclic | kIDeterministic;
479  if (fst->Properties(revuz_props, true) == revuz_props) {
480  // Acyclic minimization (Revuz).
481  VLOG(2) << "Acyclic minimization";
482  static const ILabelCompare<Arc> comp;
483  ArcSort(fst, comp);
484  AcyclicMinimizer<Arc> minimizer(*fst);
485  MergeStates(minimizer.GetPartition(), fst);
486  } else {
487  // Either the FST has cycles, or it's generated from non-deterministic input
488  // (which the Revuz algorithm can't handle), so use the cyclic minimization
489  // algorithm of Hopcroft.
490  VLOG(2) << "Cyclic minimization";
492  MergeStates(minimizer.GetPartition(), fst);
493  }
494  // Merges in appropriate semiring
495  ArcUniqueMapper<Arc> mapper(*fst);
496  StateMap(fst, mapper);
497 }
498 } // namespace internal
499 
500 // In place minimization of deterministic weighted automata and transducers, and
501 // also non-deterministic ones if they use an idempotent semiring. For
502 // transducers, if the 'sfst' argument is not null, the algorithm produces a
503 // compact factorization of the minimal transducer.
504 //
505 // In the acyclic deterministic case, we use an algorithm from Revuz; this has
506 // complexity O(e).
507 //
508 // In cyclic and non-deterministic cases, we use the classical Hopcroft
509 // minimization (which was presented for the deterministic case but which
510 // also works for non-deterministic FSTs); this has complexity O(e log v).
511 template <class Arc>
513  float delta = kShortestDelta, bool allow_nondet = false) {
514  using Weight = typename Arc::Weight;
515  static constexpr auto minimize_props =
517  const auto props = fst->Properties(minimize_props, true);
518  if (!(props & kIDeterministic)) {
519  // Our approach to minimization of non-deterministic FSTs will only work in
520  // idempotent semirings---for non-deterministic inputs, a state could have
521  // multiple transitions to states that will get merged, and we'd have to
522  // sum their weights. The algorithm doesn't handle that.
523  if constexpr (!IsIdempotent<Weight>::value) {
524  fst->SetProperties(kError, kError);
525  FSTERROR() << "Cannot minimize a non-deterministic FST over a "
526  "non-idempotent semiring";
527  return;
528  } else if (!allow_nondet) {
529  fst->SetProperties(kError, kError);
530  FSTERROR() << "Refusing to minimize a non-deterministic FST with "
531  << "allow_nondet = false";
532  return;
533  }
534  }
535  if ((props & kAcceptor) != kAcceptor) { // Transducer.
538  fst->DeleteStates();
539  gfst.SetProperties(kAcceptor, kAcceptor);
540  Push(&gfst, REWEIGHT_TO_INITIAL, delta);
544  Encode(&gfst, &encoder);
546  Decode(&gfst, encoder);
547  if (!sfst) {
550  fwfst(gfst);
551  std::unique_ptr<SymbolTable> osyms(
552  fst->OutputSymbols() ? fst->OutputSymbols()->Copy() : nullptr);
554  fst->SetOutputSymbols(osyms.get());
555  } else {
556  sfst->SetOutputSymbols(fst->OutputSymbols());
558  ArcMap(gfst, fst, &mapper);
559  fst->SetOutputSymbols(sfst->InputSymbols());
560  }
561  } else if ((props & kWeighted) == kWeighted) { // Weighted acceptor.
562  Push(fst, REWEIGHT_TO_INITIAL, delta);
563  ArcMap(fst, QuantizeMapper<Arc>(delta));
564  // We encode labels even though this is already an acceptor because weight
565  // encoding gives us a transducer.
567  Encode(fst, &encoder);
569  Decode(fst, encoder);
570  } else { // Unweighted acceptor.
572  }
573 }
574 
575 } // namespace fst
576 
577 #endif // FST_MINIMIZE_H_
typename Arc::StateId ClassId
Definition: minimize.h:321
void ArcMap(MutableFst< A > *fst, C *mapper)
Definition: arc-map.h:120
typename Arc::Weight Weight
Definition: minimize.h:66
void AcceptorMinimize(MutableFst< Arc > *fst)
Definition: minimize.h:471
typename Arc::StateId StateId
Definition: minimize.h:65
typename Arc::Label Label
Definition: minimize.h:125
typename Arc::StateId StateId
Definition: minimize.h:320
constexpr int kNoLabel
Definition: fst.h:195
virtual uint64_t Properties(uint64_t mask, bool test) const =0
AcyclicMinimizer(const ExpandedFst< Arc > &fst)
Definition: minimize.h:324
void Encode(MutableFst< Arc > *fst, EncodeMapper< Arc > *mapper)
Definition: encode.h:500
bool operator()(const StateId x, const StateId y) const
Definition: minimize.h:72
virtual size_t NumArcs(StateId) const =0
typename Arc::Weight Weight
Definition: minimize.h:128
virtual SymbolTable * Copy() const
Definition: symbol-table.h:411
constexpr uint64_t kError
Definition: properties.h:52
const Partition< StateId > & GetPartition() const
Definition: minimize.h:140
void DfsVisit(const FST &fst, Visitor *visitor, ArcFilter filter, bool access_only=false)
Definition: dfs-visit.h:112
void SetProperties(uint64_t props, uint64_t mask) override
Definition: mutable-fst.h:313
virtual Weight Final(StateId) const =0
virtual void SetStart(StateId)=0
void Connect(MutableFst< Arc > *fst)
Definition: connect.h:47
std::bool_constant<(W::Properties()&kIdempotent)!=0 > IsIdempotent
Definition: weight.h:159
void MergeStates(const Partition< typename Arc::StateId > &partition, MutableFst< Arc > *fst)
Definition: minimize.h:441
constexpr int kNoStateId
Definition: fst.h:196
const T NumClasses() const
Definition: partition.h:196
void Reverse(const Fst< Arc > &ifst, const std::vector< std::pair< typename Arc::Label, typename Arc::Label >> &parens, std::vector< typename Arc::Label > *assignments, MutableFst< RevArc > *ofst)
Definition: reverse.h:36
#define FSTERROR()
Definition: util.h:56
const SymbolTable * OutputSymbols() const override=0
constexpr uint8_t kEncodeLabels
Definition: encode.h:55
void ArcSort(MutableFst< Arc > *fst, Compare comp)
Definition: arcsort.h:109
constexpr uint64_t kAcyclic
Definition: properties.h:111
virtual void SetProperties(uint64_t props, uint64_t mask)=0
const Partition< StateId > & GetPartition()
Definition: minimize.h:329
#define VLOG(level)
Definition: log.h:54
virtual StateId Start() const =0
constexpr float kShortestDelta
constexpr uint64_t kIDeterministic
Definition: properties.h:69
void StateMap(MutableFst< A > *fst, C *mapper)
Definition: state-map.h:103
const T ClassId(T element_id) const
Definition: partition.h:192
StateComparator(const Fst< Arc > &fst, const Partition< StateId > &partition)
Definition: minimize.h:68
void Push(MutableFst< Arc > *fst, ReweightType type=REWEIGHT_TO_INITIAL, float delta=kShortestDelta, bool remove_total_weight=false)
Definition: push.h:94
constexpr uint8_t kEncodeWeights
Definition: encode.h:56
virtual void AddArc(StateId, const Arc &)=0
constexpr uint64_t kUnweighted
Definition: properties.h:106
void Minimize(MutableFst< Arc > *fst, MutableFst< Arc > *sfst=nullptr, float delta=kShortestDelta, bool allow_nondet=false)
Definition: minimize.h:512
CyclicMinimizer(const ExpandedFst< Arc > &fst)
Definition: minimize.h:135
typename Arc::Label Label
Definition: minimize.h:319
virtual void DeleteStates(const std::vector< StateId > &)=0
typename Arc::Weight Weight
Definition: minimize.h:322
virtual void SetOutputSymbols(const SymbolTable *osyms)=0
constexpr uint64_t kWeighted
Definition: properties.h:104
virtual StateId NumStates() const =0
typename Arc::StateId ClassId
Definition: minimize.h:127
typename Arc::StateId StateId
Definition: minimize.h:126
void Decode(MutableFst< Arc > *fst, const EncodeMapper< Arc > &mapper)
Definition: encode.h:507
constexpr uint64_t kAcceptor
Definition: properties.h:64
std::unique_ptr< RevArcIter > RevArcIterPtr
Definition: minimize.h:133