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 // Author: allauzen@cs.nyu.edu (Cyril Allauzen)
16 //
17 // \file
18 // Functions and classes for various Fst state queues with
19 // a unified interface.
20
21 #ifndef FST_LIB_QUEUE_H__
22 #define FST_LIB_QUEUE_H__
23
24 #include <deque>
25 #include <vector>
26
27 #include "fst/lib/arcfilter.h"
28 #include "fst/lib/connect.h"
29 #include "fst/lib/heap.h"
30 #include "fst/lib/topsort.h"
31
32 namespace fst {
33
34 // template <class S>
35 // class Queue {
36 // public:
37 // typedef typename S StateId;
38 //
39 // // Ctr: may need args (e.g., Fst, comparator) for some queues
40 // Queue(...);
41 // // Returns the head of the queue
42 // StateId Head() const;
43 // // Inserts a state
44 // void Enqueue(StateId s);
45 // // Removes the head of the queue
46 // void Dequeue();
47 // // Updates ordering of state s when weight changes, if necessary
48 // void Update(StateId s);
49 // // Does the queue contain no elements?
50 // bool Empty() const;
51 // // Remove all states from queue
52 // void Clear();
53 // };
54
55 // State queue types.
56 enum QueueType {
57 TRIVIAL_QUEUE = 0, // Single state queue
58 FIFO_QUEUE = 1, // First-in, first-out queue
59 LIFO_QUEUE = 2, // Last-in, first-out queue
60 SHORTEST_FIRST_QUEUE = 3, // Shortest-first queue
61 TOP_ORDER_QUEUE = 4, // Topologically-ordered queue
62 STATE_ORDER_QUEUE = 5, // State-ID ordered queue
63 SCC_QUEUE = 6, // Component graph top-ordered meta-queue
64 AUTO_QUEUE = 7, // Auto-selected queue
65 OTHER_QUEUE = 8
66 };
67
68
69 // QueueBase, templated on the StateId, is the base class shared by the
70 // queues considered by AutoQueue.
71 template <class S>
72 class QueueBase {
73 public:
74 typedef S StateId;
75
QueueBase(QueueType type)76 QueueBase(QueueType type) : queue_type_(type) {}
~QueueBase()77 virtual ~QueueBase() {}
Head()78 StateId Head() const { return Head_(); }
Enqueue(StateId s)79 void Enqueue(StateId s) { Enqueue_(s); }
Dequeue()80 void Dequeue() { Dequeue_(); }
Update(StateId s)81 void Update(StateId s) { Update_(s); }
Empty()82 bool Empty() const { return Empty_(); }
Clear()83 void Clear() { Clear_(); }
Type()84 QueueType Type() { return queue_type_; }
85
86 private:
87 virtual StateId Head_() const = 0;
88 virtual void Enqueue_(StateId s) = 0;
89 virtual void Dequeue_() = 0;
90 virtual void Update_(StateId s) = 0;
91 virtual bool Empty_() const = 0;
92 virtual void Clear_() = 0;
93
94 QueueType queue_type_;
95 };
96
97
98 // Trivial queue discipline, templated on the StateId. You may enqueue
99 // at most one state at a time. It is used for strongly connected components
100 // with only one state and no self loops.
101 template <class S>
102 class TrivialQueue : public QueueBase<S> {
103 public:
104 typedef S StateId;
105
TrivialQueue()106 TrivialQueue() : QueueBase<S>(TRIVIAL_QUEUE), front_(kNoStateId) {}
Head()107 StateId Head() const { return front_; }
Enqueue(StateId s)108 void Enqueue(StateId s) { front_ = s; }
Dequeue()109 void Dequeue() { front_ = kNoStateId; }
Update(StateId s)110 void Update(StateId s) {}
Empty()111 bool Empty() const { return front_ == kNoStateId; }
Clear()112 void Clear() { front_ = kNoStateId; }
113
114
115 private:
Head_()116 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)117 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()118 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)119 virtual void Update_(StateId s) { Update(s); }
Empty_()120 virtual bool Empty_() const { return Empty(); }
Clear_()121 virtual void Clear_() { return Clear(); }
122
123 StateId front_;
124 };
125
126
127 // First-in, first-out queue discipline, templated on the StateId.
128 template <class S>
129 class FifoQueue : public QueueBase<S>, public deque<S> {
130 public:
131 using deque<S>::back;
132 using deque<S>::push_front;
133 using deque<S>::pop_back;
134 using deque<S>::empty;
135 using deque<S>::clear;
136
137 typedef S StateId;
138
FifoQueue()139 FifoQueue() : QueueBase<S>(FIFO_QUEUE) {}
Head()140 StateId Head() const { return back(); }
Enqueue(StateId s)141 void Enqueue(StateId s) { push_front(s); }
Dequeue()142 void Dequeue() { pop_back(); }
Update(StateId s)143 void Update(StateId s) {}
Empty()144 bool Empty() const { return empty(); }
Clear()145 void Clear() { clear(); }
146
147 private:
Head_()148 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)149 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()150 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)151 virtual void Update_(StateId s) { Update(s); }
Empty_()152 virtual bool Empty_() const { return Empty(); }
Clear_()153 virtual void Clear_() { return Clear(); }
154 };
155
156
157 // Last-in, first-out queue discipline, templated on the StateId.
158 template <class S>
159 class LifoQueue : public QueueBase<S>, public deque<S> {
160 public:
161 using deque<S>::front;
162 using deque<S>::push_front;
163 using deque<S>::pop_front;
164 using deque<S>::empty;
165 using deque<S>::clear;
166
167 typedef S StateId;
168
LifoQueue()169 LifoQueue() : QueueBase<S>(LIFO_QUEUE) {}
Head()170 StateId Head() const { return front(); }
Enqueue(StateId s)171 void Enqueue(StateId s) { push_front(s); }
Dequeue()172 void Dequeue() { pop_front(); }
Update(StateId s)173 void Update(StateId s) {}
Empty()174 bool Empty() const { return empty(); }
Clear()175 void Clear() { clear(); }
176
177 private:
Head_()178 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)179 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()180 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)181 virtual void Update_(StateId s) { Update(s); }
Empty_()182 virtual bool Empty_() const { return Empty(); }
Clear_()183 virtual void Clear_() { return Clear(); }
184 };
185
186
187 // Shortest-first queue discipline, templated on the StateId and
188 // comparison function object. Comparison function object COMP is
189 // used to compare two StateIds. If a (single) state's order changes,
190 // it can be reordered in the queue with a call to Update().
191 template <typename S, typename C>
192 class ShortestFirstQueue : public QueueBase<S> {
193 public:
194 typedef S StateId;
195 typedef C Compare;
196
ShortestFirstQueue(C comp)197 ShortestFirstQueue(C comp)
198 : QueueBase<S>(SHORTEST_FIRST_QUEUE), heap_(comp) {}
199
Head()200 StateId Head() const { return heap_.Top(); }
201
Enqueue(StateId s)202 void Enqueue(StateId s) {
203 for (StateId i = key_.size(); i <= s; ++i)
204 key_.push_back(kNoKey);
205 key_[s] = heap_.Insert(s);
206 }
207
Dequeue()208 void Dequeue() {
209 key_[heap_.Pop()] = kNoKey;
210 }
211
Update(StateId s)212 void Update(StateId s) {
213 if (s >= (StateId)key_.size() || key_[s] == kNoKey) {
214 Enqueue(s);
215 } else {
216 heap_.Update(key_[s], s);
217 }
218 }
219
Empty()220 bool Empty() const { return heap_.Empty(); }
221
Clear()222 void Clear() {
223 heap_.Clear();
224 key_.clear();
225 }
226
227 private:
228 Heap<S, C> heap_;
229 vector<ssize_t> key_;
230
Head_()231 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)232 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()233 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)234 virtual void Update_(StateId s) { Update(s); }
Empty_()235 virtual bool Empty_() const { return Empty(); }
Clear_()236 virtual void Clear_() { return Clear(); }
237 };
238
239
240 // Given a vector that maps from states to weights and a Less
241 // comparison function object between weights, this class defines a
242 // comparison function object between states.
243 template <typename S, typename L>
244 class StateWeightCompare {
245 public:
246 typedef L Less;
247 typedef typename L::Weight Weight;
248 typedef S StateId;
249
StateWeightCompare(const vector<Weight> * weights,const L & less)250 StateWeightCompare(const vector<Weight>* weights, const L &less)
251 : weights_(weights), less_(less) {}
252
operator()253 bool operator()(const S x, const S y) const {
254 return less_((*weights_)[x], (*weights_)[y]);
255 }
256
257 private:
258 const vector<Weight>* weights_;
259 L less_;
260 };
261
262
263 // Shortest-first queue discipline, templated on the StateId and Weight is
264 // specialized to use the weight's natural order for the comparion function.
265 template <typename S, typename W>
266 class NaturalShortestFirstQueue :
267 public ShortestFirstQueue<S, StateWeightCompare<S, NaturalLess<W> > > {
268 public:
269 typedef StateWeightCompare<S, NaturalLess<W> > C;
270
NaturalShortestFirstQueue(vector<W> * distance)271 NaturalShortestFirstQueue(vector<W> *distance) :
272 ShortestFirstQueue<S, C>(C(distance, less_)) {}
273
274 private:
275 NaturalLess<W> less_;
276 };
277
278
279 // Topological-order queue discipline, templated on the StateId.
280 // States are ordered in the queue topologically. The FST must be acyclic.
281 template <class S>
282 class TopOrderQueue : public QueueBase<S> {
283 public:
284 typedef S StateId;
285
286 // This constructor computes the top. order. It accepts an arc filter
287 // to limit the transitions considered in that computation (e.g., only
288 // the epsilon graph).
289 template <class Arc, class ArcFilter>
290
TopOrderQueue(const Fst<Arc> & fst,ArcFilter filter)291 TopOrderQueue(const Fst<Arc> &fst, ArcFilter filter)
292 : QueueBase<S>(TOP_ORDER_QUEUE), front_(0), back_(kNoStateId),
293 order_(0), state_(0) {
294 bool acyclic;
295 TopOrderVisitor<Arc> top_order_visitor(&order_, &acyclic);
296 DfsVisit(fst, &top_order_visitor, filter);
297 if (!acyclic)
298 LOG(FATAL) << "TopOrderQueue: fst is not acyclic.";
299 state_.resize(order_.size(), kNoStateId);
300 }
301
302 // This constructor is passed the top. order, useful when we know it
303 // beforehand.
TopOrderQueue(const vector<StateId> & order)304 TopOrderQueue(const vector<StateId> &order)
305 : QueueBase<S>(TOP_ORDER_QUEUE), front_(0), back_(kNoStateId),
306 order_(order), state_(order.size(), kNoStateId) {}
307
Head()308 StateId Head() const { return state_[front_]; }
309
Enqueue(StateId s)310 void Enqueue(StateId s) {
311 if (front_ > back_) front_ = back_ = order_[s];
312 else if (order_[s] > back_) back_ = order_[s];
313 else if (order_[s] < front_) front_ = order_[s];
314 state_[order_[s]] = s;
315 }
316
Dequeue()317 void Dequeue() {
318 state_[front_] = kNoStateId;
319 while ((front_ <= back_) && (state_[front_] == kNoStateId)) ++front_;
320 }
321
Update(StateId s)322 void Update(StateId s) {}
323
Empty()324 bool Empty() const { return front_ > back_; }
325
Clear()326 void Clear() {
327 for (StateId i = front_; i <= back_; ++i) state_[i] = kNoStateId;
328 back_ = kNoStateId;
329 front_ = 0;
330 }
331
332 private:
333 StateId front_;
334 StateId back_;
335 vector<StateId> order_;
336 vector<StateId> state_;
337
Head_()338 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)339 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()340 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)341 virtual void Update_(StateId s) { Update(s); }
Empty_()342 virtual bool Empty_() const { return Empty(); }
Clear_()343 virtual void Clear_() { return Clear(); }
344
345 };
346
347
348 // State order queue discipline, templated on the StateId.
349 // States are ordered in the queue by state Id.
350 template <class S>
351 class StateOrderQueue : public QueueBase<S> {
352 public:
353 typedef S StateId;
354
StateOrderQueue()355 StateOrderQueue()
356 : QueueBase<S>(STATE_ORDER_QUEUE), front_(0), back_(kNoStateId) {}
357
Head()358 StateId Head() const { return front_; }
359
Enqueue(StateId s)360 void Enqueue(StateId s) {
361 if (front_ > back_) front_ = back_ = s;
362 else if (s > back_) back_ = s;
363 else if (s < front_) front_ = s;
364 while ((StateId)enqueued_.size() <= s) enqueued_.push_back(false);
365 enqueued_[s] = true;
366 }
367
Dequeue()368 void Dequeue() {
369 enqueued_[front_] = false;
370 while ((front_ <= back_) && (enqueued_[front_] == false)) ++front_;
371 }
372
Update(StateId s)373 void Update(StateId s) {}
374
Empty()375 bool Empty() const { return front_ > back_; }
376
Clear()377 void Clear() {
378 for (StateId i = front_; i <= back_; ++i) enqueued_[i] = false;
379 front_ = 0;
380 back_ = kNoStateId;
381 }
382
383 private:
384 StateId front_;
385 StateId back_;
386 vector<bool> enqueued_;
387
Head_()388 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)389 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()390 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)391 virtual void Update_(StateId s) { Update(s); }
Empty_()392 virtual bool Empty_() const { return Empty(); }
Clear_()393 virtual void Clear_() { return Clear(); }
394
395 };
396
397
398 // SCC topological-order meta-queue discipline, templated on the StateId S
399 // and a queue Q, which is used inside each SCC. It visits the SCC's
400 // of an FST in topological order. Its constructor is passed the queues to
401 // to use within an SCC.
402 template <class S, class Q>
403 class SccQueue : public QueueBase<S> {
404 public:
405 typedef S StateId;
406 typedef Q Queue;
407
408 // Constructor takes a vector specifying the SCC number per state
409 // and a vector giving the queue to use per SCC number.
SccQueue(const vector<StateId> & scc,vector<Queue * > * queue)410 SccQueue(const vector<StateId> &scc, vector<Queue*> *queue)
411 : QueueBase<S>(SCC_QUEUE), queue_(queue), scc_(scc), front_(0),
412 back_(kNoStateId) {}
413
Head()414 StateId Head() const {
415 while ((front_ <= back_) &&
416 (((*queue_)[front_] && (*queue_)[front_]->Empty())
417 || (((*queue_)[front_] == 0) &&
418 ((front_ > (StateId)trivial_queue_.size())
419 || (trivial_queue_[front_] == kNoStateId)))))
420 ++front_;
421 if (front_ > back_)
422 LOG(FATAL) << "SccQueue: head of empty queue";
423 if ((*queue_)[front_])
424 return (*queue_)[front_]->Head();
425 else
426 return trivial_queue_[front_];
427 }
428
Enqueue(StateId s)429 void Enqueue(StateId s) {
430 if (front_ > back_) front_ = back_ = scc_[s];
431 else if (scc_[s] > back_) back_ = scc_[s];
432 else if (scc_[s] < front_) front_ = scc_[s];
433 if ((*queue_)[scc_[s]]) {
434 (*queue_)[scc_[s]]->Enqueue(s);
435 } else {
436 while ( (StateId)trivial_queue_.size() <= scc_[s])
437 trivial_queue_.push_back(kNoStateId);
438 trivial_queue_[scc_[s]] = s;
439 }
440 }
441
Dequeue()442 void Dequeue() {
443 if (front_ > back_)
444 LOG(FATAL) << "SccQueue: dequeue of empty queue";
445 if ((*queue_)[front_])
446 (*queue_)[front_]->Dequeue();
447 else if (front_ < (StateId)trivial_queue_.size())
448 trivial_queue_[front_] = kNoStateId;
449 }
450
Update(StateId s)451 void Update(StateId s) {
452 if ((*queue_)[scc_[s]])
453 (*queue_)[scc_[s]]->Update(s);
454 }
455
Empty()456 bool Empty() const {
457 if (front_ < back_) // Queue scc # back_ not empty unless back_==front_
458 return false;
459 else if (front_ > back_)
460 return true;
461 else if ((*queue_)[front_])
462 return (*queue_)[front_]->Empty();
463 else
464 return (front_ > (StateId)trivial_queue_.size())
465 || (trivial_queue_[front_] == kNoStateId);
466 }
467
Clear()468 void Clear() {
469 for (StateId i = front_; i <= back_; ++i)
470 if ((*queue_)[i])
471 (*queue_)[i]->Clear();
472 else if (i < (StateId)trivial_queue_.size())
473 trivial_queue_[i] = kNoStateId;
474 front_ = 0;
475 back_ = kNoStateId;
476 }
477
478 private:
479 vector<Queue*> *queue_;
480 const vector<StateId> &scc_;
481 mutable StateId front_;
482 StateId back_;
483 vector<StateId> trivial_queue_;
484
Head_()485 virtual StateId Head_() const { return Head(); }
Enqueue_(StateId s)486 virtual void Enqueue_(StateId s) { Enqueue(s); }
Dequeue_()487 virtual void Dequeue_() { Dequeue(); }
Update_(StateId s)488 virtual void Update_(StateId s) { Update(s); }
Empty_()489 virtual bool Empty_() const { return Empty(); }
Clear_()490 virtual void Clear_() { return Clear(); }
491 };
492
493
494 // Automatic queue discipline, templated on the StateId. It selects a
495 // queue discipline for a given FST based on its properties.
496 template <class S>
497 class AutoQueue : public QueueBase<S> {
498 public:
499 typedef S StateId;
500
501 // This constructor takes a state distance vector that, if non-null and if
502 // the Weight type has the path property, will entertain the
503 // shortest-first queue using the natural order w.r.t to the distance.
504 template <class Arc, class ArcFilter>
AutoQueue(const Fst<Arc> & fst,const vector<typename Arc::Weight> * distance,ArcFilter filter)505 AutoQueue(const Fst<Arc> &fst, const vector<typename Arc::Weight> *distance,
506 ArcFilter filter) : QueueBase<S>(AUTO_QUEUE) {
507 typedef typename Arc::Weight Weight;
508 typedef StateWeightCompare< StateId, NaturalLess<Weight> > Compare;
509
510 // First check if the FST is known to have these properties.
511 uint64 props = fst.Properties(kAcyclic | kCyclic |
512 kTopSorted | kUnweighted, false);
513 if ((props & kTopSorted) || fst.Start() == kNoStateId) {
514 queue_ = new StateOrderQueue<StateId>();
515 VLOG(2) << "AutoQueue: using state-order discipline";
516 } else if (props & kAcyclic) {
517 queue_ = new TopOrderQueue<StateId>(fst, filter);
518 VLOG(2) << "AutoQueue: using top-order discipline";
519 } else if ((props & kUnweighted) && (Weight::Properties() & kIdempotent)) {
520 queue_ = new LifoQueue<StateId>();
521 VLOG(2) << "AutoQueue: using LIFO discipline";
522 } else {
523 uint64 props;
524 // Decompose into strongly-connected components.
525 SccVisitor<Arc> scc_visitor(&scc_, 0, 0, &props);
526 DfsVisit(fst, &scc_visitor, filter);
527 StateId nscc = *max_element(scc_.begin(), scc_.end()) + 1;
528 vector<QueueType> queue_types(nscc);
529 NaturalLess<Weight> *less = 0;
530 Compare *comp = 0;
531 if (distance && (Weight::Properties() & kPath)) {
532 less = new NaturalLess<Weight>;
533 comp = new Compare(distance, *less);
534 }
535 // Find the queue type to use per SCC.
536 bool unweighted;
537 bool all_trivial;
538 SccQueueType(fst, scc_, &queue_types, filter, less, &all_trivial,
539 &unweighted);
540 // If unweighted and semiring is idempotent, use lifo queue.
541 if (unweighted) {
542 queue_ = new LifoQueue<StateId>();
543 VLOG(2) << "AutoQueue: using LIFO discipline";
544 delete comp;
545 delete less;
546 return;
547 }
548 // If all the scc are trivial, FST is acyclic and the scc# gives
549 // the topological order.
550 if (all_trivial) {
551 queue_ = new TopOrderQueue<StateId>(scc_);
552 VLOG(2) << "AutoQueue: using top-order discipline";
553 delete comp;
554 delete less;
555 return;
556 }
557 VLOG(2) << "AutoQueue: using SCC meta-discipline";
558 queues_.resize(nscc);
559 for (StateId i = 0; i < nscc; ++i) {
560 switch(queue_types[i]) {
561 case TRIVIAL_QUEUE:
562 queues_[i] = 0;
563 VLOG(3) << "AutoQueue: SCC #" << i
564 << ": using trivial discipline";
565 break;
566 case SHORTEST_FIRST_QUEUE:
567 CHECK(comp);
568 queues_[i] = new ShortestFirstQueue<StateId, Compare>(*comp);
569 VLOG(3) << "AutoQueue: SCC #" << i <<
570 ": using shortest-first discipline";
571 break;
572 case LIFO_QUEUE:
573 queues_[i] = new LifoQueue<StateId>();
574 VLOG(3) << "AutoQueue: SCC #" << i
575 << ": using LIFO disciplle";
576 break;
577 case FIFO_QUEUE:
578 default:
579 queues_[i] = new FifoQueue<StateId>();
580 VLOG(3) << "AutoQueue: SCC #" << i
581 << ": using FIFO disciplle";
582 break;
583 }
584 }
585 queue_ = new SccQueue< StateId, QueueBase<StateId> >(scc_, &queues_);
586 delete comp;
587 delete less;
588 }
589 }
590
~AutoQueue()591 ~AutoQueue() {
592 for (StateId i = 0; i < (StateId)queues_.size(); ++i) /*naucen-edit*/
593 delete queues_[i];
594 delete queue_;
595 }
596
Head()597 StateId Head() const { return queue_->Head(); }
598
Enqueue(StateId s)599 void Enqueue(StateId s) { queue_->Enqueue(s); }
600
Dequeue()601 void Dequeue() { queue_->Dequeue(); }
602
Update(StateId s)603 void Update(StateId s) { queue_->Update(s); }
604
Empty()605 bool Empty() const { return queue_->Empty(); }
606
Clear()607 void Clear() { queue_->Clear(); }
608
609
610 private:
611 QueueBase<StateId> *queue_;
612 vector< QueueBase<StateId>* > queues_;
613 vector<StateId> scc_;
614
615 template <class Arc, class ArcFilter, class Less>
616 static void SccQueueType(const Fst<Arc> &fst,
617 const vector<StateId> &scc,
618 vector<QueueType> *queue_types,
619 ArcFilter filter, Less *less,
620 bool *all_trivial, bool *unweighted);
621
Head_()622 virtual StateId Head_() const { return Head(); }
623
Enqueue_(StateId s)624 virtual void Enqueue_(StateId s) { Enqueue(s); }
625
Dequeue_()626 virtual void Dequeue_() { Dequeue(); }
627
Update_(StateId s)628 virtual void Update_(StateId s) { Update(s); }
629
Empty_()630 virtual bool Empty_() const { return Empty(); }
631
Clear_()632 virtual void Clear_() { return Clear(); }
633 };
634
635
636 // Examines the states in an Fst's strongly connected components and
637 // determines which type of queue to use per SCC. Stores result in
638 // vector QUEUE_TYPES, which is assumed to have length equal to the
639 // number of SCCs. An arc filter is used to limit the transitions
640 // considered (e.g., only the epsilon graph). ALL_TRIVIAL is set
641 // to true if every queue is the trivial queue. UNWEIGHTED is set to
642 // true if the semiring is idempotent and all the arc weights are equal to
643 // Zero() or One().
644 template <class StateId>
645 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)646 void AutoQueue<StateId>::SccQueueType(const Fst<A> &fst,
647 const vector<StateId> &scc,
648 vector<QueueType> *queue_type,
649 ArcFilter filter, Less *less,
650 bool *all_trivial, bool *unweighted) {
651 typedef A Arc;
652 typedef typename A::StateId StateId;
653 typedef typename A::Weight Weight;
654
655 *all_trivial = true;
656 *unweighted = true;
657
658 for (StateId i = 0; i < (StateId)queue_type->size(); ++i)
659 (*queue_type)[i] = TRIVIAL_QUEUE;
660
661 for (StateIterator< Fst<Arc> > sit(fst); !sit.Done(); sit.Next()) {
662 StateId state = sit.Value();
663 for (ArcIterator< Fst<Arc> > ait(fst, state);
664 !ait.Done();
665 ait.Next()) {
666 const Arc &arc = ait.Value();
667 if (!filter(arc)) continue;
668 if (scc[state] == scc[arc.nextstate]) {
669 QueueType &type = (*queue_type)[scc[state]];
670 if (!less || ((*less)(arc.weight, Weight::One())))
671 type = FIFO_QUEUE;
672 else if ((type == TRIVIAL_QUEUE) || (type == LIFO_QUEUE))
673 if (!(Weight::Properties() & kIdempotent) ||
674 (arc.weight != Weight::Zero() && arc.weight != Weight::One()))
675 type = SHORTEST_FIRST_QUEUE;
676 else
677 type = LIFO_QUEUE;
678 if (type != TRIVIAL_QUEUE) *all_trivial = false;
679 }
680 if (!(Weight::Properties() & kIdempotent) ||
681 (arc.weight != Weight::Zero() && arc.weight != Weight::One()))
682 *unweighted = false;
683 }
684 }
685 }
686
687 } // namespace fst
688
689 #endif
690