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