LatticeWordAligner::ComputationState Class Reference
Collaboration diagram for LatticeWordAligner::ComputationState:

Public Member Functions

void Advance (const CompactLatticeArc &arc, LatticeWeight *weight)
 The state of the computation in which,. More...
 
bool OutputArc (const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
 If it can output a whole word, it will do so, will put it in arc_out, and return true; else it will return false. More...
 
bool OutputSilenceArc (const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
 
bool OutputOnePhoneWordArc (const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
 
bool OutputNormalWordArc (const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
 This function tries to see if it can output a normal word arc– one with at least two phones in it. More...
 
bool IsEmpty ()
 
LatticeWeight FinalWeight ()
 FinalWeight() will return "weight" if both transition_ids and word_labels are empty, otherwise it will return Weight::Zero(). More...
 
void OutputArcForce (const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
 This function may be called when you reach the end of the lattice and this structure hasn't voluntarily output words using "OutputArc". More...
 
size_t Hash () const
 
bool operator== (const ComputationState &other) const
 
 ComputationState ()
 
 ComputationState (const ComputationState &other)
 

Private Attributes

std::vector< int32transition_ids_
 
std::vector< int32word_labels_
 
LatticeWeight weight_
 

Detailed Description

Definition at line 32 of file word-align-lattice.cc.

Constructor & Destructor Documentation

◆ ComputationState() [1/2]

ComputationState ( )
inline

Definition at line 125 of file word-align-lattice.cc.

125 : weight_(LatticeWeight::One()) { } // initial state.
static const LatticeWeightTpl One()

◆ ComputationState() [2/2]

ComputationState ( const ComputationState other)
inline

Definition at line 126 of file word-align-lattice.cc.

126  :
127  transition_ids_(other.transition_ids_), word_labels_(other.word_labels_),
128  weight_(other.weight_) { }

Member Function Documentation

◆ Advance()

void Advance ( const CompactLatticeArc arc,
LatticeWeight weight 
)
inline

The state of the computation in which,.

along a single path in the lattice, we work out the word boundaries and output aligned arcs. Advance the computation state by adding the symbols and weights from this arc. We'll put the weight on the output arc; this helps keep the state-space smaller.

Definition at line 40 of file word-align-lattice.cc.

References LatticeWeightTpl< BaseFloat >::One(), fst::Times(), LatticeWordAligner::ComputationState::transition_ids_, LatticeWordAligner::ComputationState::weight_, and LatticeWordAligner::ComputationState::word_labels_.

Referenced by LatticeWordAligner::ProcessQueueElement().

40  {
41  const std::vector<int32> &string = arc.weight.String();
42  transition_ids_.insert(transition_ids_.end(),
43  string.begin(), string.end());
44  if (arc.ilabel != 0) // note: arc.ilabel==arc.olabel (acceptor)
45  word_labels_.push_back(arc.ilabel);
46  *weight = Times(weight_, arc.weight.Weight());
48  }
static const LatticeWeightTpl One()
LatticeWeightTpl< FloatType > Times(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)

◆ FinalWeight()

LatticeWeight FinalWeight ( )
inline

◆ Hash()

size_t Hash ( ) const
inline

Definition at line 108 of file word-align-lattice.cc.

References LatticeWordAligner::ComputationState::transition_ids_, and LatticeWordAligner::ComputationState::word_labels_.

Referenced by LatticeWordAligner::TupleHash::operator()().

108  {
109  VectorHasher<int32> vh;
110  return vh(transition_ids_) + 90647 * vh(word_labels_);
111  // 90647 is an arbitrary largish prime number.
112  // We don't bother including the weight in the hash--
113  // we don't really expect duplicates with the same vectors
114  // but different weights, and anyway, this is only an
115  // efficiency issue.
116  }

◆ IsEmpty()

◆ operator==()

bool operator== ( const ComputationState other) const
inline

◆ OutputArc()

bool OutputArc ( const WordBoundaryInfo info,
const TransitionModel tmodel,
CompactLatticeArc arc_out,
bool error 
)
inline

If it can output a whole word, it will do so, will put it in arc_out, and return true; else it will return false.

If it detects an error condition and *error = false, it will set *error to true and print a warning. In this case it may or may not [output an arc and return true], depending on what we think is most likely the right thing to do. Of course once *error is set, something has gone wrong so don't trust the output too fully. Note: the "next_state" of the arc will not be set, you have to do that yourself.

Definition at line 59 of file word-align-lattice.cc.

References LatticeWordAligner::ComputationState::OutputNormalWordArc(), LatticeWordAligner::ComputationState::OutputOnePhoneWordArc(), and LatticeWordAligner::ComputationState::OutputSilenceArc().

62  {
63  // order of this ||-expression doesn't matter for
64  // function behavior, only for efficiency, since the
65  // cases are disjoint.
66  return OutputNormalWordArc(info, tmodel, arc_out, error) ||
67  OutputSilenceArc(info, tmodel, arc_out, error) ||
68  OutputOnePhoneWordArc(info, tmodel, arc_out, error);
69  }
bool OutputNormalWordArc(const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
This function tries to see if it can output a normal word arc– one with at least two phones in it...
bool OutputSilenceArc(const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)
bool OutputOnePhoneWordArc(const WordBoundaryInfo &info, const TransitionModel &tmodel, CompactLatticeArc *arc_out, bool *error)

◆ OutputArcForce()

void OutputArcForce ( const WordBoundaryInfo info,
const TransitionModel tmodel,
CompactLatticeArc arc_out,
bool error 
)

This function may be called when you reach the end of the lattice and this structure hasn't voluntarily output words using "OutputArc".

If IsEmpty() == false, then you can call this function and it will output an arc. The only non-error state in which this happens, is when a word (or silence) has ended, but we don't know that it's ended because we haven't seen the first transition-id from the next word. Otherwise (error state), the output will consist of partial words, and this will only happen for lattices that were somehow broken, i.e. had not reached the final state.

Definition at line 565 of file word-align-lattice.cc.

References rnnlm::i, LatticeWordAligner::ComputationState::IsEmpty(), TransitionModel::IsFinal(), kaldi::IsPlausibleWord(), TransitionModel::IsSelfLoop(), KALDI_ASSERT, KALDI_ERR, KALDI_WARN, WordBoundaryInfo::kNonWordPhone, LatticeWeightTpl< BaseFloat >::One(), WordBoundaryInfo::partial_word_label, WordBoundaryInfo::reorder, WordBoundaryInfo::silence_label, LatticeWordAligner::ComputationState::transition_ids_, TransitionModel::TransitionIdToPhone(), WordBoundaryInfo::TypeOfPhone(), LatticeWordAligner::ComputationState::weight_, and LatticeWordAligner::ComputationState::word_labels_.

Referenced by LatticeWordAligner::ComputationState::FinalWeight(), and LatticeWordAligner::ProcessFinal().

567  {
568 
569  KALDI_ASSERT(!IsEmpty());
570  if (!word_labels_.empty()
571  && !transition_ids_.empty()) { // We have at least one word to
572  // output, and some transition-ids. We assume that the normal OutputArc was called
573  // and failed, so this means we didn't see the end of that
574  // word.
575  int32 word = word_labels_[0];
576  if (! *error && !IsPlausibleWord(info, tmodel, transition_ids_)) {
577  *error = true;
578  KALDI_WARN << "Invalid word at end of lattice [partial lattice, forced out?]";
579  }
581  *arc_out = CompactLatticeArc(word, word, cw, fst::kNoStateId);
583  transition_ids_.clear();
584  word_labels_.erase(word_labels_.begin(), word_labels_.begin()+1);
585  } else if (!word_labels_.empty() && transition_ids_.empty()) {
586  // We won't create arcs with these word labels on, as most likely
587  // this will cause errors down the road. This is an error
588  // condition anyway, in some sense.
589  if (! *error) {
590  *error = true;
591  KALDI_WARN << "Discarding word-ids at the end of a sentence, "
592  "that don't have alignments.";
593  }
595  // This creates an epsilon arc with a weight on it, but
596  // no transition-ids since the vector is empty.
597  // The word labels are discarded.
598  *arc_out = CompactLatticeArc(0, 0, cw, fst::kNoStateId);
600  word_labels_.clear();
601  } else if (!transition_ids_.empty() && word_labels_.empty()) {
602  // Transition-ids but no word label-- either silence or partial word.
603  int32 first_phone = tmodel.TransitionIdToPhone(transition_ids_[0]);
604  if (info.TypeOfPhone(first_phone) == WordBoundaryInfo::kNonWordPhone) {
605  // first phone is silence...
606  if (first_phone != tmodel.TransitionIdToPhone(transition_ids_.back())
607  && ! *error) {
608  *error = true;
609  // Phone changed-- this is a code error, because the regular OutputArc
610  // should have output an arc (a silence arc) if that phone finished.
611  // So we make it fatal.
612  KALDI_ERR << "Broken silence arc at end of utterance (the phone "
613  "changed); code error";
614  }
615  if (!*error) { // Check that it ends at the end state of silence; error otherwise.
616  int32 i = transition_ids_.size() - 1;
617  if (info.reorder)
618  while (tmodel.IsSelfLoop(transition_ids_[i]) && i > 0)
619  i--;
620  if (!tmodel.IsFinal(transition_ids_[i])) {
621  *error = true;
622  KALDI_WARN << "Broken silence arc at end of utterance (does not "
623  "reach end of silence)";
624  }
625  }
627  *arc_out = CompactLatticeArc(info.silence_label, info.silence_label,
628  cw, fst::kNoStateId);
629  } else {
630  // Not silence phone -- treat as partial word (with no word label).
631  // This is in itself an error condition, i.e. the lattice was maybe
632  // forced out.
633  if (! *error) {
634  *error = true;
635  KALDI_WARN << "Partial word detected at end of utterance";
636  }
638  *arc_out = CompactLatticeArc(info.partial_word_label, info.partial_word_label,
639  cw, fst::kNoStateId);
640  }
641  transition_ids_.clear();
643  } else {
644  KALDI_ERR << "Code error, word-aligning lattice"; // this shouldn't
645  // be able to happen; we don't call this function of they're both empty.
646  }
647 }
static const LatticeWeightTpl One()
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
Definition: kaldi-lattice.h:35
kaldi::int32 int32
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
static bool IsPlausibleWord(const WordAlignLatticeLexiconInfo &lexicon_info, const TransitionModel &tmodel, int32 word_id, const std::vector< int32 > &transition_ids)
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
Definition: kaldi-lattice.h:42

◆ OutputNormalWordArc()

bool OutputNormalWordArc ( const WordBoundaryInfo info,
const TransitionModel tmodel,
CompactLatticeArc arc_out,
bool error 
)

This function tries to see if it can output a normal word arc– one with at least two phones in it.

Definition at line 450 of file word-align-lattice.cc.

References rnnlm::i, TransitionModel::IsFinal(), TransitionModel::IsSelfLoop(), KALDI_WARN, WordBoundaryInfo::kWordBeginPhone, WordBoundaryInfo::kWordEndPhone, WordBoundaryInfo::kWordInternalPhone, LatticeWeightTpl< BaseFloat >::One(), WordBoundaryInfo::reorder, LatticeWordAligner::ComputationState::transition_ids_, TransitionModel::TransitionIdToPhone(), WordBoundaryInfo::TypeOfPhone(), LatticeWordAligner::ComputationState::weight_, and LatticeWordAligner::ComputationState::word_labels_.

Referenced by LatticeWordAligner::ComputationState::OutputArc().

452  {
453  if (transition_ids_.empty()) return false;
454  if (word_labels_.empty()) return false;
455  int32 begin_phone = tmodel.TransitionIdToPhone(transition_ids_[0]);
456  if (info.TypeOfPhone(begin_phone) != WordBoundaryInfo::kWordBeginPhone)
457  return false;
458  // we assume the start of transition_ids_ is the start of the phone.
459  // this is a precondition.
460  size_t len = transition_ids_.size(), i;
461 
462  // Eat up the transition-ids of this word-begin phone until we get to the
463  // "final" transition-id. [there may be self-loops following this though,
464  // if reorder==true]
465  for (i = 0; i < len && !tmodel.IsFinal(transition_ids_[i]); i++);
466  if (i == len) return false;
467  i++; // Skip over this final-transition.
468  if (info.reorder) // Skip over any reordered self-loops for this final-transition
469  for (; i < len && tmodel.IsSelfLoop(transition_ids_[i]); i++);
470  if (i == len) return false;
471  if (tmodel.TransitionIdToPhone(transition_ids_[i-1]) != begin_phone
472  && ! *error) { // another check.
473  KALDI_WARN << "Phone changed unexpectedly in lattice "
474  "[broken lattice or mismatched model?]";
475  *error = true;
476  }
477  // Now keep going till we hit a word-ending phone.
478  // Note: we don't expect anything except word-internal phones
479  // here, but we'll just print a warning if we get something
480  // else.
481  for (; i < len; i++) {
482  int32 this_phone = tmodel.TransitionIdToPhone(transition_ids_[i]);
483  if (info.TypeOfPhone(this_phone) == WordBoundaryInfo::kWordEndPhone)
484  break;
485  if (info.TypeOfPhone(this_phone) != WordBoundaryInfo::kWordInternalPhone
486  && !*error) {
487  KALDI_WARN << "Unexpected phone " << this_phone
488  << " found inside a word.";
489  *error = true;
490  }
491  }
492  if (i == len) return false;
493 
494  // OK, we hit a word-ending phone. Continue till we get to
495  // a "final-transition".
496 
497  // this variable just used for checks.
498  int32 final_phone = tmodel.TransitionIdToPhone(transition_ids_[i]);
499  for (; i < len; i++) {
500  int32 this_phone = tmodel.TransitionIdToPhone(transition_ids_[i]);
501  if (this_phone != final_phone && ! *error) {
502  *error = true;
503  KALDI_WARN << "Phone changed before final transition-id found "
504  "[broken lattice or mismatched model or wrong --reorder option?]";
505  }
506  if (tmodel.IsFinal(transition_ids_[i])) break;
507  }
508  if (i == len) return false;
509  i++;
510  // We got to the final-transition of the final phone;
511  // if reorder==true, continue eating up the self-loop.
512  if (info.reorder == true)
513  while (i < len && tmodel.IsSelfLoop(transition_ids_[i])) i++;
514  if (i == len) return false;
515  if (tmodel.TransitionIdToPhone(transition_ids_[i-1]) != final_phone
516  && ! *error) {
517  *error = true;
518  KALDI_WARN << "Phone changed while following final self-loop "
519  "[broken lattice or mismatched model or wrong --reorder option?]";
520  }
521 
522  // OK, we're ready to output the word.
523  // Interpret i as the number of transition-ids to consume.
524  std::vector<int32> tids_out(transition_ids_.begin(),
525  transition_ids_.begin() + i);
526 
527  // consumed transition ids from our internal state.
528  int32 word = word_labels_[0];
529  *arc_out = CompactLatticeArc(word, word,
530  CompactLatticeWeight(weight_, tids_out),
531  fst::kNoStateId);
532  transition_ids_.erase(transition_ids_.begin(),
533  transition_ids_.begin() + i); // delete these
534  // Remove the word that we just output.
535  word_labels_.erase(word_labels_.begin(),
536  word_labels_.begin() + 1);
537  weight_ = LatticeWeight::One(); // we just output the weight.
538  return true;
539 }
static const LatticeWeightTpl One()
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
Definition: kaldi-lattice.h:35
kaldi::int32 int32
#define KALDI_WARN
Definition: kaldi-error.h:150
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
Definition: kaldi-lattice.h:42

◆ OutputOnePhoneWordArc()

bool OutputOnePhoneWordArc ( const WordBoundaryInfo info,
const TransitionModel tmodel,
CompactLatticeArc arc_out,
bool error 
)

Definition at line 396 of file word-align-lattice.cc.

References rnnlm::i, TransitionModel::IsFinal(), TransitionModel::IsSelfLoop(), KALDI_WARN, WordBoundaryInfo::kWordBeginAndEndPhone, LatticeWeightTpl< BaseFloat >::One(), WordBoundaryInfo::reorder, LatticeWordAligner::ComputationState::transition_ids_, TransitionModel::TransitionIdToPhone(), WordBoundaryInfo::TypeOfPhone(), LatticeWordAligner::ComputationState::weight_, and LatticeWordAligner::ComputationState::word_labels_.

Referenced by LatticeWordAligner::ComputationState::OutputArc().

398  {
399  if (transition_ids_.empty()) return false;
400  if (word_labels_.empty()) return false;
401  int32 phone = tmodel.TransitionIdToPhone(transition_ids_[0]);
402  if (info.TypeOfPhone(phone) != WordBoundaryInfo::kWordBeginAndEndPhone)
403  return false;
404  // we assume the start of transition_ids_ is the start of the phone.
405  // this is a precondition.
406  size_t len = transition_ids_.size(), i;
407  for (i = 0; i < len; i++) {
408  int32 tid = transition_ids_[i];
409  int32 this_phone = tmodel.TransitionIdToPhone(tid);
410  if (this_phone != phone && ! *error) { // error condition: should have reached final transition-id first.
411  KALDI_WARN << "Phone changed before final transition-id found "
412  "[broken lattice or mismatched model or wrong --reorder option?]";
413  // just continue, ignoring this-- we'll probably output something...
414  }
415  if (tmodel.IsFinal(tid))
416  break;
417  }
418  if (i == len) return false; // fell off loop.
419  i++; // go past the one for which IsFinal returned true.
420  if (info.reorder) // we have to consume the following self-loop transition-ids.
421  while (i < len && tmodel.IsSelfLoop(transition_ids_[i])) i++;
422  if (i == len) return false; // we don't know if it ends here... so can't output arc.
423 
424  if (tmodel.TransitionIdToPhone(transition_ids_[i-1]) != phone
425  && ! *error) { // another check.
426  KALDI_WARN << "Phone changed unexpectedly in lattice "
427  "[broken lattice or mismatched model?]";
428  *error = true;
429  }
430 
431  // interpret i as the number of transition-ids to consume.
432  std::vector<int32> tids_out(transition_ids_.begin(),
433  transition_ids_.begin() + i);
434 
435  // consumed transition ids from our internal state.
436  int32 word = word_labels_[0];
437  *arc_out = CompactLatticeArc(word, word,
438  CompactLatticeWeight(weight_, tids_out), fst::kNoStateId);
439  transition_ids_.erase(transition_ids_.begin(),
440  transition_ids_.begin() + i); // delete these
441  // Remove the word that we just output.
442  word_labels_.erase(word_labels_.begin(), word_labels_.begin() + 1);
443  weight_ = LatticeWeight::One(); // we just output the weight.
444  return true;
445 }
static const LatticeWeightTpl One()
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
Definition: kaldi-lattice.h:35
kaldi::int32 int32
#define KALDI_WARN
Definition: kaldi-error.h:150
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
Definition: kaldi-lattice.h:42

◆ OutputSilenceArc()

bool OutputSilenceArc ( const WordBoundaryInfo info,
const TransitionModel tmodel,
CompactLatticeArc arc_out,
bool error 
)

Definition at line 350 of file word-align-lattice.cc.

References rnnlm::i, TransitionModel::IsFinal(), TransitionModel::IsSelfLoop(), KALDI_WARN, WordBoundaryInfo::kNonWordPhone, LatticeWeightTpl< BaseFloat >::One(), WordBoundaryInfo::reorder, WordBoundaryInfo::silence_label, LatticeWordAligner::ComputationState::transition_ids_, TransitionModel::TransitionIdToPhone(), WordBoundaryInfo::TypeOfPhone(), and LatticeWordAligner::ComputationState::weight_.

Referenced by LatticeWordAligner::ComputationState::OutputArc().

352  {
353  if (transition_ids_.empty()) return false;
354  int32 phone = tmodel.TransitionIdToPhone(transition_ids_[0]);
355  if (info.TypeOfPhone(phone) != WordBoundaryInfo::kNonWordPhone) return false;
356 
357  // we assume the start of transition_ids_ is the start of the phone [silence];
358  // this is a precondition.
359  size_t len = transition_ids_.size(), i;
360  // Keep going till we reach a "final" transition-id; note, if
361  // reorder==true, we have to go a bit further after this.
362  for (i = 0; i < len; i++) {
363  int32 tid = transition_ids_[i];
364  int32 this_phone = tmodel.TransitionIdToPhone(tid);
365  if (this_phone != phone && ! *error) { // error condition: should have reached final transition-id first.
366  *error = true;
367  KALDI_WARN << "Phone changed before final transition-id found "
368  "[broken lattice or mismatched model or wrong --reorder option?]";
369  }
370  if (tmodel.IsFinal(tid))
371  break;
372  }
373  if (i == len) return false; // fell off loop.
374  i++; // go past the one for which IsFinal returned true.
375  if (info.reorder) // we have to consume the following self-loop transition-ids.
376  while (i < len && tmodel.IsSelfLoop(transition_ids_[i])) i++;
377  if (i == len) return false; // we don't know if it ends here... so can't output arc.
378 
379  if (tmodel.TransitionIdToPhone(transition_ids_[i-1]) != phone
380  && ! *error) { // another check.
381  KALDI_WARN << "Phone changed unexpectedly in lattice "
382  "[broken lattice or mismatched model?]";
383  }
384  // interpret i as the number of transition-ids to consume.
385  std::vector<int32> tids_out(transition_ids_.begin(), transition_ids_.begin()+i);
386 
387  // consumed transition ids from our internal state.
388  *arc_out = CompactLatticeArc(info.silence_label, info.silence_label,
389  CompactLatticeWeight(weight_, tids_out), fst::kNoStateId);
390  transition_ids_.erase(transition_ids_.begin(), transition_ids_.begin()+i); // delete these
391  weight_ = LatticeWeight::One(); // we just output the weight.
392  return true;
393 }
static const LatticeWeightTpl One()
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
Definition: kaldi-lattice.h:35
kaldi::int32 int32
#define KALDI_WARN
Definition: kaldi-error.h:150
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
Definition: kaldi-lattice.h:42

Member Data Documentation

◆ transition_ids_

◆ weight_

◆ word_labels_


The documentation for this class was generated from the following file: