/* 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;
}