LatticeLexiconWordAligner::ComputationState Class Reference
Collaboration diagram for LatticeLexiconWordAligner::ComputationState:

Public Member Functions

void Advance (const CompactLatticeArc &arc, const TransitionModel &tmodel, LatticeWeight *leftover_weight)
 The state of the computation in which, along a single path in the lattice, we work out the word boundaries and output aligned arcs. More...
 
bool ViableIfAdvanced (const ViabilityMap &viability_map) const
 Returns true if, assuming we were to add one or more phones by calling Advance one or more times on this, we might be able later to successfully call TakeTransition. More...
 
int32 NumPhones () const
 
int32 NumWords () const
 
int32 PendingWord () const
 
Freshness WordFreshness () const
 
Freshness PhoneFreshness () const
 
void TakeForcedTransition (int32 partial_word_label, ComputationState *next_state, CompactLatticeArc *arc_out) const
 This may be called at the end of a lattice, if it was forced out. More...
 
bool TakeTransition (const LexiconMap &lexicon_map, int32 word_id, int32 num_phones, ComputationState *next_state, CompactLatticeArc *arc_out) const
 Take a transition, if possible; consume "num_phones" phones and (if word_id != 0) the word "word_id" which must be the first word in words_. More...
 
bool IsEmpty () const
 
LatticeWeight FinalWeight () const
 FinalWeight() will return "weight" if both transition_ids and word_labels are empty, otherwise it will return Weight::Zero(). More...
 
size_t Hash () const
 
bool operator== (const ComputationState &other) const
 
 ComputationState ()
 
 ComputationState (const ComputationState &other)
 

Private Attributes

std::vector< int32phones_
 
std::vector< int32words_
 
Freshness phone_fresh_
 
Freshness word_fresh_
 
std::vector< std::vector< int32 > > transition_ids_
 
LatticeWeight weight_
 

Detailed Description

Definition at line 62 of file word-align-lattice-lexicon.cc.

Constructor & Destructor Documentation

◆ ComputationState() [1/2]

◆ ComputationState() [2/2]

Member Function Documentation

◆ Advance()

void Advance ( const CompactLatticeArc arc,
const TransitionModel tmodel,
LatticeWeight leftover_weight 
)

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. Outputs weight to "leftover_weight" and sets the weight to 1.0 (this helps keep the state space small). Note: because we previously did PhoneAlignLattice, we can assume this arc corresponds to exactly one or zero phones.

Definition at line 573 of file word-align-lattice-lexicon.cc.

References KALDI_ASSERT, LatticeLexiconWordAligner::kFresh, LatticeLexiconWordAligner::kNotFresh, LatticeWeightTpl< BaseFloat >::One(), LatticeLexiconWordAligner::ComputationState::phone_fresh_, LatticeLexiconWordAligner::ComputationState::phones_, fst::Times(), LatticeLexiconWordAligner::ComputationState::transition_ids_, TransitionModel::TransitionIdToPhone(), LatticeLexiconWordAligner::ComputationState::weight_, LatticeLexiconWordAligner::ComputationState::word_fresh_, and LatticeLexiconWordAligner::ComputationState::words_.

Referenced by LatticeLexiconWordAligner::PossiblyAdvanceArc().

