queue.h revision 5b6dc79427b8f7eeb6a7ff68034ab8548ce670ea
1// queue.h
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// Copyright 2005-2010 Google, Inc.
16// Author: allauzen@google.com (Cyril Allauzen)
17//
18// \file
19// Functions and classes for various Fst state queues with
20// a unified interface.
21
22#ifndef FST_LIB_QUEUE_H__
23#define FST_LIB_QUEUE_H__
24
25#include <deque>
26using std::deque;
27#include <vector>
28using std::vector;
29
30#include <fst/arcfilter.h>
31#include <fst/connect.h>
32#include <fst/heap.h>
33#include <fst/topsort.h>
34
35
36namespace fst {
37
38// template <class S>
39// class Queue {
40//  public:
41//   typedef typename S StateId;
42//
43//   // Ctr: may need args (e.g., Fst, comparator) for some queues
44//   Queue(...);
45//   // Returns the head of the queue
46//   StateId Head() const;
47//   // Inserts a state
48//   void Enqueue(StateId s);
49//   // Removes the head of the queue
50//   void Dequeue();
51//   // Updates ordering of state s when weight changes, if necessary
52//   void Update(StateId s);
53//   // Does the queue contain no elements?
54//   bool Empty() const;
55//   // Remove all states from queue
56//   void Clear();
57// };
58
59// State queue types.
60enum QueueType {
61  TRIVIAL_QUEUE = 0,         // Single state queue
62  FIFO_QUEUE = 1,            // First-in, first-out queue
63  LIFO_QUEUE = 2,            // Last-in, first-out queue
64  SHORTEST_FIRST_QUEUE = 3,  // Shortest-first queue
65  TOP_ORDER_QUEUE = 4,       // Topologically-ordered queue
66  STATE_ORDER_QUEUE = 5,     // State-ID ordered queue
67  SCC_QUEUE = 6,             // Component graph top-ordered meta-queue
68  AUTO_QUEUE = 7,            // Auto-selected queue
69  OTHER_QUEUE = 8
70 };
71
72
73// QueueBase, templated on the StateId, is the base class shared by the
74// queues considered by AutoQueue.
75template <class S>
76class QueueBase {
77 public:
78  typedef S StateId;
79
80  QueueBase(QueueType type) : queue_type_(type), error_(false) {}
81  virtual ~QueueBase() {}
82  StateId Head() const { return Head_(); }
83  void Enqueue(StateId s) { Enqueue_(s); }
84  void Dequeue() { Dequeue_(); }
85  void Update(StateId s) { Update_(s); }
86  bool Empty() const { return Empty_(); }
87  void Clear() { Clear_(); }
88  QueueType Type() { return queue_type_; }
89  bool Error() const { return error_; }
90  void SetError(bool error) { error_ = error; }
91
92 private:
93  // This allows base-class virtual access to non-virtual derived-
94  // class members of the same name. It makes the derived class more
95  // efficient to use but unsafe to further derive.
96  virtual StateId Head_() const = 0;
97  virtual void Enqueue_(StateId s) = 0;
98  virtual void Dequeue_() = 0;
99  virtual void Update_(StateId s) = 0;
100  virtual bool Empty_() const = 0;
101  virtual void Clear_() = 0;
102
103  QueueType queue_type_;
104  bool error_;
105};
106
107
108// Trivial queue discipline, templated on the StateId. You may enqueue
109// at most one state at a time. It is used for strongly connected components
110// with only one state and no self loops.
111template <class S>
112class TrivialQueue : public QueueBase<S> {
113public:
114  typedef S StateId;
115
116  TrivialQueue() : QueueBase<S>(TRIVIAL_QUEUE), front_(kNoStateId) {}
117  StateId Head() const { return front_; }
118  void Enqueue(StateId s) { front_ = s; }
119  void Dequeue() { front_ = kNoStateId; }
120  void Update(StateId s) {}
121  bool Empty() const { return front_ == kNoStateId; }
122  void Clear() { front_ = kNoStateId; }
123
124
125private:
126  // This allows base-class virtual access to non-virtual derived-
127  // class members of the same name. It makes the derived class more
128  // efficient to use but unsafe to further derive.
129  virtual StateId Head_() const { return Head(); }
130  virtual void Enqueue_(StateId s) { Enqueue(s); }
131  virtual void Dequeue_() { Dequeue(); }
132  virtual void Update_(StateId s) { Update(s); }
133  virtual bool Empty_() const { return Empty(); }
134  virtual void Clear_() { return Clear(); }
135
136  StateId front_;
137};
138
139
140// First-in, first-out queue discipline, templated on the StateId.
141template <class S>
142class FifoQueue : public QueueBase<S>, public deque<S> {
143 public:
144  using deque<S>::back;
145  using deque<S>::push_front;
146  using deque<S>::pop_back;
147  using deque<S>::empty;
148  using deque<S>::clear;
149
150  typedef S StateId;
151
152  FifoQueue() : QueueBase<S>(FIFO_QUEUE) {}
153  StateId Head() const { return back(); }
154  void Enqueue(StateId s) { push_front(s); }
155  void Dequeue() { pop_back(); }
156  void Update(StateId s) {}
157  bool Empty() const { return empty(); }
158  void Clear() { clear(); }
159
160 private:
161  // This allows base-class virtual access to non-virtual derived-
162  // class members of the same name. It makes the derived class more
163  // efficient to use but unsafe to further derive.
164  virtual StateId Head_() const { return Head(); }
165  virtual void Enqueue_(StateId s) { Enqueue(s); }
166  virtual void Dequeue_() { Dequeue(); }
167  virtual void Update_(StateId s) { Update(s); }
168  virtual bool Empty_() const { return Empty(); }
169  virtual void Clear_() { return Clear(); }
170};
171
172
173// Last-in, first-out queue discipline, templated on the StateId.
174template <class S>
175class LifoQueue : public QueueBase<S>, public deque<S> {
176 public:
177  using deque<S>::front;
178  using deque<S>::push_front;
179  using deque<S>::pop_front;
180  using deque<S>::empty;
181  using deque<S>::clear;
182
183  typedef S StateId;
184
185  LifoQueue() : QueueBase<S>(LIFO_QUEUE) {}
186  StateId Head() const { return front(); }
187  void Enqueue(StateId s) { push_front(s); }
188  void Dequeue() { pop_front(); }
189  void Update(StateId s) {}
190  bool Empty() const { return empty(); }
191  void Clear() { clear(); }
192
193 private:
194  // This allows base-class virtual access to non-virtual derived-
195  // class members of the same name. It makes the derived class more
196  // efficient to use but unsafe to further derive.
197  virtual StateId Head_() const { return Head(); }
198  virtual void Enqueue_(StateId s) { Enqueue(s); }
199  virtual void Dequeue_() { Dequeue(); }
200  virtual void Update_(StateId s) { Update(s); }
201  virtual bool Empty_() const { return Empty(); }
202  virtual void Clear_() { return Clear(); }
203};
204
205
206// Shortest-first queue discipline, templated on the StateId and
207// comparison function object.  Comparison function object COMP is
208// used to compare two StateIds. If a (single) state's order changes,
209// it can be reordered in the queue with a call to Update().
210// If 'update == false', call to Update() does not reorder the queue.
211template <typename S, typename C, bool update = true>
212class ShortestFirstQueue : public QueueBase<S> {
213 public:
214  typedef S StateId;
215  typedef C Compare;
216
217  ShortestFirstQueue(C comp)
218      : QueueBase<S>(SHORTEST_FIRST_QUEUE), heap_(comp) {}
219
220  StateId Head() const { return heap_.Top(); }
221
222  void Enqueue(StateId s) {
223    if (update) {
224      for (StateId i = key_.size(); i <= s; ++i)
225        key_.push_back(kNoKey);
226      key_[s] = heap_.Insert(s);
227    } else {
228      heap_.Insert(s);
229    }
230  }
231
232  void Dequeue() {
233    if (update)
234      key_[heap_.Pop()] = kNoKey;
235    else
236      heap_.Pop();
237  }
238
239  void Update(StateId s) {
240    if (!update)
241      return;
242    if (s >= key_.size() || key_[s] == kNoKey) {
243      Enqueue(s);
244    } else {
245      heap_.Update(key_[s], s);
246    }
247  }
248
249  bool Empty() const { return heap_.Empty(); }
250
251  void Clear() {
252    heap_.Clear();
253    if (update) key_.clear();
254  }
255
256 private:
257  Heap<S, C, false> heap_;
258  vector<ssize_t> key_;
259
260  // This allows base-class virtual access to non-virtual derived-
261  // class members of the same name. It makes the derived class more
262  // efficient to use but unsafe to further derive.
263  virtual StateId Head_() const { return Head(); }
264  virtual void Enqueue_(StateId s) { Enqueue(s); }
265  virtual void Dequeue_() { Dequeue(); }
266  virtual void Update_(StateId s) { Update(s); }
267  virtual bool Empty_() const { return Empty(); }
268  virtual void Clear_() { return Clear(); }
269};
270
271
272// Given a vector that maps from states to weights and a Less
273// comparison function object between weights, this class defines a
274// comparison function object between states.
275template <typename S, typename L>
276class StateWeightCompare {
277 public:
278  typedef L Less;
279  typedef typename L::Weight Weight;
280  typedef S StateId;
281
282  StateWeightCompare(const vector<Weight>& weights, const L &less)
283      : weights_(weights), less_(less) {}
284
285  bool operator()(const S x, const S y) const {
286    return less_(weights_[x], weights_[y]);
287  }
288
289 private:
290  const vector<Weight>& weights_;
291  L less_;
292};
293
294
295// Shortest-first queue discipline, templated on the StateId and Weight, is
296// specialized to use the weight's natural order for the comparison function.
297template <typename S, typename W>
298class NaturalShortestFirstQueue :
299      public ShortestFirstQueue<S, StateWeightCompare<S, NaturalLess<W> > > {
300 public:
301  typedef StateWeightCompare<S, NaturalLess<W> > C;
302
303  NaturalShortestFirstQueue(const vector<W> &distance) :
304      ShortestFirstQueue<S, C>(C(distance, less_)) {}
305
306 private:
307  NaturalLess<W> less_;
308};
309
310// Topological-order queue discipline, templated on the StateId.
311// States are ordered in the queue topologically. The FST must be acyclic.
312template <class S>
313class TopOrderQueue : public QueueBase<S> {
314 public:
315  typedef S StateId;
316
317  // This constructor computes the top. order. It accepts an arc filter
318  // to limit the transitions considered in that computation (e.g., only
319  // the epsilon graph).
320  template <class Arc, class ArcFilter>
321  TopOrderQueue(const Fst<Arc> &fst, ArcFilter filter)
322      : QueueBase<S>(TOP_ORDER_QUEUE), front_(0), back_(kNoStateId),
323        order_(0), state_(0) {
324    bool acyclic;
325    TopOrderVisitor<Arc> top_order_visitor(&order_, &acyclic);
326    DfsVisit(fst, &top_order_visitor, filter);
327    if (!acyclic) {
328      FSTERROR() << "TopOrderQueue: fst is not acyclic.";
329      QueueBase<S>::SetError(true);
330    }
331    state_.resize(order_.size(), kNoStateId);
332  }
333
334  // This constructor is passed the top. order, useful when we know it
335  // beforehand.
336  TopOrderQueue(const vector<StateId> &order)
337      : QueueBase<S>(TOP_ORDER_QUEUE), front_(0), back_(kNoStateId),
338        order_(order), state_(order.size(), kNoStateId) {}
339
340  StateId Head() const { return state_[front_]; }
341
342  void Enqueue(StateId s) {
343    if (front_ > back_) front_ = back_ = order_[s];
344    else if (order_[s] > back_) back_ = order_[s];
345    else if (order_[s] < front_) front_ = order_[s];
346    state_[order_[s]] = s;
347  }
348
349  void Dequeue() {
350    state_[front_] = kNoStateId;
351    while ((front_ <= back_) && (state_[front_] == kNoStateId)) ++front_;
352  }
353
354  void Update(StateId s) {}
355
356  bool Empty() const { return front_ > back_; }
357
358  void Clear() {
359    for (StateId i = front_; i <= back_; ++i) state_[i] = kNoStateId;
360    back_ = kNoStateId;
361    front_ = 0;
362  }
363
364 private:
365  StateId front_;
366  StateId back_;
367  vector<StateId> order_;
368  vector<StateId> state_;
369
370  // This allows base-class virtual access to non-virtual derived-
371  // class members of the same name. It makes the derived class more
372  // efficient to use but unsafe to further derive.
373  virtual StateId Head_() const { return Head(); }
374  virtual void Enqueue_(StateId s) { Enqueue(s); }
375  virtual void Dequeue_() { Dequeue(); }
376  virtual void Update_(StateId s) { Update(s); }
377  virtual bool Empty_() const { return Empty(); }
378  virtual void Clear_() { return Clear(); }
379};
380
381
382// State order queue discipline, templated on the StateId.
383// States are ordered in the queue by state Id.
384template <class S>
385class StateOrderQueue : public QueueBase<S> {
386public:
387  typedef S StateId;
388
389  StateOrderQueue()
390      : QueueBase<S>(STATE_ORDER_QUEUE), front_(0), back_(kNoStateId) {}
391
392  StateId Head() const { return front_; }
393
394  void Enqueue(StateId s) {
395    if (front_ > back_) front_ = back_ = s;
396    else if (s > back_) back_ = s;
397    else if (s < front_) front_ = s;
398    while (enqueued_.size() <= s) enqueued_.push_back(false);
399    enqueued_[s] = true;
400  }
401
402  void Dequeue() {
403    enqueued_[front_] = false;
404    while ((front_ <= back_) && (enqueued_[front_] == false)) ++front_;
405  }
406
407  void Update(StateId s) {}
408
409  bool Empty() const { return front_ > back_; }
410
411  void Clear() {
412        for (StateId i = front_; i <= back_; ++i) enqueued_[i] = false;
413        front_ = 0;
414        back_ = kNoStateId;
415  }
416
417private:
418  StateId front_;
419  StateId back_;
420  vector<bool> enqueued_;
421
422  // This allows base-class virtual access to non-virtual derived-
423  // class members of the same name. It makes the derived class more
424  // efficient to use but unsafe to further derive.
425  virtual StateId Head_() const { return Head(); }
426  virtual void Enqueue_(StateId s) { Enqueue(s); }
427  virtual void Dequeue_() { Dequeue(); }
428  virtual void Update_(StateId s) { Update(s); }
429  virtual bool Empty_() const { return Empty(); }
430  virtual void Clear_() { return Clear(); }
431
432};
433
434
435// SCC topological-order meta-queue discipline, templated on the StateId S
436// and a queue Q, which is used inside each SCC.  It visits the SCC's
437// of an FST in topological order. Its constructor is passed the queues to
438// to use within an SCC.
439template <class S, class Q>
440class SccQueue : public QueueBase<S> {
441 public:
442  typedef S StateId;
443  typedef Q Queue;
444
445  // Constructor takes a vector specifying the SCC number per state
446  // and a vector giving the queue to use per SCC number.
447  SccQueue(const vector<StateId> &scc, vector<Queue*> *queue)
448    : QueueBase<S>(SCC_QUEUE), queue_(queue), scc_(scc), front_(0),
449      back_(kNoStateId) {}
450
451  StateId Head() const {
452    while ((front_ <= back_) &&
453           (((*queue_)[front_] && (*queue_)[front_]->Empty())
454            || (((*queue_)[front_] == 0) &&
455                ((front_ >= trivial_queue_.size())
456                 || (trivial_queue_[front_] == kNoStateId)))))
457      ++front_;
458    if ((*queue_)[front_])
459      return (*queue_)[front_]->Head();
460    else
461      return trivial_queue_[front_];
462  }
463
464  void Enqueue(StateId s) {
465    if (front_ > back_) front_ = back_ = scc_[s];
466    else if (scc_[s] > back_) back_ = scc_[s];
467    else if (scc_[s] < front_) front_ = scc_[s];
468    if ((*queue_)[scc_[s]]) {
469      (*queue_)[scc_[s]]->Enqueue(s);
470    } else {
471      while (trivial_queue_.size() <= scc_[s])
472        trivial_queue_.push_back(kNoStateId);
473      trivial_queue_[scc_[s]] = s;
474    }
475  }
476
477  void Dequeue() {
478    if ((*queue_)[front_])
479      (*queue_)[front_]->Dequeue();
480    else if (front_ < trivial_queue_.size())
481      trivial_queue_[front_] = kNoStateId;
482  }
483
484  void Update(StateId s) {
485    if ((*queue_)[scc_[s]])
486      (*queue_)[scc_[s]]->Update(s);
487  }
488
489  bool Empty() const {
490    if (front_ < back_)  // Queue scc # back_ not empty unless back_==front_
491      return false;
492    else if (front_ > back_)
493      return true;
494    else if ((*queue_)[front_])
495      return (*queue_)[front_]->Empty();
496    else
497      return (front_ >= trivial_queue_.size())
498        || (trivial_queue_[front_] == kNoStateId);
499  }
500
501  void Clear() {
502    for (StateId i = front_; i <= back_; ++i)
503      if ((*queue_)[i])
504        (*queue_)[i]->Clear();
505      else if (i < trivial_queue_.size())
506        trivial_queue_[i] = kNoStateId;
507    front_ = 0;
508    back_ = kNoStateId;
509  }
510
511private:
512  vector<Queue*> *queue_;
513  const vector<StateId> &scc_;
514  mutable StateId front_;
515  StateId back_;
516  vector<StateId> trivial_queue_;
517
518  // This allows base-class virtual access to non-virtual derived-
519  // class members of the same name. It makes the derived class more
520  // efficient to use but unsafe to further derive.
521  virtual StateId Head_() const { return Head(); }
522  virtual void Enqueue_(StateId s) { Enqueue(s); }
523  virtual void Dequeue_() { Dequeue(); }
524  virtual void Update_(StateId s) { Update(s); }
525  virtual bool Empty_() const { return Empty(); }
526  virtual void Clear_() { return Clear(); }
527
528  DISALLOW_COPY_AND_ASSIGN(SccQueue);
529};
530
531
532// Automatic queue discipline, templated on the StateId. It selects a
533// queue discipline for a given FST based on its properties.
534template <class S>
535class AutoQueue : public QueueBase<S> {
536public:
537  typedef S StateId;
538
539  // This constructor takes a state distance vector that, if non-null and if
540  // the Weight type has the path property, will entertain the
541  // shortest-first queue using the natural order w.r.t to the distance.
542  template <class Arc, class ArcFilter>
543  AutoQueue(const Fst<Arc> &fst, const vector<typename Arc::Weight> *distance,
544            ArcFilter filter) : QueueBase<S>(AUTO_QUEUE) {
545    typedef typename Arc::Weight Weight;
546    typedef StateWeightCompare< StateId, NaturalLess<Weight> > Compare;
547
548    //  First check if the FST is known to have these properties.
549    uint64 props = fst.Properties(kAcyclic | kCyclic |
550                                  kTopSorted | kUnweighted, false);
551    if ((props & kTopSorted) || fst.Start() == kNoStateId) {
552      queue_ = new StateOrderQueue<StateId>();
553      VLOG(2) << "AutoQueue: using state-order discipline";
554    } else if (props & kAcyclic) {
555      queue_ = new TopOrderQueue<StateId>(fst, filter);
556      VLOG(2) << "AutoQueue: using top-order discipline";
557    } else if ((props & kUnweighted) && (Weight::Properties() & kIdempotent)) {
558      queue_ = new LifoQueue<StateId>();
559      VLOG(2) << "AutoQueue: using LIFO discipline";
560    } else {
561      uint64 properties;
562      // Decompose into strongly-connected components.
563      SccVisitor<Arc> scc_visitor(&scc_, 0, 0, &properties);
564      DfsVisit(fst, &scc_visitor, filter);
565      StateId nscc = *max_element(scc_.begin(), scc_.end()) + 1;
566      vector<QueueType> queue_types(nscc);
567      NaturalLess<Weight> *less = 0;
568      Compare *comp = 0;
569      if (distance && (Weight::Properties() & kPath)) {
570        less = new NaturalLess<Weight>;
571        comp = new Compare(*distance, *less);
572      }
573      // Find the queue type to use per SCC.
574      bool unweighted;
575      bool all_trivial;
576      SccQueueType(fst, scc_, &queue_types, filter, less, &all_trivial,
577                                      &unweighted);
578      // If unweighted and semiring is idempotent, use lifo queue.
579      if (unweighted) {
580          queue_ = new LifoQueue<StateId>();
581          VLOG(2) << "AutoQueue: using LIFO discipline";
582          delete comp;
583          delete less;
584          return;
585      }
586      // If all the scc are trivial, FST is acyclic and the scc# gives
587      // the topological order.
588      if (all_trivial) {
589          queue_ = new TopOrderQueue<StateId>(scc_);
590          VLOG(2) << "AutoQueue: using top-order discipline";
591          delete comp;
592          delete less;
593          return;
594      }
595      VLOG(2) << "AutoQueue: using SCC meta-discipline";
596      queues_.resize(nscc);
597      for (StateId i = 0; i < nscc; ++i) {
598        switch(queue_types[i]) {
599          case TRIVIAL_QUEUE:
600            queues_[i] = 0;
601            VLOG(3) << "AutoQueue: SCC #" << i
602                    << ": using trivial discipline";
603            break;
604          case SHORTEST_FIRST_QUEUE:
605            queues_[i] = new ShortestFirstQueue<StateId, Compare, false>(*comp);
606            VLOG(3) << "AutoQueue: SCC #" << i <<
607              ": using shortest-first discipline";
608            break;
609          case LIFO_QUEUE:
610            queues_[i] = new LifoQueue<StateId>();
611            VLOG(3) << "AutoQueue: SCC #" << i
612                    << ": using LIFO disciplle";
613            break;
614          case FIFO_QUEUE:
615          default:
616            queues_[i] = new FifoQueue<StateId>();
617            VLOG(3) << "AutoQueue: SCC #" << i
618                    << ": using FIFO disciplle";
619            break;
620        }
621      }
622      queue_ = new SccQueue< StateId, QueueBase<StateId> >(scc_, &queues_);
623      delete comp;
624      delete less;
625    }
626  }
627
628  ~AutoQueue() {
629    for (StateId i = 0; i < queues_.size(); ++i)
630      delete queues_[i];
631    delete queue_;
632  }
633
634  StateId Head() const { return queue_->Head(); }
635
636  void Enqueue(StateId s) { queue_->Enqueue(s); }
637
638  void Dequeue() { queue_->Dequeue(); }
639
640  void Update(StateId s) { queue_->Update(s); }
641
642  bool Empty() const { return queue_->Empty(); }
643
644  void Clear() { queue_->Clear(); }
645
646
647 private:
648  QueueBase<StateId> *queue_;
649  vector< QueueBase<StateId>* > queues_;
650  vector<StateId> scc_;
651
652  template <class Arc, class ArcFilter, class Less>
653  static void SccQueueType(const Fst<Arc> &fst,
654                           const vector<StateId> &scc,
655                           vector<QueueType> *queue_types,
656                           ArcFilter filter, Less *less,
657                           bool *all_trivial, bool *unweighted);
658
659  // This allows base-class virtual access to non-virtual derived-
660  // class members of the same name. It makes the derived class more
661  // efficient to use but unsafe to further derive.
662  virtual StateId Head_() const { return Head(); }
663
664  virtual void Enqueue_(StateId s) { Enqueue(s); }
665
666  virtual void Dequeue_() { Dequeue(); }
667
668  virtual void Update_(StateId s) { Update(s); }
669
670  virtual bool Empty_() const { return Empty(); }
671
672  virtual void Clear_() { return Clear(); }
673
674  DISALLOW_COPY_AND_ASSIGN(AutoQueue);
675};
676
677
678// Examines the states in an Fst's strongly connected components and
679// determines which type of queue to use per SCC. Stores result in
680// vector QUEUE_TYPES, which is assumed to have length equal to the
681// number of SCCs. An arc filter is used to limit the transitions
682// considered (e.g., only the epsilon graph).  ALL_TRIVIAL is set
683// to true if every queue is the trivial queue. UNWEIGHTED is set to
684// true if the semiring is idempotent and all the arc weights are equal to
685// Zero() or One().
686template <class StateId>
687template <class A, class ArcFilter, class Less>
688void AutoQueue<StateId>::SccQueueType(const Fst<A> &fst,
689                                      const vector<StateId> &scc,
690                                      vector<QueueType> *queue_type,
691                                      ArcFilter filter, Less *less,
692                                      bool *all_trivial, bool *unweighted) {
693  typedef A Arc;
694  typedef typename A::StateId StateId;
695  typedef typename A::Weight Weight;
696
697  *all_trivial = true;
698  *unweighted = true;
699
700  for (StateId i = 0; i < queue_type->size(); ++i)
701    (*queue_type)[i] = TRIVIAL_QUEUE;
702
703  for (StateIterator< Fst<Arc> > sit(fst); !sit.Done(); sit.Next()) {
704    StateId state = sit.Value();
705    for (ArcIterator< Fst<Arc> > ait(fst, state);
706	 !ait.Done();
707	 ait.Next()) {
708      const Arc &arc = ait.Value();
709      if (!filter(arc)) continue;
710      if (scc[state] == scc[arc.nextstate]) {
711        QueueType &type = (*queue_type)[scc[state]];
712        if (!less || ((*less)(arc.weight, Weight::One())))
713          type = FIFO_QUEUE;
714        else if ((type == TRIVIAL_QUEUE) || (type == LIFO_QUEUE)) {
715          if (!(Weight::Properties() & kIdempotent) ||
716              (arc.weight != Weight::Zero() && arc.weight != Weight::One()))
717            type = SHORTEST_FIRST_QUEUE;
718          else
719            type = LIFO_QUEUE;
720        }
721        if (type != TRIVIAL_QUEUE) *all_trivial = false;
722      }
723      if (!(Weight::Properties() & kIdempotent) ||
724          (arc.weight != Weight::Zero() && arc.weight != Weight::One()))
725        *unweighted = false;
726    }
727  }
728}
729
730
731// An A* estimate is a function object that maps from a state ID to a
732// an estimate of the shortest distance to the final states.
733// The trivial A* estimate is always One().
734template <typename S, typename W>
735struct TrivialAStarEstimate {
736  W operator()(S s) const { return W::One(); }
737};
738
739
740// Given a vector that maps from states to weights representing the
741// shortest distance from the initial state, a Less comparison
742// function object between weights, and an estimate E of the
743// shortest distance to the final states, this class defines a
744// comparison function object between states.
745template <typename S, typename L, typename E>
746class AStarWeightCompare {
747 public:
748  typedef L Less;
749  typedef typename L::Weight Weight;
750  typedef S StateId;
751
752  AStarWeightCompare(const vector<Weight>& weights, const L &less,
753                     const E &estimate)
754      : weights_(weights), less_(less), estimate_(estimate) {}
755
756  bool operator()(const S x, const S y) const {
757    Weight wx = Times(weights_[x], estimate_(x));
758    Weight wy = Times(weights_[y], estimate_(y));
759    return less_(wx, wy);
760  }
761
762 private:
763  const vector<Weight>& weights_;
764  L less_;
765  const E &estimate_;
766};
767
768
769// A* queue discipline, templated on the StateId, Weight and an
770// estimate E of the shortest distance to the final states, is specialized
771// to use the weight's natural order for the comparison function.
772template <typename S, typename W, typename E>
773class NaturalAStarQueue :
774      public ShortestFirstQueue<S, AStarWeightCompare<S, NaturalLess<W>, E> > {
775 public:
776  typedef AStarWeightCompare<S, NaturalLess<W>, E> C;
777
778  NaturalAStarQueue(const vector<W> &distance, const E &estimate) :
779      ShortestFirstQueue<S, C>(C(distance, less_, estimate)) {}
780
781 private:
782  NaturalLess<W> less_;
783};
784
785
786// A state equivalence class is a function object that
787// maps from a state ID to an equivalence class (state) ID.
788// The trivial equivalence class maps a state to itself.
789template <typename S>
790struct TrivialStateEquivClass {
791  S operator()(S s) const { return s; }
792};
793
794
795// Distance-based pruning queue discipline: Enqueues a state 's'
796// only when its shortest distance (so far), as specified by
797// 'distance', is less than (as specified by 'comp') the shortest
798// distance Times() the 'threshold' to any state in the same
799// equivalence class, as specified by the function object
800// 'class_func'. The underlying queue discipline is specified by
801// 'queue'. The ownership of 'queue' is given to this class.
802template <typename Q, typename L, typename C>
803class PruneQueue : public QueueBase<typename Q::StateId> {
804 public:
805  typedef typename Q::StateId StateId;
806  typedef typename L::Weight Weight;
807
808  PruneQueue(const vector<Weight> &distance, Q *queue, L comp,
809	     const C &class_func, Weight threshold)
810    : QueueBase<StateId>(OTHER_QUEUE),
811      distance_(distance),
812      queue_(queue),
813      less_(comp),
814      class_func_(class_func),
815      threshold_(threshold) {}
816
817  ~PruneQueue() { delete queue_; }
818
819  StateId Head() const { return queue_->Head(); }
820
821  void Enqueue(StateId s) {
822    StateId c = class_func_(s);
823    if (c >= class_distance_.size())
824      class_distance_.resize(c + 1, Weight::Zero());
825    if (less_(distance_[s], class_distance_[c]))
826      class_distance_[c] = distance_[s];
827
828    // Enqueue only if below threshold limit
829    Weight limit = Times(class_distance_[c], threshold_);
830    if (less_(distance_[s], limit))
831      queue_->Enqueue(s);
832  }
833
834  void Dequeue() { queue_->Dequeue(); }
835
836  void Update(StateId s) {
837    StateId c = class_func_(s);
838    if (less_(distance_[s], class_distance_[c]))
839      class_distance_[c] = distance_[s];
840    queue_->Update(s);
841  }
842
843  bool Empty() const { return queue_->Empty(); }
844  void Clear() { queue_->Clear(); }
845
846 private:
847  // This allows base-class virtual access to non-virtual derived-
848  // class members of the same name. It makes the derived class more
849  // efficient to use but unsafe to further derive.
850  virtual StateId Head_() const { return Head(); }
851  virtual void Enqueue_(StateId s) { Enqueue(s); }
852  virtual void Dequeue_() { Dequeue(); }
853  virtual void Update_(StateId s) { Update(s); }
854  virtual bool Empty_() const { return Empty(); }
855  virtual void Clear_() { return Clear(); }
856
857  const vector<Weight> &distance_;         // shortest distance to state
858  Q *queue_;
859  L less_;
860  const C &class_func_;                    // eqv. class function object
861  Weight threshold_;                       // pruning weight threshold
862  vector<Weight> class_distance_;          // shortest distance to class
863
864  DISALLOW_COPY_AND_ASSIGN(PruneQueue);
865};
866
867
868// Pruning queue discipline (see above) using the weight's natural
869// order for the comparison function. The ownership of 'queue' is
870// given to this class.
871template <typename Q, typename W, typename C>
872class NaturalPruneQueue :
873      public PruneQueue<Q, NaturalLess<W>, C> {
874 public:
875  typedef typename Q::StateId StateId;
876  typedef W Weight;
877
878  NaturalPruneQueue(const vector<W> &distance, Q *queue,
879                    const C &class_func_, Weight threshold) :
880      PruneQueue<Q, NaturalLess<W>, C>(distance, queue, less_,
881                                       class_func_, threshold) {}
882
883 private:
884  NaturalLess<W> less_;
885};
886
887
888// Filter-based pruning queue discipline: Enqueues a state 's' only
889// if allowed by the filter, specified by the function object 'state_filter'.
890// The underlying queue discipline is specified by 'queue'. The ownership
891// of 'queue' is given to this class.
892template <typename Q, typename F>
893class FilterQueue : public QueueBase<typename Q::StateId> {
894 public:
895  typedef typename Q::StateId StateId;
896
897  FilterQueue(Q *queue, const F &state_filter)
898    : QueueBase<StateId>(OTHER_QUEUE),
899      queue_(queue),
900      state_filter_(state_filter) {}
901
902  ~FilterQueue() { delete queue_; }
903
904  StateId Head() const { return queue_->Head(); }
905
906  // Enqueues only if allowed by state filter.
907  void Enqueue(StateId s) {
908    if (state_filter_(s)) {
909      queue_->Enqueue(s);
910    }
911  }
912
913  void Dequeue() { queue_->Dequeue(); }
914
915  void Update(StateId s) {}
916  bool Empty() const { return queue_->Empty(); }
917  void Clear() { queue_->Clear(); }
918
919 private:
920  // This allows base-class virtual access to non-virtual derived-
921  // class members of the same name. It makes the derived class more
922  // efficient to use but unsafe to further derive.
923  virtual StateId Head_() const { return Head(); }
924  virtual void Enqueue_(StateId s) { Enqueue(s); }
925  virtual void Dequeue_() { Dequeue(); }
926  virtual void Update_(StateId s) { Update(s); }
927  virtual bool Empty_() const { return Empty(); }
928  virtual void Clear_() { return Clear(); }
929
930  Q *queue_;
931  const F &state_filter_;             // Filter to prune states
932
933  DISALLOW_COPY_AND_ASSIGN(FilterQueue);
934};
935
936}  // namespace fst
937
938#endif
939