/* FILE: sub_grph.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 <string> #include <assert.h> #include <cstdio> #include "sub_grph.h" static int checkEntry (int *itemList, int count, int item); static int checkEntry (int *itemList, int count, int item) { for (int ii= 0; ii < count; ii++) if (item == itemList[ii]) return ii; return -1; } bool IsSlot (std::string label) { int count= label.size(); int fPos= label.find_first_of ("___"); int lPos= label.find_last_of ("___") + 1; // std::cout << label << " " << count << " " << fPos << " " << lPos << std::endl; if (fPos >= 0 && lPos == count) return true; else return false; } void SubGraph::pushScope () { opStack[popOp++]= lastScope; opStack[popOp++]= startId; opStack[popOp++]= endId; opStack[popOp++]= lastId; opStack[popOp++]= arg1; opStack[popOp++]= arg2; opStack[popOp++]= numArc; return; } void SubGraph::popScope () { prevStartId= startId; prevEndId= endId; arcLoc= opStack[--popOp]; arg2= opStack[--popOp]; arg1= opStack[--popOp]; lastId= opStack[--popOp]; endId= opStack[--popOp]; startId= opStack[--popOp]; lastScope= opStack[--popOp]; return; } void SubGraph::BeginScope (int scopeType, int newArg1, int newArg2) // Begin a new scope // Create nodes for item and /item but no transitions { pushScope(); arg1= newArg1; arg2= newArg2; lastScope= scopeType; arcLoc= numArc; startId= NewVertexId(); switch (scopeType) { case SCOPE_ITEM: case SCOPE_RULE: case SCOPE_COUNT: case SCOPE_REPEAT: case SCOPE_OPT: endId= -1; lastId= startId; break; case SCOPE_ONEOF: endId= NewVertexId(); lastId= endId; break; default: printf ("Shouldn't be getting here\n"); } return; } void SubGraph::EndScope () // End the current scope { int closeId= CloseScope(); lastId= ConnectLastScope (startId, closeId); } int SubGraph::ConnectLastScope (int beginScopeId, int endScopeId) // Connect up the child network to the parent { int begLabel, endLabel, begOutLabel, endOutLabel; if (endId == -1) endId= lastId; if (lastScope == SCOPE_RULE) { begLabel= BEGINRULE_LABEL; begOutLabel= BEGINRULE_LABEL; endLabel= ENDRULE_LABEL; endOutLabel= arg1; // For inserting into closing brace } else { begLabel= BEGINSCOPE_LABEL; begOutLabel= BEGINRULE_LABEL; endLabel= ENDSCOPE_LABEL; endOutLabel= ENDSCOPE_LABEL; } popScope(); switch (lastScope) { case SCOPE_ITEM: case SCOPE_COUNT: case SCOPE_REPEAT: case SCOPE_OPT: (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId); lastId= NewVertexId(); (void) CreateArc (endLabel, endOutLabel, endScopeId, lastId); break; case SCOPE_ONEOF: (void) CreateArc (begLabel, begOutLabel, startId, beginScopeId); (void) CreateArc (endLabel, endOutLabel, endScopeId, endId); break; case SCOPE_RULE: (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId); lastId= NewVertexId(); (void) CreateArc (endLabel, ruleId, endScopeId, lastId); break; case SCOPE_ROOT: (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId); lastId= NewVertexId(); (void) CreateArc (endLabel, endOutLabel, endScopeId, lastId); break; default: printf ("Shouldn't be getting here\n"); } return lastId; } int SubGraph::CloseScope () // Closes the transitions and returns to the previous scope // Special case for count and repeats { int ii, finalId, endLoc, blockCount; switch (lastScope) { case SCOPE_ITEM: case SCOPE_RULE: case SCOPE_ONEOF: break; case SCOPE_OPT: (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, lastId); // start to end break; case SCOPE_COUNT: endLoc= numArc; blockCount= numVertex - startId - 1; // Special case, min-count= 0 for (ii= 1; ii < arg1; ii++) CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1); finalId= lastId + (arg2 - 1) * blockCount; for ( ; ii < arg2; ii++) { CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1); (void) CreateArc (NONE_LABEL, NONE_LABEL, lastId + (ii - 1) * blockCount, finalId); } if (arg1 <= 0) (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId); // start to end UpdateVertexCount (endLoc); lastId= finalId; break; case SCOPE_REPEAT: endLoc= numArc; blockCount= numVertex - startId - 1; #if 1 for (ii= 1; ii < arg1; ii++) CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1); finalId= lastId + (arg1 - 1) * blockCount; // loop CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, finalId, lastId, finalId); // start to end if (arg1 == 0) (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId); #else // loop CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, lastId, lastId, lastId); UpdateVertexCount (endLoc); // second part blockCount= numVertex - startId; CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, lastId, lastId, -1); UpdateVertexCount (endLoc); // once finalId= lastId + blockCount; blockCount= numVertex - startId; if (arg1 <= 1) CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, startId, lastId, finalId); // start to end if (arg1 == 0) (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId); #endif UpdateVertexCount (endLoc); lastId= finalId; break; default: printf ("Shouldn't be getting here\n"); } return lastId; } int SubGraph::AddItem (int inputLabel, int tagLabel) { int newId; switch (lastScope) { case SCOPE_RULE: arg1= tagLabel; case SCOPE_ITEM: case SCOPE_OPT: case SCOPE_COUNT: case SCOPE_REPEAT: newId= NewVertexId(); (void) CreateArc (inputLabel, tagLabel, lastId, newId); lastId= newId; break; case SCOPE_ONEOF: (void) CreateArc (inputLabel, tagLabel, startId, endId); lastId= endId; break; default: ; printf ("Shouldn't be getting here\n"); } return lastId; } int SubGraph::AddTag (int tagLabel) { int newId; switch (lastScope) { case SCOPE_RULE: case SCOPE_ITEM: case SCOPE_OPT: case SCOPE_COUNT: case SCOPE_REPEAT: newId= NewVertexId(); (void) CreateArc (TAG_LABEL, tagLabel, lastId, newId); lastId= newId; break; case SCOPE_ONEOF: (void) CreateArc (TAG_LABEL, tagLabel, startId, endId); lastId= endId; break; default: printf ("Shouldn't be getting here\n"); } return lastId; } void SubGraph::ExpandRules (SubGraph **subList, int *lookupList, int numSubs) { int initialId, finalId, ruleId, pos; for (int ii= 0; ii < numArc; ii++) { ruleId= arc[ii]->GetInput(); if (ruleId < 0 && ruleId > NONE_LABEL) { initialId= arc[ii]->GetFromId(); finalId= arc[ii]->GetToId(); ruleId= checkEntry (lookupList, numSubs, -ruleId); assert (ruleId >= 0); // printf ("Expanding rule (%d) %s\n", -ruleId, subList[ruleId]->title); arc[ii]->AssignInput (DISCARD_LABEL); // Clear down the rule // printf ("------------------------"); // subList[ruleId]->SortLanguage(); // subList[ruleId]->Print(); // printf ("------------------------////"); pos= numArc; CopyFastArcs (subList[ruleId], 0, subList[ruleId]->numArc, numVertex, subList[ruleId]->startId, initialId, subList[ruleId]->lastId, finalId); UpdateVertexCount (pos); } } UpdateVertexCount (0); SortLanguage (); return; } void SubGraph::UpdateVertexCount (int startLoc) { int vertId, maxVertId; maxVertId= -1; for (int ii= startLoc; ii < numArc; ii++) { vertId= arc[ii]->GetFromId(); if (maxVertId < vertId) maxVertId= vertId; vertId= arc[ii]->GetToId(); if (maxVertId < vertId) maxVertId= vertId; } maxVertId++; if (startLoc <= 0) // i.e. a fresh start numVertex= maxVertId; else if (numVertex < maxVertId) numVertex= maxVertId; return; } void SubGraph::AddTerminalConnections () { // Add terminal transition (void) CreateArc (TERMINAL_LABEL, NONE_LABEL, lastId, TERMINAL_LABEL); return; } void SubGraph::RemoveRuleConnections () { AddTerminalConnections (); RemoveTagConnections (-1, -1); RemoveRuleStarts (-1, -1); RemoveRuleEnds (-1, -1); RemoveNulls (-1, -1); ClearRuleIds (); ClearDuplicateArcs (); RemoveUnvisitedArcs (startId, lastId); RemoveDiscardedArcs (); RenumberNodes (); UpdateVertexCount (0); SortLanguage (); return; } void SubGraph::RemoveRuleStarts (int startPoint, int endPoint) { if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguage (); ProcessBegins (startPoint, endPoint, BEGINRULE_LABEL, nodeList, 0, visitList, numVertex); ClearLabelledConnections (BEGINRULE_LABEL); delete [] nodeList; delete [] visitList; return; } void SubGraph::RemoveRuleEnds (int startPoint, int endPoint) { if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguageReverse (); ProcessEnds (endPoint, startPoint, ENDRULE_LABEL, nodeList, 0, visitList, numVertex); ClearLabelledConnections (ENDRULE_LABEL); delete [] nodeList; delete [] visitList; return; } void SubGraph::RemoveNulls (int startPoint, int endPoint) { if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguage (); ProcessBegins (startPoint, endPoint, NONE_LABEL, nodeList, 0, visitList, numVertex); ClearLabelledConnections (NONE_LABEL); delete [] nodeList; delete [] visitList; return; } void SubGraph::RemoveInternalConnections () { RemoveForwardConnections (-1, -1); RemoveBackwardConnections (-1, -1); ClearDuplicateArcs (); RemoveUnvisitedArcs (startId, lastId); RemoveDiscardedArcs (); RenumberNodes (); UpdateVertexCount (0); SortLanguage (); return; } void SubGraph::RemoveForwardConnections (int startPoint, int endPoint) { // Code to pull up nodes for forward connecting transitions if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguage (); ProcessBegins (startPoint, endPoint, BEGINSCOPE_LABEL, nodeList, 0, visitList, numVertex); ClearLabelledConnections (BEGINSCOPE_LABEL); RemoveDiscardedArcs (); delete [] nodeList; delete [] visitList; return; } void SubGraph::PullUpBegins (int currId, int baseId, int finalId, int procLabel, int *nodeList, int currNum, int maxNum) { int rix; nodeList[currNum]= currId; rix= FindFromIndex (currId); if (rix < 0) return; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { if (arc[forwardList[rix]]->GetInput() == procLabel) { PullUpBegins (arc[forwardList[rix]]->GetToId(), baseId, finalId, procLabel, nodeList, currNum+1, maxNum); } else if (arc[forwardList[rix]]->GetInput() != DISCARD_LABEL) InheritArc (arc[forwardList[rix]], baseId); rix++; } return; } void SubGraph::ProcessBegins (int currId, int finalId, int procLabel, int *nodeList, int currNum, int *visitMark, int maxNum) { int rix, nextId; nodeList[currNum]= currId; rix= FindFromIndex (currId); if (rix < 0) { visitMark[currId]= 1; return; } while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { if (arc[forwardList[rix]]->GetInput() == procLabel) { PullUpBegins (arc[forwardList[rix]]->GetToId(), currId, finalId, procLabel, nodeList, currNum, maxNum); } nextId= arc[forwardList[rix]]->GetToId(); if (nextId >= 0 && nextId != finalId && checkEntry (nodeList, currNum, nextId) < 0 && visitMark[nextId] == 0) ProcessBegins (nextId, finalId, procLabel, nodeList, currNum+1, visitMark, maxNum); rix++; } visitMark[currId]= 1; return; } void SubGraph::RemoveBackwardConnections (int startPoint, int endPoint) { // Code to push back nodes for reverse connecting transitions if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguageReverse (); ProcessEnds (endPoint, startPoint, ENDSCOPE_LABEL, nodeList, 0, visitList, numVertex); ClearLabelledConnections (ENDSCOPE_LABEL); RemoveDiscardedArcs (); delete [] nodeList; delete [] visitList; return; } void SubGraph::PullUpEnds (int currId, int baseId, int initialId, int procLabel, int *nodeList, int currNum, int maxNum) { int rix; nodeList[currNum]= currId; rix= FindToIndex (currId); if (rix < 0) return; while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) { if (arc[backwardList[rix]]->GetInput() == procLabel) { PullUpEnds (arc[backwardList[rix]]->GetFromId(), baseId, initialId, procLabel, nodeList, currNum+1, maxNum); } else if (arc[backwardList[rix]]->GetInput() != DISCARD_LABEL) InheritReverseArc (arc[backwardList[rix]], baseId); rix++; } return; } void SubGraph::ProcessEnds (int currId, int initialId, int procLabel, int *nodeList, int currNum, int *visitMark, int maxNum) { int rix, nextId; nodeList[currNum]= currId; rix= FindToIndex (currId); if (rix < 0) { visitMark[currId]= 1; return; } while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) { if (arc[backwardList[rix]]->GetInput() == procLabel) { PullUpEnds (arc[backwardList[rix]]->GetFromId(), currId, initialId, procLabel, nodeList, currNum, maxNum); } nextId= arc[backwardList[rix]]->GetFromId(); if (nextId != initialId && checkEntry (nodeList, currNum, nextId) < 0 && visitMark[nextId] == 0) ProcessEnds (nextId, initialId, procLabel, nodeList, currNum+1, visitMark, maxNum); rix++; } visitMark[currId]= 1; return; } void SubGraph::RemoveUnreachedConnections (int startPoint, int endPoint) { // Obtain nodes with real transitions // Code to pull up nodes for forward connecting transitions // Code to push back nodes for reverse connecting transitions if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } ClearDuplicateArcs (); RemoveUnvisitedArcs (startPoint, endPoint); RemoveDiscardedArcs (); RenumberNodes (); UpdateVertexCount (0); return; } void SubGraph::RemoveUnreachedConnectionsDebug (int startPoint, int endPoint) { // Obtain nodes with real transitions // Code to pull up nodes for forward connecting transitions // Code to push back nodes for reverse connecting transitions if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } // ClearDuplicateArcs (); RemoveUnvisitedArcs (startPoint, endPoint); RemoveDiscardedArcs (); // RenumberNodes (); UpdateVertexCount (0); return; } void SubGraph::ReduceArcsByEquivalence () { int ii, *equivMap, *depthMap; // Sort by Input, Output and to nodes SortLanguage (); SortLanguageReverse (); // Calculate depth depthMap= new int [numVertex]; for (ii= 0; ii < numVertex; ii++) depthMap[ii]= MAXNUM; if (lastId >= 0) ReverseDepthData (lastId, depthMap, 1); ReverseDepthOnTerminal (depthMap); for (ii= 0; ii < numVertex; ii++) if (depthMap[ii] == MAXNUM) depthMap[ii]= -1; // Create equivalence list equivMap= new int [numVertex]; for (ii= 0; ii < numVertex; ii++) equivMap[ii]= ii; // Equivalence test to use equivalence list, duplicate transitions ignored // Test nodes with same equivalence IdentifyEquivalence (depthMap, equivMap); // On identification of an equivalence // Update equivalence entry MapGraphVertices (equivMap); RemoveDiscardedArcs (); // Sort for general access SortLanguage (); delete [] depthMap; delete [] equivMap; return; } void SubGraph::DeterminizeArcs () { int ii; bool allDone; SortLanguage (); DetCache *cache= new DetCache; SetupVisitationCache (); assert (VisitationConsistencyCheck () == 0); printf ("Determinization\n"); allDone= false; while (!allDone) { allDone= true; for (ii= 0; ii < numVertex; ii++) { if (QueryMinProperty(ii) == false) { if (startId == ii || QueryNodeProperty(ii) > 0) { DeterminizeAtVertex (ii, cache); SetMinProperty (ii); allDone= false; //printf (" Node %d, Total %d, Arcs %d\n", ii, numVertex, numArc); } assert (VisitationConsistencyCheck () == 0); // hmm .. this seems harmless but .. // printf("assert(0) in SubGraph::DeterminizeArcs() ii=%d allDone=%d\n", ii, allDone); // assert (0); } } } ClearVisitationCache (); delete cache; return; } int SubGraph::IsDeterminized (int currId) { int count, rix, lastInput; count= 0; lastInput= -1; rix= FindFromIndex (currId); if (rix < 0) return -1; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { if (lastInput >= 0 && lastInput == arc[forwardList[rix]]->GetInput()) count++; else lastInput= arc[forwardList[rix]]->GetInput(); rix++; } return count; } void SubGraph::ReverseGraphForOutput () { int ii, incId, outId; assert (startId == 0); UpdateVertexCount (0); for (ii= 0; ii < numArc; ii++) { incId= arc[ii]->GetFromId(); outId= arc[ii]->GetToId(); if (outId == TERMINAL_LABEL) { arc[ii]->AssignFromId (0); arc[ii]->AssignInput (NONE_LABEL); arc[ii]->AssignOutput (NONE_LABEL); arc[ii]->AssignToId (incId); } else { arc[ii]->AssignFromId (outId); if (incId == 0) arc[ii]->AssignToId (numVertex); else arc[ii]->AssignToId (incId); } } (void) CreateArc (TERMINAL_LABEL, NONE_LABEL, numVertex, TERMINAL_LABEL); // Add terminal transition numVertex++; return; } void SubGraph::RemoveTagConnections (int startPoint, int endPoint) { // Code to push back nodes for reverse connecting transitions if (startPoint == -1 && endPoint == -1) { startPoint= startId; endPoint= lastId; } int *nodeList= new int [numVertex]; int *visitList= new int [numVertex]; for (int ii= 0; ii < numVertex; ii++) visitList[ii]= 0; SortLanguageReverse (); ProcessTags (endPoint, startPoint, nodeList, 0, visitList, numVertex); ClearLabelledConnections (TAG_LABEL); RemoveDiscardedArcs (); delete [] nodeList; delete [] visitList; return; } bool SubGraph::PullUpTags (int currId, int baseId, int initialId, int outTag, int *nodeList, int currNum, int maxNum) { int rix; bool hasCascade= false; nodeList[currNum]= currId; rix= FindToIndex (currId); if (rix < 0) return hasCascade; while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) { if (arc[backwardList[rix]]->GetInput() == TAG_LABEL) { if (PullUpTags (arc[backwardList[rix]]->GetFromId(), baseId, initialId, arc[backwardList[rix]]->GetOutput(), nodeList, currNum+1, maxNum)) CreateCopyWithOutput (arc[backwardList[rix]], NONE_LABEL); hasCascade= true; } else if (arc[backwardList[rix]]->GetInput() != DISCARD_LABEL) InheritReverseArcWithTag (arc[backwardList[rix]], baseId, outTag); rix++; } return hasCascade; } void SubGraph::ProcessTags (int currId, int initialId, int *nodeList, int currNum, int *visitMark, int maxNum) { int rix, nextId; nodeList[currNum]= currId; rix= FindToIndex (currId); if (rix < 0) { visitMark[currId]= 1; return; } while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) { if (arc[backwardList[rix]]->GetInput() == TAG_LABEL) { if (PullUpTags (arc[backwardList[rix]]->GetFromId(), currId, initialId, arc[backwardList[rix]]->GetOutput(), nodeList, currNum, maxNum)) CreateCopyWithOutput (arc[backwardList[rix]], NONE_LABEL); } nextId= arc[backwardList[rix]]->GetFromId(); if (nextId != initialId && checkEntry (nodeList, currNum, nextId) < 0 && visitMark[nextId] == 0) ProcessTags (nextId, initialId, nodeList, currNum+1, visitMark, maxNum); rix++; } visitMark[currId]= 1; return; }