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, 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.
892 template <typename Q, typename F>
893 class FilterQueue : public QueueBase<typename Q::StateId> {
894 public:
895 typedef typename Q::StateId StateId;
896
FilterQueue(Q * queue,const F & state_filter)897 FilterQueue(Q *queue, const F &state_filter)
898 : QueueBase<StateId>(OTHER_QUEUE),
899 queue_(queue),
900 state_filter_(state_filter) {}
901
~FilterQueue()902 ~FilterQueue() { delete queue_; }
903
Head()904 StateId Head() const { return queue_->Head(); }
905
906 // Enqueues only if allowed by state filter.
Enqueue(StateId s)907 void Enqueue(StateId s) {
908 if (state_filter_(s)) {
909 queue_->Enqueue(s);
910 }
911 }
912
Dequeue()913 void Dequeue() { queue_->Dequeue(); }
914
Update(StateId s)915 void Update(StateId s) {}
Empty()916 bool Empty() const { return queue_->Empty(); }
Clear()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.
Head_()923 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)924 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()925 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)926 virtual void Update_(StateId s) { Update(s); }
Empty_()927 virtual bool Empty_() const { return Empty(); }
Clear_()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