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>
26 using std::deque;
27 #include <vector>
28 using 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 
36 namespace 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.
60 enum 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.
75 template <class S>
76 class QueueBase {
77  public:
78   typedef S StateId;
79 
QueueBase(QueueType type)80   QueueBase(QueueType type) : queue_type_(type), error_(false) {}
~QueueBase()81   virtual ~QueueBase() {}
Head()82   StateId Head() const { return Head_(); }
Enqueue(StateId s)83   void Enqueue(StateId s) { Enqueue_(s); }
Dequeue()84   void Dequeue() { Dequeue_(); }
Update(StateId s)85   void Update(StateId s) { Update_(s); }
Empty()86   bool Empty() const { return Empty_(); }
Clear()87   void Clear() { Clear_(); }
Type()88   QueueType Type() { return queue_type_; }
Error()89   bool Error() const { return error_; }
SetError(bool 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.
111 template <class S>
112 class TrivialQueue : public QueueBase<S> {
113 public:
114   typedef S StateId;
115 
TrivialQueue()116   TrivialQueue() : QueueBase<S>(TRIVIAL_QUEUE), front_(kNoStateId) {}
Head()117   StateId Head() const { return front_; }
Enqueue(StateId s)118   void Enqueue(StateId s) { front_ = s; }
Dequeue()119   void Dequeue() { front_ = kNoStateId; }
Update(StateId s)120   void Update(StateId s) {}
Empty()121   bool Empty() const { return front_ == kNoStateId; }
Clear()122   void Clear() { front_ = kNoStateId; }
123 
124 
125 private:
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.
Head_()129   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)130   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()131   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)132   virtual void Update_(StateId s) { Update(s); }
Empty_()133   virtual bool Empty_() const { return Empty(); }
Clear_()134   virtual void Clear_() { return Clear(); }
135 
136   StateId front_;
137 };
138 
139 
140 // First-in, first-out queue discipline, templated on the StateId.
141 template <class S>
142 class 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 
FifoQueue()152   FifoQueue() : QueueBase<S>(FIFO_QUEUE) {}
Head()153   StateId Head() const { return back(); }
Enqueue(StateId s)154   void Enqueue(StateId s) { push_front(s); }
Dequeue()155   void Dequeue() { pop_back(); }
Update(StateId s)156   void Update(StateId s) {}
Empty()157   bool Empty() const { return empty(); }
Clear()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.
Head_()164   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)165   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()166   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)167   virtual void Update_(StateId s) { Update(s); }
Empty_()168   virtual bool Empty_() const { return Empty(); }
Clear_()169   virtual void Clear_() { return Clear(); }
170 };
171 
172 
173 // Last-in, first-out queue discipline, templated on the StateId.
174 template <class S>
175 class 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 
LifoQueue()185   LifoQueue() : QueueBase<S>(LIFO_QUEUE) {}
Head()186   StateId Head() const { return front(); }
Enqueue(StateId s)187   void Enqueue(StateId s) { push_front(s); }
Dequeue()188   void Dequeue() { pop_front(); }
Update(StateId s)189   void Update(StateId s) {}
Empty()190   bool Empty() const { return empty(); }
Clear()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.
Head_()197   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)198   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()199   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)200   virtual void Update_(StateId s) { Update(s); }
Empty_()201   virtual bool Empty_() const { return Empty(); }
Clear_()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.
211 template <typename S, typename C, bool update = true>
212 class ShortestFirstQueue : public QueueBase<S> {
213  public:
214   typedef S StateId;
215   typedef C Compare;
216 
ShortestFirstQueue(C comp)217   ShortestFirstQueue(C comp)
218       : QueueBase<S>(SHORTEST_FIRST_QUEUE), heap_(comp) {}
219 
Head()220   StateId Head() const { return heap_.Top(); }
221 
Enqueue(StateId s)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 
Dequeue()232   void Dequeue() {
233     if (update)
234       key_[heap_.Pop()] = kNoKey;
235     else
236       heap_.Pop();
237   }
238 
Update(StateId s)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 
Empty()249   bool Empty() const { return heap_.Empty(); }
250 
Clear()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.
Head_()263   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)264   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()265   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)266   virtual void Update_(StateId s) { Update(s); }
Empty_()267   virtual bool Empty_() const { return Empty(); }
Clear_()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.
275 template <typename S, typename L>
276 class StateWeightCompare {
277  public:
278   typedef L Less;
279   typedef typename L::Weight Weight;
280   typedef S StateId;
281 
StateWeightCompare(const vector<Weight> & weights,const L & less)282   StateWeightCompare(const vector<Weight>& weights, const L &less)
283       : weights_(weights), less_(less) {}
284 
operator()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.
297 template <typename S, typename W>
298 class NaturalShortestFirstQueue :
299       public ShortestFirstQueue<S, StateWeightCompare<S, NaturalLess<W> > > {
300  public:
301   typedef StateWeightCompare<S, NaturalLess<W> > C;
302 
NaturalShortestFirstQueue(const vector<W> & distance)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.
312 template <class S>
313 class 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>
TopOrderQueue(const Fst<Arc> & fst,ArcFilter filter)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.
TopOrderQueue(const vector<StateId> & order)336   TopOrderQueue(const vector<StateId> &order)
337       : QueueBase<S>(TOP_ORDER_QUEUE), front_(0), back_(kNoStateId),
338         order_(order), state_(order.size(), kNoStateId) {}
339 
Head()340   StateId Head() const { return state_[front_]; }
341 
Enqueue(StateId s)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 
Dequeue()349   void Dequeue() {
350     state_[front_] = kNoStateId;
351     while ((front_ <= back_) && (state_[front_] == kNoStateId)) ++front_;
352   }
353 
Update(StateId s)354   void Update(StateId s) {}
355 
Empty()356   bool Empty() const { return front_ > back_; }
357 
Clear()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.
Head_()373   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)374   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()375   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)376   virtual void Update_(StateId s) { Update(s); }
Empty_()377   virtual bool Empty_() const { return Empty(); }
Clear_()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.
384 template <class S>
385 class StateOrderQueue : public QueueBase<S> {
386 public:
387   typedef S StateId;
388 
StateOrderQueue()389   StateOrderQueue()
390       : QueueBase<S>(STATE_ORDER_QUEUE), front_(0), back_(kNoStateId) {}
391 
Head()392   StateId Head() const { return front_; }
393 
Enqueue(StateId s)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 
Dequeue()402   void Dequeue() {
403     enqueued_[front_] = false;
404     while ((front_ <= back_) && (enqueued_[front_] == false)) ++front_;
405   }
406 
Update(StateId s)407   void Update(StateId s) {}
408 
Empty()409   bool Empty() const { return front_ > back_; }
410 
Clear()411   void Clear() {
412         for (StateId i = front_; i <= back_; ++i) enqueued_[i] = false;
413         front_ = 0;
414         back_ = kNoStateId;
415   }
416 
417 private:
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.
Head_()425   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)426   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()427   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)428   virtual void Update_(StateId s) { Update(s); }
Empty_()429   virtual bool Empty_() const { return Empty(); }
Clear_()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.
439 template <class S, class Q>
440 class 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.
SccQueue(const vector<StateId> & scc,vector<Queue * > * queue)447   SccQueue(const vector<StateId> &scc, vector<Queue*> *queue)
448     : QueueBase<S>(SCC_QUEUE), queue_(queue), scc_(scc), front_(0),
449       back_(kNoStateId) {}
450 
Head()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 
Enqueue(StateId s)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 
Dequeue()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 
Update(StateId s)484   void Update(StateId s) {
485     if ((*queue_)[scc_[s]])
486       (*queue_)[scc_[s]]->Update(s);
487   }
488 
Empty()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 
Clear()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 
511 private:
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.
Head_()521   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)522   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()523   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)524   virtual void Update_(StateId s) { Update(s); }
Empty_()525   virtual bool Empty_() const { return Empty(); }
Clear_()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.
534 template <class S>
535 class AutoQueue : public QueueBase<S> {
536 public:
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>
AutoQueue(const Fst<Arc> & fst,const vector<typename Arc::Weight> * distance,ArcFilter filter)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 
~AutoQueue()628   ~AutoQueue() {
629     for (StateId i = 0; i < queues_.size(); ++i)
630       delete queues_[i];
631     delete queue_;
632   }
633 
Head()634   StateId Head() const { return queue_->Head(); }
635 
Enqueue(StateId s)636   void Enqueue(StateId s) { queue_->Enqueue(s); }
637 
Dequeue()638   void Dequeue() { queue_->Dequeue(); }
639 
Update(StateId s)640   void Update(StateId s) { queue_->Update(s); }
641 
Empty()642   bool Empty() const { return queue_->Empty(); }
643 
Clear()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.
Head_()662   virtual StateId Head_() const { return Head(); }
663 
Enqueue_(StateId s)664   virtual void Enqueue_(StateId s) { Enqueue(s); }
665 
Dequeue_()666   virtual void Dequeue_() { Dequeue(); }
667 
Update_(StateId s)668   virtual void Update_(StateId s) { Update(s); }
669 
Empty_()670   virtual bool Empty_() const { return Empty(); }
671 
Clear_()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().
686 template <class StateId>
687 template <class A, class ArcFilter, class Less>
SccQueueType(const Fst<A> & fst,const vector<StateId> & scc,vector<QueueType> * queue_type,ArcFilter filter,Less * less,bool * all_trivial,bool * unweighted)688 void 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().
734 template <typename S, typename W>
735 struct TrivialAStarEstimate {
operatorTrivialAStarEstimate736   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.
745 template <typename S, typename L, typename E>
746 class AStarWeightCompare {
747  public:
748   typedef L Less;
749   typedef typename L::Weight Weight;
750   typedef S StateId;
751 
AStarWeightCompare(const vector<Weight> & weights,const L & less,const E & estimate)752   AStarWeightCompare(const vector<Weight>& weights, const L &less,
753                      const E &estimate)
754       : weights_(weights), less_(less), estimate_(estimate) {}
755 
operator()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.
772 template <typename S, typename W, typename E>
773 class NaturalAStarQueue :
774       public ShortestFirstQueue<S, AStarWeightCompare<S, NaturalLess<W>, E> > {
775  public:
776   typedef AStarWeightCompare<S, NaturalLess<W>, E> C;
777 
NaturalAStarQueue(const vector<W> & distance,const E & estimate)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.
789 template <typename S>
790 struct TrivialStateEquivClass {
operatorTrivialStateEquivClass791   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.
802 template <typename Q, typename L, typename C>
803 class PruneQueue : public QueueBase<typename Q::StateId> {
804  public:
805   typedef typename Q::StateId StateId;
806   typedef typename L::Weight Weight;
807 
PruneQueue(const vector<Weight> & distance,Q * queue,L comp,const C & class_func,Weight threshold)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 
~PruneQueue()817   ~PruneQueue() { delete queue_; }
818 
Head()819   StateId Head() const { return queue_->Head(); }
820 
Enqueue(StateId s)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 
Dequeue()834   void Dequeue() { queue_->Dequeue(); }
835 
Update(StateId s)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 
Empty()843   bool Empty() const { return queue_->Empty(); }
Clear()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.
Head_()850   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)851   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()852   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)853   virtual void Update_(StateId s) { Update(s); }
Empty_()854   virtual bool Empty_() const { return Empty(); }
Clear_()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.
871 template <typename Q, typename W, typename C>
872 class NaturalPruneQueue :
873       public PruneQueue<Q, NaturalLess<W>, C> {
874  public:
875   typedef typename Q::StateId StateId;
876   typedef W Weight;
877 
NaturalPruneQueue(const vector<W> & distance,Q * queue,const C & class_func_,Weight threshold)878   NaturalPruneQueue(const vector<W> &distance, Q *queue,
879                     const C &class_func_, Weight threshold) :
880       PruneQueue<Q, NaturalLess<W>, C>(distance, queue, NaturalLess<W>(),
881                                        class_func_, threshold) {}
882 };
883 
884 
885 // Filter-based pruning queue discipline: Enqueues a state 's' only
886 // if allowed by the filter, specified by the function object 'state_filter'.
887 // The underlying queue discipline is specified by 'queue'. The ownership
888 // of 'queue' is given to this class.
889 template <typename Q, typename F>
890 class FilterQueue : public QueueBase<typename Q::StateId> {
891  public:
892   typedef typename Q::StateId StateId;
893 
FilterQueue(Q * queue,const F & state_filter)894   FilterQueue(Q *queue, const F &state_filter)
895     : QueueBase<StateId>(OTHER_QUEUE),
896       queue_(queue),
897       state_filter_(state_filter) {}
898 
~FilterQueue()899   ~FilterQueue() { delete queue_; }
900 
Head()901   StateId Head() const { return queue_->Head(); }
902 
903   // Enqueues only if allowed by state filter.
Enqueue(StateId s)904   void Enqueue(StateId s) {
905     if (state_filter_(s)) {
906       queue_->Enqueue(s);
907     }
908   }
909 
Dequeue()910   void Dequeue() { queue_->Dequeue(); }
911 
Update(StateId s)912   void Update(StateId s) {}
Empty()913   bool Empty() const { return queue_->Empty(); }
Clear()914   void Clear() { queue_->Clear(); }
915 
916  private:
917   // This allows base-class virtual access to non-virtual derived-
918   // class members of the same name. It makes the derived class more
919   // efficient to use but unsafe to further derive.
Head_()920   virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)921   virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()922   virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)923   virtual void Update_(StateId s) { Update(s); }
Empty_()924   virtual bool Empty_() const { return Empty(); }
Clear_()925   virtual void Clear_() { return Clear(); }
926 
927   Q *queue_;
928   const F &state_filter_;             // Filter to prune states
929 
930   DISALLOW_COPY_AND_ASSIGN(FilterQueue);
931 };
932 
933 }  // namespace fst
934 
935 #endif
936