| /**CFile**************************************************************** |
| |
| FileName [bm.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Boolean Matching package.] |
| |
| Synopsis [Check P-equivalence and PP-equivalence of two circuits.] |
| |
| Author [Hadi Katebi] |
| |
| Affiliation [University of Michigan] |
| |
| Date [Ver. 1.0. Started - January, 2009.] |
| |
| Revision [No revisions so far] |
| |
| Comments [This is the cleaned up version of the code I used for DATE 2010 publication.] |
| [If you have any question or if you find a bug, contact me at hadik@umich.edu.] |
| [I don't guarantee that I can fix all the bugs, but I can definitely point you to |
| the right direction so you can fix the bugs yourself]. |
| |
| Debugging [There are some part of the code that are commented out. Those parts mostly print |
| the contents of the data structures to the standard output. Un-comment them if you |
| find them useful for debugging.] |
| |
| ***********************************************************************/ |
| |
| #include "base/abc/abc.h" |
| #include "opt/sim/sim.h" |
| #include "sat/bsat/satSolver.h" |
| //#include "bdd/extrab/extraBdd.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| #define FALSE 0 |
| #define TRUE 1 |
| |
| int match1by1(Abc_Ntk_t * pNtk1, Vec_Ptr_t ** nodesInLevel1, Vec_Int_t ** iMatch1, Vec_Int_t ** iDep1, Vec_Int_t * matchedInputs1, int * iGroup1, Vec_Int_t ** oMatch1, int * oGroup1, |
| Abc_Ntk_t * pNtk2, Vec_Ptr_t ** nodesInLevel2, Vec_Int_t ** iMatch2, Vec_Int_t ** iDep2, Vec_Int_t * matchedInputs2, int * iGroup2, Vec_Int_t ** oMatch2, int * oGroup2, |
| Vec_Int_t * matchedOutputs1, Vec_Int_t * matchedOutputs2, Vec_Int_t * oMatchedGroups, Vec_Int_t * iNonSingleton, int ii, int idx); |
| |
| int Abc_NtkBmSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Vec_Ptr_t * iMatchPairs, Vec_Ptr_t * oMatchPairs, Vec_Int_t * mismatch, int mode); |
| |
| void getDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep) |
| { |
| Vec_Ptr_t * vSuppFun; |
| int i, j; |
| |
| vSuppFun = Sim_ComputeFunSupp(pNtk, 0); |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) { |
| char * seg = (char *)vSuppFun->pArray[i]; |
| |
| for(j = 0; j < Abc_NtkPiNum(pNtk); j+=8) { |
| if(((*seg) & 0x01) == 0x01) |
| Vec_IntPushOrder(oDep[i], j); |
| if(((*seg) & 0x02) == 0x02) |
| Vec_IntPushOrder(oDep[i], j+1); |
| if(((*seg) & 0x04) == 0x04) |
| Vec_IntPushOrder(oDep[i], j+2); |
| if(((*seg) & 0x08) == 0x08) |
| Vec_IntPushOrder(oDep[i], j+3); |
| if(((*seg) & 0x10) == 0x10) |
| Vec_IntPushOrder(oDep[i], j+4); |
| if(((*seg) & 0x20) == 0x20) |
| Vec_IntPushOrder(oDep[i], j+5); |
| if(((*seg) & 0x40) == 0x40) |
| Vec_IntPushOrder(oDep[i], j+6); |
| if(((*seg) & 0x80) == 0x80) |
| Vec_IntPushOrder(oDep[i], j+7); |
| |
| seg++; |
| } |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| Vec_IntPush(iDep[Vec_IntEntry(oDep[i], j)], i); |
| |
| |
| /*for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| { |
| printf("Output %d: ", i); |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| printf("%d ", Vec_IntEntry(oDep[i], j)); |
| printf("\n"); |
| } |
| |
| printf("\n"); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| { |
| printf("Input %d: ", i); |
| for(j = 0; j < Vec_IntSize(iDep[i]); j++) |
| printf("%d ", Vec_IntEntry(iDep[i], j)); |
| printf("\n"); |
| } |
| |
| printf("\n"); */ |
| } |
| |
| void initMatchList(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep, Vec_Int_t** iMatch, int* iLastItem, Vec_Int_t** oMatch, int* oLastItem, int* iGroup, int* oGroup, int p_equivalence) |
| { |
| int i, j, curr; |
| Vec_Int_t** temp; |
| |
| if(!p_equivalence) { |
| temp = ABC_ALLOC( Vec_Int_t*, Abc_NtkPiNum(pNtk)+1); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk)+1; i++) |
| temp[i] = Vec_IntAlloc( 0 ); |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| Vec_IntPush(temp[Vec_IntSize(oDep[i])], i); |
| |
| curr = 0; |
| for(i = 0; i < Abc_NtkPiNum(pNtk)+1; i++) |
| { |
| if(Vec_IntSize(temp[i]) == 0) |
| Vec_IntFree( temp[i] ); |
| |
| else |
| { |
| oMatch[curr] = temp[i]; |
| |
| for(j = 0; j < Vec_IntSize(temp[i]); j++) |
| oGroup[Vec_IntEntry(oMatch[curr], j)] = curr; |
| |
| curr++; |
| } |
| } |
| |
| *oLastItem = curr; |
| |
| ABC_FREE( temp ); |
| } |
| else { |
| // the else part fixes the outputs for P-equivalence checking |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| { |
| Vec_IntPush(oMatch[i], i); |
| oGroup[i] = i; |
| (*oLastItem) = Abc_NtkPoNum(pNtk); |
| } |
| } |
| |
| /*for(j = 0; j < *oLastItem; j++) |
| { |
| printf("oMatch %d: ", j); |
| for(i = 0; i < Vec_IntSize(oMatch[j]); i++) |
| printf("%d ", Vec_IntEntry(oMatch[j], i)); |
| printf("\n"); |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| printf("%d: %d ", i, oGroup[i]);*/ |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| temp = ABC_ALLOC( Vec_Int_t*, Abc_NtkPoNum(pNtk)+1 ); |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk)+1; i++) |
| temp[i] = Vec_IntAlloc( 0 ); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| Vec_IntPush(temp[Vec_IntSize(iDep[i])], i); |
| |
| curr = 0; |
| for(i = 0; i < Abc_NtkPoNum(pNtk)+1; i++) |
| { |
| if(Vec_IntSize(temp[i]) == 0) |
| Vec_IntFree( temp[i] ); |
| else |
| { |
| iMatch[curr] = temp[i]; |
| for(j = 0; j < Vec_IntSize(iMatch[curr]); j++) |
| iGroup[Vec_IntEntry(iMatch[curr], j)] = curr; |
| curr++; |
| } |
| } |
| |
| *iLastItem = curr; |
| |
| ABC_FREE( temp ); |
| |
| /*printf("\n"); |
| for(j = 0; j < *iLastItem; j++) |
| { |
| printf("iMatch %d: ", j); |
| for(i = 0; i < Vec_IntSize(iMatch[j]); i++) |
| printf("%d ", Vec_IntEntry(iMatch[j], i)); |
| printf("\n"); |
| } |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| printf("%d: %d ", i, iGroup[i]); |
| printf("\n");*/ |
| } |
| |
| void iSortDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, int* oGroup) |
| { |
| int i, j, k; |
| Vec_Int_t * temp; |
| Vec_Int_t * oGroupList; |
| |
| oGroupList = Vec_IntAlloc( 10 ); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| { |
| if(Vec_IntSize(iDep[i]) == 1) |
| continue; |
| |
| temp = Vec_IntAlloc( Vec_IntSize(iDep[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(iDep[i]); j++) |
| Vec_IntPushUniqueOrder(oGroupList, oGroup[Vec_IntEntry(iDep[i], j)]); |
| |
| for(j = 0; j < Vec_IntSize(oGroupList); j++) |
| { |
| for(k = 0; k < Vec_IntSize(iDep[i]); k++) |
| if(oGroup[Vec_IntEntry(iDep[i], k)] == Vec_IntEntry(oGroupList, j)) |
| { |
| Vec_IntPush( temp, Vec_IntEntry(iDep[i], k) ); |
| Vec_IntRemove( iDep[i], Vec_IntEntry(iDep[i], k) ); |
| k--; |
| } |
| } |
| |
| Vec_IntFree( iDep[i] ); |
| iDep[i] = temp; |
| Vec_IntClear( oGroupList ); |
| |
| /*printf("Input %d: ", i); |
| for(j = 0; j < Vec_IntSize(iDep[i]); j++) |
| printf("%d ", Vec_IntEntry(iDep[i], j)); |
| printf("\n");*/ |
| } |
| |
| Vec_IntFree( oGroupList ); |
| } |
| |
| void oSortDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** oDep, int* iGroup) |
| { |
| int i, j, k; |
| Vec_Int_t * temp; |
| Vec_Int_t * iGroupList; |
| |
| iGroupList = Vec_IntAlloc( 10 ); |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| { |
| if(Vec_IntSize(oDep[i]) == 1) |
| continue; |
| |
| temp = Vec_IntAlloc( Vec_IntSize(oDep[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| Vec_IntPushUniqueOrder(iGroupList, iGroup[Vec_IntEntry(oDep[i], j)]); |
| |
| for(j = 0; j < Vec_IntSize(iGroupList); j++) |
| { |
| for(k = 0; k < Vec_IntSize(oDep[i]); k++) |
| if(iGroup[Vec_IntEntry(oDep[i], k)] == Vec_IntEntry(iGroupList, j)) |
| { |
| Vec_IntPush( temp, Vec_IntEntry(oDep[i], k) ); |
| Vec_IntRemove( oDep[i], Vec_IntEntry(oDep[i], k) ); |
| k--; |
| } |
| } |
| |
| Vec_IntFree( oDep[i] ); |
| oDep[i] = temp; |
| Vec_IntClear( iGroupList ); |
| |
| /*printf("Output %d: ", i); |
| for(j = 0; j < Vec_IntSize(oDep[i]); j++) |
| printf("%d ", Vec_IntEntry(oDep[i], j)); |
| printf("\n");*/ |
| } |
| |
| Vec_IntFree( iGroupList ); |
| } |
| |
| int oSplitByDep(Abc_Ntk_t *pNtk, Vec_Int_t** oDep, Vec_Int_t** oMatch, int* oGroup, int* oLastItem, int* iGroup) |
| { |
| int i, j, k; |
| int numOfItemsAdded; |
| Vec_Int_t * array, * sortedArray; |
| |
| numOfItemsAdded = 0; |
| |
| for(i = 0; i < *oLastItem; i++) |
| { |
| if(Vec_IntSize(oMatch[i]) == 1) |
| continue; |
| |
| array = Vec_IntAlloc( Vec_IntSize(oMatch[i]) ); |
| sortedArray = Vec_IntAlloc( Vec_IntSize(oMatch[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(oMatch[i]); j++) |
| { |
| int factor, encode; |
| |
| encode = 0; |
| factor = 1; |
| |
| for(k = 0; k < Vec_IntSize(oDep[Vec_IntEntry(oMatch[i], j)]); k++) |
| encode += iGroup[Vec_IntEntry(oDep[Vec_IntEntry(oMatch[i], j)], k)] * factor; |
| |
| Vec_IntPush(array, encode); |
| Vec_IntPushUniqueOrder(sortedArray, encode); |
| |
| if( encode < 0) |
| printf("WARNING! Integer overflow!"); |
| |
| //printf("%d ", Vec_IntEntry(array, j)); |
| } |
| |
| while( Vec_IntSize(sortedArray) > 1 ) |
| { |
| for(k = 0; k < Vec_IntSize(oMatch[i]); k++) |
| { |
| if(Vec_IntEntry(array, k) == Vec_IntEntryLast(sortedArray)) |
| { |
| Vec_IntPush(oMatch[*oLastItem+numOfItemsAdded], Vec_IntEntry(oMatch[i], k)); |
| oGroup[Vec_IntEntry(oMatch[i], k)] = *oLastItem+numOfItemsAdded; |
| Vec_IntRemove( oMatch[i], Vec_IntEntry(oMatch[i], k) ); |
| Vec_IntRemove( array, Vec_IntEntry(array, k) ); |
| k--; |
| } |
| } |
| numOfItemsAdded++; |
| Vec_IntPop(sortedArray); |
| } |
| |
| Vec_IntFree( array ); |
| Vec_IntFree( sortedArray ); |
| //printf("\n"); |
| } |
| |
| *oLastItem += numOfItemsAdded; |
| |
| /*printf("\n"); |
| for(j = 0; j < *oLastItem ; j++) |
| { |
| printf("oMatch %d: ", j); |
| for(i = 0; i < Vec_IntSize(oMatch[j]); i++) |
| printf("%d ", Vec_IntEntry(oMatch[j], i)); |
| printf("\n"); |
| }*/ |
| |
| return numOfItemsAdded; |
| } |
| |
| int iSplitByDep(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** iMatch, int* iGroup, int* iLastItem, int* oGroup) |
| { |
| int i, j, k; |
| int numOfItemsAdded = 0; |
| Vec_Int_t * array, * sortedArray; |
| |
| for(i = 0; i < *iLastItem; i++) |
| { |
| if(Vec_IntSize(iMatch[i]) == 1) |
| continue; |
| |
| array = Vec_IntAlloc( Vec_IntSize(iMatch[i]) ); |
| sortedArray = Vec_IntAlloc( Vec_IntSize(iMatch[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(iMatch[i]); j++) |
| { |
| int factor, encode; |
| |
| encode = 0; |
| factor = 1; |
| |
| for(k = 0; k < Vec_IntSize(iDep[Vec_IntEntry(iMatch[i], j)]); k++) |
| encode += oGroup[Vec_IntEntry(iDep[Vec_IntEntry(iMatch[i], j)], k)] * factor; |
| |
| Vec_IntPush(array, encode); |
| Vec_IntPushUniqueOrder(sortedArray, encode); |
| |
| //printf("%d ", Vec_IntEntry(array, j)); |
| } |
| |
| while( Vec_IntSize(sortedArray) > 1 ) |
| { |
| for(k = 0; k < Vec_IntSize(iMatch[i]); k++) |
| { |
| if(Vec_IntEntry(array, k) == Vec_IntEntryLast(sortedArray)) |
| { |
| Vec_IntPush(iMatch[*iLastItem+numOfItemsAdded], Vec_IntEntry(iMatch[i], k)); |
| iGroup[Vec_IntEntry(iMatch[i], k)] = *iLastItem+numOfItemsAdded; |
| Vec_IntRemove( iMatch[i], Vec_IntEntry(iMatch[i], k) ); |
| Vec_IntRemove( array, Vec_IntEntry(array, k) ); |
| k--; |
| } |
| } |
| numOfItemsAdded++; |
| Vec_IntPop(sortedArray); |
| } |
| |
| Vec_IntFree( array ); |
| Vec_IntFree( sortedArray ); |
| //printf("\n"); |
| } |
| |
| *iLastItem += numOfItemsAdded; |
| |
| /*printf("\n"); |
| for(j = 0; j < *iLastItem ; j++) |
| { |
| printf("iMatch %d: ", j); |
| for(i = 0; i < Vec_IntSize(iMatch[j]); i++) |
| printf("%d ", Vec_IntEntry(iMatch[j], i)); |
| printf("\n"); |
| }*/ |
| |
| return numOfItemsAdded; |
| } |
| |
| Vec_Ptr_t ** findTopologicalOrder( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t ** vNodes; |
| Abc_Obj_t * pObj, * pFanout; |
| int i, k; |
| |
| extern void Abc_NtkDfsReverse_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ); |
| |
| // start the array of nodes |
| vNodes = ABC_ALLOC(Vec_Ptr_t *, Abc_NtkPiNum(pNtk)); |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| vNodes[i] = Vec_PtrAlloc(50); |
| |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| { |
| // set the traversal ID |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NodeSetTravIdCurrent( pObj ); |
| pObj = Abc_ObjFanout0Ntk(pObj); |
| Abc_ObjForEachFanout( pObj, pFanout, k ) |
| Abc_NtkDfsReverse_rec( pFanout, vNodes[i] ); |
| } |
| |
| return vNodes; |
| } |
| |
| |
| int * Abc_NtkSimulateOneNode( Abc_Ntk_t * pNtk, int * pModel, int input, Vec_Ptr_t ** topOrder ) |
| { |
| Abc_Obj_t * pNode; |
| Vec_Ptr_t * vNodes; |
| int * pValues, Value0, Value1, i; |
| |
| vNodes = Vec_PtrAlloc( 50 ); |
| /* |
| printf( "Counter example: " ); |
| Abc_NtkForEachCi( pNtk, pNode, i ) |
| printf( " %d", pModel[i] ); |
| printf( "\n" ); |
| */ |
| // increment the trav ID |
| Abc_NtkIncrementTravId( pNtk ); |
| // set the CI values |
| Abc_AigConst1(pNtk)->pCopy = (Abc_Obj_t *)1; |
| pNode = Abc_NtkCi(pNtk, input); |
| pNode->iTemp = pModel[input]; |
| |
| // simulate in the topological order |
| for(i = Vec_PtrSize(topOrder[input])-1; i >= 0; i--) |
| { |
| pNode = (Abc_Obj_t *)Vec_PtrEntry(topOrder[input], i); |
| |
| Value0 = ((int)(ABC_PTRUINT_T)Abc_ObjFanin0(pNode)->pCopy) ^ Abc_ObjFaninC0(pNode); |
| Value1 = ((int)(ABC_PTRUINT_T)Abc_ObjFanin1(pNode)->pCopy) ^ Abc_ObjFaninC1(pNode); |
| |
| if( pNode->iTemp != (Value0 & Value1)) |
| { |
| pNode->iTemp = (Value0 & Value1); |
| Vec_PtrPush(vNodes, pNode); |
| } |
| |
| } |
| // fill the output values |
| pValues = ABC_ALLOC( int, Abc_NtkCoNum(pNtk) ); |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| pValues[i] = ((int)(ABC_PTRUINT_T)Abc_ObjFanin0(pNode)->pCopy) ^ Abc_ObjFaninC0(pNode); |
| |
| pNode = Abc_NtkCi(pNtk, input); |
| if(pNode->pCopy == (Abc_Obj_t *)1) |
| pNode->pCopy = (Abc_Obj_t *)0; |
| else |
| pNode->pCopy = (Abc_Obj_t *)1; |
| |
| for(i = 0; i < Vec_PtrSize(vNodes); i++) |
| { |
| pNode = (Abc_Obj_t *)Vec_PtrEntry(vNodes, i); |
| |
| if(pNode->pCopy == (Abc_Obj_t *)1) |
| pNode->pCopy = (Abc_Obj_t *)0; |
| else |
| pNode->pCopy = (Abc_Obj_t *)1; |
| } |
| |
| Vec_PtrFree( vNodes ); |
| |
| return pValues; |
| } |
| |
| int refineIOBySimulation(Abc_Ntk_t *pNtk, Vec_Int_t** iMatch, int* iLastItem, int * iGroup, Vec_Int_t** iDep, Vec_Int_t** oMatch, int* oLastItem, int * oGroup, Vec_Int_t** oDep, char * vPiValues, int * observability, Vec_Ptr_t ** topOrder) |
| { |
| Abc_Obj_t * pObj; |
| int * pModel;//, ** pModel2; |
| int * output, * output2; |
| int lastItem; |
| int i, j, k; |
| Vec_Int_t * iComputedNum, * iComputedNumSorted; |
| Vec_Int_t * oComputedNum; // encoding the number of flips |
| int factor; |
| int isRefined = FALSE; |
| |
| pModel = ABC_ALLOC( int, Abc_NtkCiNum(pNtk) ); |
| |
| Abc_NtkForEachPi( pNtk, pObj, i ) |
| pModel[i] = vPiValues[i] - '0'; |
| Abc_NtkForEachLatch( pNtk, pObj, i ) |
| pModel[Abc_NtkPiNum(pNtk)+i] = pObj->iData - 1; |
| |
| output = Abc_NtkVerifySimulatePattern( pNtk, pModel ); |
| |
| oComputedNum = Vec_IntAlloc( Abc_NtkPoNum(pNtk) ); |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| Vec_IntPush(oComputedNum, 0); |
| |
| /****************************************************************************************/ |
| /********** group outputs that produce 1 and outputs that produce 0 together ************/ |
| |
| lastItem = *oLastItem; |
| for(i = 0; i < lastItem && (*oLastItem) != Abc_NtkPoNum(pNtk); i++) |
| { |
| int flag = FALSE; |
| |
| if(Vec_IntSize(oMatch[i]) == 1) |
| continue; |
| |
| for(j = 1; j < Vec_IntSize(oMatch[i]); j++) |
| if(output[Vec_IntEntry(oMatch[i], 0)] != output[Vec_IntEntry(oMatch[i], j)]) |
| { |
| flag = TRUE; |
| break; |
| } |
| |
| if(flag) |
| { |
| for(j = 0; j < Vec_IntSize(oMatch[i]); j++) |
| if(output[Vec_IntEntry(oMatch[i], j)]) |
| { |
| Vec_IntPush(oMatch[*oLastItem], Vec_IntEntry(oMatch[i], j)); |
| oGroup[Vec_IntEntry(oMatch[i], j)] = *oLastItem; |
| Vec_IntRemove(oMatch[i], Vec_IntEntry(oMatch[i], j)); |
| j--; |
| } |
| |
| (*oLastItem)++; |
| } |
| } |
| |
| if( (*oLastItem) > lastItem ) |
| { |
| isRefined = TRUE; |
| iSortDependencies(pNtk, iDep, oGroup); |
| } |
| |
| /****************************************************************************************/ |
| /************* group inputs that make the same number of flips in outpus ****************/ |
| |
| lastItem = *iLastItem; |
| for(i = 0; i < lastItem && (*iLastItem) != Abc_NtkPiNum(pNtk); i++) |
| { |
| int num; |
| |
| if(Vec_IntSize(iMatch[i]) == 1) |
| continue; |
| |
| iComputedNum = Vec_IntAlloc( Vec_IntSize(iMatch[i]) ); |
| iComputedNumSorted = Vec_IntAlloc( Vec_IntSize(iMatch[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(iMatch[i]); j++) |
| { |
| if( vPiValues[Vec_IntEntry(iMatch[i], j)] == '0' ) |
| pModel[Vec_IntEntry(iMatch[i], j)] = 1; |
| else |
| pModel[Vec_IntEntry(iMatch[i], j)] = 0; |
| |
| //output2 = Abc_NtkVerifySimulatePattern( pNtk, pModel ); |
| output2 = Abc_NtkSimulateOneNode( pNtk, pModel, Vec_IntEntry(iMatch[i], j), topOrder ); |
| |
| num = 0; |
| factor = 1; |
| for(k = 0; k < Vec_IntSize(iDep[Vec_IntEntry(iMatch[i], j)]); k++) |
| { |
| int outputIndex = Vec_IntEntry(iDep[Vec_IntEntry(iMatch[i], j)], k); |
| |
| if(output2[outputIndex]) |
| num += (oGroup[outputIndex] + 1) * factor; |
| |
| if(output[outputIndex] != output2[outputIndex]) |
| { |
| int temp = Vec_IntEntry(oComputedNum, outputIndex) + i + 1; |
| Vec_IntWriteEntry(oComputedNum, outputIndex, temp); |
| observability[Vec_IntEntry(iMatch[i], j)]++; |
| } |
| } |
| |
| Vec_IntPush(iComputedNum, num); |
| Vec_IntPushUniqueOrder(iComputedNumSorted, num); |
| |
| pModel[Vec_IntEntry(iMatch[i], j)] = vPiValues[Vec_IntEntry(iMatch[i], j)] - '0'; |
| ABC_FREE( output2 ); |
| } |
| |
| while( Vec_IntSize( iComputedNumSorted ) > 1 ) |
| { |
| for(k = 0; k < Vec_IntSize(iMatch[i]); k++) |
| { |
| if(Vec_IntEntry(iComputedNum, k) == Vec_IntEntryLast(iComputedNumSorted) ) |
| { |
| Vec_IntPush(iMatch[*iLastItem], Vec_IntEntry(iMatch[i], k)); |
| iGroup[Vec_IntEntry(iMatch[i], k)] = *iLastItem; |
| Vec_IntRemove( iMatch[i], Vec_IntEntry(iMatch[i], k) ); |
| Vec_IntRemove( iComputedNum, Vec_IntEntry(iComputedNum, k) ); |
| k--; |
| } |
| } |
| (*iLastItem)++; |
| Vec_IntPop( iComputedNumSorted ); |
| } |
| |
| Vec_IntFree( iComputedNum ); |
| Vec_IntFree( iComputedNumSorted ); |
| } |
| |
| if( (*iLastItem) > lastItem ) |
| { |
| isRefined = TRUE; |
| oSortDependencies(pNtk, oDep, iGroup); |
| } |
| |
| /****************************************************************************************/ |
| /********** encode the number of flips in each output by flipping the outputs ***********/ |
| /********** and group all the outputs that have the same encoding ***********/ |
| |
| lastItem = *oLastItem; |
| for(i = 0; i < lastItem && (*oLastItem) != Abc_NtkPoNum(pNtk); i++) |
| { |
| Vec_Int_t * encode, * sortedEncode; // encoding the number of flips |
| |
| if(Vec_IntSize(oMatch[i]) == 1) |
| continue; |
| |
| encode = Vec_IntAlloc( Vec_IntSize(oMatch[i]) ); |
| sortedEncode = Vec_IntAlloc( Vec_IntSize(oMatch[i]) ); |
| |
| for(j = 0; j < Vec_IntSize(oMatch[i]); j++) |
| { |
| Vec_IntPush(encode, Vec_IntEntry(oComputedNum, Vec_IntEntry(oMatch[i], j)) ); |
| Vec_IntPushUniqueOrder( sortedEncode, Vec_IntEntry(encode, j) ); |
| } |
| |
| while( Vec_IntSize(sortedEncode) > 1 ) |
| { |
| for(j = 0; j < Vec_IntSize(oMatch[i]); j++) |
| if(Vec_IntEntry(encode, j) == Vec_IntEntryLast(sortedEncode)) |
| { |
| Vec_IntPush(oMatch[*oLastItem], Vec_IntEntry(oMatch[i], j)); |
| oGroup[Vec_IntEntry(oMatch[i], j)] = *oLastItem; |
| Vec_IntRemove( oMatch[i], Vec_IntEntry(oMatch[i], j) ); |
| Vec_IntRemove( encode, Vec_IntEntry(encode, j) ); |
| j --; |
| } |
| |
| (*oLastItem)++; |
| Vec_IntPop( sortedEncode ); |
| } |
| |
| Vec_IntFree( encode ); |
| Vec_IntFree( sortedEncode ); |
| } |
| |
| if( (*oLastItem) > lastItem ) |
| isRefined = TRUE; |
| |
| ABC_FREE( pModel ); |
| ABC_FREE( output ); |
| Vec_IntFree( oComputedNum ); |
| |
| return isRefined; |
| } |
| |
| Abc_Ntk_t * Abc_NtkMiterBm( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Vec_Ptr_t * iCurrMatch, Vec_Ptr_t * oCurrMatch ) |
| { |
| char Buffer[1000]; |
| Abc_Ntk_t * pNtkMiter; |
| |
| pNtkMiter = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 ); |
| sprintf( Buffer, "%s_%s_miter", pNtk1->pName, pNtk2->pName ); |
| pNtkMiter->pName = Extra_UtilStrsav(Buffer); |
| |
| //Abc_NtkMiterPrepare( pNtk1, pNtk2, pNtkMiter, fComb, nPartSize ); |
| { |
| Abc_Obj_t * pObj, * pObjNew; |
| int i; |
| |
| Abc_AigConst1(pNtk1)->pCopy = Abc_AigConst1(pNtkMiter); |
| Abc_AigConst1(pNtk2)->pCopy = Abc_AigConst1(pNtkMiter); |
| |
| // create new PIs and remember them in the old PIs |
| if(iCurrMatch == NULL) |
| { |
| Abc_NtkForEachCi( pNtk1, pObj, i ) |
| { |
| pObjNew = Abc_NtkCreatePi( pNtkMiter ); |
| // remember this PI in the old PIs |
| pObj->pCopy = pObjNew; |
| pObj = Abc_NtkCi(pNtk2, i); |
| pObj->pCopy = pObjNew; |
| // add name |
| Abc_ObjAssignName( pObjNew, Abc_ObjName(pObj), NULL ); |
| } |
| } |
| else |
| { |
| for(i = 0; i < Vec_PtrSize( iCurrMatch ); i += 2) |
| { |
| pObjNew = Abc_NtkCreatePi( pNtkMiter ); |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(iCurrMatch, i); |
| pObj->pCopy = pObjNew; |
| pObj = (Abc_Obj_t *)Vec_PtrEntry(iCurrMatch, i+1); |
| pObj->pCopy = pObjNew; |
| // add name |
| Abc_ObjAssignName( pObjNew, Abc_ObjName(pObj), NULL ); |
| } |
| } |
| |
| // create the only PO |
| pObjNew = Abc_NtkCreatePo( pNtkMiter ); |
| // add the PO name |
| Abc_ObjAssignName( pObjNew, "miter", NULL ); |
| } |
| |
| // Abc_NtkMiterAddOne( pNtk1, pNtkMiter ); |
| { |
| Abc_Obj_t * pNode; |
| int i; |
| assert( Abc_NtkIsDfsOrdered(pNtk1) ); |
| Abc_AigForEachAnd( pNtk1, pNode, i ) |
| pNode->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkMiter->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) ); |
| } |
| |
| // Abc_NtkMiterAddOne( pNtk2, pNtkMiter ); |
| { |
| Abc_Obj_t * pNode; |
| int i; |
| assert( Abc_NtkIsDfsOrdered(pNtk2) ); |
| Abc_AigForEachAnd( pNtk2, pNode, i ) |
| pNode->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkMiter->pManFunc, Abc_ObjChild0Copy(pNode), Abc_ObjChild1Copy(pNode) ); |
| } |
| |
| // Abc_NtkMiterFinalize( pNtk1, pNtk2, pNtkMiter, fComb, nPartSize ); |
| { |
| Vec_Ptr_t * vPairs; |
| Abc_Obj_t * pMiter; |
| int i; |
| |
| vPairs = Vec_PtrAlloc( 100 ); |
| |
| // collect the CO nodes for the miter |
| if(oCurrMatch != NULL) |
| { |
| for(i = 0; i < Vec_PtrSize( oCurrMatch ); i += 2) |
| { |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy((Abc_Obj_t *)Vec_PtrEntry(oCurrMatch, i)) ); |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy((Abc_Obj_t *)Vec_PtrEntry(oCurrMatch, i+1)) ); |
| } |
| } |
| else |
| { |
| Abc_Obj_t * pNode; |
| |
| Abc_NtkForEachCo( pNtk1, pNode, i ) |
| { |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy(pNode) ); |
| pNode = Abc_NtkCo( pNtk2, i ); |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy(pNode) ); |
| } |
| } |
| |
| pMiter = Abc_AigMiter( (Abc_Aig_t *)pNtkMiter->pManFunc, vPairs, 0 ); |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkMiter,0), pMiter ); |
| Vec_PtrFree(vPairs); |
| } |
| |
| //Abc_AigCleanup(pNtkMiter->pManFunc); |
| |
| return pNtkMiter; |
| } |
| |
| int * pValues1__, * pValues2__; |
| |
| void Abc_NtkVerifyReportError( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int * pModel, Vec_Int_t * mismatch ) |
| { |
| Vec_Ptr_t * vNodes; |
| Abc_Obj_t * pNode; |
| int nErrors, nPrinted, i, iNode = -1; |
| |
| assert( Abc_NtkCiNum(pNtk1) == Abc_NtkCiNum(pNtk2) ); |
| assert( Abc_NtkCoNum(pNtk1) == Abc_NtkCoNum(pNtk2) ); |
| // get the CO values under this model |
| pValues1__ = Abc_NtkVerifySimulatePattern( pNtk1, pModel ); |
| pValues2__ = Abc_NtkVerifySimulatePattern( pNtk2, pModel ); |
| // count the mismatches |
| nErrors = 0; |
| for ( i = 0; i < Abc_NtkCoNum(pNtk1); i++ ) |
| nErrors += (int)( pValues1__[i] != pValues2__[i] ); |
| //printf( "Verification failed for at least %d outputs: ", nErrors ); |
| // print the first 3 outputs |
| nPrinted = 0; |
| for ( i = 0; i < Abc_NtkCoNum(pNtk1); i++ ) |
| if ( pValues1__[i] != pValues2__[i] ) |
| { |
| if ( iNode == -1 ) |
| iNode = i; |
| //printf( " %s", Abc_ObjName(Abc_NtkCo(pNtk1,i)) ); |
| if ( ++nPrinted == 3 ) |
| break; |
| } |
| /*if ( nPrinted != nErrors ) |
| printf( " ..." ); |
| printf( "\n" );*/ |
| // report mismatch for the first output |
| if ( iNode >= 0 ) |
| { |
| /*printf( "Output %s: Value in Network1 = %d. Value in Network2 = %d.\n", |
| Abc_ObjName(Abc_NtkCo(pNtk1,iNode)), pValues1[iNode], pValues2[iNode] ); |
| printf( "Input pattern: " );*/ |
| // collect PIs in the cone |
| pNode = Abc_NtkCo(pNtk1,iNode); |
| vNodes = Abc_NtkNodeSupport( pNtk1, &pNode, 1 ); |
| // set the PI numbers |
| Abc_NtkForEachCi( pNtk1, pNode, i ) |
| pNode->iTemp = i; |
| // print the model |
| pNode = (Abc_Obj_t *)Vec_PtrEntry( vNodes, 0 ); |
| if ( Abc_ObjIsCi(pNode) ) |
| { |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) |
| { |
| assert( Abc_ObjIsCi(pNode) ); |
| //printf( " %s=%d", Abc_ObjName(pNode), pModel[(int)pNode->pCopy] ); |
| Vec_IntPush(mismatch, Abc_ObjId(pNode)-1); |
| Vec_IntPush(mismatch, pModel[(int)(size_t)pNode->pCopy]); |
| } |
| } |
| //printf( "\n" ); |
| Vec_PtrFree( vNodes ); |
| } |
| free( pValues1__ ); |
| free( pValues2__ ); |
| } |
| |
| int Abc_NtkMiterSatBm( Abc_Ntk_t * pNtk, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, int fVerbose, ABC_INT64_T * pNumConfs, ABC_INT64_T * pNumInspects) |
| { |
| static sat_solver * pSat = NULL; |
| lbool status; |
| int RetValue = 0; |
| abctime clk; |
| |
| extern int Abc_NodeAddClausesTop( sat_solver * pSat, Abc_Obj_t * pNode, Vec_Int_t * vVars ); |
| extern Vec_Int_t * Abc_NtkGetCiSatVarNums( Abc_Ntk_t * pNtk ); |
| |
| if ( pNumConfs ) |
| *pNumConfs = 0; |
| if ( pNumInspects ) |
| *pNumInspects = 0; |
| |
| assert( Abc_NtkLatchNum(pNtk) == 0 ); |
| |
| // if ( Abc_NtkPoNum(pNtk) > 1 ) |
| // fprintf( stdout, "Warning: The miter has %d outputs. SAT will try to prove all of them.\n", Abc_NtkPoNum(pNtk) ); |
| |
| // load clauses into the sat_solver |
| clk = Abc_Clock(); |
| |
| |
| |
| pSat = (sat_solver *)Abc_NtkMiterSatCreate( pNtk, 0 ); |
| |
| if ( pSat == NULL ) |
| return 1; |
| //printf( "%d \n", pSat->clauses.size ); |
| //sat_solver_delete( pSat ); |
| //return 1; |
| |
| // printf( "Created SAT problem with %d variable and %d clauses. ", sat_solver_nvars(pSat), sat_solver_nclauses(pSat) ); |
| // PRT( "Time", Abc_Clock() - clk ); |
| |
| // simplify the problem |
| clk = Abc_Clock(); |
| status = sat_solver_simplify(pSat); |
| // printf( "Simplified the problem to %d variables and %d clauses. ", sat_solver_nvars(pSat), sat_solver_nclauses(pSat) ); |
| // PRT( "Time", Abc_Clock() - clk ); |
| if ( status == 0 ) |
| { |
| sat_solver_delete( pSat ); |
| // printf( "The problem is UNSATISFIABLE after simplification.\n" ); |
| return 1; |
| } |
| |
| // solve the miter |
| clk = Abc_Clock(); |
| if ( fVerbose ) |
| pSat->verbosity = 1; |
| status = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfLimit, (ABC_INT64_T)nInsLimit, (ABC_INT64_T)0, (ABC_INT64_T)0 ); |
| if ( status == l_Undef ) |
| { |
| // printf( "The problem timed out.\n" ); |
| RetValue = -1; |
| } |
| else if ( status == l_True ) |
| { |
| // printf( "The problem is SATISFIABLE.\n" ); |
| RetValue = 0; |
| } |
| else if ( status == l_False ) |
| { |
| // printf( "The problem is UNSATISFIABLE.\n" ); |
| RetValue = 1; |
| } |
| else |
| assert( 0 ); |
| // PRT( "SAT sat_solver time", Abc_Clock() - clk ); |
| // printf( "The number of conflicts = %d.\n", (int)pSat->sat_solver_stats.conflicts ); |
| |
| // if the problem is SAT, get the counterexample |
| if ( status == l_True ) |
| { |
| // Vec_Int_t * vCiIds = Abc_NtkGetCiIds( pNtk ); |
| Vec_Int_t * vCiIds = Abc_NtkGetCiSatVarNums( pNtk ); |
| pNtk->pModel = Sat_SolverGetModel( pSat, vCiIds->pArray, vCiIds->nSize ); |
| Vec_IntFree( vCiIds ); |
| } |
| // free the sat_solver |
| if ( fVerbose ) |
| Sat_SolverPrintStats( stdout, pSat ); |
| |
| if ( pNumConfs ) |
| *pNumConfs = (int)pSat->stats.conflicts; |
| if ( pNumInspects ) |
| *pNumInspects = (int)pSat->stats.inspects; |
| |
| //sat_solver_store_write( pSat, "trace.cnf" ); |
| sat_solver_store_free( pSat ); |
| sat_solver_delete( pSat ); |
| return RetValue; |
| } |
| |
| int Abc_NtkBmSat( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, Vec_Ptr_t * iMatchPairs, Vec_Ptr_t * oMatchPairs, Vec_Int_t * mismatch, int mode) |
| { |
| extern Abc_Ntk_t * Abc_NtkMulti( Abc_Ntk_t * pNtk, int nThresh, int nFaninMax, int fCnf, int fMulti, int fSimple, int fFactor ); |
| |
| Abc_Ntk_t * pMiter = NULL; |
| Abc_Ntk_t * pCnf; |
| int RetValue = 0; |
| |
| // get the miter of the two networks |
| if( mode == 0 ) |
| { |
| //Abc_NtkDelete( pMiter ); |
| pMiter = Abc_NtkMiterBm( pNtk1, pNtk2, iMatchPairs, oMatchPairs ); |
| } |
| else if( mode == 1 ) // add new outputs |
| { |
| int i; |
| Abc_Obj_t * pObj; |
| Vec_Ptr_t * vPairs; |
| Abc_Obj_t * pNtkMiter; |
| |
| vPairs = Vec_PtrAlloc( 100 ); |
| |
| Abc_NtkForEachCo( pMiter, pObj, i ) |
| Abc_ObjRemoveFanins( pObj ); |
| |
| for(i = 0; i < Vec_PtrSize( oMatchPairs ); i += 2) |
| { |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy((Abc_Obj_t *)Vec_PtrEntry(oMatchPairs, i)) ); |
| Vec_PtrPush( vPairs, Abc_ObjChild0Copy((Abc_Obj_t *)Vec_PtrEntry(oMatchPairs, i+1)) ); |
| } |
| pNtkMiter = Abc_AigMiter( (Abc_Aig_t *)pMiter->pManFunc, vPairs, 0 ); |
| Abc_ObjAddFanin( Abc_NtkPo(pMiter,0), pNtkMiter ); |
| Vec_PtrFree( vPairs); |
| } |
| else if( mode == 2 ) // add some outputs |
| { |
| |
| } |
| else if( mode == 3) // remove all outputs |
| { |
| } |
| |
| if ( pMiter == NULL ) |
| { |
| printf("Miter computation has failed."); |
| return -1; |
| } |
| RetValue = Abc_NtkMiterIsConstant( pMiter ); |
| if ( RetValue == 0) |
| { |
| /*printf("Networks are NOT EQUIVALENT after structural hashing."); */ |
| // report the error |
| if(mismatch != NULL) |
| { |
| pMiter->pModel = Abc_NtkVerifyGetCleanModel( pMiter, 1 ); |
| Abc_NtkVerifyReportError( pNtk1, pNtk2, pMiter->pModel, mismatch ); |
| ABC_FREE( pMiter->pModel ); |
| } |
| Abc_NtkDelete( pMiter ); |
| return RetValue; |
| } |
| if( RetValue == 1 ) |
| { |
| /*printf("Networks are equivalent after structural hashing."); */ |
| Abc_NtkDelete( pMiter ); |
| return RetValue; |
| } |
| |
| // convert the miter into a CNF |
| //if(mode == 0) |
| pCnf = Abc_NtkMulti( pMiter, 0, 100, 1, 0, 0, 0 ); |
| Abc_NtkDelete( pMiter ); |
| if ( pCnf == NULL ) |
| { |
| printf("Renoding for CNF has failed."); |
| return -1; |
| } |
| |
| // solve the CNF using the SAT solver |
| RetValue = Abc_NtkMiterSat( pCnf, (ABC_INT64_T)10000, (ABC_INT64_T)0, 0, NULL, NULL); |
| /*if ( RetValue == -1 ) |
| printf("Networks are undecided (SAT solver timed out)."); |
| else if ( RetValue == 0 ) |
| printf("Networks are NOT EQUIVALENT after SAT."); |
| else |
| printf("Networks are equivalent after SAT."); */ |
| if ( mismatch != NULL && pCnf->pModel ) |
| Abc_NtkVerifyReportError( pNtk1, pNtk2, pCnf->pModel, mismatch ); |
| |
| ABC_FREE( pCnf->pModel ); |
| Abc_NtkDelete( pCnf ); |
| |
| return RetValue; |
| } |
| |
| int checkEquivalence( Abc_Ntk_t * pNtk1, Vec_Int_t* matchedInputs1, Vec_Int_t * matchedOutputs1, |
| Abc_Ntk_t * pNtk2, Vec_Int_t* matchedInputs2, Vec_Int_t * matchedOutputs2) |
| { |
| Vec_Ptr_t * iMatchPairs, * oMatchPairs; |
| int i; |
| int result; |
| |
| iMatchPairs = Vec_PtrAlloc( Abc_NtkPiNum( pNtk1 ) * 2); |
| oMatchPairs = Vec_PtrAlloc( Abc_NtkPoNum( pNtk1 ) * 2); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk1); i++) |
| { |
| Vec_PtrPush(iMatchPairs, Abc_NtkPi(pNtk2, Vec_IntEntry(matchedInputs2, i))); |
| Vec_PtrPush(iMatchPairs, Abc_NtkPi(pNtk1, Vec_IntEntry(matchedInputs1, i))); |
| } |
| |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk1); i++) |
| { |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(pNtk2, Vec_IntEntry(matchedOutputs2, i))); |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(pNtk1, Vec_IntEntry(matchedOutputs1, i))); |
| } |
| |
| result = Abc_NtkBmSat(pNtk1, pNtk2, iMatchPairs, oMatchPairs, NULL, 0); |
| |
| if( result ) |
| printf("*** Circuits are equivalent ***\n"); |
| else |
| printf("*** Circuits are NOT equivalent ***\n"); |
| |
| Vec_PtrFree( iMatchPairs ); |
| Vec_PtrFree( oMatchPairs ); |
| |
| return result; |
| } |
| |
| Abc_Ntk_t * computeCofactor(Abc_Ntk_t * pNtk, Vec_Ptr_t ** nodesInLevel, int * bitVector, Vec_Int_t * currInputs) |
| { |
| Abc_Ntk_t * subNtk; |
| Abc_Obj_t * pObj, * pObjNew; |
| int i, j, numOfLevels; |
| |
| numOfLevels = Abc_AigLevel( pNtk ); // number of levels excludes PI/POs |
| |
| // start a new network |
| subNtk = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 ); |
| subNtk->pName = Extra_UtilStrsav("subNtk"); |
| |
| Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(subNtk); |
| |
| // clean the node copy fields and mark the nodes that need to be copied to the new network |
| Abc_NtkCleanCopy( pNtk ); |
| |
| if(bitVector != NULL) |
| { |
| for(i = 0; i < Abc_NtkPiNum(pNtk); i++) |
| if(bitVector[i]) |
| { |
| pObj = Abc_NtkPi(pNtk, i); |
| pObj->pCopy = (Abc_Obj_t *)(1); |
| } |
| } |
| |
| for(i = 0; i < Vec_IntSize(currInputs); i++) |
| { |
| pObj = Abc_NtkPi(pNtk, Vec_IntEntry(currInputs, i)); |
| pObjNew = Abc_NtkDupObj( subNtk, pObj, 1 ); |
| pObj->pCopy = pObjNew; |
| } |
| |
| |
| // i = 0 are the inputs and the inputs are not added to the 2d array ( nodesInLevel ) |
| for( i = 0; i <= numOfLevels; i++ ) |
| for( j = 0; j < Vec_PtrSize( nodesInLevel[i] ); j++) |
| { |
| pObj = (Abc_Obj_t *)Vec_PtrEntry( nodesInLevel[i], j ); |
| |
| if(Abc_ObjChild0Copy(pObj) == NULL && Abc_ObjChild1Copy(pObj) == NULL) |
| pObj->pCopy = NULL; |
| else if(Abc_ObjChild0Copy(pObj) == NULL && Abc_ObjChild1Copy(pObj) == (void*)(1)) |
| pObj->pCopy = NULL; |
| else if(Abc_ObjChild0Copy(pObj) == NULL && (Abc_ObjChild1Copy(pObj) != (NULL) && Abc_ObjChild1Copy(pObj) != (void*)(1)) ) |
| pObj->pCopy = NULL; |
| else if(Abc_ObjChild0Copy(pObj) == (void*)(1) && Abc_ObjChild1Copy(pObj) == NULL) |
| pObj->pCopy = NULL; |
| else if(Abc_ObjChild0Copy(pObj) == (void*)(1) && Abc_ObjChild1Copy(pObj) == (void*)(1)) |
| pObj->pCopy = (Abc_Obj_t *)(1); |
| else if(Abc_ObjChild0Copy(pObj) == (void*)(1) && (Abc_ObjChild1Copy(pObj) != (NULL) && Abc_ObjChild1Copy(pObj) != (void*)(1)) ) |
| pObj->pCopy = Abc_ObjChild1Copy(pObj); |
| else if( (Abc_ObjChild0Copy(pObj) != (NULL) && Abc_ObjChild0Copy(pObj) != (void*)(1)) && Abc_ObjChild1Copy(pObj) == NULL ) |
| pObj->pCopy = NULL; |
| else if( (Abc_ObjChild0Copy(pObj) != (NULL) && Abc_ObjChild0Copy(pObj) != (void*)(1)) && Abc_ObjChild1Copy(pObj) == (void*)(1) ) |
| pObj->pCopy = Abc_ObjChild0Copy(pObj); |
| else if( (Abc_ObjChild0Copy(pObj) != (NULL) && Abc_ObjChild0Copy(pObj) != (void*)(1)) && |
| (Abc_ObjChild1Copy(pObj) != (NULL) && Abc_ObjChild1Copy(pObj) != (void*)(1)) ) |
| pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)subNtk->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) ); |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk); i++) |
| { |
| pObj = Abc_NtkPo(pNtk, i); |
| pObjNew = Abc_NtkDupObj( subNtk, pObj, 1 ); |
| |
| if( Abc_ObjChild0Copy(pObj) == NULL) |
| { |
| Abc_ObjAddFanin( pObjNew, Abc_AigConst1(subNtk)); |
| pObjNew->fCompl0 = 1; |
| } |
| else if( Abc_ObjChild0Copy(pObj) == (void*)(1) ) |
| { |
| Abc_ObjAddFanin( pObjNew, Abc_AigConst1(subNtk)); |
| pObjNew->fCompl0 = 0; |
| } |
| else |
| Abc_ObjAddFanin( pObjNew, Abc_ObjChild0Copy(pObj) ); |
| } |
| |
| return subNtk; |
| } |
| |
| FILE *matchFile; |
| |
| int matchNonSingletonOutputs(Abc_Ntk_t * pNtk1, Vec_Ptr_t ** nodesInLevel1, Vec_Int_t ** iMatch1, Vec_Int_t ** iDep1, Vec_Int_t * matchedInputs1, int * iGroup1, Vec_Int_t ** oMatch1, int * oGroup1, |
| Abc_Ntk_t * pNtk2, Vec_Ptr_t ** nodesInLevel2, Vec_Int_t ** iMatch2, Vec_Int_t ** iDep2, Vec_Int_t * matchedInputs2, int * iGroup2, Vec_Int_t ** oMatch2, int * oGroup2, |
| Vec_Int_t * matchedOutputs1, Vec_Int_t * matchedOutputs2, Vec_Int_t * oMatchedGroups, Vec_Int_t * iNonSingleton, |
| Abc_Ntk_t * subNtk1, Abc_Ntk_t * subNtk2, Vec_Ptr_t * oMatchPairs, |
| Vec_Int_t * oNonSingleton, int oI, int idx, int ii, int iidx) |
| { |
| static int MATCH_FOUND; |
| int i; |
| int j, temp; |
| Vec_Int_t * mismatch; |
| int * skipList; |
| static int counter = 0; |
| |
| MATCH_FOUND = FALSE; |
| |
| if( oI == Vec_IntSize( oNonSingleton ) ) |
| { |
| if( iNonSingleton != NULL) |
| if( match1by1(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, ii, iidx) ) |
| MATCH_FOUND = TRUE; |
| |
| if( iNonSingleton == NULL) |
| MATCH_FOUND = TRUE; |
| |
| return MATCH_FOUND; |
| } |
| |
| i = Vec_IntEntry(oNonSingleton, oI); |
| |
| mismatch = Vec_IntAlloc(10); |
| |
| skipList = ABC_ALLOC(int, Vec_IntSize(oMatch1[i])); |
| |
| for(j = 0; j < Vec_IntSize(oMatch1[i]); j++) |
| skipList[j] = FALSE; |
| |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(subNtk1, Vec_IntEntry(oMatch1[i], idx)) ); |
| Vec_IntPush(matchedOutputs1, Vec_IntEntry(oMatch1[i], idx)); |
| |
| for(j = 0; j < Vec_IntSize( oMatch2[i] ) && MATCH_FOUND == FALSE; j++) |
| { |
| if( Vec_IntEntry(oMatch2[i], j) == -1 || skipList[j] == TRUE) |
| continue; |
| |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(subNtk2, Vec_IntEntry(oMatch2[i], j))); |
| Vec_IntPush(matchedOutputs2, Vec_IntEntry(oMatch2[i], j)); |
| |
| counter++; |
| if( Abc_NtkBmSat( subNtk1, subNtk2, NULL, oMatchPairs, mismatch, 0) ) |
| { |
| /*fprintf(matchFile, "%s matched to %s\n", Abc_ObjName(Abc_NtkPo(pNtk1, Vec_IntEntry(oMatch1[i], idx))), |
| Abc_ObjName(Abc_NtkPo(pNtk2, Vec_IntEntry(oMatch2[i], j)))); */ |
| |
| temp = Vec_IntEntry(oMatch2[i], j); |
| Vec_IntWriteEntry(oMatch2[i], j, -1); |
| |
| if(idx != Vec_IntSize( oMatch1[i] ) - 1) |
| // call the same function with idx+1 |
| matchNonSingletonOutputs(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, |
| subNtk1, subNtk2, oMatchPairs, |
| oNonSingleton, oI, idx+1, ii, iidx); |
| else |
| // call the same function with idx = 0 and oI++ |
| matchNonSingletonOutputs(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, |
| subNtk1, subNtk2, oMatchPairs, |
| oNonSingleton, oI+1, 0, ii, iidx); |
| |
| Vec_IntWriteEntry(oMatch2[i], j, temp); |
| } |
| else |
| { |
| int * output1, * output2; |
| int k; |
| Abc_Obj_t * pObj; |
| int * pModel; |
| char * vPiValues; |
| |
| |
| vPiValues = ABC_ALLOC( char, Abc_NtkPiNum(subNtk1) + 1); |
| vPiValues[Abc_NtkPiNum(subNtk1)] = '\0'; |
| |
| for(k = 0; k < Abc_NtkPiNum(subNtk1); k++) |
| vPiValues[k] = '0'; |
| |
| for(k = 0; k < Vec_IntSize(mismatch); k += 2) |
| vPiValues[Vec_IntEntry(mismatch, k)] = Vec_IntEntry(mismatch, k+1); |
| |
| pModel = ABC_ALLOC( int, Abc_NtkCiNum(subNtk1) ); |
| |
| Abc_NtkForEachPi( subNtk1, pObj, k ) |
| pModel[k] = vPiValues[k] - '0'; |
| Abc_NtkForEachLatch( subNtk1, pObj, k ) |
| pModel[Abc_NtkPiNum(subNtk1)+k] = pObj->iData - 1; |
| |
| output1 = Abc_NtkVerifySimulatePattern( subNtk1, pModel ); |
| |
| Abc_NtkForEachLatch( subNtk2, pObj, k ) |
| pModel[Abc_NtkPiNum(subNtk2)+k] = pObj->iData - 1; |
| |
| output2 = Abc_NtkVerifySimulatePattern( subNtk2, pModel ); |
| |
| |
| for(k = 0; k < Vec_IntSize( oMatch1[i] ); k++) |
| if(output1[Vec_IntEntry(oMatch1[i], idx)] != output2[Vec_IntEntry(oMatch2[i], k)]) |
| { |
| skipList[k] = TRUE; |
| /*printf("Output is SKIPPED");*/ |
| } |
| |
| ABC_FREE( vPiValues ); |
| ABC_FREE( pModel ); |
| ABC_FREE( output1 ); |
| ABC_FREE( output2 ); |
| } |
| |
| if(MATCH_FOUND == FALSE ) |
| { |
| Vec_PtrPop(oMatchPairs); |
| Vec_IntPop(matchedOutputs2); |
| } |
| } |
| |
| if(MATCH_FOUND == FALSE ) |
| { |
| Vec_PtrPop(oMatchPairs); |
| Vec_IntPop(matchedOutputs1); |
| } |
| |
| if(MATCH_FOUND && counter != 0) |
| { |
| /*printf("Number of OUTPUT SAT instances = %d", counter);*/ |
| counter = 0; |
| } |
| |
| ABC_FREE( mismatch ); |
| ABC_FREE( skipList ); |
| |
| return MATCH_FOUND; |
| } |
| |
| int match1by1(Abc_Ntk_t * pNtk1, Vec_Ptr_t ** nodesInLevel1, Vec_Int_t ** iMatch1, Vec_Int_t ** iDep1, Vec_Int_t * matchedInputs1, int * iGroup1, Vec_Int_t ** oMatch1, int * oGroup1, |
| Abc_Ntk_t * pNtk2, Vec_Ptr_t ** nodesInLevel2, Vec_Int_t ** iMatch2, Vec_Int_t ** iDep2, Vec_Int_t * matchedInputs2, int * iGroup2, Vec_Int_t ** oMatch2, int * oGroup2, |
| Vec_Int_t * matchedOutputs1, Vec_Int_t * matchedOutputs2, Vec_Int_t * oMatchedGroups, Vec_Int_t * iNonSingleton, int ii, int idx) |
| { |
| static int MATCH_FOUND = FALSE; |
| Abc_Ntk_t * subNtk1, * subNtk2; |
| Vec_Int_t * oNonSingleton; |
| Vec_Ptr_t * oMatchPairs; |
| int * skipList; |
| int j, m; |
| int i; |
| static int counter = 0; |
| |
| MATCH_FOUND = FALSE; |
| |
| if( ii == Vec_IntSize(iNonSingleton) ) |
| { |
| MATCH_FOUND = TRUE; |
| return TRUE; |
| } |
| |
| i = Vec_IntEntry(iNonSingleton, ii); |
| |
| if( idx == Vec_IntSize(iMatch1[i]) ) |
| { |
| // call again with the next element in iNonSingleton |
| return match1by1(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, ii+1, 0); |
| |
| } |
| |
| oNonSingleton = Vec_IntAlloc(10); |
| oMatchPairs = Vec_PtrAlloc(100); |
| skipList = ABC_ALLOC(int, Vec_IntSize(iMatch1[i])); |
| |
| for(j = 0; j < Vec_IntSize(iMatch1[i]); j++) |
| skipList[j] = FALSE; |
| |
| Vec_IntPush(matchedInputs1, Vec_IntEntry(iMatch1[i], idx)); |
| idx++; |
| |
| if(idx == 1) |
| { |
| for(j = 0; j < Vec_IntSize(iDep1[Vec_IntEntryLast(iMatch1[i])]); j++) |
| { |
| if( Vec_IntSize(oMatch1[oGroup1[Vec_IntEntry(iDep1[Vec_IntEntryLast(iMatch1[i])], j)]]) == 1 ) |
| continue; |
| if( Vec_IntFind( oMatchedGroups, oGroup1[Vec_IntEntry(iDep1[Vec_IntEntryLast(iMatch1[i])], j)]) != -1) |
| continue; |
| |
| Vec_IntPushUnique(oNonSingleton, oGroup1[Vec_IntEntry(iDep1[Vec_IntEntryLast(iMatch1[i])], j)]); |
| Vec_IntPushUnique(oMatchedGroups, oGroup1[Vec_IntEntry(iDep1[Vec_IntEntryLast(iMatch1[i])], j)]); |
| } |
| } |
| |
| subNtk1 = computeCofactor(pNtk1, nodesInLevel1, NULL, matchedInputs1); |
| |
| for(j = idx-1; j < Vec_IntSize(iMatch2[i]) && MATCH_FOUND == FALSE; j++) |
| { |
| int tempJ; |
| Vec_Int_t * mismatch; |
| |
| if( skipList[j] ) |
| continue; |
| |
| mismatch = Vec_IntAlloc(10); |
| |
| Vec_IntPush(matchedInputs2, Vec_IntEntry(iMatch2[i], j)); |
| |
| subNtk2 = computeCofactor(pNtk2, nodesInLevel2, NULL, matchedInputs2); |
| |
| for(m = 0; m < Vec_IntSize(matchedOutputs1); m++) |
| { |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(subNtk1, Vec_IntEntry(matchedOutputs1, m))); |
| Vec_PtrPush(oMatchPairs, Abc_NtkPo(subNtk2, Vec_IntEntry(matchedOutputs2, m))); |
| } |
| |
| counter++; |
| |
| if( Abc_NtkBmSat( subNtk2, subNtk1, NULL, oMatchPairs, mismatch, 0) ) |
| { |
| if(idx-1 != j) |
| { |
| tempJ = Vec_IntEntry(iMatch2[i], idx-1); |
| Vec_IntWriteEntry(iMatch2[i], idx-1, Vec_IntEntry(iMatch2[i], j)); |
| Vec_IntWriteEntry(iMatch2[i], j, tempJ); |
| } |
| |
| /*fprintf(matchFile, "%s matched to %s\n", Abc_ObjName(Abc_NtkPi(pNtk1, Vec_IntEntry(iMatch1[i], idx-1))), |
| Abc_ObjName(Abc_NtkPi(pNtk2, Vec_IntEntry(iMatch2[i], j))));*/ |
| |
| // we look for a match for outputs in oNonSingleton |
| matchNonSingletonOutputs(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, |
| subNtk1, subNtk2, oMatchPairs, oNonSingleton, 0, 0, ii, idx); |
| |
| |
| if(idx-1 != j) |
| { |
| tempJ = Vec_IntEntry(iMatch2[i], idx-1); |
| Vec_IntWriteEntry(iMatch2[i], idx-1, Vec_IntEntry(iMatch2[i], j)); |
| Vec_IntWriteEntry(iMatch2[i], j, tempJ); |
| } |
| } |
| else |
| { |
| Abc_Ntk_t * FpNtk1, * FpNtk2; |
| int * bitVector1, * bitVector2; |
| Vec_Int_t * currInputs1, * currInputs2; |
| Vec_Ptr_t * vSupp; |
| Abc_Obj_t * pObj; |
| int suppNum1 = 0; |
| int * suppNum2; |
| |
| bitVector1 = ABC_ALLOC( int, Abc_NtkPiNum(pNtk1) ); |
| bitVector2 = ABC_ALLOC( int, Abc_NtkPiNum(pNtk2) ); |
| |
| currInputs1 = Vec_IntAlloc(10); |
| currInputs2 = Vec_IntAlloc(10); |
| |
| suppNum2 = ABC_ALLOC(int, Vec_IntSize(iMatch2[i])-idx+1); |
| |
| for(m = 0; m < Abc_NtkPiNum(pNtk1); m++) |
| { |
| bitVector1[m] = 0; |
| bitVector2[m] = 0; |
| } |
| |
| for(m = 0; m < Vec_IntSize(iMatch2[i])-idx+1; m++) |
| suppNum2[m]= 0; |
| |
| // First of all set the value of the inputs that are already matched and are in mismatch |
| for(m = 0; m < Vec_IntSize(mismatch); m += 2) |
| { |
| int n = Vec_IntEntry(mismatch, m); |
| |
| bitVector1[Vec_IntEntry(matchedInputs1, n)] = Vec_IntEntry(mismatch, m+1); |
| bitVector2[Vec_IntEntry(matchedInputs2, n)] = Vec_IntEntry(mismatch, m+1); |
| |
| } |
| |
| for(m = idx-1; m < Vec_IntSize(iMatch1[i]); m++) |
| { |
| Vec_IntPush(currInputs1, Vec_IntEntry(iMatch1[i], m)); |
| Vec_IntPush(currInputs2, Vec_IntEntry(iMatch2[i], m)); |
| } |
| |
| // Then add all the inputs that are not yet matched to the currInputs |
| for(m = 0; m < Abc_NtkPiNum(pNtk1); m++) |
| { |
| if(Vec_IntFind( matchedInputs1, m ) == -1) |
| Vec_IntPushUnique(currInputs1, m); |
| |
| if(Vec_IntFind( matchedInputs2, m ) == -1) |
| Vec_IntPushUnique(currInputs2, m); |
| } |
| |
| FpNtk1 = computeCofactor(pNtk1, nodesInLevel1, bitVector1, currInputs1); |
| FpNtk2 = computeCofactor(pNtk2, nodesInLevel2, bitVector2, currInputs2); |
| |
| Abc_NtkForEachPo( FpNtk1, pObj, m ) |
| { |
| int n; |
| vSupp = Abc_NtkNodeSupport( FpNtk1, &pObj, 1 ); |
| |
| for(n = 0; n < vSupp->nSize; n++) |
| if( Abc_ObjId((Abc_Obj_t *)vSupp->pArray[n]) == 1 ) |
| suppNum1 += Vec_IntFind( matchedOutputs1, m) + 1; |
| |
| Vec_PtrFree( vSupp ); |
| } |
| |
| Abc_NtkForEachPo( FpNtk2, pObj, m ) |
| { |
| int n; |
| vSupp = Abc_NtkNodeSupport( FpNtk2, &pObj, 1 ); |
| |
| for(n = 0; n < vSupp->nSize; n++) |
| if( (int)Abc_ObjId((Abc_Obj_t *)vSupp->pArray[n])-1 < (Vec_IntSize(iMatch2[i]))-idx+1 && |
| (int)Abc_ObjId((Abc_Obj_t *)vSupp->pArray[n])-1 >= 0) |
| suppNum2[Abc_ObjId((Abc_Obj_t *)vSupp->pArray[n])-1] += Vec_IntFind( matchedOutputs2, m) + 1; |
| |
| Vec_PtrFree( vSupp ); |
| } |
| |
| /*if(suppNum1 != 0) |
| printf("Ntk1 is trigged"); |
| |
| if(suppNum2[0] != 0) |
| printf("Ntk2 is trigged");*/ |
| |
| for(m = 0; m < Vec_IntSize(iMatch2[i])-idx+1; m++) |
| if(suppNum2[m] != suppNum1) |
| { |
| skipList[m+idx-1] = TRUE; |
| /*printf("input is skipped");*/ |
| } |
| |
| Abc_NtkDelete( FpNtk1 ); |
| Abc_NtkDelete( FpNtk2 ); |
| ABC_FREE( bitVector1 ); |
| ABC_FREE( bitVector2 ); |
| Vec_IntFree( currInputs1 ); |
| Vec_IntFree( currInputs2 ); |
| ABC_FREE( suppNum2 ); |
| } |
| |
| Vec_PtrClear(oMatchPairs); |
| Abc_NtkDelete( subNtk2 ); |
| Vec_IntFree(mismatch); |
| |
| //Vec_IntWriteEntry(iMatch2[i], j, tempJ); |
| |
| if( MATCH_FOUND == FALSE ) |
| Vec_IntPop(matchedInputs2); |
| } |
| |
| if( MATCH_FOUND == FALSE ) |
| { |
| Vec_IntPop(matchedInputs1); |
| |
| if(idx == 1) |
| { |
| for(m = 0; m < Vec_IntSize(oNonSingleton); m++) |
| Vec_IntPop( oMatchedGroups ); |
| } |
| } |
| |
| Vec_IntFree( oNonSingleton ); |
| Vec_PtrFree( oMatchPairs ); |
| ABC_FREE( skipList ); |
| Abc_NtkDelete( subNtk1 ); |
| |
| if(MATCH_FOUND && counter != 0) |
| { |
| /*printf("Number of INPUT SAT instances = %d\n", counter);*/ |
| |
| counter = 0; |
| } |
| |
| return MATCH_FOUND; |
| } |
| |
| float refineBySAT(Abc_Ntk_t * pNtk1, Vec_Int_t ** iMatch1, int * iGroup1, Vec_Int_t ** iDep1, int* iLastItem1, Vec_Int_t ** oMatch1, int * oGroup1, Vec_Int_t ** oDep1, int* oLastItem1, int * observability1, |
| Abc_Ntk_t * pNtk2, Vec_Int_t ** iMatch2, int * iGroup2, Vec_Int_t ** iDep2, int* iLastItem2, Vec_Int_t ** oMatch2, int * oGroup2, Vec_Int_t ** oDep2, int* oLastItem2, int * observability2) |
| { |
| int i, j; |
| Abc_Obj_t * pObj; |
| Vec_Int_t * iNonSingleton; |
| Vec_Int_t * matchedInputs1, * matchedInputs2; |
| Vec_Int_t * matchedOutputs1, * matchedOutputs2; |
| Vec_Ptr_t ** nodesInLevel1, ** nodesInLevel2; |
| Vec_Int_t * oMatchedGroups; |
| FILE *result; |
| int matchFound; |
| abctime clk = Abc_Clock(); |
| float satTime = 0.0; |
| |
| /*matchFile = fopen("satmatch.txt", "w");*/ |
| |
| iNonSingleton = Vec_IntAlloc(10); |
| |
| matchedInputs1 = Vec_IntAlloc( Abc_NtkPiNum(pNtk1) ); |
| matchedInputs2 = Vec_IntAlloc( Abc_NtkPiNum(pNtk2) ); |
| |
| matchedOutputs1 = Vec_IntAlloc( Abc_NtkPoNum(pNtk1) ); |
| matchedOutputs2 = Vec_IntAlloc( Abc_NtkPoNum(pNtk2) ); |
| |
| nodesInLevel1 = ABC_ALLOC( Vec_Ptr_t *, Abc_AigLevel( pNtk1 ) + 1); // why numOfLevels+1? because the inputs are in level 0 |
| for(i = 0; i <= Abc_AigLevel( pNtk1 ); i++) |
| nodesInLevel1[i] = Vec_PtrAlloc( 20 ); |
| |
| // bucket sort the objects based on their levels |
| Abc_AigForEachAnd( pNtk1, pObj, i ) |
| Vec_PtrPush(nodesInLevel1[Abc_ObjLevel(pObj)], pObj); |
| |
| nodesInLevel2 = ABC_ALLOC( Vec_Ptr_t *, Abc_AigLevel( pNtk2 ) + 1); // why numOfLevels+1? because the inputs are in level 0 |
| for(i = 0; i <= Abc_AigLevel( pNtk2 ); i++) |
| nodesInLevel2[i] = Vec_PtrAlloc( 20 ); |
| |
| // bucket sort the objects based on their levels |
| Abc_AigForEachAnd( pNtk2, pObj, i ) |
| Vec_PtrPush(nodesInLevel2[Abc_ObjLevel(pObj)], pObj); |
| |
| oMatchedGroups = Vec_IntAlloc( 10 ); |
| |
| for(i = 0; i < *iLastItem1; i++) |
| { |
| if(Vec_IntSize(iMatch1[i]) == 1) |
| { |
| Vec_IntPush(matchedInputs1, Vec_IntEntryLast(iMatch1[i])); |
| Vec_IntPush(matchedInputs2, Vec_IntEntryLast(iMatch2[i])); |
| } |
| else |
| Vec_IntPush(iNonSingleton, i); |
| } |
| |
| for(i = 0; i < *oLastItem1; i++) |
| { |
| if(Vec_IntSize(oMatch1[i]) == 1) |
| { |
| Vec_IntPush(matchedOutputs1, Vec_IntEntryLast(oMatch1[i])); |
| Vec_IntPush(matchedOutputs2, Vec_IntEntryLast(oMatch2[i])); |
| } |
| } |
| |
| for(i = 0; i < Vec_IntSize(iNonSingleton) - 1; i++) |
| { |
| for(j = i + 1; j < Vec_IntSize(iNonSingleton); j++) |
| if( observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, j)], 0)] > |
| observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, i)], 0)] ) |
| { |
| int temp = Vec_IntEntry(iNonSingleton, i); |
| Vec_IntWriteEntry( iNonSingleton, i, Vec_IntEntry(iNonSingleton, j) ); |
| Vec_IntWriteEntry( iNonSingleton, j, temp ); |
| } |
| else if( observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, j)], 0)] == |
| observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, i)], 0)] ) |
| { |
| if( Vec_IntSize(iMatch2[Vec_IntEntry(iNonSingleton, j)]) < Vec_IntSize(iMatch2[Vec_IntEntry(iNonSingleton, i)]) ) |
| { |
| int temp = Vec_IntEntry(iNonSingleton, i); |
| Vec_IntWriteEntry( iNonSingleton, i, Vec_IntEntry(iNonSingleton, j) ); |
| Vec_IntWriteEntry( iNonSingleton, j, temp ); |
| } |
| } |
| } |
| |
| /*for(i = 0; i < Vec_IntSize(iNonSingleton) - 1; i++) |
| { |
| for(j = i + 1; j < Vec_IntSize(iNonSingleton); j++) |
| if( Vec_IntSize(oDep2[oGroup2[Vec_IntEntryLast(iMatch2[Vec_IntEntry(iNonSingleton, j)])]]) > |
| Vec_IntSize(oDep2[oGroup2[Vec_IntEntryLast(iMatch2[Vec_IntEntry(iNonSingleton, i)])]]) ) |
| { |
| int temp = Vec_IntEntry(iNonSingleton, i); |
| Vec_IntWriteEntry( iNonSingleton, i, Vec_IntEntry(iNonSingleton, j) ); |
| Vec_IntWriteEntry( iNonSingleton, j, temp ); |
| } |
| else if( Vec_IntSize(oDep2[oGroup2[Vec_IntEntryLast(iMatch2[Vec_IntEntry(iNonSingleton, j)])]]) == |
| Vec_IntSize(oDep2[oGroup2[Vec_IntEntryLast(iMatch2[Vec_IntEntry(iNonSingleton, i)])]]) ) |
| { |
| if( observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, j)], 0)] > |
| observability2[Vec_IntEntry(iMatch2[Vec_IntEntry(iNonSingleton, i)], 0)] ) |
| { |
| int temp = Vec_IntEntry(iNonSingleton, i); |
| Vec_IntWriteEntry( iNonSingleton, i, Vec_IntEntry(iNonSingleton, j) ); |
| Vec_IntWriteEntry( iNonSingleton, j, temp ); |
| } |
| } |
| }*/ |
| |
| matchFound = match1by1(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup2, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, iNonSingleton, 0, 0); |
| |
| if( matchFound && Vec_IntSize(matchedOutputs1) != Abc_NtkPoNum(pNtk1) ) |
| { |
| Vec_Int_t * oNonSingleton; |
| Vec_Ptr_t * oMatchPairs; |
| Abc_Ntk_t * subNtk1, * subNtk2; |
| |
| oNonSingleton = Vec_IntAlloc( 10 ); |
| |
| oMatchPairs = Vec_PtrAlloc(Abc_NtkPoNum(pNtk1) * 2); |
| |
| for(i = 0; i < *oLastItem1; i++) |
| if( Vec_IntSize(oMatch1[i]) > 1 && Vec_IntFind( oMatchedGroups, i) == -1 ) |
| Vec_IntPush(oNonSingleton, i); |
| |
| subNtk1 = computeCofactor(pNtk1, nodesInLevel1, NULL, matchedInputs1); |
| subNtk2 = computeCofactor(pNtk2, nodesInLevel2, NULL, matchedInputs2); |
| |
| matchFound = matchNonSingletonOutputs(pNtk1, nodesInLevel1, iMatch1, iDep1, matchedInputs1, iGroup1, oMatch1, oGroup1, |
| pNtk2, nodesInLevel2, iMatch2, iDep2, matchedInputs2, iGroup1, oMatch2, oGroup2, |
| matchedOutputs1, matchedOutputs2, oMatchedGroups, NULL, |
| subNtk1, subNtk2, oMatchPairs, oNonSingleton, 0, 0, 0, 0); |
| |
| Vec_IntFree( oNonSingleton ); |
| Vec_PtrFree( oMatchPairs ); |
| |
| Abc_NtkDelete(subNtk1); |
| Abc_NtkDelete(subNtk2); |
| } |
| |
| satTime = (float)(Abc_Clock() - clk)/(float)(CLOCKS_PER_SEC); |
| |
| if( matchFound ) |
| { |
| checkEquivalence( pNtk1, matchedInputs1, matchedOutputs1, pNtk2, matchedInputs2, matchedOutputs2); |
| |
| result = fopen("IOmatch.txt", "w"); |
| |
| fprintf(result, "I/O = %d / %d \n\n", Abc_NtkPiNum(pNtk1), Abc_NtkPoNum(pNtk1)); |
| |
| for(i = 0; i < Vec_IntSize(matchedInputs1) ; i++) |
| fprintf(result, "{%s}\t{%s}\n", Abc_ObjName(Abc_NtkPi(pNtk1, Vec_IntEntry(matchedInputs1, i))), Abc_ObjName(Abc_NtkPi(pNtk2, Vec_IntEntry(matchedInputs2, i))) ); |
| |
| fprintf(result, "\n-----------------------------------------\n"); |
| |
| for(i = 0; i < Vec_IntSize(matchedOutputs1) ; i++) |
| fprintf(result, "{%s}\t{%s}\n", Abc_ObjName(Abc_NtkPo(pNtk1, Vec_IntEntry(matchedOutputs1, i))), Abc_ObjName(Abc_NtkPo(pNtk2, Vec_IntEntry(matchedOutputs2, i))) ); |
| |
| fclose( result ); |
| } |
| |
| Vec_IntFree( matchedInputs1 ); |
| Vec_IntFree( matchedInputs2 ); |
| Vec_IntFree( matchedOutputs1 ); |
| Vec_IntFree( matchedOutputs2 ); |
| Vec_IntFree( iNonSingleton ); |
| Vec_IntFree( oMatchedGroups ); |
| |
| for(i = 0; i <= Abc_AigLevel( pNtk1 ); i++) |
| Vec_PtrFree( nodesInLevel1[i] ); |
| for(i = 0; i <= Abc_AigLevel( pNtk2 ); i++) |
| Vec_PtrFree( nodesInLevel2[i] ); |
| |
| |
| ABC_FREE( nodesInLevel1 ); |
| ABC_FREE( nodesInLevel2 ); |
| /*fclose(matchFile);*/ |
| |
| return satTime; |
| } |
| |
| int checkListConsistency(Vec_Int_t ** iMatch1, Vec_Int_t ** oMatch1, Vec_Int_t ** iMatch2, Vec_Int_t ** oMatch2, int iLastItem1, int oLastItem1, int iLastItem2, int oLastItem2) |
| { |
| //int i; |
| |
| if(iLastItem1 != iLastItem2 || oLastItem1 != oLastItem2) |
| return FALSE; |
| |
| /*for(i = 0; i < iLastItem1; i++) { |
| if(Vec_IntSize(iMatch1[i]) != Vec_IntSize(iMatch2[i])) |
| return FALSE; |
| } |
| |
| for(i = 0; i < oLastItem1; i++) { |
| if(Vec_IntSize(oMatch1[i]) != Vec_IntSize(oMatch2[i])) |
| return FALSE; |
| }*/ |
| |
| return TRUE; |
| } |
| |
| |
| void bmGateWay( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int p_equivalence ) |
| { |
| Vec_Int_t ** iDep1, ** oDep1; |
| Vec_Int_t ** iDep2, ** oDep2; |
| Vec_Int_t ** iMatch1, ** oMatch1; |
| Vec_Int_t ** iMatch2, ** oMatch2; |
| int * iGroup1, * oGroup1; |
| int * iGroup2, * oGroup2; |
| int iLastItem1, oLastItem1; |
| int iLastItem2, oLastItem2; |
| int i, j; |
| |
| char * vPiValues1, * vPiValues2; |
| int * observability1, * observability2; |
| abctime clk = Abc_Clock(); |
| float initTime; |
| float simulTime; |
| float satTime; |
| Vec_Ptr_t ** topOrder1 = NULL, ** topOrder2 = NULL; |
| |
| extern void getDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep); |
| extern void initMatchList(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** oDep, Vec_Int_t** iMatch, int* iLastItem, Vec_Int_t** oMatch, int* oLastItem, int* iGroup, int* oGroup, int p_equivalence); |
| extern void iSortDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, int* oGroup); |
| extern void oSortDependencies(Abc_Ntk_t *pNtk, Vec_Int_t** oDep, int* iGroup); |
| extern int iSplitByDep(Abc_Ntk_t *pNtk, Vec_Int_t** iDep, Vec_Int_t** iMatch, int* iGroup, int* iLastItem, int* oGroup); |
| extern int oSplitByDep(Abc_Ntk_t *pNtk, Vec_Int_t** oDep, Vec_Int_t** oMatch, int* oGroup, int* oLastItem, int* iGroup); |
| extern Vec_Ptr_t ** findTopologicalOrder(Abc_Ntk_t * pNtk); |
| extern int refineIOBySimulation(Abc_Ntk_t *pNtk, Vec_Int_t** iMatch, int* iLastItem, int * iGroup, Vec_Int_t** iDep, Vec_Int_t** oMatch, int* oLastItem, int * oGroup, Vec_Int_t** oDep, char * vPiValues, int * observability, Vec_Ptr_t ** topOrder); |
| extern float refineBySAT(Abc_Ntk_t * pNtk1, Vec_Int_t ** iMatch1, int * iGroup1, Vec_Int_t ** iDep1, int* iLastItem1, Vec_Int_t ** oMatch1, int * oGroup1, Vec_Int_t ** oDep1, int* oLastItem1, int * observability1, |
| Abc_Ntk_t * pNtk2, Vec_Int_t ** iMatch2, int * iGroup2, Vec_Int_t ** iDep2, int* iLastItem2, Vec_Int_t ** oMatch2, int * oGroup2, Vec_Int_t ** oDep2, int* oLastItem2, int * observability2); |
| int checkListConsistency(Vec_Int_t ** iMatch1, Vec_Int_t ** oMatch1, Vec_Int_t ** iMatch2, Vec_Int_t ** oMatch2, int iLastItem1, int oLastItem1, int iLastItem2, int oLastItem2); |
| |
| iDep1 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPiNum(pNtk1) ); |
| oDep1 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPoNum(pNtk1) ); |
| |
| iDep2 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPiNum(pNtk2) ); |
| oDep2 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPoNum(pNtk2) ); |
| |
| iMatch1 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPiNum(pNtk1) ); |
| oMatch1 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPoNum(pNtk1) ); |
| |
| iMatch2 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPiNum(pNtk2) ); |
| oMatch2 = ABC_ALLOC( Vec_Int_t*, (unsigned)Abc_NtkPoNum(pNtk2) ); |
| |
| iGroup1 = ABC_ALLOC( int, Abc_NtkPiNum(pNtk1) ); |
| oGroup1 = ABC_ALLOC( int, Abc_NtkPoNum(pNtk1) ); |
| |
| iGroup2 = ABC_ALLOC( int, Abc_NtkPiNum(pNtk2) ); |
| oGroup2 = ABC_ALLOC( int, Abc_NtkPoNum(pNtk2) ); |
| |
| vPiValues1 = ABC_ALLOC( char, Abc_NtkPiNum(pNtk1) + 1); |
| vPiValues1[Abc_NtkPiNum(pNtk1)] = '\0'; |
| |
| vPiValues2 = ABC_ALLOC( char, Abc_NtkPiNum(pNtk2) + 1); |
| vPiValues2[Abc_NtkPiNum(pNtk2)] = '\0'; |
| |
| observability1 = ABC_ALLOC(int, (unsigned)Abc_NtkPiNum(pNtk1)); |
| observability2 = ABC_ALLOC(int, (unsigned)Abc_NtkPiNum(pNtk2)); |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk1); i++) |
| { |
| iDep1[i] = Vec_IntAlloc( 1 ); |
| iMatch1[i] = Vec_IntAlloc( 1 ); |
| |
| iDep2[i] = Vec_IntAlloc( 1 ); |
| iMatch2[i] = Vec_IntAlloc( 1 ); |
| |
| vPiValues1[i] = '0'; |
| vPiValues2[i] = '0'; |
| |
| observability1[i] = 0; |
| observability2[i] = 0; |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk1); i++) |
| { |
| oDep1[i] = Vec_IntAlloc( 1 ); |
| oMatch1[i] = Vec_IntAlloc( 1 ); |
| |
| oDep2[i] = Vec_IntAlloc( 1 ); |
| oMatch2[i] = Vec_IntAlloc( 1 ); |
| } |
| |
| /************* Strashing ************/ |
| pNtk1 = Abc_NtkStrash( pNtk1, 0, 0, 0 ); |
| pNtk2 = Abc_NtkStrash( pNtk2, 0, 0, 0 ); |
| printf("Network strashing is done!\n"); |
| /************************************/ |
| |
| /******* Getting Dependencies *******/ |
| getDependencies(pNtk1, iDep1, oDep1); |
| getDependencies(pNtk2, iDep2, oDep2); |
| printf("Getting dependencies is done!\n"); |
| /************************************/ |
| |
| /***** Intializing match lists ******/ |
| initMatchList(pNtk1, iDep1, oDep1, iMatch1, &iLastItem1, oMatch1, &oLastItem1, iGroup1, oGroup1, p_equivalence); |
| initMatchList(pNtk2, iDep2, oDep2, iMatch2, &iLastItem2, oMatch2, &oLastItem2, iGroup2, oGroup2, p_equivalence); |
| printf("Initializing match lists is done!\n"); |
| /************************************/ |
| |
| if( !checkListConsistency(iMatch1, oMatch1, iMatch2, oMatch2, iLastItem1, oLastItem1, iLastItem2, oLastItem2) ) |
| { |
| fprintf( stdout, "I/O dependencies of two circuits are different.\n"); |
| goto freeAndExit; |
| } |
| |
| printf("Refining IOs by dependencies ..."); |
| // split match lists further by checking dependencies |
| do |
| { |
| int iNumOfItemsAdded = 1, oNumOfItemsAdded = 1; |
| |
| do |
| { |
| if( oNumOfItemsAdded ) |
| { |
| iSortDependencies(pNtk1, iDep1, oGroup1); |
| iSortDependencies(pNtk2, iDep2, oGroup2); |
| } |
| |
| if( iNumOfItemsAdded ) |
| { |
| oSortDependencies(pNtk1, oDep1, iGroup1); |
| oSortDependencies(pNtk2, oDep2, iGroup2); |
| } |
| |
| if( iLastItem1 < Abc_NtkPiNum(pNtk1) ) |
| { |
| iSplitByDep(pNtk1, iDep1, iMatch1, iGroup1, &iLastItem1, oGroup1); |
| if( oLastItem1 < Abc_NtkPoNum(pNtk1) ) |
| oSplitByDep(pNtk1, oDep1, oMatch1, oGroup1, &oLastItem1, iGroup1); |
| } |
| |
| if( iLastItem2 < Abc_NtkPiNum(pNtk2) ) |
| iNumOfItemsAdded = iSplitByDep(pNtk2, iDep2, iMatch2, iGroup2, &iLastItem2, oGroup2); |
| else |
| iNumOfItemsAdded = 0; |
| |
| if( oLastItem2 < Abc_NtkPoNum(pNtk2) ) |
| oNumOfItemsAdded = oSplitByDep(pNtk2, oDep2, oMatch2, oGroup2, &oLastItem2, iGroup2); |
| else |
| oNumOfItemsAdded = 0; |
| |
| if(!checkListConsistency(iMatch1, oMatch1, iMatch2, oMatch2, iLastItem1, oLastItem1, iLastItem2, oLastItem2)) |
| { |
| fprintf( stdout, "I/O dependencies of two circuits are different.\n"); |
| goto freeAndExit; |
| } |
| }while(iNumOfItemsAdded != 0 || oNumOfItemsAdded != 0); |
| |
| }while(0); |
| |
| printf(" done!\n"); |
| |
| initTime = ((float)(Abc_Clock() - clk)/(float)(CLOCKS_PER_SEC)); |
| clk = Abc_Clock(); |
| |
| topOrder1 = findTopologicalOrder(pNtk1); |
| topOrder2 = findTopologicalOrder(pNtk2); |
| |
| printf("Refining IOs by simulation ..."); |
| |
| do |
| { |
| int counter = 0; |
| int ioSuccess1, ioSuccess2; |
| |
| do |
| { |
| for(i = 0; i < iLastItem1; i++) |
| { |
| int temp = (int)(SIM_RANDOM_UNSIGNED % 2); |
| |
| if(Vec_IntSize(iMatch1[i]) != Vec_IntSize(iMatch2[i])) |
| { |
| fprintf( stdout, "Input refinement by simulation finds two circuits different.\n"); |
| goto freeAndExit; |
| } |
| |
| for(j = 0; j < Vec_IntSize(iMatch1[i]); j++) |
| { |
| vPiValues1[Vec_IntEntry(iMatch1[i], j)] = temp + '0'; |
| vPiValues2[Vec_IntEntry(iMatch2[i], j)] = temp + '0'; |
| } |
| } |
| |
| ioSuccess1 = refineIOBySimulation(pNtk1, iMatch1, &iLastItem1, iGroup1, iDep1, oMatch1, &oLastItem1, oGroup1, oDep1, vPiValues1, observability1, topOrder1); |
| ioSuccess2 = refineIOBySimulation(pNtk2, iMatch2, &iLastItem2, iGroup2, iDep2, oMatch2, &oLastItem2, oGroup2, oDep2, vPiValues2, observability2, topOrder2); |
| |
| if(ioSuccess1 && ioSuccess2) |
| counter = 0; |
| else |
| counter++; |
| |
| if(ioSuccess1 != ioSuccess2 || |
| !checkListConsistency(iMatch1, oMatch1, iMatch2, oMatch2, iLastItem1, oLastItem1, iLastItem2, oLastItem2)) |
| { |
| fprintf( stdout, "Input refinement by simulation finds two circuits different.\n"); |
| goto freeAndExit; |
| } |
| }while(counter <= 200); |
| |
| }while(0); |
| |
| printf(" done!\n"); |
| |
| simulTime = (float)(Abc_Clock() - clk)/(float)(CLOCKS_PER_SEC); |
| printf("SAT-based search started ...\n"); |
| |
| satTime = refineBySAT(pNtk1, iMatch1, iGroup1, iDep1, &iLastItem1, oMatch1, oGroup1, oDep1, &oLastItem1, observability1, |
| pNtk2, iMatch2, iGroup2, iDep2, &iLastItem2, oMatch2, oGroup2, oDep2, &oLastItem2, observability2); |
| |
| printf( "Init Time = %4.2f\n", initTime ); |
| printf( "Simulation Time = %4.2f\n", simulTime ); |
| printf( "SAT Time = %4.2f\n", satTime ); |
| printf( "Overall Time = %4.2f\n", initTime + simulTime + satTime ); |
| |
| freeAndExit: |
| |
| for(i = 0; i < iLastItem1 ; i++) |
| { |
| |
| Vec_IntFree( iMatch1[i] ); |
| Vec_IntFree( iMatch2[i] ); |
| } |
| |
| for(i = 0; i < oLastItem1 ; i++) |
| { |
| |
| Vec_IntFree( oMatch1[i] ); |
| Vec_IntFree( oMatch2[i] ); |
| } |
| |
| for(i = 0; i < Abc_NtkPiNum(pNtk1); i++) |
| { |
| Vec_IntFree( iDep1[i] ); |
| Vec_IntFree( iDep2[i] ); |
| if(topOrder1 != NULL) { |
| Vec_PtrFree( topOrder1[i] ); |
| Vec_PtrFree( topOrder2[i] ); |
| } |
| } |
| |
| for(i = 0; i < Abc_NtkPoNum(pNtk1); i++) |
| { |
| Vec_IntFree( oDep1[i] ); |
| Vec_IntFree( oDep2[i] ); |
| } |
| |
| ABC_FREE( iMatch1 ); |
| ABC_FREE( iMatch2 ); |
| ABC_FREE( oMatch1 ); |
| ABC_FREE( oMatch2 ); |
| ABC_FREE( iDep1 ); |
| ABC_FREE( iDep2 ); |
| ABC_FREE( oDep1 ); |
| ABC_FREE( oDep2 ); |
| ABC_FREE( iGroup1 ); |
| ABC_FREE( iGroup2 ); |
| ABC_FREE( oGroup1 ); |
| ABC_FREE( oGroup2 ); |
| ABC_FREE( vPiValues1 ); |
| ABC_FREE( vPiValues2 ); |
| ABC_FREE( observability1 ); |
| ABC_FREE( observability2 ); |
| if(topOrder1 != NULL) { |
| ABC_FREE( topOrder1 ); |
| ABC_FREE( topOrder2 ); |
| } |
| }ABC_NAMESPACE_IMPL_END |
| |