118 const int32 p1 = 11117, p2 = 90647, p3 = 3967, p4 = 3557;
169 std::vector<std::vector<int32> >::const_iterator input_begin,
170 std::vector<std::vector<int32> >::const_iterator input_end,
171 std::vector<int32> *output);
175 input_state(input_state), comp_state(comp_state) {}
182 size_t operator() (
const Tuple &state)
const {
188 bool operator () (
const Tuple &state1,
const Tuple &state2)
const {
195 typedef unordered_map<Tuple, StateId, TupleHash, TupleEqual>
MapType;
199 MapType::iterator iter =
map_.find(tuple);
200 if (iter ==
map_.end()) {
201 StateId output_state =
lat_out_->AddState();
202 map_[tuple] = output_state;
203 queue_.push_back(std::make_pair(tuple, output_state));
212 const Tuple &next_tuple,
215 lat_out_->AddArc(prev_output_state, *arc);
258 KALDI_WARN <<
"Word-aligning lattice: lattice was forced out, will have partial words at end.";
263 KALDI_WARN <<
"Word-aligning lattice: had no final-states even after forcing out " 264 <<
"(result will be empty). This probably indicates wrong input.";
271 StateId output_state =
queue_.back().second;
282 final_queue_.push_back(std::make_pair(tuple, output_state));
289 int32 partial_word_label,
295 kTemporaryEpsilon : partial_word_label),
311 std::vector<int32> syms_to_remove;
312 syms_to_remove.push_back(kTemporaryEpsilon);
314 Project(
lat_out_, fst::PROJECT_INPUT);
319 if (
lat_in_.Start() == fst::kNoStateId) {
320 KALDI_WARN <<
"Trying to word-align empty lattice.";
324 Tuple initial_tuple(
lat_in_.Start(), initial_comp_state);
330 KALDI_WARN <<
"Number of states in lattice exceeded max-states of " 332 <<
lat_in_.NumStates() <<
" states. Returning empty lattice.";
351 std::vector<std::pair<Tuple, StateId> >
queue_;
364 std::vector<std::vector<int32> >::const_iterator input_begin,
365 std::vector<std::vector<int32> >::const_iterator input_end,
366 std::vector<int32> *output) {
368 for (std::vector<std::vector<int32> >::const_iterator iter = input_begin;
371 size += iter->size();
373 output->reserve(size);
374 for (std::vector<std::vector<int32> >::const_iterator iter = input_begin;
377 output->insert(output->end(), iter->begin(), iter->end());
385 NumPhonesMap::const_iterator iter =
395 int32 min_num_phones, max_num_phones;
402 min_num_phones = iter->second.first;
403 max_num_phones = std::min(iter->second.second, comp_state.
NumPhones());
408 if (num_phones >= iter->second.first &&
409 num_phones <= iter->second.second) {
410 min_num_phones = num_phones;
411 max_num_phones = num_phones;
419 if (min_num_phones == 0)
420 KALDI_ERR <<
"Lexicon error: epsilon transition that produces no output:";
422 for (
int32 num_phones = min_num_phones;
423 num_phones <= max_num_phones;
444 int32 min_num_phones, max_num_phones;
452 NumPhonesMap::const_iterator iter =
455 KALDI_ERR <<
"Word " << word_id <<
" is not present in the lexicon.";
457 min_num_phones = iter->second.first;
458 max_num_phones = std::min(iter->second.second,
464 max_num_phones = min_num_phones;
469 for (
int32 num_phones = min_num_phones;
470 num_phones <= max_num_phones;
492 !aiter.Done(); aiter.Next()) {
503 std::vector<int32>()),
512 bool saw_final =
false;
522 std::vector<int32> empty_vec;
532 for (fst::ArcIterator<CompactLattice> aiter(*
lat_out_, output_state);
533 !aiter.Done(); aiter.Next()) {
535 if (arc.ilabel != 0 || arc.olabel != 0 || !arc.weight.String().empty())
543 std::vector<std::pair<Tuple, StateId> > new_final_queue_;
564 arc.nextstate = new_state;
565 lat_out_->AddArc(output_state, arc);
566 new_final_queue_.push_back(std::make_pair(next_tuple, new_state));
575 const std::vector<int32> &tids = arc.weight.String();
577 if (tids.empty()) phone = 0;
581 "Error: lattice is not phone-aligned.");
583 if (arc.ilabel != 0) {
584 words_.push_back(arc.ilabel);
613 if (
phones_.empty())
return true;
614 if (
words_.empty())
return true;
620 ViabilityMap::const_iterator iter = viability_map.find(
phones_);
621 if (iter == viability_map.end())
return false;
623 const std::vector<int32> &this_set = iter->second;
627 return (this_set.front() == 0 ||
628 std::binary_search(this_set.begin(), this_set.end(),
words_[0]));
635 int32 partial_word_label,
641 next_state->
words_.clear();
654 KALDI_WARN <<
"Word-aligning lattice: discarding extra word at end of lattice" 657 word_id = partial_word_label;
661 std::vector<int32> appended_transition_ids;
664 &appended_transition_ids);
665 arc_out->ilabel = word_id;
666 arc_out->olabel = word_id;
668 appended_transition_ids);
679 std::vector<int32> lexicon_key;
680 lexicon_key.reserve(1 + num_phones);
681 lexicon_key.push_back(word_id);
682 lexicon_key.insert(lexicon_key.end(),
684 LexiconMap::const_iterator iter = lexicon_map.find(lexicon_key);
685 if (iter == lexicon_map.end()) {
689 next_state->
words_.assign(
words_.begin() + (word_id == 0 ? 0 : 1),
703 if (num_phones == 0 && word_id != 0 && !next_state->
phones_.empty())
709 std::ostringstream ostr;
710 for (
size_t i = 0;
i < num_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();
720 Label word_id = iter->second;
726 std::vector<int32> appended_transition_ids;
729 &appended_transition_ids);
730 arc_out->ilabel = word_id;
731 arc_out->olabel = word_id;
733 appended_transition_ids);
748 const std::vector<int32> &transition_ids) {
750 std::vector<std::vector<int32> > split_alignment;
751 if (!
SplitToPhones(tmodel, transition_ids, &split_alignment)) {
752 KALDI_WARN <<
"Could not split word into phones correctly (forced-out?)";
754 std::vector<int32> phones(split_alignment.size());
755 for (
size_t i = 0;
i < split_alignment.size();
i++) {
759 std::vector<int32> lexicon_entry;
760 lexicon_entry.push_back(word_id);
761 lexicon_entry.insert(lexicon_entry.end(), phones.begin(), phones.end());
764 std::ostringstream ostr;
765 for (
size_t i = 0;
i < lexicon_entry.size();
i++)
766 ostr << lexicon_entry[
i] <<
' ';
767 KALDI_WARN <<
"Invalid arc in aligned lattice (code error?) lexicon-entry is " << ostr.str();
775 const std::vector<int32> &lexicon_entry) {
776 int32 word = lexicon_entry[0];
777 int32 num_phones =
static_cast<int32>(lexicon_entry.size()) - 2;
778 std::vector<int32> phones;
780 phones.reserve(num_phones - 1);
784 for (
int32 n = 0;
n < num_phones - 1;
n++) {
785 phones.push_back(lexicon_entry[
n + 2]);
787 viability_map_[phones].push_back(word);
792 for (ViabilityMap::iterator iter = viability_map_.begin();
793 iter != viability_map_.end();
795 std::vector<int32> &
words = iter->second;
797 KALDI_ASSERT(words[0] >= 0 &&
"Error: negative labels in lexicon.");
805 const std::vector<int32> &lexicon_entry) {
807 std::vector<int32> key;
808 key.reserve(lexicon_entry.size() - 1);
810 key.push_back(lexicon_entry[0]);
812 key.insert(key.end(), lexicon_entry.begin() + 2, lexicon_entry.end());
813 int32 new_word = lexicon_entry[1];
817 if (lexicon_map_.count(key) != 0) {
818 if (lexicon_map_[key] == new_word)
819 KALDI_WARN <<
"Duplicate entry in lexicon map for word " << lexicon_entry[0];
821 KALDI_ERR <<
"Duplicate entry in lexicon map for word " << lexicon_entry[0]
822 <<
" with inconsistent to-word.";
824 lexicon_map_[key] = new_word;
826 if (lexicon_entry[0] != lexicon_entry[1]) {
828 key[0] = lexicon_entry[1];
832 reverse_lexicon_map_[key] = lexicon_entry[0];
837 const std::vector<int32> &lexicon_entry) {
838 int32 num_phones =
static_cast<int32>(lexicon_entry.size()) - 2;
839 int32 word = lexicon_entry[0];
840 if (num_phones_map_.count(word) == 0)
841 num_phones_map_[word] = std::make_pair(num_phones, num_phones);
843 std::pair<int32, int32> &pr = num_phones_map_[word];
844 pr.first = std::min(pr.first, num_phones);
845 pr.second = std::max(pr.second, num_phones);
846 if (pr.first == 0 && word == 0)
847 KALDI_ERR <<
"Zero word with empty pronunciation is not allowed.";
855 LexiconMap::const_iterator iter = lexicon_map_.find(entry);
856 if (iter != lexicon_map_.end()) {
857 int32 tgt_word = (iter->second == kTemporaryEpsilon ? 0 : iter->second);
858 if (tgt_word == entry[0])
return true;
863 return (reverse_lexicon_map_.count(entry) != 0);
867 unordered_map<int32, int32>::const_iterator iter =
868 equivalence_map_.find(word);
869 if (iter == equivalence_map_.end())
return word;
870 else return iter->second;
874 const std::vector<std::vector<int32> > &lexicon) {
875 std::vector<std::pair<int32, int32> > equiv_pairs;
877 for (
size_t i = 0;
i < lexicon.size();
i++) {
879 int32 w1 = lexicon[
i][0], w2 = lexicon[
i][1];
880 if (w1 == w2)
continue;
884 equiv_pairs.push_back(std::make_pair(w1, w2));
887 equivalence_map_.clear();
888 for (
size_t i = 0;
i < equiv_pairs.size();
i++) {
889 int32 w1 = equiv_pairs[
i].first, w2 = equiv_pairs[
i].second,
890 w1dash = EquivalenceClassOf(w1);
891 equivalence_map_[w2] = w1dash;
897 const std::vector<std::vector<int32> > &lexicon) {
898 for (
size_t i = 0;
i < lexicon.size();
i++) {
899 const std::vector<int32> &lexicon_entry = lexicon[
i];
901 UpdateViabilityMap(lexicon_entry);
902 UpdateLexiconMap(lexicon_entry);
903 UpdateNumPhonesMap(lexicon_entry);
905 FinalizeViabilityMap();
906 UpdateEquivalenceMap(lexicon);
915 for (StateId s = 0; s < lat->NumStates(); s++) {
916 for (fst::MutableArcIterator<CompactLattice> aiter(lat, s);
917 !aiter.Done(); aiter.Next()) {
921 arc.olabel = arc.ilabel;
931 bool allow_duplicate_paths) {
932 int32 max_err = 5, num_err = 0;
941 TopSort(&aligned_lat);
944 if (fabs(like_before - like_after) >
945 1.0e-04 * (fabs(like_before) + fabs(like_after))) {
946 KALDI_WARN <<
"Forward-backward likelihoods differ in word-aligned lattice " 947 <<
"testing, " << like_before <<
" != " << like_after;
948 if (!allow_duplicate_paths)
956 for (fst::ArcIterator<CompactLattice> aiter(aligned_clat, s);
957 !aiter.Done(); aiter.Next()) {
960 int32 word_id = arc.ilabel;
961 const std::vector<int32> &tids = arc.weight.String();
962 if (word_id == 0 && tids.empty())
continue;
964 if (num_err < max_err)
969 if (!aligned_clat.Final(s).String().empty()) {
970 KALDI_WARN <<
"Aligned lattice has nonempty string on its final-prob.";
984 int32 num_paths = 5, seed =
Rand(), max_path_length = -1;
989 if (!RandEquivalent(clat, aligned_clat, num_paths, delta, seed, max_path_length)) {
990 KALDI_WARN <<
"Equivalence test failed during lattice alignment.";
995 return (num_err == 0);
1013 uint64 props = lat.Properties(fst::kIDeterministic|fst::kIEpsilons, test);
1014 if (props != fst::kIDeterministic) {
1015 KALDI_WARN <<
"[Lattice has input epsilons and/or is not input-deterministic " 1016 <<
"(in Mohri sense)]-- i.e. lattice is not deterministic. " 1017 <<
"Word-alignment may be slow and-or blow up in memory.";
1022 &phone_aligned_lat);
1031 max_states = kNumStatesOffset + opts.
max_expand * phone_aligned_lat.NumStates();
1040 if (ans && opts.
test) {
1043 KALDI_WARN <<
"Lattice failed test (activated because --test=true). " 1044 <<
"Probable code error, please contact Kaldi maintainers.";
1052 std::vector<std::vector<int32> > *lexicon) {
1055 while (std::getline(is, line)) {
1056 std::vector<int32> this_entry;
1058 this_entry.size() < 2) {
1059 KALDI_WARN <<
"Lexicon line '" << line <<
"' is invalid";
1062 lexicon->push_back(this_entry);
1064 return (!lexicon->empty());
fst::StdArc::StateId StateId
StateId GetStateForTuple(const Tuple &tuple)
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
ViabilityMap viability_map_
void ProcessTransition(StateId prev_output_state, const Tuple &next_tuple, CompactLatticeArc *arc)
int32 partial_word_label_
LatticeLexiconWordAligner(const CompactLattice &lat, const TransitionModel &tmodel, const WordAlignLatticeLexiconInfo &lexicon_info, int32 max_states, int32 partial_word_label, CompactLattice *lat_out)
std::vector< std::pair< Tuple, StateId > > final_queue_
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)
Tuple(StateId input_state, ComputationState comp_state)
unordered_map< Tuple, StateId, TupleHash, TupleEqual > MapType
A hashing function-object for vectors.
static void MapSymbols(const WordAlignLatticeLexiconInfo &lexicon_info, CompactLattice *lat)
Testing code; map word symbols in the lattice "lat" using the equivalence-classes obtained from the l...
ComputationState(const ComputationState &other)
Freshness WordFreshness() const
static const LatticeWeightTpl One()
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.
bool SplitStringToIntegers(const std::string &full, const char *delim, bool omit_empty_strings, std::vector< I > *out)
Split a string (e.g.
std::vector< int32 > phones_
int32 GetVerboseLevel()
Get verbosity level, usually set via command line '–verbose=' switch.
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 t...
void UpdateViabilityMap(const std::vector< int32 > &lexicon_entry)
bool ReadLexiconForWordAlign(std::istream &is, std::vector< std::vector< int32 > > *lexicon)
Read the lexicon in the special format required for word alignment.
unordered_map< std::vector< int32 >, int32, VectorHasher< int32 > > LexiconMap
This is a map from a vector (orig-word-symbol phone1 phone2 ...
fst::CompactLatticeWeightTpl< LatticeWeight, int32 > CompactLatticeWeight
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" ...
bool IsValidEntry(const std::vector< int32 > &entry) const
Returns true if this lexicon-entry can appear, intepreted as (output-word phone1 phone2 ...
void PossiblyAdvanceArc(const Tuple &tuple, StateId output_state)
void swap(basic_filebuf< CharT, Traits > &x, basic_filebuf< CharT, Traits > &y)
bool WordAlignLatticeLexicon(const CompactLattice &lat, const TransitionModel &tmodel, const WordAlignLatticeLexiconInfo &lexicon_info, const WordAlignLatticeLexiconOpts &opts, CompactLattice *lat_out)
Align lattice so that each arc has the transition-ids on it that correspond to the word that is on th...
LatticeWeight FinalWeight() const
FinalWeight() will return "weight" if both transition_ids and word_labels are empty, otherwise it will return Weight::Zero().
bool operator==(const ComputationState &other) const
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
static bool TestWordAlignedLattice(const WordAlignLatticeLexiconInfo &lexicon_info, const TransitionModel &tmodel, CompactLattice clat, CompactLattice aligned_clat, bool allow_duplicate_paths)
int32 PendingWord() const
WordAlignLatticeLexiconInfo::ViabilityMap ViabilityMap
const TransitionModel & tmodel_
bool SplitToPhones(const TransitionModel &trans_model, const std::vector< int32 > &alignment, std::vector< std::vector< int32 > > *split_alignment)
SplitToPhones splits up the TransitionIds in "alignment" into their individual phones (one vector per...
void ProcessWordTransitions(const Tuple &tuple, StateId output_state)
unordered_map< int32, std::pair< int32, int32 > > NumPhonesMap
This is a map from the word-id (as present in the original lattice) to the minimum and maximum #phone...
LatticeWeightTpl< FloatType > Times(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
NumPhonesMap num_phones_map_
CompactLatticeArc::StateId StateId
std::vector< std::vector< std::pair< int32, BaseFloat > > > Posterior
Posterior is a typedef for storing acoustic-state (actually, transition-id) posteriors over an uttera...
ComputationState comp_state
WordAlignLatticeLexiconInfo::NumPhonesMap NumPhonesMap
BaseFloat LatticeForwardBackward(const Lattice &lat, Posterior *post, double *acoustic_like_sum)
This function does the forward-backward over lattices and computes the posterior probabilities of the...
std::vector< std::pair< Tuple, StateId > > queue_
static const CompactLatticeWeightTpl< WeightType, IntType > One()
std::vector< std::vector< int32 > > transition_ids_
Arc::StateId CreateSuperFinal(MutableFst< Arc > *fst)
void ConvertLattice(const ExpandedFst< ArcTpl< Weight > > &ifst, MutableFst< ArcTpl< CompactLatticeWeightTpl< Weight, Int > > > *ofst, bool invert)
Convert lattice from a normal FST to a CompactLattice FST.
static const LatticeWeightTpl Zero()
void ProcessFinalForceOut()
Creates arcs from all the tuples that were final in the original lattice but have no arcs out of them...
fst::VectorFst< LatticeArc > Lattice
unordered_map< std::vector< int32 >, std::vector< int32 >, VectorHasher< int32 > > ViabilityMap
The type ViabilityMap maps from sequences of phones (excluding the empty sequence), to the sets of all word-labels [on the input lattice] that could correspond to phone sequences that start with s [but are longer than s].
static bool IsPlausibleWord(const WordAlignLatticeLexiconInfo &lexicon_info, const TransitionModel &tmodel, int32 word_id, const std::vector< int32 > &transition_ids)
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 bound...
int Rand(struct RandomState *state)
WordAlignLatticeLexiconInfo::LexiconMap LexiconMap
void UpdateEquivalenceMap(const std::vector< std::vector< int32 > > &lexicon)
fst::VectorFst< CompactLatticeArc > CompactLattice
void ProcessFinalWrapper()
Freshness PhoneFreshness() const
void FinalizeViabilityMap()
CompactLatticeArc::Label Label
bool replace_output_symbols
#define KALDI_ASSERT(cond)
This class extracts some information from the lexicon and stores it in a suitable form for the word-a...
static const CompactLatticeWeightTpl< WeightType, IntType > Zero()
void UpdateNumPhonesMap(const std::vector< int32 > &lexicon_entry)
bool allow_duplicate_paths
CompactLattice * lat_out_
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
WordAlignLatticeLexiconInfo(const std::vector< std::vector< int32 > > &lexicon)
bool PhoneAlignLattice(const CompactLattice &lat, const TransitionModel &tmodel, const PhoneAlignLatticeOptions &opts, CompactLattice *lat_out)
Outputs a lattice in which the arcs correspond exactly to sequences of phones, so the boundaries betw...
std::vector< int32 > words_
void UpdateLexiconMap(const std::vector< int32 > &lexicon_entry)
Update the map from a vector (orig-word-symbol phone1 phone2 ...
bool ProcessFinal()
Process all final-probs (normal case, no forcing-out).
int32 TransitionIdToPhone(int32 trans_id) const
void ProcessEpsilonTransitions(const Tuple &tuple, StateId output_state)
const int kTemporaryEpsilon
int32 EquivalenceClassOf(int32 word) const
Purely for the testing code, we map words into equivalence classes derived from the mappings in the f...
void ProcessQueueElement()
const WordAlignLatticeLexiconInfo & lexicon_info_
const int kNumStatesOffset
bool HasNonEpsArcsOut(StateId output_state)
This function returns true if the state "output_state" in the output lattice has arcs out that have e...
void RemoveEpsilonsFromLattice()
void RemoveSomeInputSymbols(const std::vector< I > &to_remove, MutableFst< Arc > *fst)
RemoveSomeInputSymbols removes any symbol that appears in "to_remove", from the input side of the FST...