574  {
575  const std::vector<int32> &tids = arc.weight.String();
576  int32 phone;
577  if (tids.empty()) phone = 0;
578  else {
579  phone = tmodel.TransitionIdToPhone(tids.front());
580  KALDI_ASSERT(phone == tmodel.TransitionIdToPhone(tids.back()) &&
581  "Error: lattice is not phone-aligned.");
582  }
583  if (arc.ilabel != 0) { // note: arc.ilabel==arc.olabel (acceptor)
584  words_.push_back(arc.ilabel);
585  // Note: the word freshness only applies to the word in position 0,
586  // so only if the word-sequence is now of size 1, is it fresh.
587  if (words_.size() == 1) word_fresh_ = kFresh;
588  else word_fresh_ = kNotFresh;
589  } else { // No word added -> word not fresh.
591  }
592  if (phone != 0) {
593  phones_.push_back(phone);
594  transition_ids_.push_back(tids);
596  } else {
598  }
599  *weight = Times(weight_, arc.weight.Weight()); // will go on arc in output lattice
601 }
static const LatticeWeightTpl One()
kaldi::int32 int32
LatticeWeightTpl< FloatType > Times(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ FinalWeight()

LatticeWeight FinalWeight ( ) const
inline

FinalWeight() will return "weight" if both transition_ids and word_labels are empty, otherwise it will return Weight::Zero().

Definition at line 112 of file word-align-lattice-lexicon.cc.

References LatticeLexiconWordAligner::ComputationState::IsEmpty(), LatticeLexiconWordAligner::ComputationState::weight_, and LatticeWeightTpl< BaseFloat >::Zero().

Referenced by LatticeLexiconWordAligner::ProcessFinal().

◆ Hash()

size_t Hash ( ) const
inline

Definition at line 116 of file word-align-lattice-lexicon.cc.

References rnnlm::i, LatticeLexiconWordAligner::ComputationState::phone_fresh_, LatticeLexiconWordAligner::ComputationState::transition_ids_, LatticeLexiconWordAligner::ComputationState::word_fresh_, and LatticeLexiconWordAligner::ComputationState::words_.

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

116  {
117  VectorHasher<int32> vh;
118  const int32 p1 = 11117, p2 = 90647, p3 = 3967, p4 = 3557; // primes.
119  size_t ans = 0;
120  for (int32 i = 0; i < static_cast<int32>(transition_ids_.size()); i++) {
121  ans *= p1;
122  ans += vh(transition_ids_[i]);
123  }
124  ans += p2 * vh(words_)
125  + static_cast<int32>(word_fresh_) * p3
126  + static_cast<int32>(phone_fresh_) * p4;
127  // phones_ is determined by transition-id sequence so we don't
128  // need to include it in the hash.
129  return ans;
130  }
kaldi::int32 int32

◆ IsEmpty()

◆ NumPhones()

◆ NumWords()

◆ operator==()

bool operator== ( const ComputationState other) const
inline

◆ PendingWord()

int32 PendingWord ( ) const
inline

◆ PhoneFreshness()

◆ TakeForcedTransition()

void TakeForcedTransition ( int32  partial_word_label,
ComputationState next_state,
CompactLatticeArc arc_out 
) const

This may be called at the end of a lattice, if it was forced out.

Note: we will only use "partial_word_label" if there are phones without corresponding words; otherwise we'll use the word label that was there.

Definition at line 634 of file word-align-lattice-lexicon.cc.

References LatticeLexiconWordAligner::AppendVectors(), LatticeLexiconWordAligner::ComputationState::IsEmpty(), KALDI_ASSERT, KALDI_WARN, LatticeLexiconWordAligner::kFresh, LatticeWeightTpl< BaseFloat >::One(), LatticeLexiconWordAligner::ComputationState::phone_fresh_, LatticeLexiconWordAligner::ComputationState::phones_, LatticeLexiconWordAligner::ComputationState::transition_ids_, LatticeLexiconWordAligner::ComputationState::weight_, LatticeLexiconWordAligner::ComputationState::word_fresh_, and LatticeLexiconWordAligner::ComputationState::words_.

Referenced by LatticeLexiconWordAligner::ComputationState::PhoneFreshness(), and LatticeLexiconWordAligner::ProcessFinalForceOut().

637  {
638  KALDI_ASSERT(!IsEmpty());
639 
640  next_state->phones_.clear();
641  next_state->words_.clear();
642  next_state->transition_ids_.clear();
643  // neither of the following variables should matter, actually,
644  // they will never be inspected. So just set them to kFresh for consistency,
645  // so they end up at the same place in the tuple-map_.
646  next_state->word_fresh_ = kFresh;
647  next_state->phone_fresh_ = kFresh;
648  next_state->weight_ = LatticeWeight::One();
649 
650  int32 word_id;
651  if (words_.size() >= 1) {
652  word_id = words_[0];
653  if (words_.size() > 1)
654  KALDI_WARN << "Word-aligning lattice: discarding extra word at end of lattice"
655  << "(forced-out).";
656  } else {
657  word_id = partial_word_label;
658  }
659  KALDI_ASSERT(word_id != 0); // any zeros would have been replaced with
660  // 'temporary epsilon' = 2.
661  std::vector<int32> appended_transition_ids;
663  transition_ids_.end(),
664  &appended_transition_ids);
665  arc_out->ilabel = word_id;
666  arc_out->olabel = word_id;
667  arc_out->weight = CompactLatticeWeight(weight_,
668  appended_transition_ids);
669  // arc_out->nextstate will be set by the calling code.
670 }
static void AppendVectors(std::vector< std::vector< int32 > >::const_iterator input_begin, std::vector< std::vector< int32 > >::const_iterator input_end, std::vector< int32 > *output)
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
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ TakeTransition()

