/* FILE: sub_phon.cpp * DATE MODIFIED: 31-Aug-07 * DESCRIPTION: Part of the SREC graph compiler project source files. * * Copyright 2007, 2008 Nuance Communciations, Inc. * * * * Licensed under the Apache License, Version 2.0 (the 'License'); * * you may not use this file except in compliance with the License. * * * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an 'AS IS' BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * *---------------------------------------------------------------------------*/ #include <iostream> #include <sstream> #include <string> #include <assert.h> #define DEBUG 0 #include "sub_grph.h" #include "grxmldoc.h" void SubGraph::ExpandPhonemes ( GRXMLDoc &doc ) { int ii, wordId, phoneId, currId, newId, nextId, arcCount; Pronunciation pron; int pronCount; NUANArc *arcOne; std::string modelLabel, word; { std::stringstream ss; ss << SILENCE_CONTEXT; modelLabel= ss.str(); silenceId = doc.addPhonemeToList(modelLabel); } { std::stringstream ss; ss << INTRA_SILENCE_CONTEXT; modelLabel= ss.str(); intraId = doc.addPhonemeToList(modelLabel); } UpdateVertexCount (0); arcCount= numArc; for (ii= 0; ii < arcCount; ii++) { wordId= arc[ii]->GetInput(); if (wordId >= 0) { doc.findLabel(wordId, word ); if (IsSlot (word)) { // std::cout << "Found slot "<< word <<std::endl; newId= NewVertexId(); arcOne= CreateArc (NONE_LABEL, NONE_LABEL, arc[ii]->GetFromId(), newId); arcOne->AssignCentre (NONE_LABEL); nextId= NewVertexId(); // special case arcOne= CreateArc (-wordId, wordId, newId, nextId); arcOne->AssignCentre (NONE_LABEL); // (void) CreateArc (-wordId, NONE_LABEL, arc[ii]->GetFromId(), newId); arcOne= CreateArc (WB_LABEL, NONE_LABEL, nextId, arc[ii]->GetToId()); arcOne->AssignCentre (NONE_LABEL); // (void) CreateArc (WB_LABEL, wordId, newId, arc[ii]->GetToId()); } else { pron.clear(); pron.lookup( *(doc.getVocabulary()), word ); pronCount = pron.getPronCount(); for (int jj= 0; jj < pronCount; jj++) { currId= arc[ii]->GetFromId(); int modelCount = pron.getPhonemeCount(jj); for (int kk= 0; kk < modelCount; kk++) { newId= NewVertexId(); pron.getPhoneme(jj, kk, modelLabel); //std::cout << "ExpandPhonemes adding "<< modelLabel <<std::endl; phoneId = doc.addPhonemeToList( modelLabel ); arcOne= CreateArc (phoneId, NONE_LABEL, currId, newId); if (phoneId == intraId) arcOne->AssignCentre (silenceId); else arcOne->AssignCentre (phoneId); currId= newId; } arcOne= CreateArc (WB_LABEL, wordId, currId, arc[ii]->GetToId()); arcOne->AssignCentre (NONE_LABEL); } // End of loop } arc[ii]->AssignInput (DISCARD_LABEL); // Delete original arc } } RemoveDiscardedArcs (); for (ii= 0; ii < numArc; ii++) { arc[ii]->AssignLeft (NONE_LABEL); arc[ii]->AssignRight (NONE_LABEL); } SortLanguage (); return; } void SubGraph::AddLeftContexts () { int ii, rix, currId, leftC; SortLanguage(); SortLanguageReverse(); for (ii= 0; ii < numArc; ii++) { if (arc[ii]->GetInput() >= 0) { currId= arc[ii]->GetFromId(); rix= FindToIndex (currId); if (rix >= 0) { leftC= arc[backwardList[rix]]->GetCentre(); arc[ii]->AssignLeft(leftC); } else if (currId != startId) printf ("Shouldn't get here (L) %d\n", currId); } else arc[ii]->AssignLeft (NONE_LABEL); } return; } void SubGraph::AddRightContexts () { int ii, rix, currId, rightC; SortLanguage(); SortLanguageReverse(); for (ii= 0; ii < numArc; ii++) { if (arc[ii]->GetInput() >= 0) { currId= arc[ii]->GetToId(); rix= FindFromIndex (currId); if (rix >= 0) { rightC= arc[forwardList[rix]]->GetCentre(); arc[ii]->AssignRight (rightC); } else printf ("Shouldn't get here (R) %d\n", currId); } else arc[ii]->AssignRight (NONE_LABEL); } return; } void SubGraph::ExpandToHMMs ( GRXMLDoc &doc ) { int ii, currId, newId, arcCount, left, right, centre; int modelCount; NUANArc *arcOne; UpdateVertexCount (0); arcCount= numArc; for (ii= 0; ii < arcCount; ii++) { std::vector<int> modelSequence; if (arc[ii]->GetInput() >= 0) { // i.e. proper phoneme centre= arc[ii]->GetCentre(); left= arc[ii]->GetLeft(); right= arc[ii]->GetRight(); #if DEBUG std::cout << "HMM PIC:" << left <<" " << centre <<" " << right << std::endl; #endif doc.getHMMSequence (centre, left, right, modelSequence); modelCount = modelSequence.size(); #if DEBUG std::cout << "HMM: " << centre << " number of HMMs = " << modelCount <<std::endl; #endif if (modelCount >= 0) { currId= arc[ii]->GetFromId(); for (int jj= 0; jj < modelCount; jj++) { if (jj == (modelCount - 1)) newId= arc[ii]->GetToId(); else newId= NewVertexId(); arcOne= CreateArc (modelSequence[jj], NONE_LABEL, currId, newId); arcOne->AssignCentre (arc[ii]->GetInput()); arcOne->AssignLeft (arc[ii]->GetLeft()); arcOne->AssignRight (arc[ii]->GetRight()); #if DEBUG std::cout << "HMM phoneme: " << modelSequence[jj] << " "; #endif currId= newId; } #if DEBUG std::cout << " centre " << arc[ii]->GetInput() << std::endl; #endif arc[ii]->AssignInput (DISCARD_LABEL); // Delete original arc } } } RemoveDiscardedArcs (); SortLanguage (); return; } void SubGraph::ExpandIntraWordSilence ( GRXMLDoc &doc ) { int ii, fix, bix, firstId, newId, modelCount, followCount, currId, count; int left, centre, right; NUANArc *arcOne; SortLanguage(); SortLanguageReverse(); #if DEBUG std::cout << "Intra sil search " << intraId << std::endl; #endif count= numArc; for (ii= 0; ii < count; ii++) { if (arc[ii]->GetCentre() == intraId) { #if DEBUG std::cout << "Intra sil: " << arc[ii]->GetFromId() << " " << arc[ii]->GetToId() << std::endl; #endif fix= FindToIndex (arc[ii]->GetFromId()); if (fix < 0) return; while (fix < sortRevNum && arc[backwardList[fix]]->GetToId() == arc[ii]->GetFromId()) { // left triphone newId= NewVertexId(); left= arc[backwardList[fix]]->GetLeft(); centre= arc[ii]->GetLeft(); right= arc[ii]->GetRight(); #if DEBUG std::cout << "HMM PIC:" << left <<" " << centre <<" " << right << std::endl; #endif std::vector<int> modelSequence; doc.getHMMSequence (centre, left, right, modelSequence); modelCount = modelSequence.size(); #if DEBUG std::cout << "HMM: " << centre << " number of HMMs = " << modelCount <<std::endl; #endif if (modelCount >= 0) { currId= arc[backwardList[fix]]->GetFromId(); for (int jj= 0; jj < modelCount; jj++) { newId= NewVertexId(); arcOne= CreateArc (modelSequence[jj], arc[backwardList[fix]]->GetOutput(), currId, newId); arcOne->AssignCentre (centre); #if DEBUG std::cout << "HMM phoneme: " << modelSequence[jj] << " "; #endif currId= newId; } #if DEBUG std::cout << " " << centre << std::endl; #endif } firstId= newId; // right block bix= FindFromIndex (arc[ii]->GetToId()); if (bix < 0) return; while (bix < sortNum && arc[forwardList[bix]]->GetFromId() == arc[ii]->GetToId()) { fix++; // right triphone left= arc[ii]->GetLeft(); centre= arc[ii]->GetRight(); right= arc[forwardList[bix]]->GetRight(); #if DEBUG std::cout << "HMM PIC:" << left <<" " << centre <<" " << right << std::endl; #endif std::vector<int> followSequence; doc.getHMMSequence (centre, left, right, followSequence); followCount = followSequence.size(); #if DEBUG std::cout << "HMM: " << centre << " number of HMMs = " << followCount <<std::endl; #endif if (followCount >= 0) { currId= firstId; for (int jj= 0; jj < followCount; jj++) { if (jj == (followCount - 1)) newId= arc[forwardList[bix]]->GetToId(); else newId= NewVertexId(); arcOne= CreateArc (followSequence[jj], arc[forwardList[bix]]->GetOutput(), currId, newId); arcOne->AssignCentre (centre); #if DEBUG std::cout << "HMM phoneme: " << followSequence[jj] << " "; #endif currId= newId; } #if DEBUG std::cout << " " << centre << std::endl; #endif } bix++; } fix++; } // arc[ii]->AssignInput (silenceId); } } return; } void SubGraph::ShiftOutputsToLeft () { UpdateVertexCount (0); SortLanguage(); SortLanguageReverse(); ReverseMarkArcs(); MarkNodesByOutputAndClearArcs(); return; } void SubGraph::ReverseMarkArcs () { int ii; for (ii= 0; ii < numArc; ii++) if (arc[ii]->GetInput() == WB_LABEL) ReverseMarkOutput (arc[ii]->GetFromId(), startId, arc[ii]->GetOutput()); return; } void SubGraph::ReverseMarkOutput (int currId, int initialId, int outId) { int rix; rix= FindToIndex (currId); if (rix < 0) return; while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) { if (arc[backwardList[rix]]->GetOutput() != DISCARD_LABEL // not resolved yet && arc[backwardList[rix]]->GetInput() >= 0) { // excludes word boundary if (arc[backwardList[rix]]->GetOutput() == NONE_LABEL) arc[backwardList[rix]]->AssignOutput (outId); else if (outId != arc[backwardList[rix]]->GetOutput()) arc[backwardList[rix]]->AssignOutput(DISCARD_LABEL); ReverseMarkOutput (arc[backwardList[rix]]->GetFromId(), initialId, outId); } rix++; } return; } void SubGraph::MarkNodesByOutputAndClearArcs () { int ii, currId, rix; int *nodeList= new int [numVertex]; for (ii= 0; ii < numVertex; ii++) nodeList[ii]= NONE_LABEL; // Associate outputs with destination node for (ii= 0; ii < numArc; ii++) { currId= arc[ii]->GetToId(); if (currId >= 0) { if (arc[ii]->GetInput() == WB_LABEL) nodeList[currId]= DISCARD_LABEL; else if (nodeList[currId] != DISCARD_LABEL) { if (nodeList[currId] == NONE_LABEL) nodeList[currId]= arc[ii]->GetOutput(); else if (nodeList[currId] != arc[ii]->GetOutput()) nodeList[currId]= DISCARD_LABEL; } } } // Now discard all arcs other than those emanating from unique assignments for (ii= 0; ii < numArc; ii++) { currId= arc[ii]->GetFromId(); if (nodeList[currId] >= 0 && arc[ii]->GetOutput() >= 0) // unique ones arc[ii]->AssignOutput(DISCARD_LABEL); } // Finally, special case for intra-word silence for (ii= 0; ii < numArc; ii++) { if (arc[ii]->GetOutput() >= 0 && arc[ii]->GetCentre() == intraId) { currId= arc[ii]->GetToId(); #if DEBUG std::cout << "Intra silence: " << currId << " " << arc[ii]->GetFromId() << std::endl; #endif rix= FindFromIndex (currId); if (rix < 0) continue; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { assert (arc[forwardList[rix]]->GetOutput() == DISCARD_LABEL); arc[forwardList[rix]]->AssignOutput(arc[ii]->GetOutput()); rix++; } arc[ii]->AssignOutput(DISCARD_LABEL); } } delete [] nodeList; return; } void SubGraph::FinalProcessing (GRXMLDoc &doc) { ExpandWordBoundaries (doc); AddInitialFinalSilences (doc); return; } void SubGraph::ExpandWordBoundaries (GRXMLDoc &doc) { int ii, newId, count; NUANArc *arcOne; count= numArc; for (ii= 0; ii < count; ii++) { std::vector<int> modelSequence; doc.getHMMSequence (silenceId, -1, -1, modelSequence); if (arc[ii]->GetInput() == WB_LABEL) { newId= NewVertexId(); // (void) CreateArc (NONE_LABEL, NONE_LABEL, arc[ii]->GetFromId(), newId); // arcOne= CreateArc (modelSequence[0], NONE_LABEL, arc[ii]->GetFromId(), newId); arcOne= CreateArc (modelSequence[0], NONE_LABEL, arc[ii]->GetFromId(), newId); arcOne->AssignCentre (silenceId); (void) CreateArc (WB_LABEL, arc[ii]->GetOutput(), newId, arc[ii]->GetToId()); // arc[ii]->AssignInput (DISCARD_LABEL); } } return; } void SubGraph::AddInitialFinalSilences (GRXMLDoc &doc) { int ii, rix, newId, intId, count; NUANArc *arcOne; SortLanguage(); newId= NewVertexId(); rix= FindFromIndex (startId); if (rix < 0) return; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == startId) { arc[forwardList[rix]]->AssignFromId (newId); rix++; } std::vector<int> modelSequence; doc.getHMMSequence (silenceId, -1, -1, modelSequence); intId= NewVertexId(); arcOne= CreateArc (modelSequence[0], INITIAL_LABEL, startId, intId); arcOne->AssignCentre (silenceId); (void) CreateArc (WB_LABEL, NONE_LABEL, intId, newId); count= numArc; newId= NewVertexId(); for (ii= 0; ii < count; ii++) { if (arc[ii]->GetInput() == TERMINAL_LABEL) { arc[ii]->AssignInput (modelSequence[0]); arc[ii]->AssignCentre (silenceId); arc[ii]->AssignOutput (FINAL_LABEL); arc[ii]->AssignToId (newId); } } (void) CreateArc (TERMINAL_LABEL, TERMINAL_LABEL, newId, newId); return; }