/* FILE: sub_min.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" #define SYMBOL_COMPARE(x,y) (arc[x]->CompareSymbol(arc[y])) #define COMPARE(x,y) (arc[x]->Compare(arc[y])) // Minimization to facilitate moving output symbols - mainly for phoneme networks // Check partial merge // Move the output symbol if only one node /* 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; } */ void SubGraph::ViewNode (int currId) { int rix; printf ("Node: %d\n", currId); rix= FindFromIndex (currId); if (rix < 0) return; while (rix < numArc && arc[forwardList[rix]]->GetFromId() == currId) { arc[forwardList[rix]]->Print(); rix++; } return; } bool SubGraph::EquivalenceTestForward (int firstId, int secondId, int *equivMap) { int fix, six, fnxt, snxt, tof, tos, count; assert (firstId != secondId); fix= FindFromIndex (firstId); six= FindFromIndex (secondId); if (fix < 0 || six < 0) return false; count= 0; do { // Move to next valid transitions while (fix < numArc && arc[forwardList[fix]]->GetFromId() == firstId && arc[forwardList[fix]]->GetToId() == DISCARD_LABEL) fix++; if (fix < numArc && arc[forwardList[fix]]->GetFromId() == firstId) fnxt= arc[forwardList[fix]]->GetFromId(); else fnxt= -1; while (six < numArc && arc[forwardList[six]]->GetFromId() == secondId && arc[forwardList[six]]->GetToId() == DISCARD_LABEL) six++; if (six < numArc && arc[forwardList[six]]->GetFromId() == secondId) snxt= arc[forwardList[six]]->GetFromId(); else snxt= -1; if (fnxt != firstId && snxt != secondId) return true; else if (fnxt != firstId || snxt != secondId) return false; tos= arc[forwardList[six]]->GetToId(); tof= arc[forwardList[fix]]->GetToId(); // printf ("Debug inner %d %d, %d %d\n", tof, tos, equivMap[tof], equivMap[tos]); // if (tof >= 0) bogus assert // assert (tof == equivMap[tof]); // if (tos >= 0) // assert (tos == equivMap[tos]); // Test if (!arc[forwardList[fix]]->HasSameLabels (arc[forwardList[six]]) || tos != tof) return false; count++; fix++; six++; } while (fnxt >= 0 && snxt >= 0); return false; } void SubGraph::IdentifyEquivalence (int *depthMap, int *equivMap) { int ii, jj, dd, maxDepth, count, itCnt; maxDepth= 0; for (ii= 0; ii < numVertex; ii++) { if (maxDepth < depthMap[ii]) maxDepth= depthMap[ii]; } itCnt= 0; do { count= 0; for (dd= 0; dd <= maxDepth; dd++) for (ii= 0; ii < numVertex; ii++) if (depthMap[ii] == dd && ii == equivMap[ii]) { CheckForChangeAndResort (ii, equivMap); for (jj= ii+1; jj < numVertex; jj++) if (depthMap[jj] == dd && jj == equivMap[jj]) { // Equivalence test CheckForChangeAndResort (jj, equivMap); // printf ("Try %d %d, ", ii, jj); if (EquivalenceTestForward (ii, jj, equivMap)) { equivMap[jj]= ii; // printf ("Merged %d %d\n", ii, jj); count++; } } } itCnt++; // printf ("Total %d mergers\n", count); } while (count > 0 && itCnt < MAXITS); return; } void SubGraph::CheckForChangeAndResort (int currId, int *mapList) { int rix, rixBegin, nextId; bool needSort; needSort= false; rixBegin= rix= FindFromIndex (currId); if (rix < 0) return; while (rix < numArc && arc[forwardList[rix]]->GetFromId() == currId) { nextId= arc[forwardList[rix]]->GetToId(); if (nextId >= 0 && mapList[nextId] != nextId) { needSort= true; arc[forwardList[rix]]->AssignToId(mapList[nextId]); } rix++; } // Resort if (needSort) RemoveDuplicatesAtNode (rixBegin, rix); return; } void SubGraph::DeterminizeAtVertex (int baseId, DetCache *cache) { int fix, six, firstId, secondId, vertEnd; fix= FindFromIndex (baseId); if (fix < 0) return; // Remove duplicates vertEnd= fix; six= -1; while (vertEnd < sortNum && arc[forwardList[vertEnd]]->GetFromId() == baseId) { vertEnd++; } vertEnd++; // Iteration over first node firstId= -1; while (fix < sortNum && arc[forwardList[fix]]->GetFromId() == baseId) { // Iterator for firstId while (fix < sortNum && arc[forwardList[fix]]->GetFromId() == baseId && (arc[forwardList[fix]]->GetToId() == firstId || arc[forwardList[fix]]->GetInput() == TERMINAL_LABEL || arc[forwardList[fix]]->GetInput() == DISCARD_LABEL)) fix++; // Terminal Condition if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != baseId) break; else firstId= arc[forwardList[fix]]->GetToId(); // Iteration over second node six= fix; secondId= firstId; while (six < sortNum && arc[forwardList[six]]->GetFromId() == baseId) { // Iterator for secondId while (six < sortNum && arc[forwardList[six]]->GetFromId() == baseId && (arc[forwardList[six]]->GetToId() == secondId || arc[forwardList[six]]->GetInput() == TERMINAL_LABEL || arc[forwardList[six]]->GetInput() == DISCARD_LABEL)) six++; // Terminal condition if (six >= sortNum || arc[forwardList[six]]->GetFromId() != baseId) break; else secondId= arc[forwardList[six]]->GetToId(); // Now we have both Ids worked out assert (firstId >= 0); assert (secondId >= 0); assert (arc[forwardList[fix]]->GetInput() != DISCARD_LABEL); assert (arc[forwardList[six]]->GetInput() != DISCARD_LABEL); if (PairwiseDeterminize (baseId, firstId, fix, secondId, six, cache) > 0) { SortLanguageAtSortIndices (fix, vertEnd); // Are we done with the first node? while (fix < sortNum && arc[forwardList[fix]]->GetFromId() == baseId && arc[forwardList[fix]]->GetInput() == DISCARD_LABEL) fix++; // Terminal condition if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != baseId || arc[forwardList[fix]]->GetToId() != firstId) break; } } } return; } int SubGraph::PairwiseDeterminize (int baseId, int firstId, int fixStart, int secondId, int sixStart, DetCache *cache) { int fix, six, fmiss, smiss, nmatch, symTst, newId; bool isCached; fix= fixStart; six= sixStart; assert (arc[forwardList[fix]]->GetInput() != DISCARD_LABEL); assert (arc[forwardList[six]]->GetInput() != DISCARD_LABEL); // Count isCached= false; fmiss= smiss= nmatch= 0; newId= -1; while (six < sortNum && fix < sortNum) { assert (arc[forwardList[fix]]->GetInput() != DISCARD_LABEL); assert (arc[forwardList[six]]->GetInput() != DISCARD_LABEL); symTst= SYMBOL_COMPARE (forwardList[fix], forwardList[six]); if (symTst == 0) { if (newId == -1) { newId= cache->QueryEntry (firstId, secondId); if (newId < 0) newId= NewVertexId (); else isCached= true; // printf ("Forming %d with %d and %d at %d\n", newId, firstId, secondId, baseId); } // Assign second to new Vertex arc[forwardList[six]]->AssignToId (newId); // Assign first to DISCARD Index arc[forwardList[fix]]->AssignInput (DISCARD_LABEL); // Increment to next do { fix++; } while (fix < sortNum && arc[forwardList[fix]]->GetInput() == DISCARD_LABEL); if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != baseId || arc[forwardList[fix]]->GetToId() != firstId) fix= sortNum; do { six++; } while (six < sortNum && arc[forwardList[six]]->GetInput() == DISCARD_LABEL); if (six >= sortNum || arc[forwardList[six]]->GetFromId() != baseId || arc[forwardList[six]]->GetToId() != secondId) six= sortNum; nmatch++; } else if (symTst < 0) { do { fix++; } while (fix < sortNum && arc[forwardList[fix]]->GetInput() == DISCARD_LABEL); if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != baseId || arc[forwardList[fix]]->GetToId() != firstId) fix= sortNum; fmiss++; } else if (symTst > 0) { do { six++; } while (six < sortNum && arc[forwardList[six]]->GetInput() == DISCARD_LABEL); if (six >= sortNum || arc[forwardList[six]]->GetFromId() != baseId || arc[forwardList[six]]->GetToId() != secondId) six= sortNum; smiss++; } } // SortLanguageAtSortIndices (fixStart, fix); if (newId >= 0) { if (isCached == false) { // numLast= numArc; MergeVertices (newId, firstId, secondId); cache->AddEntry (newId, firstId, secondId); // UpdateVisitationCache (numLast); } assert (nmatch > 0); } // Update fan-in count if (nmatch > 0) { // printf ("Merging %d %d to create %d\n", firstId, secondId, newId); for (int ii= 0; ii < nmatch; ii++) { // IncNodeProperty (newId); IncVisitationCache (newId); DecVisitationCache (firstId); DecVisitationCache (secondId); } } return nmatch; } void SubGraph::MergeVertices (int newId, int firstId, int secondId) { int fix, six, symTst, numStart; NUANArc *arcOne; numStart= numArc; fix= FindFromIndex (firstId); six= FindFromIndex (secondId); if (fix < 0 || six < 0) { if (fix >= 0) while (fix < sortNum && arc[forwardList[fix]]->GetFromId() == firstId) { if (arc[forwardList[fix]]->GetInput() != DISCARD_LABEL) InheritArc (arc[forwardList[fix]], newId); fix++; } else if (six >= 0) while (six < sortNum && arc[forwardList[six]]->GetFromId() == secondId) { if (arc[forwardList[six]]->GetInput() != DISCARD_LABEL) InheritArc (arc[forwardList[six]], newId); six++; } } else { while (six < sortNum && fix < sortNum) { symTst= SYMBOL_COMPARE (forwardList[fix], forwardList[six]); if (symTst == 0) { if (arc[forwardList[fix]]->GetToId() == firstId && arc[forwardList[six]]->GetToId() == secondId) { arcOne= InheritArc (arc[forwardList[fix]], newId); arcOne->AssignToId (newId); } else if (arc[forwardList[fix]]->GetToId() == arc[forwardList[six]]->GetToId()) { InheritArc (arc[forwardList[fix]], newId); } else { InheritArc (arc[forwardList[fix]], newId); InheritArc (arc[forwardList[six]], newId); } // Increment to next do { fix++; } while (fix < sortNum && arc[forwardList[fix]]->GetInput() == DISCARD_LABEL); if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != firstId || arc[forwardList[fix]]->GetFromId() != firstId) fix= sortNum; do { six++; } while (six < sortNum && arc[forwardList[six]]->GetInput() == DISCARD_LABEL); if (six >= sortNum || arc[forwardList[six]]->GetFromId() != secondId) six= sortNum; } else if (symTst < 0) { InheritArc (arc[forwardList[fix]], newId); do { fix++; } while (fix < sortNum && arc[forwardList[fix]]->GetInput() == DISCARD_LABEL); if (fix >= sortNum || arc[forwardList[fix]]->GetFromId() != firstId || arc[forwardList[fix]]->GetFromId() != firstId) fix= sortNum; } else if (symTst > 0) { InheritArc (arc[forwardList[six]], newId); do { six++; } while (six < sortNum && arc[forwardList[six]]->GetInput() == DISCARD_LABEL); if (six >= sortNum || arc[forwardList[six]]->GetFromId() != secondId || arc[forwardList[six]]->GetFromId() != secondId) six= sortNum; } } while (fix < sortNum && arc[forwardList[fix]]->GetFromId() == firstId) { if (arc[forwardList[fix]]->GetInput() != DISCARD_LABEL) InheritArc (arc[forwardList[fix]], newId); fix++; } while (six < sortNum && arc[forwardList[six]]->GetFromId() == secondId) { if (arc[forwardList[six]]->GetInput() != DISCARD_LABEL) InheritArc (arc[forwardList[six]], newId); six++; } } // Update the sort list UpdateSortForLanguage (); // RemoveDuplicatesAtNode (numStart, numArc); // ViewNode (newId); assert (CheckSort()); // printf ("Merging %d %d to create %d\n", firstId, secondId, newId); return; } void SubGraph::SetupVisitationCache () { int ii; CreateNodeProperty (); for (ii= 0; ii < numArc; ii++) if (arc[ii]->GetInput() != DISCARD_LABEL && arc[ii]->GetToId() >= 0) IncNodeProperty (arc[ii]->GetToId()); return; } void SubGraph::ClearVisitationCache () { DeleteNodeProperty (); return; } void SubGraph::UpdateVisitationCache (int startNo) { int ii; for (ii= startNo; ii < numArc; ii++) if (arc[ii]->GetInput() != DISCARD_LABEL && arc[ii]->GetToId() >= 0) { IncNodeProperty (arc[ii]->GetToId()); // std::cout << " (" << arc[ii]->GetToId() << " " << QueryNodeProperty (arc[ii]->GetToId()) << ") "; } // std::cout << std::endl; return; } void SubGraph::DecVisitationCache (int currId) { int rix; DecNodeProperty (currId); // std::cout << " [" << currId << " " << QueryNodeProperty (currId) << "] "; if (QueryNodeProperty (currId) <= 0) { // std::cout << " [" << currId << "] "; rix= FindFromIndex (currId); if (rix < 0) return; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { if (arc[forwardList[rix]]->GetInput() != DISCARD_LABEL && arc[forwardList[rix]]->GetToId() >= 0) { if (arc[forwardList[rix]]->GetFromId() == arc[forwardList[rix]]->GetToId()) DecNodeProperty (currId); else if (QueryNodeProperty (arc[forwardList[rix]]->GetToId()) > 0) DecVisitationCache (arc[forwardList[rix]]->GetToId()); } rix++; } } return; } void SubGraph::IncVisitationCache (int currId) { int rix; if (QueryNodeProperty (currId) <= 0) { IncNodeProperty (currId); // std::cout << " (" << currId << ") "; rix= FindFromIndex (currId); if (rix < 0) return; while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) { if (arc[forwardList[rix]]->GetInput() != DISCARD_LABEL && arc[forwardList[rix]]->GetToId() >= 0) { // IncNodeProperty (arc[forwardList[rix]]->GetToId()); // if (currId != arc[forwardList[rix]]->GetToId()) IncVisitationCache (arc[forwardList[rix]]->GetToId()); } rix++; } } else IncNodeProperty (currId); // std::cout << " (" << currId << " " << QueryNodeProperty (currId) << ") "; return; } int SubGraph::VisitationConsistencyCheck () { int ii, failCount; int *nodeCount= new int [numVertex]; UpdateVertexCount (0); // std::cout << "Count: "; for (ii= 0; ii <numVertex; ii++) { // std::cout << ii << " (" << vertexProp[ii] << ") "; nodeCount[ii]= 0; } // std::cout << std::endl; for (ii= 0; ii <numArc; ii++) if (arc[ii]->GetInput() != DISCARD_LABEL && arc[ii]->GetToId() >= 0 && (vertexProp[arc[ii]->GetFromId()] > 0 || arc[ii]->GetFromId() == startId)) nodeCount[arc[ii]->GetToId()]++; failCount= 0; // std::cout << "Failure list: "; for (ii= 0; ii <numVertex; ii++) if (vertexProp[ii] != nodeCount[ii]) { // std::cout << ii << " (" << vertexProp[ii] << " " << nodeCount[ii] << ") "; failCount++; } // std::cout << std::endl; // return failCount; delete [] nodeCount; return 0; }