bool TakeTransition ( const LexiconMap lexicon_map,
int32  word_id,
int32  num_phones,
ComputationState next_state,
CompactLatticeArc arc_out 
) const

Take a transition, if possible; consume "num_phones" phones and (if word_id != 0) the word "word_id" which must be the first word in words_.

Returns true if we could take the transition.

Definition at line 673 of file word-align-lattice-lexicon.cc.

References LatticeLexiconWordAligner::AppendVectors(), kaldi::GetVerboseLevel(), rnnlm::i, KALDI_ASSERT, KALDI_VLOG, LatticeLexiconWordAligner::kAllFresh, LatticeLexiconWordAligner::kFresh, LatticeLexiconWordAligner::kNotFresh, LatticeWeightTpl< BaseFloat >::One(), LatticeLexiconWordAligner::ComputationState::phone_fresh_, LatticeLexiconWordAligner::ComputationState::phones_, LatticeLexiconWordAligner::ComputationState::transition_ids_, LatticeLexiconWordAligner::ComputationState::weight_, LatticeLexiconWordAligner::ComputationState::word_fresh_, and LatticeLexiconWordAligner::ComputationState::words_.

Referenced by LatticeLexiconWordAligner::ComputationState::PhoneFreshness(), LatticeLexiconWordAligner::ProcessEpsilonTransitions(), and LatticeLexiconWordAligner::ProcessWordTransitions().

