diff options
author | Alan Mishchenko <alanmi@berkeley.edu> | 2007-10-01 08:01:00 -0700 |
---|---|---|
committer | Alan Mishchenko <alanmi@berkeley.edu> | 2007-10-01 08:01:00 -0700 |
commit | 4812c90424dfc40d26725244723887a2d16ddfd9 (patch) | |
tree | b32ace96e7e2d84d586e09ba605463b6f49c3271 /src/bdd/dsd/dsdProc.c | |
parent | e54d9691616b9a0326e2fdb3156bb4eeb8abfcd7 (diff) | |
download | abc-4812c90424dfc40d26725244723887a2d16ddfd9.tar.gz abc-4812c90424dfc40d26725244723887a2d16ddfd9.tar.bz2 abc-4812c90424dfc40d26725244723887a2d16ddfd9.zip |
Version abc71001
Diffstat (limited to 'src/bdd/dsd/dsdProc.c')
-rw-r--r-- | src/bdd/dsd/dsdProc.c | 1617 |
1 files changed, 1617 insertions, 0 deletions
diff --git a/src/bdd/dsd/dsdProc.c b/src/bdd/dsd/dsdProc.c new file mode 100644 index 00000000..543ad387 --- /dev/null +++ b/src/bdd/dsd/dsdProc.c @@ -0,0 +1,1617 @@ +/**CFile**************************************************************** + + FileName [dsdProc.c] + + PackageName [DSD: Disjoint-support decomposition package.] + + Synopsis [The core procedures of the package.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 8.0. Started - September 22, 2003.] + + Revision [$Id: dsdProc.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "dsdInt.h" + + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// the most important procedures +void dsdKernelDecompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs ); +static Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * F ); + +// additional procedures +static Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity ); +static int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH ); +static void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor ); +static int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall ); + +// list copying +static void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize ); +static void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int Skipped ); + +// debugging procedures +static int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE ); + +//////////////////////////////////////////////////////////////////////// +/// STATIC VARIABLES /// +//////////////////////////////////////////////////////////////////////// + +// the counter of marks +static int s_Mark; + +// debugging flag +static int s_Show = 0; +// temporary var used for debugging +static int Depth = 0; + +static int s_Loops1; +static int s_Loops2; +static int s_Loops3; +static int s_Pivot; +static int s_PivotNo; +static int s_Common; +static int s_CommonNo; + +static int s_Case4Calls; +static int s_Case4CallsSpecial; + +static int s_Case5; +static int s_Loops2Useless; + + +static int s_DecNodesTotal; +static int s_DecNodesUsed; + +// statistical variables +static int s_nDecBlocks; +static int s_nLiterals; +static int s_nExorGates; +static int s_nReusedBlocks; +static int s_nCascades; +static float s_nArea; +static float s_MaxDelay; +static long s_Time; +static int s_nInvertors; +static int s_nPrimeBlocks; + +static int HashSuccess = 0; +static int HashFailure = 0; + +static int s_CacheEntries; + + +//////////////////////////////////////////////////////////////////////// +/// DECOMPOSITION FUNCTIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs DSD for the array of functions represented by BDDs.] + + Description [This function takes the DSD manager, which should be + previously allocated by the call to Dsd_ManagerStart(). The resulting + DSD tree is stored in the DSD manager (pDsdMan->pRoots, pDsdMan->nRoots). + Access to the tree is through the APIs of the manager. The resulting + tree is a shared DSD DAG for the functions given in the array. For one + function the resulting DAG is always a tree. The root node pointers can + be complemented, as discussed in the literature referred to in "dsd.h". + This procedure can be called repeatedly for different functions. There is + no need to remove the decomposition tree after it is returned, because + the next call to the DSD manager will "recycle" the tree. The user should + not modify or dereference any data associated with the nodes of the + DSD trees (the user can only change the contents of a temporary + mark associated with each node by the calling to Dsd_NodeSetMark()). + All the decomposition trees and intermediate nodes will be removed when + the DSD manager is deallocated at the end by calling Dsd_ManagerStop().] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dsd_Decompose( Dsd_Manager_t * pDsdMan, DdNode ** pbFuncs, int nFuncs ) +{ + DdManager * dd = pDsdMan->dd; + int i; + long clk; + Dsd_Node_t * pTemp; + int SumMaxGateSize = 0; + int nDecOutputs = 0; + int nCBFOutputs = 0; +/* +s_Loops1 = 0; +s_Loops2 = 0; +s_Loops3 = 0; +s_Case4Calls = 0; +s_Case4CallsSpecial = 0; +s_Case5 = 0; +s_Loops2Useless = 0; +*/ + // resize the number of roots in the manager + if ( pDsdMan->nRootsAlloc < nFuncs ) + { + if ( pDsdMan->nRootsAlloc > 0 ) + free( pDsdMan->pRoots ); + pDsdMan->nRootsAlloc = nFuncs; + pDsdMan->pRoots = (Dsd_Node_t **) malloc( pDsdMan->nRootsAlloc * sizeof(Dsd_Node_t *) ); + } + + if ( pDsdMan->fVerbose ) + printf( "\nDecomposability statistics for individual outputs:\n" ); + + // set the counter of decomposition nodes + s_nDecBlocks = 0; + + // perform decomposition for all outputs + clk = clock(); + pDsdMan->nRoots = 0; + s_nCascades = 0; + for ( i = 0; i < nFuncs; i++ ) + { + int nLiteralsPrev; + int nDecBlocksPrev; + int nExorGatesPrev; + int nReusedBlocksPres; + int nCascades; + int MaxBlock; + int nPrimeBlocks; + long clk; + + clk = clock(); + nLiteralsPrev = s_nLiterals; + nDecBlocksPrev = s_nDecBlocks; + nExorGatesPrev = s_nExorGates; + nReusedBlocksPres = s_nReusedBlocks; + nPrimeBlocks = s_nPrimeBlocks; + + pDsdMan->pRoots[ pDsdMan->nRoots++ ] = dsdKernelDecompose_rec( pDsdMan, pbFuncs[i] ); + + Dsd_TreeNodeGetInfoOne( pDsdMan->pRoots[i], &nCascades, &MaxBlock ); + s_nCascades = ddMax( s_nCascades, nCascades ); + pTemp = Dsd_Regular(pDsdMan->pRoots[i]); + if ( pTemp->Type != DSD_NODE_PRIME || pTemp->nDecs != Extra_bddSuppSize(dd,pTemp->S) ) + nDecOutputs++; + if ( MaxBlock < 3 ) + nCBFOutputs++; + SumMaxGateSize += MaxBlock; + + if ( pDsdMan->fVerbose ) + { + printf("#%02d: ", i ); + printf("Ins=%2d. ", Cudd_SupportSize(dd,pbFuncs[i]) ); + printf("Gts=%3d. ", Dsd_TreeCountNonTerminalNodesOne( pDsdMan->pRoots[i] ) ); + printf("Pri=%3d. ", Dsd_TreeCountPrimeNodesOne( pDsdMan->pRoots[i] ) ); + printf("Max=%3d. ", MaxBlock ); + printf("Reuse=%2d. ", s_nReusedBlocks-nReusedBlocksPres ); + printf("Csc=%2d. ", nCascades ); + printf("T= %.2f s. ", (float)(clock()-clk)/(float)(CLOCKS_PER_SEC) ) ; + printf("Bdd=%2d. ", Cudd_DagSize(pbFuncs[i]) ); + printf("\n"); + fflush( stdout ); + } + } + assert( pDsdMan->nRoots == nFuncs ); + + if ( pDsdMan->fVerbose ) + { + printf( "\n" ); + printf( "The cumulative decomposability statistics:\n" ); + printf( " Total outputs = %5d\n", nFuncs ); + printf( " Decomposable outputs = %5d\n", nDecOutputs ); + printf( " Completely decomposable outputs = %5d\n", nCBFOutputs ); + printf( " The sum of max gate sizes = %5d\n", SumMaxGateSize ); + printf( " Shared BDD size = %5d\n", Cudd_SharingSize( pbFuncs, nFuncs ) ); + printf( " Decomposition entries = %5d\n", st_count( pDsdMan->Table ) ); + printf( " Pure decomposition time = %.2f sec\n", (float)(clock() - clk)/(float)(CLOCKS_PER_SEC) ); + } +/* + printf( "s_Loops1 = %d.\n", s_Loops1 ); + printf( "s_Loops2 = %d.\n", s_Loops2 ); + printf( "s_Loops3 = %d.\n", s_Loops3 ); + printf( "s_Case4Calls = %d.\n", s_Case4Calls ); + printf( "s_Case4CallsSpecial = %d.\n", s_Case4CallsSpecial ); + printf( "s_Case5 = %d.\n", s_Case5 ); + printf( "s_Loops2Useless = %d.\n", s_Loops2Useless ); +*/ +} + +/**Function************************************************************* + + Synopsis [Performs decomposition for one function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dsd_Node_t * Dsd_DecomposeOne( Dsd_Manager_t * pDsdMan, DdNode * bFunc ) +{ + return dsdKernelDecompose_rec( pDsdMan, bFunc ); +} + +/**Function************************************************************* + + Synopsis [The main function of this module. Recursive implementation of DSD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dsd_Node_t * dsdKernelDecompose_rec( Dsd_Manager_t * pDsdMan, DdNode * bFunc0 ) +{ + DdManager * dd = pDsdMan->dd; + DdNode * bLow; + DdNode * bLowR; + DdNode * bHigh; + + int VarInt; + DdNode * bVarCur; + Dsd_Node_t * pVarCurDE; + // works only if var indices start from 0!!! + DdNode * bSuppNew = NULL, * bTemp; + + int fContained; + int nSuppLH; + int nSuppL; + int nSuppH; + + + + // various decomposition nodes + Dsd_Node_t * pThis, * pL, * pH, * pLR, * pHR; + + Dsd_Node_t * pSmallR, * pLargeR; + Dsd_Node_t * pTableEntry; + + + // treat the complemented case + DdNode * bF = Cudd_Regular(bFunc0); + int fCompF = (int)(bF != bFunc0); + + // check cache + if ( st_lookup( pDsdMan->Table, (char*)bF, (char**)&pTableEntry ) ) + { // the entry is present + HashSuccess++; + return Dsd_NotCond( pTableEntry, fCompF ); + } + HashFailure++; + Depth++; + + // proceed to consider "four cases" + ////////////////////////////////////////////////////////////////////// + // TERMINAL CASES - CASES 1 and 2 + ////////////////////////////////////////////////////////////////////// + bLow = cuddE(bF); + bLowR = Cudd_Regular(bLow); + bHigh = cuddT(bF); + VarInt = bF->index; + bVarCur = dd->vars[VarInt]; + pVarCurDE = pDsdMan->pInputs[VarInt]; + // works only if var indices start from 0!!! + bSuppNew = NULL; + + if ( bLowR->index == CUDD_CONST_INDEX || bHigh->index == CUDD_CONST_INDEX ) + { // one of the cofactors in the constant + if ( bHigh == b1 ) // bHigh cannot be equal to b0, because then it will be complemented + if ( bLow == b0 ) // bLow cannot be equal to b1, because then the node will have bLow == bHigh + ///////////////////////////////////////////////////////////////// + // bLow == 0, bHigh == 1, F = x'&0 + x&1 = x + ///////////////////////////////////////////////////////////////// + { // create the elementary variable node + assert(0); // should be already in the hash table + pThis = Dsd_TreeNodeCreate( DSD_NODE_BUF, 1, s_nDecBlocks++ ); + pThis->pDecs[0] = NULL; + } + else // if ( bLow != constant ) + ///////////////////////////////////////////////////////////////// + // bLow != const, bHigh == 1, F = x'&bLow + x&1 = bLow + x --- DSD_NODE_OR(x,bLow) + ///////////////////////////////////////////////////////////////// + { + pL = dsdKernelDecompose_rec( pDsdMan, bLow ); + pLR = Dsd_Regular( pL ); + bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew); + if ( pLR->Type == DSD_NODE_OR && pL == pLR ) // OR and no complement + { // add to the components + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pL->nDecs+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, pVarCurDE, pL->pDecs, pL->nDecs ); + } + else // all other cases + { // create a new 2-input OR-gate + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 ); + } + } + else // if ( bHigh != const ) // meaning that bLow should be a constant + { + pH = dsdKernelDecompose_rec( pDsdMan, bHigh ); + pHR = Dsd_Regular( pH ); + bSuppNew = Cudd_bddAnd( dd, bVarCur, pHR->S ); Cudd_Ref(bSuppNew); + if ( bLow == b0 ) + ///////////////////////////////////////////////////////////////// + // Low == 0, High != 1, F = x'&0+x&High = (x'+High')'--- NOR(x',High') + ///////////////////////////////////////////////////////////////// + if ( pHR->Type == DSD_NODE_OR && pH != pHR ) // DSD_NODE_OR and complement + { // add to the components + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pHR->nDecs+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pHR->pDecs, pHR->nDecs ); + pThis = Dsd_Not(pThis); + } + else // all other cases + { // create a new 2-input NOR gate + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ ); + pH = Dsd_Not(pH); + dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 ); + pThis = Dsd_Not(pThis); + } + else // if ( bLow == b1 ) + ///////////////////////////////////////////////////////////////// + // Low == 1, High != 1, F = x'&1 + x&High = x' + High --- DSD_NODE_OR(x',High) + ///////////////////////////////////////////////////////////////// + if ( pHR->Type == DSD_NODE_OR && pH == pHR ) // OR and no complement + { // add to the components + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, pH->nDecs+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), pH->pDecs, pH->nDecs ); + } + else // all other cases + { // create a new 2-input OR-gate + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, Dsd_Not(pVarCurDE), &pH, 1 ); + } + } + goto EXIT; + } + // else if ( bLow != const && bHigh != const ) + + // the case of equal cofactors (up to complementation) + if ( bLowR == bHigh ) + ///////////////////////////////////////////////////////////////// + // Low == G, High == G', F = x'&G + x&G' = (x(+)G) --- EXOR(x,Low) + ///////////////////////////////////////////////////////////////// + { + pL = dsdKernelDecompose_rec( pDsdMan, bLow ); + pLR = Dsd_Regular( pL ); + bSuppNew = Cudd_bddAnd( dd, bVarCur, pLR->S ); Cudd_Ref(bSuppNew); + if ( pLR->Type == DSD_NODE_EXOR ) // complemented or not - does not matter! + { // add to the components + pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, pLR->nDecs+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, pVarCurDE, pLR->pDecs, pLR->nDecs ); + if ( pL != pLR ) + pThis = Dsd_Not( pThis ); + } + else // all other cases + { // create a new 2-input EXOR-gate + pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ ); + if ( pL != pLR ) // complemented + { + dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pLR, 1 ); + pThis = Dsd_Not( pThis ); + } + else // non-complemented + dsdKernelCopyListPlusOne( pThis, pVarCurDE, &pL, 1 ); + } + goto EXIT; + } + + ////////////////////////////////////////////////////////////////////// + // solve subproblems + ////////////////////////////////////////////////////////////////////// + pL = dsdKernelDecompose_rec( pDsdMan, bLow ); + pH = dsdKernelDecompose_rec( pDsdMan, bHigh ); + pLR = Dsd_Regular( pL ); + pHR = Dsd_Regular( pH ); + + assert( pLR->Type == DSD_NODE_BUF || pLR->Type == DSD_NODE_OR || pLR->Type == DSD_NODE_EXOR || pLR->Type == DSD_NODE_PRIME ); + assert( pHR->Type == DSD_NODE_BUF || pHR->Type == DSD_NODE_OR || pHR->Type == DSD_NODE_EXOR || pHR->Type == DSD_NODE_PRIME ); + +/* +if ( Depth == 1 ) +{ +// PRK(bLow,pDecTreeTotal->nInputs); +// PRK(bHigh,pDecTreeTotal->nInputs); +if ( s_Show ) +{ + PRD( pL ); + PRD( pH ); +} +} +*/ + // compute the new support + bTemp = Cudd_bddAnd( dd, pLR->S, pHR->S ); Cudd_Ref( bTemp ); + nSuppL = Extra_bddSuppSize( dd, pLR->S ); + nSuppH = Extra_bddSuppSize( dd, pHR->S ); + nSuppLH = Extra_bddSuppSize( dd, bTemp ); + bSuppNew = Cudd_bddAnd( dd, bTemp, bVarCur ); Cudd_Ref( bSuppNew ); + Cudd_RecursiveDeref( dd, bTemp ); + + + // several possibilities are possible + // (1) support of one component contains another + // (2) none of the supports is contained in another + fContained = dsdKernelCheckContainment( pDsdMan, pLR, pHR, &pLargeR, &pSmallR ); + + ////////////////////////////////////////////////////////////////////// + // CASE 3.b One of the cofactors in a constant (OR and EXOR) + ////////////////////////////////////////////////////////////////////// + // the support of the larger component should contain the support of the smaller + // it is possible to have PRIME function in this role + // for example: F = ITE( a+b, c(+)d, e+f ), F0 = ITE( b, c(+)d, e+f ), F1 = c(+)d + if ( fContained ) + { + Dsd_Node_t * pSmall, * pLarge; + int c, iCompLarge; // the number of the component is Large is equal to the whole of Small + int fLowIsLarge; + + DdNode * bFTemp; // the changed input function + Dsd_Node_t * pDETemp, * pDENew; + + Dsd_Node_t * pComp = NULL; + int nComp; + + if ( pSmallR == pLR ) + { // Low is Small => High is Large + pSmall = pL; + pLarge = pH; + fLowIsLarge = 0; + } + else + { // vice versa + pSmall = pH; + pLarge = pL; + fLowIsLarge = 1; + } + + // treat the situation when the larger is PRIME + if ( pLargeR->Type == DSD_NODE_PRIME ) //&& pLargeR->nDecs != pSmallR->nDecs ) + { + // QUESTION: Is it possible for pLargeR->nDecs > 3 + // and pSmall contained as one of input in pLarge? + // Yes, for example F = a'c + a & MUX(b,c',d) = a'c + abc' + ab'd is non-decomposable + // Consider the function H(a->xy) = F( xy, b, c, d ) + // H0 = H(x=0) = F(0,b,c,d) = c + // H1 = F(x=1) = F(y,b,c,d) - non-decomposable + // + // QUESTION: Is it possible that pLarge is PRIME(3) and pSmall is OR(2), + // which is not contained in PRIME as one input? + // Yes, for example F = abcd + b'c'd' + a'c'd' = PRIME(ab, c, d) + // F(a=0) = c'd' = NOT(OR(a,d)) F(a=1) = bcd + b'c'd' = PRIME(b,c,d) + // To find decomposition, we have to prove that F(a=1)|b=0 = F(a=0) + + // Is it possible that (pLargeR->nDecs == pSmallR->nDecs) and yet this case holds? + // Yes, consider the function such that F(a=0) = PRIME(a,b+c,d,e) and F(a=1) = OR(b,c,d,e) + // They have the same number of inputs and it is possible that they will be the cofactors + // as discribed in the previous example. + + // find the component, which when substituted for 0 or 1, produces the desired result + int g, fFoundComp; // {0,1} depending on whether setting cofactor to 0 or 1 worked out + + DdNode * bLarge, * bSmall; + if ( fLowIsLarge ) + { + bLarge = bLow; + bSmall = bHigh; + } + else + { + bLarge = bHigh; + bSmall = bLow; + } + + for ( g = 0; g < pLargeR->nDecs; g++ ) +// if ( g != c ) + { + pDETemp = pLargeR->pDecs[g]; // cannot be complemented + if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, pDETemp->G, b1 ) ) + { + fFoundComp = 1; + break; + } + + s_Loops1++; + + if ( Dsd_CheckRootFunctionIdentity( dd, bLarge, bSmall, Cudd_Not(pDETemp->G), b1 ) ) + { + fFoundComp = 0; + break; + } + + s_Loops1++; + } + + if ( g != pLargeR->nDecs ) + { // decomposition is found + if ( fFoundComp ) + if ( fLowIsLarge ) + bFTemp = Cudd_bddOr( dd, bVarCur, pLargeR->pDecs[g]->G ); + else + bFTemp = Cudd_bddOr( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G ); + else + if ( fLowIsLarge ) + bFTemp = Cudd_bddAnd( dd, Cudd_Not(bVarCur), pLargeR->pDecs[g]->G ); + else + bFTemp = Cudd_bddAnd( dd, bVarCur, pLargeR->pDecs[g]->G ); + Cudd_Ref( bFTemp ); + + pDENew = dsdKernelDecompose_rec( pDsdMan, bFTemp ); + pDENew = Dsd_Regular( pDENew ); + Cudd_RecursiveDeref( dd, bFTemp ); + + // get the new gate + pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLargeR->nDecs, s_nDecBlocks++ ); + dsdKernelCopyListPlusOneMinusOne( pThis, pDENew, pLargeR->pDecs, pLargeR->nDecs, g ); + goto EXIT; + } + } + + // try to find one component in the pLarger that is equal to the whole of pSmaller + for ( c = 0; c < pLargeR->nDecs; c++ ) + if ( pLargeR->pDecs[c] == pSmall || pLargeR->pDecs[c] == Dsd_Not(pSmall) ) + { + iCompLarge = c; + break; + } + + // assign the equal component + if ( c != pLargeR->nDecs ) // the decomposition is possible! + { + pComp = pLargeR->pDecs[iCompLarge]; + nComp = 1; + } + else // the decomposition is still possible + { // for example F = OR(ab,c,d), F(a=0) = OR(c,d), F(a=1) = OR(b,c,d) + // supp(F0) is contained in supp(F1), Polarity(F(a=0)) == Polarity(F(a=1)) + + // try to find a group of common components + if ( pLargeR->Type == pSmallR->Type && + (pLargeR->Type == DSD_NODE_EXOR || pSmallR->Type == DSD_NODE_OR&& ((pLarge==pLargeR) == (pSmall==pSmallR))) ) + { + Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL; + int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLargeR, pSmallR, &pCommon, &pLastDiffL, &pLastDiffH ); + // if all the components of pSmall are contained in pLarge, + // then the decomposition exists + if ( nCommon == pSmallR->nDecs ) + { + pComp = pSmallR; + nComp = pSmallR->nDecs; + } + } + } + + if ( pComp ) // the decomposition is possible! + { +// Dsd_Node_t * pComp = pLargeR->pDecs[iCompLarge]; + Dsd_Node_t * pCompR = Dsd_Regular( pComp ); + int fComp1 = (int)( pLarge != pLargeR ); + int fComp2 = (int)( pComp != pCompR ); + int fComp3 = (int)( pSmall != pSmallR ); + + DdNode * bFuncComp; // the function of the given component + DdNode * bFuncNew; // the function of the input component + + if ( pLargeR->Type == DSD_NODE_OR ) // Figure 4 of Matsunaga's paper + { + // the decomposition exists only if the polarity assignment + // along the paths is the same + if ( (fComp1 ^ fComp2) == fComp3 ) + { // decomposition exists = consider 4 cases + // consideration of cases leads to the following conclusion + // fComp1 gives the polarity of the resulting DSD_NODE_OR gate + // fComp2 gives the polarity of the common component feeding into the DSD_NODE_OR gate + // + // | fComp1 pL/ |pS + // <> .........<=>....... <> | + // | / | + // [OR] [OR] | fComp3 + // / \ fComp2 / | \ | + // <> <> .......<=>... /..|..<> | + // / \ / | \| + // [OR] [C] S1 S2 C + // / \ + // <> \ + // / \ + // [OR] [x] + // / \ + // S1 S2 + // + + + // at this point we have the function F (bFTemp) and the common component C (bFuncComp) + // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0 + // we compute the following R = Exist( F - C, supp(C) ) + bFTemp = (fComp1)? Cudd_Not( bF ): bF; + bFuncComp = (fComp2)? Cudd_Not( pCompR->G ): pCompR->G; + bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bFuncComp), pCompR->S ); Cudd_Ref( bFuncNew ); + + // there is no need to copy the dec entry list first, because pComp is a component + // which will not be destroyed by the recursive call to decomposition + pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew ); + assert( Dsd_IsComplement(pDENew) ); // follows from the consideration of cases + Cudd_RecursiveDeref( dd, bFuncNew ); + + // get the new gate + if ( nComp == 1 ) + { + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, 2, s_nDecBlocks++ ); + pThis->pDecs[0] = pDENew; + pThis->pDecs[1] = pComp; // takes the complement + } + else + { // pComp is not complemented + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nComp+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp ); + } + + if ( fComp1 ) + pThis = Dsd_Not( pThis ); + goto EXIT; + } + } + else if ( pLargeR->Type == DSD_NODE_EXOR ) // Figure 5 of Matsunaga's paper (with correction) + { // decomposition always exists = consider 4 cases + + // consideration of cases leads to the following conclusion + // fComp3 gives the COMPLEMENT of the polarity of the resulting EXOR gate + // (if fComp3 is 0, the EXOR gate is complemented, and vice versa) + // + // | fComp1 pL/ |pS + // <> .........<=>....... /....| fComp3 + // | / | + // [XOR] [XOR] | + // / \ fComp2==0 / | \ | + // / \ / | \ | + // / \ / | \| + // [OR] [C] S1 S2 C + // / \ + // <> \ + // / \ + // [XOR] [x] + // / \ + // S1 S2 + // + + assert( fComp2 == 0 ); + // find the functionality of the lower gates + bFTemp = (fComp3)? bF: Cudd_Not( bF ); + bFuncNew = Cudd_bddXor( dd, bFTemp, pComp->G ); Cudd_Ref( bFuncNew ); + + pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew ); + assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases + Cudd_RecursiveDeref( dd, bFuncNew ); + + // get the new gate + if ( nComp == 1 ) + { + pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, 2, s_nDecBlocks++ ); + pThis->pDecs[0] = pDENew; + pThis->pDecs[1] = pComp; + } + else + { // pComp is not complemented + pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nComp+1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, pDENew, pComp->pDecs, nComp ); + } + + if ( !fComp3 ) + pThis = Dsd_Not( pThis ); + goto EXIT; + } + } + } + + // this case was added to fix the trivial bug found November 4, 2002 in Japan + // by running the example provided by T. Sasao + if ( nSuppLH == nSuppL + nSuppH ) // the supports of the components are disjoint + { + // create a new component of the type ITE( a, pH, pL ) + pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, 3, s_nDecBlocks++ ); + if ( dd->perm[pLR->S->index] < dd->perm[pHR->S->index] ) // pLR is higher in the varible order + { + pThis->pDecs[1] = pLR; + pThis->pDecs[2] = pHR; + } + else // pHR is higher in the varible order + { + pThis->pDecs[1] = pHR; + pThis->pDecs[2] = pLR; + } + // add the first component + pThis->pDecs[0] = pVarCurDE; + goto EXIT; + } + + + ////////////////////////////////////////////////////////////////////// + // CASE 3.a Neither of the cofactors is a constant (OR, EXOR, PRIME) + ////////////////////////////////////////////////////////////////////// + // the component types are identical + // and if they are OR, they are either both complemented or both not complemented + // and if they are PRIME, their dec numbers should be the same + if ( pLR->Type == pHR->Type && + pLR->Type != DSD_NODE_BUF && + (pLR->Type != DSD_NODE_OR || ( pL == pLR && pH == pHR || pL != pLR && pH != pHR ) ) && + (pLR->Type != DSD_NODE_PRIME || pLR->nDecs == pHR->nDecs) ) + { + // array to store common comps in pL and pH + Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL; + int nCommon = dsdKernelFindCommonComponents( pDsdMan, pLR, pHR, &pCommon, &pLastDiffL, &pLastDiffH ); + if ( nCommon ) + { + if ( pLR->Type == DSD_NODE_OR ) // Figure 2 of Matsunaga's paper + { // at this point we have the function F and the group of common components C + // to get the remainder, R, in the relationship F = R + C, supp(R) & supp(C) = 0 + // we compute the following R = Exist( F - C, supp(C) ) + + // compute the sum total of the common components and the union of their supports + DdNode * bCommF, * bCommS, * bFTemp, * bFuncNew; + Dsd_Node_t * pDENew; + + dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, &bCommS, 0 ); + Cudd_Ref( bCommF ); + Cudd_Ref( bCommS ); + bFTemp = ( pL != pLR )? Cudd_Not(bF): bF; + + bFuncNew = Cudd_bddAndAbstract( dd, bFTemp, Cudd_Not(bCommF), bCommS ); Cudd_Ref( bFuncNew ); + Cudd_RecursiveDeref( dd, bCommF ); + Cudd_RecursiveDeref( dd, bCommS ); + + // get the new gate + + // copy the components first, then call the decomposition + // because decomposition will distroy the list used for copying + pThis = Dsd_TreeNodeCreate( DSD_NODE_OR, nCommon + 1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon ); + + // call the decomposition recursively + pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew ); +// assert( !Dsd_IsComplement(pDENew) ); // follows from the consideration of cases + Cudd_RecursiveDeref( dd, bFuncNew ); + + // add the first component + pThis->pDecs[0] = pDENew; + + if ( pL != pLR ) + pThis = Dsd_Not( pThis ); + goto EXIT; + } + else + if ( pLR->Type == DSD_NODE_EXOR ) // Figure 3 of Matsunaga's paper + { + // compute the sum total of the common components and the union of their supports + DdNode * bCommF, * bFuncNew; + Dsd_Node_t * pDENew; + int fCompExor; + + dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, 1 ); + Cudd_Ref( bCommF ); + + bFuncNew = Cudd_bddXor( dd, bF, bCommF ); Cudd_Ref( bFuncNew ); + Cudd_RecursiveDeref( dd, bCommF ); + + // get the new gate + + // copy the components first, then call the decomposition + // because decomposition will distroy the list used for copying + pThis = Dsd_TreeNodeCreate( DSD_NODE_EXOR, nCommon + 1, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon ); + + // call the decomposition recursively + pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew ); + Cudd_RecursiveDeref( dd, bFuncNew ); + + // remember the fact that it was complemented + fCompExor = Dsd_IsComplement(pDENew); + pDENew = Dsd_Regular(pDENew); + + // add the first component + pThis->pDecs[0] = pDENew; + + + if ( fCompExor ) + pThis = Dsd_Not( pThis ); + goto EXIT; + } + else + if ( pLR->Type == DSD_NODE_PRIME && (nCommon == pLR->nDecs-1 || nCommon == pLR->nDecs) ) + { + // for example the function F(a,b,c,d) = ITE(b,c,a(+)d) produces + // two cofactors F(a=0) = PRIME(b,c,d) and F(a=1) = PRIME(b,c,d) + // with exactly the same list of common components + + Dsd_Node_t * pDENew; + DdNode * bFuncNew; + int fCompComp = 0; // this flag can be {0,1,2} + // if it is 0 there is no identity + // if it is 1/2, the cofactored functions are equal in the direct/complemented polarity + + if ( nCommon == pLR->nDecs ) + { // all the components are the same + // find the formal input, in which pLow and pHigh differ (if such input exists) + int m; + Dsd_Node_t * pTempL, * pTempH; + + s_Common++; + for ( m = 0; m < pLR->nDecs; m++ ) + { + pTempL = pLR->pDecs[m]; // cannot be complemented + pTempH = pHR->pDecs[m]; // cannot be complemented + + if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pTempL->G, Cudd_Not(pTempH->G) ) && + Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pTempL->G), pTempH->G ) ) + { + pLastDiffL = pTempL; + pLastDiffH = pTempH; + assert( pLastDiffL == pLastDiffH ); + fCompComp = 2; + break; + } + + s_Loops2++; + s_Loops2++; +/* + if ( s_Loops2 % 10000 == 0 ) + { + int i; + for ( i = 0; i < pLR->nDecs; i++ ) + printf( " %d(s=%d)", pLR->pDecs[i]->Type, + Extra_bddSuppSize(dd, pLR->pDecs[i]->S) ); + printf( "\n" ); + } +*/ + + } +// if ( pLR->nDecs == Extra_bddSuppSize(dd, pLR->S) ) +// s_Loops2Useless += pLR->nDecs * 2; + + if ( fCompComp ) + { // put the equal components into pCommon, so that they could be copied into the new dec entry + nCommon = 0; + for ( m = 0; m < pLR->nDecs; m++ ) + if ( pLR->pDecs[m] != pLastDiffL ) + pCommon[nCommon++] = pLR->pDecs[m]; + assert( nCommon = pLR->nDecs-1 ); + } + } + else + { // the differing components are known - check that they have compatible PRIME function + + s_CommonNo++; + + // find the numbers of different components + assert( pLastDiffL ); + assert( pLastDiffH ); + // also, they cannot be complemented, because the decomposition type is PRIME + + if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), Cudd_Not(pLastDiffH->G) ) && + Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, pLastDiffH->G ) ) + fCompComp = 1; + else if ( Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, pLastDiffL->G, Cudd_Not(pLastDiffH->G) ) && + Dsd_CheckRootFunctionIdentity( dd, bLow, bHigh, Cudd_Not(pLastDiffL->G), pLastDiffH->G ) ) + fCompComp = 2; + + s_Loops3 += 4; + } + + if ( fCompComp ) + { + if ( fCompComp == 1 ) // it is true that bLow(G=0) == bHigh(H=0) && bLow(G=1) == bHigh(H=1) + bFuncNew = Cudd_bddIte( dd, bVarCur, pLastDiffH->G, pLastDiffL->G ); + else // it is true that bLow(G=0) == bHigh(H=1) && bLow(G=1) == bHigh(H=0) + bFuncNew = Cudd_bddIte( dd, bVarCur, Cudd_Not(pLastDiffH->G), pLastDiffL->G ); + Cudd_Ref( bFuncNew ); + + // get the new gate + + // copy the components first, then call the decomposition + // because decomposition will distroy the list used for copying + pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, pLR->nDecs, s_nDecBlocks++ ); + dsdKernelCopyListPlusOne( pThis, NULL, pCommon, nCommon ); + + // create a new component + pDENew = dsdKernelDecompose_rec( pDsdMan, bFuncNew ); + Cudd_RecursiveDeref( dd, bFuncNew ); + // the BDD of the argument function in PRIME decomposition, should be regular + pDENew = Dsd_Regular(pDENew); + + // add the first component + pThis->pDecs[0] = pDENew; + goto EXIT; + } + } // end of PRIME type + } // end of existing common components + } // end of CASE 3.a + +// if ( Depth != 1) +// { + +//CASE4: + ////////////////////////////////////////////////////////////////////// + // CASE 4 + ////////////////////////////////////////////////////////////////////// + { + // estimate the number of entries in the list + int nEntriesMax = pDsdMan->nInputs - dd->perm[VarInt]; + + // create the new decomposition entry + int nEntries = 0; + + DdNode * SuppL, * SuppH, * SuppL_init, * SuppH_init; + Dsd_Node_t *pHigher, *pLower, * pTemp, * pDENew; + + + int levTopSuppL; + int levTopSuppH; + int levTop; + + pThis = Dsd_TreeNodeCreate( DSD_NODE_PRIME, nEntriesMax, s_nDecBlocks++ ); + pThis->pDecs[ nEntries++ ] = pVarCurDE; + // other entries will be added to this list one-by-one during analysis + + // count how many times does it happen that the decomposition entries are + s_Case4Calls++; + + // consider the simplest case: when the supports are equal + // and at least one of the components + // is the PRIME without decompositions, or + // when both of them are without decomposition + if ( (((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) || (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) && pLR->S == pHR->S) || + ((pLR->Type == DSD_NODE_PRIME && nSuppL == pLR->nDecs) && (pHR->Type == DSD_NODE_PRIME && nSuppH == pHR->nDecs)) ) + { + + s_Case4CallsSpecial++; + // walk through both supports and create the decomposition list composed of simple entries + SuppL = pLR->S; + SuppH = pHR->S; + do + { + // determine levels + levTopSuppL = cuddI(dd,SuppL->index); + levTopSuppH = cuddI(dd,SuppH->index); + + // skip the topmost variable in both supports + if ( levTopSuppL <= levTopSuppH ) + { + levTop = levTopSuppL; + SuppL = cuddT(SuppL); + } + else + levTop = levTopSuppH; + + if ( levTopSuppH <= levTopSuppL ) + SuppH = cuddT(SuppH); + + // set the new decomposition entry + pThis->pDecs[ nEntries++ ] = pDsdMan->pInputs[ dd->invperm[levTop] ]; + } + while ( SuppL != b1 || SuppH != b1 ); + } + else + { + + // compare two different decomposition lists + SuppL_init = pLR->S; + SuppH_init = pHR->S; + // start references (because these supports will change) + SuppL = pLR->S; Cudd_Ref( SuppL ); + SuppH = pHR->S; Cudd_Ref( SuppH ); + while ( SuppL != b1 || SuppH != b1 ) + { + // determine the top level in cofactors and + // whether they have the same top level + int TopLevL = cuddI(dd,SuppL->index); + int TopLevH = cuddI(dd,SuppH->index); + int TopLevel = TopLevH; + int fEqualLevel = 0; + + DdNode * bVarTop; + DdNode * bSuppSubract; + + + if ( TopLevL < TopLevH ) + { + pHigher = pLR; + pLower = pHR; + TopLevel = TopLevL; + } + else if ( TopLevL > TopLevH ) + { + pHigher = pHR; + pLower = pLR; + } + else + fEqualLevel = 1; + assert( TopLevel != CUDD_CONST_INDEX ); + + + // find the currently top variable in the decomposition lists + bVarTop = dd->vars[dd->invperm[TopLevel]]; + + if ( !fEqualLevel ) + { + // find the lower support + DdNode * bSuppLower = (TopLevL < TopLevH)? SuppH_init: SuppL_init; + + // find the first component in pHigher + // whose support does not overlap with supp(Lower) + // and remember the previous component + int fPolarity; + Dsd_Node_t * pPrev = NULL; // the pointer to the component proceeding pCur + Dsd_Node_t * pCur = pHigher; // the first component not contained in supp(Lower) + while ( Extra_bddSuppOverlapping( dd, pCur->S, bSuppLower ) ) + { // get the next component + pPrev = pCur; + pCur = dsdKernelFindContainingComponent( pDsdMan, pCur, bVarTop, &fPolarity ); + }; + + // look for the possibility to subtract more than one component + if ( pPrev == NULL || pPrev->Type == DSD_NODE_PRIME ) + { // if there is no previous component, or if the previous component is PRIME + // there is no way to subtract more than one component + + // add the new decomposition entry (it is already regular) + pThis->pDecs[ nEntries++ ] = pCur; + // assign the support to be subtracted from both components + bSuppSubract = pCur->S; + } + else // all other types + { + // go through the decomposition list of pPrev and find components + // whose support does not overlap with supp(Lower) + + static Dsd_Node_t * pNonOverlap[MAXINPUTS]; + int i, nNonOverlap = 0; + for ( i = 0; i < pPrev->nDecs; i++ ) + { + pTemp = Dsd_Regular( pPrev->pDecs[i] ); + if ( !Extra_bddSuppOverlapping( dd, pTemp->S, bSuppLower ) ) + pNonOverlap[ nNonOverlap++ ] = pPrev->pDecs[i]; + } + assert( nNonOverlap > 0 ); + + if ( nNonOverlap == 1 ) + { // one one component was found, which is the original one + assert( Dsd_Regular(pNonOverlap[0]) == pCur); + // add the new decomposition entry + pThis->pDecs[ nEntries++ ] = pCur; + // assign the support to be subtracted from both components + bSuppSubract = pCur->S; + } + else // more than one components was found + { + // find the OR (EXOR) of the non-overlapping components + DdNode * bCommF; + dsdKernelComputeSumOfComponents( pDsdMan, pNonOverlap, nNonOverlap, &bCommF, NULL, (int)(pPrev->Type==DSD_NODE_EXOR) ); + Cudd_Ref( bCommF ); + + // create a new gated + pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF ); + Cudd_RecursiveDeref(dd, bCommF); + // make it regular... it must be regular already + assert( !Dsd_IsComplement(pDENew) ); + + // add the new decomposition entry + pThis->pDecs[ nEntries++ ] = pDENew; + // assign the support to be subtracted from both components + bSuppSubract = pDENew->S; + } + } + + // subtract its support from the support of upper component + if ( TopLevL < TopLevH ) + { + SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ); Cudd_Ref( SuppL ); + Cudd_RecursiveDeref(dd, bTemp); + } + else + { + SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ); Cudd_Ref( SuppH ); + Cudd_RecursiveDeref(dd, bTemp); + } + } // end of if ( !fEqualLevel ) + else // if ( fEqualLevel ) -- they have the same top level var + { + static Dsd_Node_t * pMarkedLeft[MAXINPUTS]; // the pointers to the marked blocks + static char pMarkedPols[MAXINPUTS]; // polarities of the marked blocks + int nMarkedLeft = 0; + + int fPolarity = 0; + Dsd_Node_t * pTempL = pLR; + + int fPolarityCurH = 0; + Dsd_Node_t * pPrevH = NULL, * pCurH = pHR; + + int fPolarityCurL = 0; + Dsd_Node_t * pPrevL = NULL, * pCurL = pLR; // = pMarkedLeft[0]; + int index = 1; + + // set the new mark + s_Mark++; + + // go over the dec list of pL, mark all components that contain the given variable + assert( Extra_bddSuppContainVar( dd, pLR->S, bVarTop ) ); + assert( Extra_bddSuppContainVar( dd, pHR->S, bVarTop ) ); + do { + pTempL->Mark = s_Mark; + pMarkedLeft[ nMarkedLeft ] = pTempL; + pMarkedPols[ nMarkedLeft ] = fPolarity; + nMarkedLeft++; + } while ( pTempL = dsdKernelFindContainingComponent( pDsdMan, pTempL, bVarTop, &fPolarity ) ); + + // go over the dec list of pH, and find the component that is marked and the previos one + // (such component always exists, because they have common variables) + while ( pCurH->Mark != s_Mark ) + { + pPrevH = pCurH; + pCurH = dsdKernelFindContainingComponent( pDsdMan, pCurH, bVarTop, &fPolarityCurH ); + assert( pCurH ); + } + + // go through the first list once again and find + // the component proceeding the one marked found in the second list + while ( pCurL != pCurH ) + { + pPrevL = pCurL; + pCurL = pMarkedLeft[index]; + fPolarityCurL = pMarkedPols[index]; + index++; + } + + // look for the possibility to subtract more than one component + if ( !pPrevL || !pPrevH || pPrevL->Type != pPrevH->Type || pPrevL->Type == DSD_NODE_PRIME || fPolarityCurL != fPolarityCurH ) + { // there is no way to extract more than one + pThis->pDecs[ nEntries++ ] = pCurH; + // assign the support to be subtracted from both components + bSuppSubract = pCurH->S; + } + else + { + // find the equal components in two decomposition lists + Dsd_Node_t ** pCommon, * pLastDiffL = NULL, * pLastDiffH = NULL; + int nCommon = dsdKernelFindCommonComponents( pDsdMan, pPrevL, pPrevH, &pCommon, &pLastDiffL, &pLastDiffH ); + + if ( nCommon == 0 || nCommon == 1 ) + { // one one component was found, which is the original one + // assert( Dsd_Regular(pCommon[0]) == pCurL); + // add the new decomposition entry + pThis->pDecs[ nEntries++ ] = pCurL; + // assign the support to be subtracted from both components + bSuppSubract = pCurL->S; + } + else // more than one components was found + { + // find the OR (EXOR) of the non-overlapping components + DdNode * bCommF; + dsdKernelComputeSumOfComponents( pDsdMan, pCommon, nCommon, &bCommF, NULL, (int)(pPrevL->Type==DSD_NODE_EXOR) ); + Cudd_Ref( bCommF ); + + pDENew = dsdKernelDecompose_rec( pDsdMan, bCommF ); + assert( !Dsd_IsComplement(pDENew) ); // cannot be complemented because of construction + Cudd_RecursiveDeref( dd, bCommF ); + + // add the new decomposition entry + pThis->pDecs[ nEntries++ ] = pDENew; + + // assign the support to be subtracted from both components + bSuppSubract = pDENew->S; + } + } + + SuppL = Cudd_bddExistAbstract( dd, bTemp = SuppL, bSuppSubract ), Cudd_Ref( SuppL ); + Cudd_RecursiveDeref(dd, bTemp); + + SuppH = Cudd_bddExistAbstract( dd, bTemp = SuppH, bSuppSubract ), Cudd_Ref( SuppH ); + Cudd_RecursiveDeref(dd, bTemp); + + } // end of if ( fEqualLevel ) + + } // end of decomposition list comparison + Cudd_RecursiveDeref( dd, SuppL ); + Cudd_RecursiveDeref( dd, SuppH ); + + } + + // check that the estimation of the number of entries was okay + assert( nEntries <= nEntriesMax ); + +// if ( nEntries != Extra_bddSuppSize(dd, bSuppNew) ) +// s_Case5++; + + // update the number of entries in the new decomposition list + pThis->nDecs = nEntries; + } +//} +EXIT: + + { + // if the component created is complemented, it represents a function without complement + // therefore, as it is, without complement, it should recieve the complemented function + Dsd_Node_t * pThisR = Dsd_Regular( pThis ); + assert( pThisR->G == NULL ); + assert( pThisR->S == NULL ); + + if ( pThisR == pThis ) // set regular function + pThisR->G = bF; + else // set complemented function + pThisR->G = Cudd_Not(bF); + Cudd_Ref(bF); // reference the function in the component + + assert( bSuppNew ); + pThisR->S = bSuppNew; // takes the reference from the new support + if ( st_insert( pDsdMan->Table, (char*)bF, (char*)pThis ) ) + { + assert( 0 ); + } + s_CacheEntries++; + + +/* + if ( dsdKernelVerifyDecomposition(dd, pThis) == 0 ) + { + // write the function, for which verification does not work + cout << endl << "Internal verification failed!"" ); + + // create the variable mask + static int s_pVarMask[MAXINPUTS]; + int nInputCounter = 0; + + Cudd_SupportArray( dd, bF, s_pVarMask ); + int k; + for ( k = 0; k < dd->size; k++ ) + if ( s_pVarMask[k] ) + nInputCounter++; + + cout << endl << "The problem function is "" ); + + DdNode * zNewFunc = Cudd_zddIsopCover( dd, bF, bF ); Cudd_Ref( zNewFunc ); + cuddWriteFunctionSop( stdout, dd, zNewFunc, -1, dd->size, "1", s_pVarMask ); + Cudd_RecursiveDerefZdd( dd, zNewFunc ); + } +*/ + + } + + Depth--; + return Dsd_NotCond( pThis, fCompF ); +} + + +//////////////////////////////////////////////////////////////////////// +/// OTHER FUNCTIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Finds the corresponding decomposition entry.] + + Description [This function returns the non-complemented pointer to the + DecEntry of that component which contains the given variable in its + support, or NULL if no such component exists] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dsd_Node_t * dsdKernelFindContainingComponent( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pWhere, DdNode * Var, int * fPolarity ) + +{ + Dsd_Node_t * pTemp; + int i; + +// assert( !Dsd_IsComplement( pWhere ) ); +// assert( Extra_bddSuppContainVar( pDsdMan->dd, pWhere->S, Var ) ); + + if ( pWhere->nDecs == 1 ) + return NULL; + + for( i = 0; i < pWhere->nDecs; i++ ) + { + pTemp = Dsd_Regular( pWhere->pDecs[i] ); + if ( Extra_bddSuppContainVar( pDsdMan->dd, pTemp->S, Var ) ) + { + *fPolarity = (int)( pTemp != pWhere->pDecs[i] ); + return pTemp; + } + } + assert( 0 ); + return NULL; +} + +/**Function************************************************************* + + Synopsis [Find the common decomposition components.] + + Description [This function determines the common components. It counts + the number of common components in the decomposition lists of pL and pH + and returns their number and the lists of common components. It assumes + that pL and pH are regular pointers. It retuns also the pointers to the + last different components encountered in pL and pH.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int dsdKernelFindCommonComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t *** pCommon, Dsd_Node_t ** pLastDiffL, Dsd_Node_t ** pLastDiffH ) +{ + static Dsd_Node_t * Common[MAXINPUTS]; + int nCommon = 0; + + // pointers to the current decomposition entries + Dsd_Node_t * pLcur; + Dsd_Node_t * pHcur; + + // the pointers to their supports + DdNode * bSLcur; + DdNode * bSHcur; + + // the top variable in the supports + int TopVar; + + // the indices running through the components + int iCurL = 0; + int iCurH = 0; + while ( iCurL < pL->nDecs && iCurH < pH->nDecs ) + { // both did not run out + + pLcur = Dsd_Regular(pL->pDecs[iCurL]); + pHcur = Dsd_Regular(pH->pDecs[iCurH]); + + bSLcur = pLcur->S; + bSHcur = pHcur->S; + + // find out what component is higher in the BDD + if ( pDsdMan->dd->perm[bSLcur->index] < pDsdMan->dd->perm[bSHcur->index] ) + TopVar = bSLcur->index; + else + TopVar = bSHcur->index; + + if ( TopVar == bSLcur->index && TopVar == bSHcur->index ) + { + // the components may be equal - should match exactly! + if ( pL->pDecs[iCurL] == pH->pDecs[iCurH] ) + Common[nCommon++] = pL->pDecs[iCurL]; + else + { + *pLastDiffL = pL->pDecs[iCurL]; + *pLastDiffH = pH->pDecs[iCurH]; + } + + // skip both + iCurL++; + iCurH++; + } + else if ( TopVar == bSLcur->index ) + { // the components cannot be equal + // skip the top-most one + *pLastDiffL = pL->pDecs[iCurL++]; + } + else // if ( TopVar == bSHcur->index ) + { // the components cannot be equal + // skip the top-most one + *pLastDiffH = pH->pDecs[iCurH++]; + } + } + + // if one of the lists still has components, write the first one down + if ( iCurL < pL->nDecs ) + *pLastDiffL = pL->pDecs[iCurL]; + + if ( iCurH < pH->nDecs ) + *pLastDiffH = pH->pDecs[iCurH]; + + // return the pointer to the array + *pCommon = Common; + // return the number of common components + return nCommon; +} + +/**Function************************************************************* + + Synopsis [Computes the sum (OR or EXOR) of the functions of the components.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void dsdKernelComputeSumOfComponents( Dsd_Manager_t * pDsdMan, Dsd_Node_t ** pCommon, int nCommon, DdNode ** pCompF, DdNode ** pCompS, int fExor ) +{ + DdManager * dd = pDsdMan->dd; + DdNode * bF, * bS, * bFadd, * bTemp; + Dsd_Node_t * pDE, * pDER; + int i; + + // start the function + bF = b0; Cudd_Ref( bF ); + // start the support + if ( pCompS ) + bS = b1, Cudd_Ref( bS ); + + assert( nCommon > 0 ); + for ( i = 0; i < nCommon; i++ ) + { + pDE = pCommon[i]; + pDER = Dsd_Regular( pDE ); + bFadd = (pDE != pDER)? Cudd_Not(pDER->G): pDER->G; + // add to the function + if ( fExor ) + bF = Cudd_bddXor( dd, bTemp = bF, bFadd ); + else + bF = Cudd_bddOr( dd, bTemp = bF, bFadd ); + Cudd_Ref( bF ); + Cudd_RecursiveDeref( dd, bTemp ); + if ( pCompS ) + { + // add to the support + bS = Cudd_bddAnd( dd, bTemp = bS, pDER->S ); Cudd_Ref( bS ); + Cudd_RecursiveDeref( dd, bTemp ); + } + } + // return the function + Cudd_Deref( bF ); + *pCompF = bF; + + // return the support + if ( pCompS ) + Cudd_Deref( bS ), *pCompS = bS; +} + +/**Function************************************************************* + + Synopsis [Checks support containment of the decomposition components.] + + Description [This function returns 1 if support of one component is contained + in that of another. In this case, pLarge (pSmall) is assigned to point to the + larger (smaller) support. If the supports are identical return 0, and does not + assign the components.] +] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int dsdKernelCheckContainment( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pL, Dsd_Node_t * pH, Dsd_Node_t ** pLarge, Dsd_Node_t ** pSmall ) +{ + DdManager * dd = pDsdMan->dd; + DdNode * bSuppLarge, * bSuppSmall; + int RetValue; + + RetValue = Extra_bddSuppCheckContainment( dd, pL->S, pH->S, &bSuppLarge, &bSuppSmall ); + + if ( RetValue == 0 ) + return 0; + + if ( pH->S == bSuppLarge ) + { + *pLarge = pH; + *pSmall = pL; + } + else // if ( pL->S == bSuppLarge ) + { + *pLarge = pL; + *pSmall = pH; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Copies the list of components plus one.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void dsdKernelCopyListPlusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize ) +{ + int i; + assert( nListSize+1 == p->nDecs ); + p->pDecs[0] = First; + for( i = 0; i < nListSize; i++ ) + p->pDecs[i+1] = ppList[i]; +} + +/**Function************************************************************* + + Synopsis [Copies the list of components plus one, and skips one.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void dsdKernelCopyListPlusOneMinusOne( Dsd_Node_t * p, Dsd_Node_t * First, Dsd_Node_t ** ppList, int nListSize, int iSkipped ) +{ + int i, Counter; + assert( nListSize == p->nDecs ); + p->pDecs[0] = First; + for( i = 0, Counter = 1; i < nListSize; i++ ) + if ( i != iSkipped ) + p->pDecs[Counter++] = ppList[i]; +} + +/**Function************************************************************* + + Synopsis [Debugging procedure to compute the functionality of the decomposed structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int dsdKernelVerifyDecomposition( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pDE ) +{ + DdManager * dd = pDsdMan->dd; + Dsd_Node_t * pR = Dsd_Regular(pDE); + int fCompP = (int)( pDE != pR ); + int RetValue; + + DdNode * bRes; + if ( pR->Type == DSD_NODE_CONST1 ) + bRes = b1; + else if ( pR->Type == DSD_NODE_BUF ) + bRes = pR->G; + else if ( pR->Type == DSD_NODE_OR || pR->Type == DSD_NODE_EXOR ) + dsdKernelComputeSumOfComponents( pDsdMan, pR->pDecs, pR->nDecs, &bRes, NULL, (int)(pR->Type == DSD_NODE_EXOR) ); + else if ( pR->Type == DSD_NODE_PRIME ) + { + int i; + static DdNode * bGVars[MAXINPUTS]; + // transform the function of this block, so that it depended on inputs + // corresponding to the formal inputs + DdNode * bNewFunc = Dsd_TreeGetPrimeFunctionOld( dd, pR, 1 ); Cudd_Ref( bNewFunc ); + + // compose this function with the inputs + // create the elementary permutation + for ( i = 0; i < dd->size; i++ ) + bGVars[i] = dd->vars[i]; + + // assign functions to be composed + for ( i = 0; i < pR->nDecs; i++ ) + bGVars[dd->invperm[i]] = pR->pDecs[i]->G; + + // perform the composition + bRes = Cudd_bddVectorCompose( dd, bNewFunc, bGVars ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bNewFunc ); + + ///////////////////////////////////////////////////////// + RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) ); + ///////////////////////////////////////////////////////// + Cudd_Deref( bRes ); + } + else + { + assert(0); + } + + Cudd_Ref( bRes ); + RetValue = (int)( bRes == pR->G );//|| bRes == Cudd_Not(pR->G) ); + Cudd_RecursiveDeref( dd, bRes ); + return RetValue; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// |