/**Function******************************************************************** Synopsis [Computes the classical symmetry information for the function.] Description [Uses the naive way of comparing cofactors.] SideEffects [] SeeAlso [] ******************************************************************************/ Extra_SymmInfo_t * Extra_SymmPairsComputeNaive( DdManager * dd, DdNode * bFunc ) { DdNode * bSupp, * bTemp; int nSuppSize; Extra_SymmInfo_t * p; int i, k; // compute the support bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); nSuppSize = Extra_bddSuppSize( dd, bSupp ); //printf( "Support = %d. ", nSuppSize ); //Extra_bddPrint( dd, bSupp ); //printf( "%d ", nSuppSize ); // allocate the storage for symmetry info p = Extra_SymmPairsAllocate( nSuppSize ); // assign the variables p->nVarsMax = dd->size; for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) p->pVars[i] = bTemp->index; // go through the candidate pairs and check using Idea1 for ( i = 0; i < nSuppSize; i++ ) for ( k = i+1; k < nSuppSize; k++ ) { p->pSymms[k][i] = p->pSymms[i][k] = Extra_bddCheckVarsSymmetricNaive( dd, bFunc, p->pVars[i], p->pVars[k] ); if ( p->pSymms[i][k] ) p->nSymms++; } Cudd_RecursiveDeref( dd, bSupp ); return p; } /* end of Extra_SymmPairsComputeNaive */
/**Function******************************************************************** Synopsis [Creates the symmetry information structure from ZDD.] Description [ZDD representation of symmetries is the set of cubes, each of which has two variables in the positive polarity. These variables correspond to the symmetric variable pair.] SideEffects [] SeeAlso [] ******************************************************************************/ Extra_SymmInfo_t * Extra_SymmPairsCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp ) { int i; int nSuppSize; Extra_SymmInfo_t * p; int * pMapVars2Nums; DdNode * bTemp; DdNode * zSet, * zCube, * zTemp; int iVar1, iVar2; nSuppSize = Extra_bddSuppSize( dd, bSupp ); // allocate and clean the storage for symmetry info p = Extra_SymmPairsAllocate( nSuppSize ); // allocate the storage for the temporary map pMapVars2Nums = ABC_ALLOC( int, dd->size ); memset( pMapVars2Nums, 0, dd->size * sizeof(int) ); // assign the variables p->nVarsMax = dd->size; // p->nNodes = Cudd_DagSize( zPairs ); p->nNodes = 0; for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) { p->pVars[i] = bTemp->index; pMapVars2Nums[bTemp->index] = i; } // write the symmetry info into the structure zSet = zPairs; Cudd_Ref( zSet ); while ( zSet != z0 ) { // get the next cube zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube ); // add these two variables to the data structure assert( cuddT( cuddT(zCube) ) == z1 ); iVar1 = zCube->index/2; iVar2 = cuddT(zCube)->index/2; if ( pMapVars2Nums[iVar1] < pMapVars2Nums[iVar2] ) p->pSymms[ pMapVars2Nums[iVar1] ][ pMapVars2Nums[iVar2] ] = 1; else p->pSymms[ pMapVars2Nums[iVar2] ][ pMapVars2Nums[iVar1] ] = 1; // count the symmetric pairs p->nSymms ++; // update the cuver and deref the cube zSet = Cudd_zddDiff( dd, zTemp = zSet, zCube ); Cudd_Ref( zSet ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zCube ); } // for each cube Cudd_RecursiveDerefZdd( dd, zSet ); ABC_FREE( pMapVars2Nums ); return p; } /* end of Extra_SymmPairsCreateFromZdd */
/**Function************************************************************* Synopsis [Merges two nodes.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Extra_ImageNode_t * Extra_CombineTwoNodes( DdManager * dd, DdNode * bCube, Extra_ImageNode_t * pNode1, Extra_ImageNode_t * pNode2 ) { Extra_ImageNode_t * pNode; Extra_ImagePart_t * pPart; // create a new partition pPart = ABC_ALLOC( Extra_ImagePart_t, 1 ); memset( pPart, 0, sizeof(Extra_ImagePart_t) ); // create the function pPart->bFunc = Cudd_bddAndAbstract( dd, pNode1->pPart->bFunc, pNode2->pPart->bFunc, bCube ); Cudd_Ref( pPart->bFunc ); // update the support the partition pPart->bSupp = Cudd_bddAndAbstract( dd, pNode1->pPart->bSupp, pNode2->pPart->bSupp, bCube ); Cudd_Ref( pPart->bSupp ); // update the numbers pPart->nSupp = Extra_bddSuppSize( dd, pPart->bSupp ); pPart->nNodes = Cudd_DagSize( pPart->bFunc ); pPart->iPart = -1; /* ABC_PRB( dd, pNode1->pPart->bSupp ); ABC_PRB( dd, pNode2->pPart->bSupp ); ABC_PRB( dd, pPart->bSupp ); */ // create a new node pNode = ABC_ALLOC( Extra_ImageNode_t, 1 ); memset( pNode, 0, sizeof(Extra_ImageNode_t) ); pNode->dd = dd; pNode->pPart = pPart; pNode->pNode1 = pNode1; pNode->pNode2 = pNode2; // compute the image pNode->bImage = Cudd_bddAndAbstract( dd, pNode1->bImage, pNode2->bImage, bCube ); Cudd_Ref( pNode->bImage ); // save the cube if ( bCube != b1 ) { pNode->bCube = bCube; Cudd_Ref( bCube ); } return pNode; }
/**Function******************************************************************** Synopsis [Performs a recursive step of Extra_SymmPairsCompute.] Description [Returns the set of symmetric variable pairs represented as a set of two-literal ZDD cubes. Both variables always appear in the positive polarity in the cubes. This function works without building new BDD nodes. Some relatively small number of ZDD nodes may be built to ensure proper bookkeeping of the symmetry information.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraZddSymmPairsCompute( DdManager * dd, /* the manager */ DdNode * bFunc, /* the function whose symmetries are computed */ DdNode * bVars ) /* the set of variables on which this function depends */ { DdNode * zRes; DdNode * bFR = Cudd_Regular(bFunc); if ( cuddIsConstant(bFR) ) { int nVars, i; // determine how many vars are in the bVars nVars = Extra_bddSuppSize( dd, bVars ); if ( nVars < 2 ) return z0; else { DdNode * bVarsK; // create the BDD bVarsK corresponding to K = 2; bVarsK = bVars; for ( i = 0; i < nVars-2; i++ ) bVarsK = cuddT( bVarsK ); return extraZddTuplesFromBdd( dd, bVarsK, bVars ); } } assert( bVars != b1 ); if ( (zRes = cuddCacheLookup2Zdd(dd, extraZddSymmPairsCompute, bFunc, bVars)) ) return zRes; else { DdNode * zRes0, * zRes1; DdNode * zTemp, * zPlus, * zSymmVars; DdNode * bF0, * bF1; DdNode * bVarsNew; int nVarsExtra; int LevelF; // every variable in bF should be also in bVars, therefore LevelF cannot be above LevelV // if LevelF is below LevelV, scroll through the vars in bVars to the same level as F // count how many extra vars are there in bVars nVarsExtra = 0; LevelF = dd->perm[bFR->index]; for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) nVarsExtra++; // the indexes (level) of variables should be synchronized now assert( bFR->index == bVarsNew->index ); // cofactor the function if ( bFR != bFunc ) // bFunc is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } // solve subproblems zRes0 = extraZddSymmPairsCompute( dd, bF0, cuddT(bVarsNew) ); if ( zRes0 == NULL ) return NULL; cuddRef( zRes0 ); // if there is no symmetries in the negative cofactor // there is no need to test the positive cofactor if ( zRes0 == z0 ) zRes = zRes0; // zRes takes reference else { zRes1 = extraZddSymmPairsCompute( dd, bF1, cuddT(bVarsNew) ); if ( zRes1 == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); return NULL; } cuddRef( zRes1 ); // only those variables are pair-wise symmetric // that are pair-wise symmetric in both cofactors // therefore, intersect the solutions zRes = cuddZddIntersect( dd, zRes0, zRes1 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); } // consider the current top-most variable and find all the vars // that are pairwise symmetric with it // these variables are returned as a set of ZDD singletons zSymmVars = extraZddGetSymmetricVars( dd, bF1, bF0, cuddT(bVarsNew) ); if ( zSymmVars == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zSymmVars ); // attach the topmost variable to the set, to get the variable pairs // use the positive polarity ZDD variable for the purpose // there is no need to do so, if zSymmVars is empty if ( zSymmVars == z0 ) Cudd_RecursiveDerefZdd( dd, zSymmVars ); else { zPlus = cuddZddGetNode( dd, 2*bFR->index, zSymmVars, z0 ); if ( zPlus == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); Cudd_RecursiveDerefZdd( dd, zSymmVars ); return NULL; } cuddRef( zPlus ); cuddDeref( zSymmVars ); // add these variable pairs to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } // only zRes is referenced at this point // if we skipped some variables, these variables cannot be symmetric with // any variables that are currently in the support of bF, but they can be // symmetric with the variables that are in bVars but not in the support of bF if ( nVarsExtra ) { // it is possible to improve this step: // (1) there is no need to enter here, if nVarsExtra < 2 // create the set of topmost nVarsExtra in bVars DdNode * bVarsExtra; int nVars; // remove from bVars all the variable that are in the support of bFunc bVarsExtra = extraBddReduceVarSet( dd, bVars, bFunc ); if ( bVarsExtra == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( bVarsExtra ); // determine how many vars are in the bVarsExtra nVars = Extra_bddSuppSize( dd, bVarsExtra ); if ( nVars < 2 ) { Cudd_RecursiveDeref( dd, bVarsExtra ); } else { int i; DdNode * bVarsK; // create the BDD bVarsK corresponding to K = 2; bVarsK = bVarsExtra; for ( i = 0; i < nVars-2; i++ ) bVarsK = cuddT( bVarsK ); // create the 2 variable tuples zPlus = extraZddTuplesFromBdd( dd, bVarsK, bVarsExtra ); if ( zPlus == NULL ) { Cudd_RecursiveDeref( dd, bVarsExtra ); Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zPlus ); Cudd_RecursiveDeref( dd, bVarsExtra ); // add these to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } } cuddDeref( zRes ); /* insert the result into cache */ cuddCacheInsert2(dd, extraZddSymmPairsCompute, bFunc, bVars, zRes); return zRes; } } /* end of extraZddSymmPairsCompute */
/**Function************************************************************* Synopsis [Builds the tree.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Extra_BuildTreeNode( DdManager * dd, int nNodes, Extra_ImageNode_t ** pNodes, int nVars, Extra_ImageVar_t ** pVars ) { Extra_ImageNode_t * pNode1, * pNode2; Extra_ImageVar_t * pVar; Extra_ImageNode_t * pNode; DdNode * bCube, * bTemp, * bSuppTemp, * bParts; int iNode1, iNode2; int iVarBest, nSupp, v; // find the best variable iVarBest = Extra_FindBestVariable( dd, nNodes, pNodes, nVars, pVars ); if ( iVarBest == -1 ) return 0; pVar = pVars[iVarBest]; // this var cannot appear in one partition only nSupp = Extra_bddSuppSize( dd, pVar->bParts ); assert( nSupp == pVar->nParts ); assert( nSupp != 1 ); // if it appears in only two partitions, quantify it if ( pVar->nParts == 2 ) { // get the nodes iNode1 = pVar->bParts->index; iNode2 = cuddT(pVar->bParts)->index; pNode1 = pNodes[iNode1]; pNode2 = pNodes[iNode2]; // get the quantification cube bCube = dd->vars[pVar->iNum]; Cudd_Ref( bCube ); // add the variables that appear only in these partitions for ( v = 0; v < nVars; v++ ) if ( pVars[v] && v != iVarBest && pVars[v]->bParts == pVars[iVarBest]->bParts ) { // add this var bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[pVars[v]->iNum] ); Cudd_Ref( bCube ); Cudd_RecursiveDeref( dd, bTemp ); // clean this var Cudd_RecursiveDeref( dd, pVars[v]->bParts ); ABC_FREE( pVars[v] ); } // clean the best var Cudd_RecursiveDeref( dd, pVars[iVarBest]->bParts ); ABC_FREE( pVars[iVarBest] ); // combines two nodes pNode = Extra_CombineTwoNodes( dd, bCube, pNode1, pNode2 ); Cudd_RecursiveDeref( dd, bCube ); } else // if ( pVar->nParts > 2 ) { // find two smallest BDDs that have this var Extra_FindBestPartitions( dd, pVar->bParts, nNodes, pNodes, &iNode1, &iNode2 ); pNode1 = pNodes[iNode1]; pNode2 = pNodes[iNode2]; // it is not possible that a var appears only in these two // otherwise, it would have a different cost bParts = Cudd_bddAnd( dd, dd->vars[iNode1], dd->vars[iNode2] ); Cudd_Ref( bParts ); for ( v = 0; v < nVars; v++ ) if ( pVars[v] && pVars[v]->bParts == bParts ) assert( 0 ); Cudd_RecursiveDeref( dd, bParts ); // combines two nodes pNode = Extra_CombineTwoNodes( dd, b1, pNode1, pNode2 ); } // clean the old nodes pNodes[iNode1] = pNode; pNodes[iNode2] = NULL; // update the variables that appear in pNode[iNode2] for ( bSuppTemp = pNode2->pPart->bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) ) { pVar = pVars[bSuppTemp->index]; if ( pVar == NULL ) // this variable is not be quantified continue; // quantify this var assert( Cudd_bddLeq( dd, pVar->bParts, dd->vars[iNode2] ) ); pVar->bParts = Cudd_bddExistAbstract( dd, bTemp = pVar->bParts, dd->vars[iNode2] ); Cudd_Ref( pVar->bParts ); Cudd_RecursiveDeref( dd, bTemp ); // add the new var pVar->bParts = Cudd_bddAnd( dd, bTemp = pVar->bParts, dd->vars[iNode1] ); Cudd_Ref( pVar->bParts ); Cudd_RecursiveDeref( dd, bTemp ); // update the score pVar->nParts = Extra_bddSuppSize( dd, pVar->bParts ); } return 1; }