675  {
676  KALDI_ASSERT(word_id == 0 || (!words_.empty() && word_id == words_[0]));
677  KALDI_ASSERT(num_phones <= static_cast<int32>(phones_.size()));
678 
679  std::vector<int32> lexicon_key;
680  lexicon_key.reserve(1 + num_phones);
681  lexicon_key.push_back(word_id); // put 1st word in lexicon_key.
682  lexicon_key.insert(lexicon_key.end(),
683  phones_.begin(), phones_.begin() + num_phones);
684  LexiconMap::const_iterator iter = lexicon_map.find(lexicon_key);
685  if (iter == lexicon_map.end()) { // no such entry
686  return false;
687  } else { // Entry exists. We'll create an arc.
688  next_state->phones_.assign(phones_.begin() + num_phones, phones_.end());
689  next_state->words_.assign(words_.begin() + (word_id == 0 ? 0 : 1),
690  words_.end());
691  next_state->transition_ids_.assign(transition_ids_.begin() + num_phones,
692  transition_ids_.end());
693  next_state->word_fresh_ =
694  (word_id != 0 && !next_state->words_.empty()) ? kFresh : kNotFresh;
695  next_state->phone_fresh_ =
696  (next_state->phones_.empty() || num_phones == 0) ? kNotFresh : kAllFresh;
697 
698  // this next thing is a bit hard to explain. If we just consumed a word with
699  // no phones, we treat the phones as fresh. The idea is that if we need to
700  // both consume a word with no phones and a phone with no words (e.g.
701  // an empty word and then silence), we need to have the phones marked
702  // as fresh in order for this to be possible.
703  if (num_phones == 0 && word_id != 0 && !next_state->phones_.empty())
704  next_state->phone_fresh_ = kAllFresh;
705 
706  next_state->weight_ = LatticeWeight::One();
707 
708  if (GetVerboseLevel() >= 5) {
709  std::ostringstream ostr;
710  for (size_t i = 0; i < num_phones; i++)
711  ostr << phones_[i] << " ";
712  KALDI_VLOG(5) << "Taking arc with word = " << word_id
713  << " and phones = " << ostr.str()
714  << ", output-word = " << iter->second
715  << ", dest-state has num-words = " << next_state->words_.size()
716  << " and num-phones = " << next_state->phones_.size();
717  }
718 
719  // Set arc_out:
720  Label word_id = iter->second; // word_id will typically be
721  // the same as words_[0], i.e. the
722  // word we consumed.
723 
724  KALDI_ASSERT(word_id != 0); // we replaced zeros with 'temporary epsilon' = -2.
725 
726  std::vector<int32> appended_transition_ids;
728  transition_ids_.begin() + num_phones,
729  &appended_transition_ids);
730  arc_out->ilabel = word_id;
731  arc_out->olabel = word_id;
732  arc_out->weight = CompactLatticeWeight(weight_,
733  appended_transition_ids);
734  // arc_out->nextstate will be set in the calling code.
735  return true;
736  }
737 }
static void AppendVectors(std::vector< std::vector< int32 > >::const_iterator input_begin, std::vector< std::vector< int32 > >::const_iterator input_end, std::vector< int32 > *output)
static const LatticeWeightTpl One()
int32 GetVerboseLevel()
Get verbosity level, usually set via command line &#39;–verbose=&#39; switch.
Definition: kaldi-error.h:60
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
Definition: kaldi-lattice.h:35
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156

◆ ViableIfAdvanced()

bool ViableIfAdvanced ( const ViabilityMap viability_map) const

Returns true if, assuming we were to add one or more phones by calling Advance one or more times on this, we might be able later to successfully call TakeTransition.

It's a kind of co-accessibility test that avoids us creating an exponentially large number of states that would contribute nothing to the final output.

Definition at line 604 of file word-align-lattice-lexicon.cc.

References LatticeLexiconWordAligner::ComputationState::phones_, and LatticeLexiconWordAligner::ComputationState::words_.

Referenced by LatticeLexiconWordAligner::PossiblyAdvanceArc().

605  {
606  /* This will ideally to return true if and only if we can ever take
607  any kind of transition out of this state after "advancing" it by adding
608  words and/or phones. It's OK to return true in some cases where the
609  condition is false, though, if it's a pain to check, because the result
610  will just be doing extra work for nothing (those states won't be
611  co-accessible in the output).
612  */
613  if (phones_.empty()) return true;
614  if (words_.empty()) return true;
615  else {
616  // neither phones_ or words_ is empty. Return true if a longer sequence
617  // than this phone sequence can have either zero (<eps>/epsilon) or the
618  // first element of words_, as an entry in the lexicon with that phone
619  // sequence.
620  ViabilityMap::const_iterator iter = viability_map.find(phones_);
621  if (iter == viability_map.end()) return false;
622  else {
623  const std::vector<int32> &this_set = iter->second; // sorted vector.
624  // Return true if either 0 or words_[0] is in the set. If 0 is
625  // in the set, it will be the 1st element of the vector, because it's
626  // the lowest element.
627  return (this_set.front() == 0 ||
628  std::binary_search(this_set.begin(), this_set.end(), words_[0]));
629  }
630  }
631 }

◆ WordFreshness()

Member Data Documentation

◆ phone_fresh_

◆ phones_

◆ transition_ids_

◆ weight_

◆ word_fresh_

◆ words_


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