From 24f2a120f2203acc8038ccce4e8dd141564a7a04 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 24 Aug 2015 21:09:50 -0700 Subject: Changes to be able to compile ABC without CUDD. --- src/bdd/bbr/bbr.h | 93 ++ src/bdd/bbr/bbrCex.c | 172 +++ src/bdd/bbr/bbrImage.c | 1327 +++++++++++++++++++++++ src/bdd/bbr/bbrNtbdd.c | 218 ++++ src/bdd/bbr/bbrReach.c | 615 +++++++++++ src/bdd/bbr/bbr_.c | 52 + src/bdd/bbr/module.make | 4 + src/bdd/extrab/extraBdd.h | 317 ++++++ src/bdd/extrab/extraBddAuto.c | 1563 +++++++++++++++++++++++++++ src/bdd/extrab/extraBddCas.c | 1235 +++++++++++++++++++++ src/bdd/extrab/extraBddImage.c | 1162 ++++++++++++++++++++ src/bdd/extrab/extraBddKmap.c | 876 +++++++++++++++ src/bdd/extrab/extraBddMisc.c | 2342 ++++++++++++++++++++++++++++++++++++++++ src/bdd/extrab/extraBddSymm.c | 1474 +++++++++++++++++++++++++ src/bdd/extrab/extraBddTime.c | 660 +++++++++++ src/bdd/extrab/extraBddUnate.c | 646 +++++++++++ src/bdd/extrab/module.make | 8 + src/bdd/llb/llb.c | 52 + src/bdd/llb/llb.h | 96 ++ src/bdd/llb/llb1Cluster.c | 356 ++++++ src/bdd/llb/llb1Constr.c | 313 ++++++ src/bdd/llb/llb1Core.c | 222 ++++ src/bdd/llb/llb1Group.c | 474 ++++++++ src/bdd/llb/llb1Hint.c | 226 ++++ src/bdd/llb/llb1Man.c | 218 ++++ src/bdd/llb/llb1Matrix.c | 430 ++++++++ src/bdd/llb/llb1Pivot.c | 254 +++++ src/bdd/llb/llb1Reach.c | 904 ++++++++++++++++ src/bdd/llb/llb1Sched.c | 257 +++++ src/bdd/llb/llb2Bad.c | 138 +++ src/bdd/llb/llb2Core.c | 777 +++++++++++++ src/bdd/llb/llb2Driver.c | 222 ++++ src/bdd/llb/llb2Dump.c | 104 ++ src/bdd/llb/llb2Flow.c | 1376 +++++++++++++++++++++++ src/bdd/llb/llb2Image.c | 482 +++++++++ src/bdd/llb/llb3Image.c | 1095 +++++++++++++++++++ src/bdd/llb/llb3Nonlin.c | 872 +++++++++++++++ src/bdd/llb/llb4Cex.c | 320 ++++++ src/bdd/llb/llb4Cluster.c | 452 ++++++++ src/bdd/llb/llb4Image.c | 863 +++++++++++++++ src/bdd/llb/llb4Map.c | 123 +++ src/bdd/llb/llb4Nonlin.c | 1185 ++++++++++++++++++++ src/bdd/llb/llb4Sweep.c | 589 ++++++++++ src/bdd/llb/llbInt.h | 212 ++++ src/bdd/llb/module.make | 22 + src/bdd/parse/module.make | 3 - src/bdd/parse/parse.h | 62 -- src/bdd/parse/parseCore.c | 536 --------- src/bdd/parse/parseEqn.c | 358 ------ src/bdd/parse/parseInt.h | 79 -- src/bdd/parse/parseStack.c | 248 ----- 51 files changed, 25398 insertions(+), 1286 deletions(-) create mode 100644 src/bdd/bbr/bbr.h create mode 100644 src/bdd/bbr/bbrCex.c create mode 100644 src/bdd/bbr/bbrImage.c create mode 100644 src/bdd/bbr/bbrNtbdd.c create mode 100644 src/bdd/bbr/bbrReach.c create mode 100644 src/bdd/bbr/bbr_.c create mode 100644 src/bdd/bbr/module.make create mode 100644 src/bdd/extrab/extraBdd.h create mode 100644 src/bdd/extrab/extraBddAuto.c create mode 100644 src/bdd/extrab/extraBddCas.c create mode 100644 src/bdd/extrab/extraBddImage.c create mode 100644 src/bdd/extrab/extraBddKmap.c create mode 100644 src/bdd/extrab/extraBddMisc.c create mode 100644 src/bdd/extrab/extraBddSymm.c create mode 100644 src/bdd/extrab/extraBddTime.c create mode 100644 src/bdd/extrab/extraBddUnate.c create mode 100644 src/bdd/extrab/module.make create mode 100644 src/bdd/llb/llb.c create mode 100644 src/bdd/llb/llb.h create mode 100644 src/bdd/llb/llb1Cluster.c create mode 100644 src/bdd/llb/llb1Constr.c create mode 100644 src/bdd/llb/llb1Core.c create mode 100644 src/bdd/llb/llb1Group.c create mode 100644 src/bdd/llb/llb1Hint.c create mode 100644 src/bdd/llb/llb1Man.c create mode 100644 src/bdd/llb/llb1Matrix.c create mode 100644 src/bdd/llb/llb1Pivot.c create mode 100644 src/bdd/llb/llb1Reach.c create mode 100644 src/bdd/llb/llb1Sched.c create mode 100644 src/bdd/llb/llb2Bad.c create mode 100644 src/bdd/llb/llb2Core.c create mode 100644 src/bdd/llb/llb2Driver.c create mode 100644 src/bdd/llb/llb2Dump.c create mode 100644 src/bdd/llb/llb2Flow.c create mode 100644 src/bdd/llb/llb2Image.c create mode 100644 src/bdd/llb/llb3Image.c create mode 100644 src/bdd/llb/llb3Nonlin.c create mode 100644 src/bdd/llb/llb4Cex.c create mode 100644 src/bdd/llb/llb4Cluster.c create mode 100644 src/bdd/llb/llb4Image.c create mode 100644 src/bdd/llb/llb4Map.c create mode 100644 src/bdd/llb/llb4Nonlin.c create mode 100644 src/bdd/llb/llb4Sweep.c create mode 100644 src/bdd/llb/llbInt.h create mode 100644 src/bdd/llb/module.make delete mode 100644 src/bdd/parse/module.make delete mode 100644 src/bdd/parse/parse.h delete mode 100644 src/bdd/parse/parseCore.c delete mode 100644 src/bdd/parse/parseEqn.c delete mode 100644 src/bdd/parse/parseInt.h delete mode 100644 src/bdd/parse/parseStack.c (limited to 'src/bdd') diff --git a/src/bdd/bbr/bbr.h b/src/bdd/bbr/bbr.h new file mode 100644 index 00000000..1db638e8 --- /dev/null +++ b/src/bdd/bbr/bbr.h @@ -0,0 +1,93 @@ +/**CFile**************************************************************** + + FileName [bbr.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability analysis.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: bbr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef ABC__aig__bbr__bbr_h +#define ABC__aig__bbr__bbr_h + + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "aig/aig/aig.h" +#include "aig/saig/saig.h" +#include "bdd/cudd/cuddInt.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + + + +ABC_NAMESPACE_HEADER_START + + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline DdNode * Aig_ObjGlobalBdd( Aig_Obj_t * pObj ) { return (DdNode *)pObj->pData; } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== bbrImage.c ==========================================================*/ +typedef struct Bbr_ImageTree_t_ Bbr_ImageTree_t; +extern Bbr_ImageTree_t * Bbr_bddImageStart( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int nBddMax, int fVerbose ); +extern DdNode * Bbr_bddImageCompute( Bbr_ImageTree_t * pTree, DdNode * bCare ); +extern void Bbr_bddImageTreeDelete( Bbr_ImageTree_t * pTree ); +extern DdNode * Bbr_bddImageRead( Bbr_ImageTree_t * pTree ); +typedef struct Bbr_ImageTree2_t_ Bbr_ImageTree2_t; +extern Bbr_ImageTree2_t * Bbr_bddImageStart2( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int fVerbose ); +extern DdNode * Bbr_bddImageCompute2( Bbr_ImageTree2_t * pTree, DdNode * bCare ); +extern void Bbr_bddImageTreeDelete2( Bbr_ImageTree2_t * pTree ); +extern DdNode * Bbr_bddImageRead2( Bbr_ImageTree2_t * pTree ); +/*=== bbrNtbdd.c ==========================================================*/ +extern void Aig_ManFreeGlobalBdds( Aig_Man_t * p, DdManager * dd ); +extern int Aig_ManSizeOfGlobalBdds( Aig_Man_t * p ); +extern DdManager * Aig_ManComputeGlobalBdds( Aig_Man_t * p, int nBddSizeMax, int fDropInternal, int fReorder, int fVerbose ); +/*=== bbrReach.c ==========================================================*/ +extern int Aig_ManVerifyUsingBdds( Aig_Man_t * p, Saig_ParBbr_t * pPars ); +extern void Bbr_ManSetDefaultParams( Saig_ParBbr_t * p ); + + + +ABC_NAMESPACE_HEADER_END + + + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/bdd/bbr/bbrCex.c b/src/bdd/bbr/bbrCex.c new file mode 100644 index 00000000..31a46d61 --- /dev/null +++ b/src/bdd/bbr/bbrCex.c @@ -0,0 +1,172 @@ +/**CFile**************************************************************** + + FileName [bbrCex.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability analysis.] + + Synopsis [Procedures to derive a satisfiable counter-example.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: bbrCex.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bbr.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern DdNode * Bbr_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Derives the counter-example using the set of reached states.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Aig_ManVerifyUsingBddsCountExample( Aig_Man_t * p, DdManager * dd, + DdNode ** pbParts, Vec_Ptr_t * vOnionRings, DdNode * bCubeFirst, + int iOutput, int fVerbose, int fSilent ) +{ + Abc_Cex_t * pCex; + Aig_Obj_t * pObj; + Bbr_ImageTree_t * pTree; + DdNode * bCubeNs, * bState, * bImage; + DdNode * bTemp, * bVar, * bRing; + int i, v, RetValue, nPiOffset; + char * pValues; + abctime clk = Abc_Clock(); +//printf( "\nDeriving counter-example.\n" ); + + // allocate room for the counter-example + pCex = Abc_CexAlloc( Saig_ManRegNum(p), Saig_ManPiNum(p), Vec_PtrSize(vOnionRings)+1 ); + pCex->iFrame = Vec_PtrSize(vOnionRings); + pCex->iPo = iOutput; + nPiOffset = Saig_ManRegNum(p) + Saig_ManPiNum(p) * Vec_PtrSize(vOnionRings); + + // create the cube of NS variables + bCubeNs = Bbr_bddComputeRangeCube( dd, Saig_ManCiNum(p), Saig_ManCiNum(p)+Saig_ManRegNum(p) ); Cudd_Ref( bCubeNs ); + pTree = Bbr_bddImageStart( dd, bCubeNs, Saig_ManRegNum(p), pbParts, Saig_ManCiNum(p), dd->vars, 100000000, fVerbose ); + Cudd_RecursiveDeref( dd, bCubeNs ); + if ( pTree == NULL ) + { + if ( !fSilent ) + printf( "BDDs blew up during qualitification scheduling. " ); + return NULL; + } + + // allocate room for the cube + pValues = ABC_ALLOC( char, dd->size ); + + // get the last cube + RetValue = Cudd_bddPickOneCube( dd, bCubeFirst, pValues ); + assert( RetValue ); + + // write PIs of counter-example + Saig_ManForEachPi( p, pObj, i ) + if ( pValues[i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + nPiOffset -= Saig_ManPiNum(p); + + // write state in terms of NS variables + bState = (dd)->one; Cudd_Ref( bState ); + Saig_ManForEachLo( p, pObj, i ) + { + bVar = Cudd_NotCond( dd->vars[Saig_ManCiNum(p)+i], pValues[Saig_ManPiNum(p)+i] != 1 ); + bState = Cudd_bddAnd( dd, bTemp = bState, bVar ); Cudd_Ref( bState ); + Cudd_RecursiveDeref( dd, bTemp ); + } + + // perform backward analysis + Vec_PtrForEachEntryReverse( DdNode *, vOnionRings, bRing, v ) + { + // compute the next states + bImage = Bbr_bddImageCompute( pTree, bState ); + if ( bImage == NULL ) + { + Cudd_RecursiveDeref( dd, bState ); + if ( !fSilent ) + printf( "BDDs blew up during image computation. " ); + Bbr_bddImageTreeDelete( pTree ); + ABC_FREE( pValues ); + return NULL; + } + Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bState ); + + // intersect with the previous set + bImage = Cudd_bddAnd( dd, bTemp = bImage, bRing ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + + // find any assignment of the BDD + RetValue = Cudd_bddPickOneCube( dd, bImage, pValues ); + assert( RetValue ); + Cudd_RecursiveDeref( dd, bImage ); + + // write PIs of counter-example + Saig_ManForEachPi( p, pObj, i ) + if ( pValues[i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + nPiOffset -= Saig_ManPiNum(p); + + // check that we get the init state + if ( v == 0 ) + { + Saig_ManForEachLo( p, pObj, i ) + assert( pValues[Saig_ManPiNum(p)+i] == 0 ); + break; + } + + // write state in terms of NS variables + bState = (dd)->one; Cudd_Ref( bState ); + Saig_ManForEachLo( p, pObj, i ) + { + bVar = Cudd_NotCond( dd->vars[Saig_ManCiNum(p)+i], pValues[Saig_ManPiNum(p)+i] != 1 ); + bState = Cudd_bddAnd( dd, bTemp = bState, bVar ); Cudd_Ref( bState ); + Cudd_RecursiveDeref( dd, bTemp ); + } + } + // cleanup + Bbr_bddImageTreeDelete( pTree ); + ABC_FREE( pValues ); + // verify the counter example + if ( Vec_PtrSize(vOnionRings) < 1000 ) + { + RetValue = Saig_ManVerifyCex( p, pCex ); + if ( RetValue == 0 && !fSilent ) + printf( "Aig_ManVerifyUsingBdds(): Counter-example verification has FAILED.\n" ); + } + if ( fVerbose && !fSilent ) + { + ABC_PRT( "Counter-example generation time", Abc_Clock() - clk ); + } + return pCex; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/bbr/bbrImage.c b/src/bdd/bbr/bbrImage.c new file mode 100644 index 00000000..1ff3d0b6 --- /dev/null +++ b/src/bdd/bbr/bbrImage.c @@ -0,0 +1,1327 @@ +/**CFile**************************************************************** + + FileName [bbrImage.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability analysis.] + + Synopsis [Performs image computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: bbrImage.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bbr.h" +#include "bdd/mtr/mtr.h" + +ABC_NAMESPACE_IMPL_START + + +/* + The ideas implemented in this file are inspired by the paper: + Pankaj Chauhan, Edmund Clarke, Somesh Jha, Jim Kukula, Tom Shiple, + Helmut Veith, Dong Wang. Non-linear Quantification Scheduling in + Image Computation. ICCAD, 2001. +*/ + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +typedef struct Bbr_ImageNode_t_ Bbr_ImageNode_t; +typedef struct Bbr_ImagePart_t_ Bbr_ImagePart_t; +typedef struct Bbr_ImageVar_t_ Bbr_ImageVar_t; + +struct Bbr_ImageTree_t_ +{ + Bbr_ImageNode_t * pRoot; // the root of quantification tree + Bbr_ImageNode_t * pCare; // the leaf node with the care set + DdNode * bCareSupp; // the cube to quantify from the care + int fVerbose; // the verbosity flag + int nNodesMax; // the max number of nodes in one iter + int nNodesMaxT; // the overall max number of nodes + int nIter; // the number of iterations with this tree + int nBddMax; // the number of node to stop +}; + +struct Bbr_ImageNode_t_ +{ + DdManager * dd; // the manager + DdNode * bCube; // the cube to quantify + DdNode * bImage; // the partial image + Bbr_ImageNode_t * pNode1; // the first branch + Bbr_ImageNode_t * pNode2; // the second branch + Bbr_ImagePart_t * pPart; // the partition (temporary) +}; + +struct Bbr_ImagePart_t_ +{ + DdNode * bFunc; // the partition + DdNode * bSupp; // the support of this partition + int nNodes; // the number of BDD nodes + short nSupp; // the number of support variables + short iPart; // the number of this partition +}; + +struct Bbr_ImageVar_t_ +{ + int iNum; // the BDD index of this variable + DdNode * bParts; // the partition numbers + int nParts; // the number of partitions +}; + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +#define b0 Cudd_Not((dd)->one) +#define b1 (dd)->one + +#ifndef ABC_PRB +#define ABC_PRB(dd,f) printf("%s = ", #f); Bbr_bddPrint(dd,f); printf("\n") +#endif + +/**AutomaticStart*************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static Bbr_ImagePart_t ** Bbr_CreateParts( DdManager * dd, + int nParts, DdNode ** pbParts, DdNode * bCare ); +static Bbr_ImageVar_t ** Bbr_CreateVars( DdManager * dd, + int nParts, Bbr_ImagePart_t ** pParts, + int nVars, DdNode ** pbVarsNs ); +static Bbr_ImageNode_t ** Bbr_CreateNodes( DdManager * dd, + int nParts, Bbr_ImagePart_t ** pParts, + int nVars, Bbr_ImageVar_t ** pVars ); +static void Bbr_DeleteParts_rec( Bbr_ImageNode_t * pNode ); +static int Bbr_BuildTreeNode( DdManager * dd, + int nNodes, Bbr_ImageNode_t ** pNodes, + int nVars, Bbr_ImageVar_t ** pVars, int * pfStop, int nBddMax ); +static Bbr_ImageNode_t * Bbr_MergeTopNodes( DdManager * dd, + int nNodes, Bbr_ImageNode_t ** pNodes ); +static void Bbr_bddImageTreeDelete_rec( Bbr_ImageNode_t * pNode ); +static int Bbr_bddImageCompute_rec( Bbr_ImageTree_t * pTree, Bbr_ImageNode_t * pNode ); +static int Bbr_FindBestVariable( DdManager * dd, + int nNodes, Bbr_ImageNode_t ** pNodes, + int nVars, Bbr_ImageVar_t ** pVars ); +static void Bbr_FindBestPartitions( DdManager * dd, DdNode * bParts, + int nNodes, Bbr_ImageNode_t ** pNodes, + int * piNode1, int * piNode2 ); +static Bbr_ImageNode_t * Bbr_CombineTwoNodes( DdManager * dd, DdNode * bCube, + Bbr_ImageNode_t * pNode1, Bbr_ImageNode_t * pNode2 ); + +static void Bbr_bddImagePrintLatchDependency( DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars ); +static void Bbr_bddImagePrintLatchDependencyOne( DdManager * dd, DdNode * bFunc, + DdNode * bVarsCs, DdNode * bVarsNs, int iPart ); + +static void Bbr_bddImagePrintTree( Bbr_ImageTree_t * pTree ); +static void Bbr_bddImagePrintTree_rec( Bbr_ImageNode_t * pNode, int nOffset ); + +static void Bbr_bddPrint( DdManager * dd, DdNode * F ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Starts the image computation using tree-based scheduling.] + + Description [This procedure starts the image computation. It uses + the given care set to test-run the image computation and creates the + quantification tree by scheduling variable quantifications. The tree can + be used to compute images for other care sets without rescheduling. + In this case, Bbr_bddImageCompute() should be called.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageTree_t * Bbr_bddImageStart( + DdManager * dd, DdNode * bCare, // the care set + int nParts, DdNode ** pbParts, // the partitions for image computation + int nVars, DdNode ** pbVars, int nBddMax, int fVerbose ) // the NS and parameter variables (not quantified!) +{ + Bbr_ImageTree_t * pTree; + Bbr_ImagePart_t ** pParts; + Bbr_ImageVar_t ** pVars; + Bbr_ImageNode_t ** pNodes, * pCare; + int fStop, v; + + if ( fVerbose && dd->size <= 80 ) + Bbr_bddImagePrintLatchDependency( dd, bCare, nParts, pbParts, nVars, pbVars ); + + // create variables, partitions and leaf nodes + pParts = Bbr_CreateParts( dd, nParts, pbParts, bCare ); + pVars = Bbr_CreateVars( dd, nParts + 1, pParts, nVars, pbVars ); + pNodes = Bbr_CreateNodes( dd, nParts + 1, pParts, dd->size, pVars ); + pCare = pNodes[nParts]; + + // process the nodes + while ( Bbr_BuildTreeNode( dd, nParts + 1, pNodes, dd->size, pVars, &fStop, nBddMax ) ); + + // consider the case of BDD node blowup + if ( fStop ) + { + for ( v = 0; v < dd->size; v++ ) + if ( pVars[v] ) + ABC_FREE( pVars[v] ); + ABC_FREE( pVars ); + for ( v = 0; v <= nParts; v++ ) + if ( pNodes[v] ) + { + Bbr_DeleteParts_rec( pNodes[v] ); + Bbr_bddImageTreeDelete_rec( pNodes[v] ); + } + ABC_FREE( pNodes ); + ABC_FREE( pParts ); + return NULL; + } + + // make sure the variables are gone + for ( v = 0; v < dd->size; v++ ) + assert( pVars[v] == NULL ); + ABC_FREE( pVars ); + + // create the tree + pTree = ABC_ALLOC( Bbr_ImageTree_t, 1 ); + memset( pTree, 0, sizeof(Bbr_ImageTree_t) ); + pTree->pCare = pCare; + pTree->nBddMax = nBddMax; + pTree->fVerbose = fVerbose; + + // merge the topmost nodes + while ( (pTree->pRoot = Bbr_MergeTopNodes( dd, nParts + 1, pNodes )) == NULL ); + + // make sure the nodes are gone + for ( v = 0; v < nParts + 1; v++ ) + assert( pNodes[v] == NULL ); + ABC_FREE( pNodes ); + +// if ( fVerbose ) +// Bbr_bddImagePrintTree( pTree ); + + // set the support of the care set + pTree->bCareSupp = Cudd_Support( dd, bCare ); Cudd_Ref( pTree->bCareSupp ); + + // clean the partitions + Bbr_DeleteParts_rec( pTree->pRoot ); + ABC_FREE( pParts ); + + return pTree; +} + +/**Function************************************************************* + + Synopsis [Compute the image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Bbr_bddImageCompute( Bbr_ImageTree_t * pTree, DdNode * bCare ) +{ + DdManager * dd = pTree->pCare->dd; + DdNode * bSupp, * bRem; + + pTree->nIter++; + + // make sure the supports are okay + bSupp = Cudd_Support( dd, bCare ); Cudd_Ref( bSupp ); + if ( bSupp != pTree->bCareSupp ) + { + bRem = Cudd_bddExistAbstract( dd, bSupp, pTree->bCareSupp ); Cudd_Ref( bRem ); + if ( bRem != b1 ) + { +printf( "Original care set support: " ); +ABC_PRB( dd, pTree->bCareSupp ); +printf( "Current care set support: " ); +ABC_PRB( dd, bSupp ); + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDeref( dd, bRem ); + printf( "The care set depends on some vars that were not in the care set during scheduling.\n" ); + return NULL; + } + Cudd_RecursiveDeref( dd, bRem ); + } + Cudd_RecursiveDeref( dd, bSupp ); + + // remove the previous image + Cudd_RecursiveDeref( dd, pTree->pCare->bImage ); + pTree->pCare->bImage = bCare; Cudd_Ref( bCare ); + + // compute the image + pTree->nNodesMax = 0; + if ( !Bbr_bddImageCompute_rec( pTree, pTree->pRoot ) ) + return NULL; + if ( pTree->nNodesMaxT < pTree->nNodesMax ) + pTree->nNodesMaxT = pTree->nNodesMax; + +// if ( pTree->fVerbose ) +// printf( "Iter %2d : Max nodes = %5d.\n", pTree->nIter, pTree->nNodesMax ); + return pTree->pRoot->bImage; +} + +/**Function************************************************************* + + Synopsis [Delete the tree.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImageTreeDelete( Bbr_ImageTree_t * pTree ) +{ + if ( pTree->bCareSupp ) + Cudd_RecursiveDeref( pTree->pRoot->dd, pTree->bCareSupp ); + Bbr_bddImageTreeDelete_rec( pTree->pRoot ); + ABC_FREE( pTree ); +} + +/**Function************************************************************* + + Synopsis [Reads the image from the tree.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Bbr_bddImageRead( Bbr_ImageTree_t * pTree ) +{ + return pTree->pRoot->bImage; +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Outputs the BDD in a readable format.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +void Bbr_bddPrint( DdManager * dd, DdNode * F ) +{ + DdGen * Gen; + int * Cube; + CUDD_VALUE_TYPE Value; + int nVars = dd->size; + int fFirstCube = 1; + int i; + + if ( F == NULL ) + { + printf("NULL"); + return; + } + if ( F == b0 ) + { + printf("Constant 0"); + return; + } + if ( F == b1 ) + { + printf("Constant 1"); + return; + } + + Cudd_ForeachCube( dd, F, Gen, Cube, Value ) + { + if ( fFirstCube ) + fFirstCube = 0; + else +// Output << " + "; + printf( " + " ); + + for ( i = 0; i < nVars; i++ ) + if ( Cube[i] == 0 ) + printf( "[%d]'", i ); +// printf( "%c'", (char)('a'+i) ); + else if ( Cube[i] == 1 ) + printf( "[%d]", i ); +// printf( "%c", (char)('a'+i) ); + } + +// printf("\n"); +} + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Creates partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImagePart_t ** Bbr_CreateParts( DdManager * dd, + int nParts, DdNode ** pbParts, DdNode * bCare ) +{ + Bbr_ImagePart_t ** pParts; + int i; + + // start the partitions + pParts = ABC_ALLOC( Bbr_ImagePart_t *, nParts + 1 ); + // create structures for each variable + for ( i = 0; i < nParts; i++ ) + { + pParts[i] = ABC_ALLOC( Bbr_ImagePart_t, 1 ); + pParts[i]->bFunc = pbParts[i]; Cudd_Ref( pParts[i]->bFunc ); + pParts[i]->bSupp = Cudd_Support( dd, pParts[i]->bFunc ); Cudd_Ref( pParts[i]->bSupp ); + pParts[i]->nSupp = Cudd_SupportSize( dd, pParts[i]->bSupp ); + pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); + pParts[i]->iPart = i; + } + // add the care set as the last partition + pParts[nParts] = ABC_ALLOC( Bbr_ImagePart_t, 1 ); + pParts[nParts]->bFunc = bCare; Cudd_Ref( pParts[nParts]->bFunc ); + pParts[nParts]->bSupp = Cudd_Support( dd, pParts[nParts]->bFunc ); Cudd_Ref( pParts[nParts]->bSupp ); + pParts[nParts]->nSupp = Cudd_SupportSize( dd, pParts[nParts]->bSupp ); + pParts[nParts]->nNodes = Cudd_DagSize( pParts[nParts]->bFunc ); + pParts[nParts]->iPart = nParts; + return pParts; +} + +/**Function************************************************************* + + Synopsis [Creates variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageVar_t ** Bbr_CreateVars( DdManager * dd, + int nParts, Bbr_ImagePart_t ** pParts, + int nVars, DdNode ** pbVars ) +{ + Bbr_ImageVar_t ** pVars; + DdNode ** pbFuncs; + DdNode * bCubeNs, * bSupp, * bParts, * bTemp, * bSuppTemp; + int nVarsTotal, iVar, p, Counter; + + // put all the functions into one array + pbFuncs = ABC_ALLOC( DdNode *, nParts ); + for ( p = 0; p < nParts; p++ ) + pbFuncs[p] = pParts[p]->bSupp; + bSupp = Cudd_VectorSupport( dd, pbFuncs, nParts ); Cudd_Ref( bSupp ); + ABC_FREE( pbFuncs ); + + // remove the NS vars + bCubeNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bCubeNs ); + bSupp = Cudd_bddExistAbstract( dd, bTemp = bSupp, bCubeNs ); Cudd_Ref( bSupp ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCubeNs ); + + // get the number of I and CS variables to be quantified + nVarsTotal = Cudd_SupportSize( dd, bSupp ); + + // start the variables + pVars = ABC_ALLOC( Bbr_ImageVar_t *, dd->size ); + memset( pVars, 0, sizeof(Bbr_ImageVar_t *) * dd->size ); + // create structures for each variable + for ( bSuppTemp = bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) ) + { + iVar = bSuppTemp->index; + pVars[iVar] = ABC_ALLOC( Bbr_ImageVar_t, 1 ); + pVars[iVar]->iNum = iVar; + // collect all the parts this var belongs to + Counter = 0; + bParts = b1; Cudd_Ref( bParts ); + for ( p = 0; p < nParts; p++ ) + if ( Cudd_bddLeq( dd, pParts[p]->bSupp, dd->vars[bSuppTemp->index] ) ) + { + bParts = Cudd_bddAnd( dd, bTemp = bParts, dd->vars[p] ); Cudd_Ref( bParts ); + Cudd_RecursiveDeref( dd, bTemp ); + Counter++; + } + pVars[iVar]->bParts = bParts; // takes ref + pVars[iVar]->nParts = Counter; + } + Cudd_RecursiveDeref( dd, bSupp ); + return pVars; +} + +/**Function************************************************************* + + Synopsis [Creates variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageNode_t ** Bbr_CreateNodes( DdManager * dd, + int nParts, Bbr_ImagePart_t ** pParts, + int nVars, Bbr_ImageVar_t ** pVars ) +{ + Bbr_ImageNode_t ** pNodes; + Bbr_ImageNode_t * pNode; + DdNode * bTemp; + int i, v, iPart; +/* + DdManager * dd; // the manager + DdNode * bCube; // the cube to quantify + DdNode * bImage; // the partial image + Bbr_ImageNode_t * pNode1; // the first branch + Bbr_ImageNode_t * pNode2; // the second branch + Bbr_ImagePart_t * pPart; // the partition (temporary) +*/ + // start the partitions + pNodes = ABC_ALLOC( Bbr_ImageNode_t *, nParts ); + // create structures for each leaf nodes + for ( i = 0; i < nParts; i++ ) + { + pNodes[i] = ABC_ALLOC( Bbr_ImageNode_t, 1 ); + memset( pNodes[i], 0, sizeof(Bbr_ImageNode_t) ); + pNodes[i]->dd = dd; + pNodes[i]->pPart = pParts[i]; + } + // find the quantification cubes for each leaf node + for ( v = 0; v < nVars; v++ ) + { + if ( pVars[v] == NULL ) + continue; + assert( pVars[v]->nParts > 0 ); + if ( pVars[v]->nParts > 1 ) + continue; + iPart = pVars[v]->bParts->index; + if ( pNodes[iPart]->bCube == NULL ) + { + pNodes[iPart]->bCube = dd->vars[v]; + Cudd_Ref( dd->vars[v] ); + } + else + { + pNodes[iPart]->bCube = Cudd_bddAnd( dd, bTemp = pNodes[iPart]->bCube, dd->vars[v] ); + Cudd_Ref( pNodes[iPart]->bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + // remove these variables + Cudd_RecursiveDeref( dd, pVars[v]->bParts ); + ABC_FREE( pVars[v] ); + } + + // assign the leaf node images + for ( i = 0; i < nParts; i++ ) + { + pNode = pNodes[i]; + if ( pNode->bCube ) + { + // update the partition + pParts[i]->bFunc = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bFunc, pNode->bCube ); + Cudd_Ref( pParts[i]->bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + // update the support the partition + pParts[i]->bSupp = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bSupp, pNode->bCube ); + Cudd_Ref( pParts[i]->bSupp ); + Cudd_RecursiveDeref( dd, bTemp ); + // update the numbers + pParts[i]->nSupp = Cudd_SupportSize( dd, pParts[i]->bSupp ); + pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); + // get rid of the cube + // save the last (care set) quantification cube + if ( i < nParts - 1 ) + { + Cudd_RecursiveDeref( dd, pNode->bCube ); + pNode->bCube = NULL; + } + } + // copy the function + pNode->bImage = pParts[i]->bFunc; Cudd_Ref( pNode->bImage ); + } +/* + for ( i = 0; i < nParts; i++ ) + { + pNode = pNodes[i]; +ABC_PRB( dd, pNode->bCube ); +ABC_PRB( dd, pNode->pPart->bFunc ); +ABC_PRB( dd, pNode->pPart->bSupp ); +printf( "\n" ); + } +*/ + return pNodes; +} + + +/**Function************************************************************* + + Synopsis [Delete the partitions from the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_DeleteParts_rec( Bbr_ImageNode_t * pNode ) +{ + Bbr_ImagePart_t * pPart; + if ( pNode->pNode1 ) + Bbr_DeleteParts_rec( pNode->pNode1 ); + if ( pNode->pNode2 ) + Bbr_DeleteParts_rec( pNode->pNode2 ); + pPart = pNode->pPart; + Cudd_RecursiveDeref( pNode->dd, pPart->bFunc ); + Cudd_RecursiveDeref( pNode->dd, pPart->bSupp ); + ABC_FREE( pNode->pPart ); +} + +/**Function************************************************************* + + Synopsis [Delete the partitions from the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImageTreeDelete_rec( Bbr_ImageNode_t * pNode ) +{ + if ( pNode->pNode1 ) + Bbr_bddImageTreeDelete_rec( pNode->pNode1 ); + if ( pNode->pNode2 ) + Bbr_bddImageTreeDelete_rec( pNode->pNode2 ); + if ( pNode->bCube ) + Cudd_RecursiveDeref( pNode->dd, pNode->bCube ); + if ( pNode->bImage ) + Cudd_RecursiveDeref( pNode->dd, pNode->bImage ); + assert( pNode->pPart == NULL ); + ABC_FREE( pNode ); +} + +/**Function************************************************************* + + Synopsis [Recompute the image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Bbr_bddImageCompute_rec( Bbr_ImageTree_t * pTree, Bbr_ImageNode_t * pNode ) +{ + DdManager * dd = pNode->dd; + DdNode * bTemp; + int nNodes; + + // trivial case + if ( pNode->pNode1 == NULL ) + { + if ( pNode->bCube ) + { + pNode->bImage = Cudd_bddExistAbstract( dd, bTemp = pNode->bImage, pNode->bCube ); + Cudd_Ref( pNode->bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + } + return 1; + } + + // compute the children + if ( pNode->pNode1 ) + if ( !Bbr_bddImageCompute_rec( pTree, pNode->pNode1 ) ) + return 0; + if ( pNode->pNode2 ) + if ( !Bbr_bddImageCompute_rec( pTree, pNode->pNode2 ) ) + return 0; + + // clean the old image + if ( pNode->bImage ) + Cudd_RecursiveDeref( dd, pNode->bImage ); + pNode->bImage = NULL; + + // compute the new image + if ( pNode->bCube ) + pNode->bImage = Cudd_bddAndAbstract( dd, + pNode->pNode1->bImage, pNode->pNode2->bImage, pNode->bCube ); + else + pNode->bImage = Cudd_bddAnd( dd, pNode->pNode1->bImage, pNode->pNode2->bImage ); + Cudd_Ref( pNode->bImage ); + + if ( pTree->fVerbose ) + { + nNodes = Cudd_DagSize( pNode->bImage ); + if ( pTree->nNodesMax < nNodes ) + pTree->nNodesMax = nNodes; + } + if ( dd->keys-dd->dead > (unsigned)pTree->nBddMax ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Builds the tree.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Bbr_BuildTreeNode( DdManager * dd, + int nNodes, Bbr_ImageNode_t ** pNodes, + int nVars, Bbr_ImageVar_t ** pVars, int * pfStop, int nBddMax ) +{ + Bbr_ImageNode_t * pNode1, * pNode2; + Bbr_ImageVar_t * pVar; + Bbr_ImageNode_t * pNode; + DdNode * bCube, * bTemp, * bSuppTemp;//, * bParts; + int iNode1, iNode2; + int iVarBest, nSupp, v; + + // find the best variable + iVarBest = Bbr_FindBestVariable( dd, nNodes, pNodes, nVars, pVars ); + if ( iVarBest == -1 ) + return 0; +/* +for ( v = 0; v < nVars; v++ ) +{ + DdNode * bSupp; + if ( pVars[v] == NULL ) + continue; + printf( "%3d :", v ); + printf( "%3d ", pVars[v]->nParts ); + bSupp = Cudd_Support( dd, pVars[v]->bParts ); Cudd_Ref( bSupp ); + Bbr_bddPrint( dd, bSupp ); printf( "\n" ); + Cudd_RecursiveDeref( dd, bSupp ); +} +*/ + pVar = pVars[iVarBest]; + + // this var cannot appear in one partition only + nSupp = Cudd_SupportSize( dd, pVar->bParts ); + assert( nSupp == pVar->nParts ); + assert( nSupp != 1 ); +//printf( "var = %d supp = %d\n\n", iVarBest, nSupp ); + + // 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 = Bbr_CombineTwoNodes( dd, bCube, pNode1, pNode2 ); + Cudd_RecursiveDeref( dd, bCube ); + } + else // if ( pVar->nParts > 2 ) + { + // find two smallest BDDs that have this var + Bbr_FindBestPartitions( dd, pVar->bParts, nNodes, pNodes, &iNode1, &iNode2 ); + pNode1 = pNodes[iNode1]; + pNode2 = pNodes[iNode2]; +//printf( "smallest bdds with this var: %d %d\n", iNode1, 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 = Bbr_CombineTwoNodes( dd, b1, pNode1, pNode2 ); + } + + // clean the old nodes + pNodes[iNode1] = pNode; + pNodes[iNode2] = NULL; +//printf( "Removing node %d (leaving node %d)\n", iNode2, iNode1 ); + + // 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 = Cudd_SupportSize( dd, pVar->bParts ); + } + + *pfStop = 0; + if ( dd->keys-dd->dead > (unsigned)nBddMax ) + { + *pfStop = 1; + return 0; + } + return 1; +} + + +/**Function************************************************************* + + Synopsis [Merges the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageNode_t * Bbr_MergeTopNodes( + DdManager * dd, int nNodes, Bbr_ImageNode_t ** pNodes ) +{ + Bbr_ImageNode_t * pNode; + int n1 = -1, n2 = -1, n; + + // find the first and the second non-empty spots + for ( n = 0; n < nNodes; n++ ) + if ( pNodes[n] ) + { + if ( n1 == -1 ) + n1 = n; + else if ( n2 == -1 ) + { + n2 = n; + break; + } + } + assert( n1 != -1 ); + // check the situation when only one such node is detected + if ( n2 == -1 ) + { + // save the node + pNode = pNodes[n1]; + // clean the node + pNodes[n1] = NULL; + return pNode; + } + + // combines two nodes + pNode = Bbr_CombineTwoNodes( dd, b1, pNodes[n1], pNodes[n2] ); + + // clean the old nodes + pNodes[n1] = pNode; + pNodes[n2] = NULL; + return NULL; +} + +/**Function************************************************************* + + Synopsis [Merges two nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageNode_t * Bbr_CombineTwoNodes( DdManager * dd, DdNode * bCube, + Bbr_ImageNode_t * pNode1, Bbr_ImageNode_t * pNode2 ) +{ + Bbr_ImageNode_t * pNode; + Bbr_ImagePart_t * pPart; + + // create a new partition + pPart = ABC_ALLOC( Bbr_ImagePart_t, 1 ); + memset( pPart, 0, sizeof(Bbr_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 = Cudd_SupportSize( 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( Bbr_ImageNode_t, 1 ); + memset( pNode, 0, sizeof(Bbr_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 [Computes the best variable.] + + Description [The variables is the best if the sum of squares of the + BDD sizes of the partitions, in which it participates, is the minimum.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Bbr_FindBestVariable( DdManager * dd, + int nNodes, Bbr_ImageNode_t ** pNodes, + int nVars, Bbr_ImageVar_t ** pVars ) +{ + DdNode * bTemp; + int iVarBest, v; + double CostBest, CostCur; + + CostBest = 100000000000000.0; + iVarBest = -1; + + // check if there are two-variable partitions + for ( v = 0; v < nVars; v++ ) + if ( pVars[v] && pVars[v]->nParts == 2 ) + { + CostCur = 0; + for ( bTemp = pVars[v]->bParts; bTemp != b1; bTemp = cuddT(bTemp) ) + CostCur += pNodes[bTemp->index]->pPart->nNodes * + pNodes[bTemp->index]->pPart->nNodes; + if ( CostBest > CostCur ) + { + CostBest = CostCur; + iVarBest = v; + } + } + if ( iVarBest >= 0 ) + return iVarBest; + + // find other partition + for ( v = 0; v < nVars; v++ ) + if ( pVars[v] ) + { + assert( pVars[v]->nParts > 1 ); + CostCur = 0; + for ( bTemp = pVars[v]->bParts; bTemp != b1; bTemp = cuddT(bTemp) ) + CostCur += pNodes[bTemp->index]->pPart->nNodes * + pNodes[bTemp->index]->pPart->nNodes; + if ( CostBest > CostCur ) + { + CostBest = CostCur; + iVarBest = v; + } + } + return iVarBest; +} + +/**Function************************************************************* + + Synopsis [Computes two smallest partions that have this var.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_FindBestPartitions( DdManager * dd, DdNode * bParts, + int nNodes, Bbr_ImageNode_t ** pNodes, + int * piNode1, int * piNode2 ) +{ + DdNode * bTemp; + int iPart1, iPart2; + int CostMin1, CostMin2, Cost; + + // go through the partitions + iPart1 = iPart2 = -1; + CostMin1 = CostMin2 = 1000000; + for ( bTemp = bParts; bTemp != b1; bTemp = cuddT(bTemp) ) + { + Cost = pNodes[bTemp->index]->pPart->nNodes; + if ( CostMin1 > Cost ) + { + CostMin2 = CostMin1; iPart2 = iPart1; + CostMin1 = Cost; iPart1 = bTemp->index; + } + else if ( CostMin2 > Cost ) + { + CostMin2 = Cost; iPart2 = bTemp->index; + } + } + + *piNode1 = iPart1; + *piNode2 = iPart2; +} + +/**Function************************************************************* + + Synopsis [Prints the latch dependency matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImagePrintLatchDependency( + DdManager * dd, DdNode * bCare, // the care set + int nParts, DdNode ** pbParts, // the partitions for image computation + int nVars, DdNode ** pbVars ) // the NS and parameter variables (not quantified!) +{ + int i; + DdNode * bVarsCs, * bVarsNs; + + bVarsCs = Cudd_Support( dd, bCare ); Cudd_Ref( bVarsCs ); + bVarsNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bVarsNs ); + + printf( "The latch dependency matrix:\n" ); + printf( "Partitions = %d Variables: total = %d non-quantifiable = %d\n", + nParts, dd->size, nVars ); + printf( " : " ); + for ( i = 0; i < dd->size; i++ ) + printf( "%d", i % 10 ); + printf( "\n" ); + + for ( i = 0; i < nParts; i++ ) + Bbr_bddImagePrintLatchDependencyOne( dd, pbParts[i], bVarsCs, bVarsNs, i ); + Bbr_bddImagePrintLatchDependencyOne( dd, bCare, bVarsCs, bVarsNs, nParts ); + + Cudd_RecursiveDeref( dd, bVarsCs ); + Cudd_RecursiveDeref( dd, bVarsNs ); +} + +/**Function************************************************************* + + Synopsis [Prints one row of the latch dependency matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImagePrintLatchDependencyOne( + DdManager * dd, DdNode * bFunc, // the function + DdNode * bVarsCs, DdNode * bVarsNs, // the current/next state vars + int iPart ) +{ + DdNode * bSupport; + int v; + bSupport = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupport ); + printf( " %3d : ", iPart ); + for ( v = 0; v < dd->size; v++ ) + { + if ( Cudd_bddLeq( dd, bSupport, dd->vars[v] ) ) + { + if ( Cudd_bddLeq( dd, bVarsCs, dd->vars[v] ) ) + printf( "c" ); + else if ( Cudd_bddLeq( dd, bVarsNs, dd->vars[v] ) ) + printf( "n" ); + else + printf( "i" ); + } + else + printf( "." ); + } + printf( "\n" ); + Cudd_RecursiveDeref( dd, bSupport ); +} + + +/**Function************************************************************* + + Synopsis [Prints the tree for quenstification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImagePrintTree( Bbr_ImageTree_t * pTree ) +{ + printf( "The quantification scheduling tree:\n" ); + Bbr_bddImagePrintTree_rec( pTree->pRoot, 1 ); +} + +/**Function************************************************************* + + Synopsis [Prints the tree for quenstification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImagePrintTree_rec( Bbr_ImageNode_t * pNode, int Offset ) +{ + DdNode * Cube; + int i; + + Cube = pNode->bCube; + + if ( pNode->pNode1 == NULL ) + { + printf( "<%d> ", pNode->pPart->iPart ); + if ( Cube != NULL ) + { + ABC_PRB( pNode->dd, Cube ); + } + else + printf( "\n" ); + return; + } + + printf( "<*> " ); + if ( Cube != NULL ) + { + ABC_PRB( pNode->dd, Cube ); + } + else + printf( "\n" ); + + for ( i = 0; i < Offset; i++ ) + printf( " " ); + Bbr_bddImagePrintTree_rec( pNode->pNode1, Offset + 1 ); + + for ( i = 0; i < Offset; i++ ) + printf( " " ); + Bbr_bddImagePrintTree_rec( pNode->pNode2, Offset + 1 ); +} + +/**Function******************************************************************** + + Synopsis [Computes the positive polarty cube composed of the first vars in the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Bbr_bddComputeCube( DdManager * dd, DdNode ** bXVars, int nVars ) +{ + DdNode * bRes; + DdNode * bTemp; + int i; + + bRes = b1; Cudd_Ref( bRes ); + for ( i = 0; i < nVars; i++ ) + { + bRes = Cudd_bddAnd( dd, bTemp = bRes, bXVars[i] ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + + Cudd_Deref( bRes ); + return bRes; +} + + + + + +struct Bbr_ImageTree2_t_ +{ + DdManager * dd; + DdNode * bRel; + DdNode * bCube; + DdNode * bImage; +}; + +/**Function************************************************************* + + Synopsis [Starts the monolithic image computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Bbr_ImageTree2_t * Bbr_bddImageStart2( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int fVerbose ) +{ + Bbr_ImageTree2_t * pTree; + DdNode * bCubeAll, * bCubeNot, * bTemp; + int i; + + pTree = ABC_ALLOC( Bbr_ImageTree2_t, 1 ); + pTree->dd = dd; + pTree->bImage = NULL; + + bCubeAll = Bbr_bddComputeCube( dd, dd->vars, dd->size ); Cudd_Ref( bCubeAll ); + bCubeNot = Bbr_bddComputeCube( dd, pbVars, nVars ); Cudd_Ref( bCubeNot ); + pTree->bCube = Cudd_bddExistAbstract( dd, bCubeAll, bCubeNot ); Cudd_Ref( pTree->bCube ); + Cudd_RecursiveDeref( dd, bCubeAll ); + Cudd_RecursiveDeref( dd, bCubeNot ); + + // derive the monolithic relation + pTree->bRel = b1; Cudd_Ref( pTree->bRel ); + for ( i = 0; i < nParts; i++ ) + { + pTree->bRel = Cudd_bddAnd( dd, bTemp = pTree->bRel, pbParts[i] ); Cudd_Ref( pTree->bRel ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Bbr_bddImageCompute2( pTree, bCare ); + return pTree; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Bbr_bddImageCompute2( Bbr_ImageTree2_t * pTree, DdNode * bCare ) +{ + if ( pTree->bImage ) + Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); + pTree->bImage = Cudd_bddAndAbstract( pTree->dd, pTree->bRel, bCare, pTree->bCube ); + Cudd_Ref( pTree->bImage ); + return pTree->bImage; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_bddImageTreeDelete2( Bbr_ImageTree2_t * pTree ) +{ + if ( pTree->bRel ) + Cudd_RecursiveDeref( pTree->dd, pTree->bRel ); + if ( pTree->bCube ) + Cudd_RecursiveDeref( pTree->dd, pTree->bCube ); + if ( pTree->bImage ) + Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); + ABC_FREE( pTree ); +} + +/**Function************************************************************* + + Synopsis [Returns the previously computed image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Bbr_bddImageRead2( Bbr_ImageTree2_t * pTree ) +{ + return pTree->bImage; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/bbr/bbrNtbdd.c b/src/bdd/bbr/bbrNtbdd.c new file mode 100644 index 00000000..f61c3d73 --- /dev/null +++ b/src/bdd/bbr/bbrNtbdd.c @@ -0,0 +1,218 @@ +/**CFile**************************************************************** + + FileName [bbrNtbdd.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability analysis.] + + Synopsis [Procedures to construct global BDDs for the network.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: bbrNtbdd.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bbr.h" +//#include "bar.h" + +ABC_NAMESPACE_IMPL_START + + +typedef char ProgressBar; + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline void Aig_ObjSetGlobalBdd( Aig_Obj_t * pObj, DdNode * bFunc ) { pObj->pData = bFunc; } +static inline void Aig_ObjCleanGlobalBdd( DdManager * dd, Aig_Obj_t * pObj ) { Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); pObj->pData = NULL; } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Derives the global BDD for one AIG node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Bbr_NodeGlobalBdds_rec( DdManager * dd, Aig_Obj_t * pNode, int nBddSizeMax, int fDropInternal, ProgressBar * pProgress, int * pCounter, int fVerbose ) +{ + DdNode * bFunc, * bFunc0, * bFunc1; + assert( !Aig_IsComplement(pNode) ); + if ( Cudd_ReadKeys(dd)-Cudd_ReadDead(dd) > (unsigned)nBddSizeMax ) + { +// Extra_ProgressBarStop( pProgress ); + if ( fVerbose ) + printf( "The number of live nodes reached %d.\n", nBddSizeMax ); + fflush( stdout ); + return NULL; + } + // if the result is available return + if ( Aig_ObjGlobalBdd(pNode) == NULL ) + { + // compute the result for both branches + bFunc0 = Bbr_NodeGlobalBdds_rec( dd, Aig_ObjFanin0(pNode), nBddSizeMax, fDropInternal, pProgress, pCounter, fVerbose ); + if ( bFunc0 == NULL ) + return NULL; + Cudd_Ref( bFunc0 ); + bFunc1 = Bbr_NodeGlobalBdds_rec( dd, Aig_ObjFanin1(pNode), nBddSizeMax, fDropInternal, pProgress, pCounter, fVerbose ); + if ( bFunc1 == NULL ) + return NULL; + Cudd_Ref( bFunc1 ); + bFunc0 = Cudd_NotCond( bFunc0, Aig_ObjFaninC0(pNode) ); + bFunc1 = Cudd_NotCond( bFunc1, Aig_ObjFaninC1(pNode) ); + // get the final result + bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bFunc0 ); + Cudd_RecursiveDeref( dd, bFunc1 ); + // add the number of used nodes + (*pCounter)++; + // set the result + assert( Aig_ObjGlobalBdd(pNode) == NULL ); + Aig_ObjSetGlobalBdd( pNode, bFunc ); + // increment the progress bar +// if ( pProgress ) +// Extra_ProgressBarUpdate( pProgress, *pCounter, NULL ); + } + // prepare the return value + bFunc = Aig_ObjGlobalBdd(pNode); + // dereference BDD at the node + if ( --pNode->nRefs == 0 && fDropInternal ) + { + Cudd_Deref( bFunc ); + Aig_ObjSetGlobalBdd( pNode, NULL ); + } + return bFunc; +} + +/**Function************************************************************* + + Synopsis [Frees the global BDDs of the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Aig_ManFreeGlobalBdds( Aig_Man_t * p, DdManager * dd ) +{ + Aig_Obj_t * pObj; + int i; + Aig_ManForEachObj( p, pObj, i ) + if ( Aig_ObjGlobalBdd(pObj) ) + Aig_ObjCleanGlobalBdd( dd, pObj ); +} + +/**Function************************************************************* + + Synopsis [Returns the shared size of global BDDs of the COs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Aig_ManSizeOfGlobalBdds( Aig_Man_t * p ) +{ + Vec_Ptr_t * vFuncsGlob; + Aig_Obj_t * pObj; + int RetValue, i; + // complement the global functions + vFuncsGlob = Vec_PtrAlloc( Aig_ManCoNum(p) ); + Aig_ManForEachCo( p, pObj, i ) + Vec_PtrPush( vFuncsGlob, Aig_ObjGlobalBdd(pObj) ); + RetValue = Cudd_SharingSize( (DdNode **)Vec_PtrArray(vFuncsGlob), Vec_PtrSize(vFuncsGlob) ); + Vec_PtrFree( vFuncsGlob ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Recursively computes global BDDs for the AIG in the manager.] + + Description [On exit, BDDs are stored in the pNode->pData fields.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Aig_ManComputeGlobalBdds( Aig_Man_t * p, int nBddSizeMax, int fDropInternal, int fReorder, int fVerbose ) +{ + ProgressBar * pProgress = NULL; + Aig_Obj_t * pObj; + DdManager * dd; + DdNode * bFunc; + int i, Counter; + // start the manager + dd = Cudd_Init( Aig_ManCiNum(p), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + // set reordering + if ( fReorder ) + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + // prepare to construct global BDDs + Aig_ManCleanData( p ); + // assign the constant node BDD + Aig_ObjSetGlobalBdd( Aig_ManConst1(p), dd->one ); Cudd_Ref( dd->one ); + // set the elementary variables + Aig_ManForEachCi( p, pObj, i ) + { + Aig_ObjSetGlobalBdd( pObj, dd->vars[i] ); Cudd_Ref( dd->vars[i] ); + } + + // collect the global functions of the COs + Counter = 0; + // construct the BDDs +// pProgress = Extra_ProgressBarStart( stdout, Aig_ManNodeNum(p) ); + Aig_ManForEachCo( p, pObj, i ) + { + bFunc = Bbr_NodeGlobalBdds_rec( dd, Aig_ObjFanin0(pObj), nBddSizeMax, fDropInternal, pProgress, &Counter, fVerbose ); + if ( bFunc == NULL ) + { + if ( fVerbose ) + printf( "Constructing global BDDs is aborted.\n" ); + Aig_ManFreeGlobalBdds( p, dd ); + Cudd_Quit( dd ); + // reset references + Aig_ManResetRefs( p ); + return NULL; + } + bFunc = Cudd_NotCond( bFunc, Aig_ObjFaninC0(pObj) ); Cudd_Ref( bFunc ); + Aig_ObjSetGlobalBdd( pObj, bFunc ); + } +// Extra_ProgressBarStop( pProgress ); + // reset references + Aig_ManResetRefs( p ); + // reorder one more time + if ( fReorder ) + { + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 1 ); + Cudd_AutodynDisable( dd ); + } +// Cudd_PrintInfo( dd, stdout ); + return dd; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/bbr/bbrReach.c b/src/bdd/bbr/bbrReach.c new file mode 100644 index 00000000..b5125ec7 --- /dev/null +++ b/src/bdd/bbr/bbrReach.c @@ -0,0 +1,615 @@ +/**CFile**************************************************************** + + FileName [bbrReach.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability analysis.] + + Synopsis [Procedures to perform reachability analysis.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: bbrReach.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bbr.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern Abc_Cex_t * Aig_ManVerifyUsingBddsCountExample( Aig_Man_t * p, DdManager * dd, + DdNode ** pbParts, Vec_Ptr_t * vOnionRings, DdNode * bCubeFirst, + int iOutput, int fVerbose, int fSilent ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [This procedure sets default resynthesis parameters.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_ManSetDefaultParams( Saig_ParBbr_t * p ) +{ + memset( p, 0, sizeof(Saig_ParBbr_t) ); + p->TimeLimit = 0; + p->nBddMax = 50000; + p->nIterMax = 1000; + p->fPartition = 1; + p->fReorder = 1; + p->fReorderImage = 1; + p->fVerbose = 0; + p->fSilent = 0; + p->iFrame = -1; +} + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddMove().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Bbr_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ) +{ + DdNode * bTemp, * bProd; + int i; + assert( iStart <= iStop ); + assert( iStart >= 0 && iStart <= dd->size ); + assert( iStop >= 0 && iStop <= dd->size ); + bProd = (dd)->one; Cudd_Ref( bProd ); + for ( i = iStart; i < iStop; i++ ) + { + bProd = Cudd_bddAnd( dd, bTemp = bProd, dd->vars[i] ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bProd ); + return bProd; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Bbr_StopManager( DdManager * dd ) +{ + int RetValue; + // check for remaining references in the package + RetValue = Cudd_CheckZeroRef( dd ); + if ( RetValue > 0 ) + printf( "\nThe number of referenced nodes = %d\n\n", RetValue ); +// Cudd_PrintInfo( dd, stdout ); + Cudd_Quit( dd ); +} + +/**Function************************************************************* + + Synopsis [Computes the initial state and sets up the variable map.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Aig_ManInitStateVarMap( DdManager * dd, Aig_Man_t * p, int fVerbose ) +{ + DdNode ** pbVarsX, ** pbVarsY; + DdNode * bTemp, * bProd; + Aig_Obj_t * pLatch; + int i; + + // set the variable mapping for Cudd_bddVarMap() + pbVarsX = ABC_ALLOC( DdNode *, dd->size ); + pbVarsY = ABC_ALLOC( DdNode *, dd->size ); + bProd = (dd)->one; Cudd_Ref( bProd ); + Saig_ManForEachLo( p, pLatch, i ) + { + pbVarsX[i] = dd->vars[ Saig_ManPiNum(p) + i ]; + pbVarsY[i] = dd->vars[ Saig_ManCiNum(p) + i ]; + // get the initial value of the latch + bProd = Cudd_bddAnd( dd, bTemp = bProd, Cudd_Not(pbVarsX[i]) ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_SetVarMap( dd, pbVarsX, pbVarsY, Saig_ManRegNum(p) ); + ABC_FREE( pbVarsX ); + ABC_FREE( pbVarsY ); + + Cudd_Deref( bProd ); + return bProd; +} + +/**Function************************************************************* + + Synopsis [Collects the array of output BDDs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode ** Aig_ManCreateOutputs( DdManager * dd, Aig_Man_t * p ) +{ + DdNode ** pbOutputs; + Aig_Obj_t * pNode; + int i; + // compute the transition relation + pbOutputs = ABC_ALLOC( DdNode *, Saig_ManPoNum(p) ); + Saig_ManForEachPo( p, pNode, i ) + { + pbOutputs[i] = Aig_ObjGlobalBdd(pNode); Cudd_Ref( pbOutputs[i] ); + } + return pbOutputs; +} + +/**Function************************************************************* + + Synopsis [Collects the array of partition BDDs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode ** Aig_ManCreatePartitions( DdManager * dd, Aig_Man_t * p, int fReorder, int fVerbose ) +{ + DdNode ** pbParts; + DdNode * bVar; + Aig_Obj_t * pNode; + int i; + + // extand the BDD manager to represent NS variables + assert( dd->size == Saig_ManCiNum(p) ); + Cudd_bddIthVar( dd, Saig_ManCiNum(p) + Saig_ManRegNum(p) - 1 ); + + // enable reordering + if ( fReorder ) + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + else + Cudd_AutodynDisable( dd ); + + // compute the transition relation + pbParts = ABC_ALLOC( DdNode *, Saig_ManRegNum(p) ); + Saig_ManForEachLi( p, pNode, i ) + { + bVar = Cudd_bddIthVar( dd, Saig_ManCiNum(p) + i ); + pbParts[i] = Cudd_bddXnor( dd, bVar, Aig_ObjGlobalBdd(pNode) ); Cudd_Ref( pbParts[i] ); + } + // free global BDDs + Aig_ManFreeGlobalBdds( p, dd ); + + // reorder and disable reordering + if ( fReorder ) + { + if ( fVerbose ) + fprintf( stdout, "BDD nodes in the partitions before reordering %d.\n", Cudd_SharingSize(pbParts,Saig_ManRegNum(p)) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + Cudd_AutodynDisable( dd ); + if ( fVerbose ) + fprintf( stdout, "BDD nodes in the partitions after reordering %d.\n", Cudd_SharingSize(pbParts,Saig_ManRegNum(p)) ); + } + return pbParts; +} + +/**Function************************************************************* + + Synopsis [Computes the set of unreachable states.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Aig_ManComputeReachable( DdManager * dd, Aig_Man_t * p, DdNode ** pbParts, DdNode * bInitial, DdNode ** pbOutputs, Saig_ParBbr_t * pPars, int fCheckOutputs ) +{ + int fInternalReorder = 0; + Bbr_ImageTree_t * pTree = NULL; // Suppress "might be used uninitialized" + Bbr_ImageTree2_t * pTree2 = NULL; // Supprses "might be used uninitialized" + DdNode * bReached, * bCubeCs; + DdNode * bCurrent; + DdNode * bNext = NULL; // Suppress "might be used uninitialized" + DdNode * bTemp; + Cudd_ReorderingType method; + int i, nIters, nBddSize = 0, status; + int nThreshold = 10000; + abctime clk = Abc_Clock(); + Vec_Ptr_t * vOnionRings; + int fixedPoint = 0; + + status = Cudd_ReorderingStatus( dd, &method ); + if ( status ) + Cudd_AutodynDisable( dd ); + + // start the image computation + bCubeCs = Bbr_bddComputeRangeCube( dd, Saig_ManPiNum(p), Saig_ManCiNum(p) ); Cudd_Ref( bCubeCs ); + if ( pPars->fPartition ) + pTree = Bbr_bddImageStart( dd, bCubeCs, Saig_ManRegNum(p), pbParts, Saig_ManRegNum(p), dd->vars+Saig_ManCiNum(p), pPars->nBddMax, pPars->fVerbose ); + else + pTree2 = Bbr_bddImageStart2( dd, bCubeCs, Saig_ManRegNum(p), pbParts, Saig_ManRegNum(p), dd->vars+Saig_ManCiNum(p), pPars->fVerbose ); + Cudd_RecursiveDeref( dd, bCubeCs ); + if ( pTree == NULL ) + { + if ( !pPars->fSilent ) + printf( "BDDs blew up during qualitification scheduling. " ); + return -1; + } + + if ( status ) + Cudd_AutodynEnable( dd, method ); + + // start the onion rings + vOnionRings = Vec_PtrAlloc( 1000 ); + + // perform reachability analysis + bCurrent = bInitial; Cudd_Ref( bCurrent ); + bReached = bInitial; Cudd_Ref( bReached ); + Vec_PtrPush( vOnionRings, bCurrent ); Cudd_Ref( bCurrent ); + for ( nIters = 0; nIters < pPars->nIterMax; nIters++ ) + { + // check the runtime limit + if ( pPars->TimeLimit && pPars->TimeLimit <= (Abc_Clock()-clk)/CLOCKS_PER_SEC ) + { + printf( "Reached timeout after image computation (%d seconds).\n", pPars->TimeLimit ); + Vec_PtrFree( vOnionRings ); + // undo the image tree + if ( pPars->fPartition ) + Bbr_bddImageTreeDelete( pTree ); + else + Bbr_bddImageTreeDelete2( pTree2 ); + pPars->iFrame = nIters - 1; + return -1; + } + + // compute the next states + if ( pPars->fPartition ) + bNext = Bbr_bddImageCompute( pTree, bCurrent ); + else + bNext = Bbr_bddImageCompute2( pTree2, bCurrent ); + if ( bNext == NULL ) + { + if ( !pPars->fSilent ) + printf( "BDDs blew up during image computation. " ); + if ( pPars->fPartition ) + Bbr_bddImageTreeDelete( pTree ); + else + Bbr_bddImageTreeDelete2( pTree2 ); + Vec_PtrFree( vOnionRings ); + pPars->iFrame = nIters - 1; + return -1; + } + Cudd_Ref( bNext ); + Cudd_RecursiveDeref( dd, bCurrent ); + + // remap these states into the current state vars + bNext = Cudd_bddVarMap( dd, bTemp = bNext ); Cudd_Ref( bNext ); + Cudd_RecursiveDeref( dd, bTemp ); + // check if there are any new states + if ( Cudd_bddLeq( dd, bNext, bReached ) ) { + fixedPoint = 1; + break; + } + // check the BDD size + nBddSize = Cudd_DagSize(bNext); + if ( nBddSize > pPars->nBddMax ) + break; + // check the result + for ( i = 0; i < Saig_ManPoNum(p); i++ ) + { + if ( fCheckOutputs && !Cudd_bddLeq( dd, bNext, Cudd_Not(pbOutputs[i]) ) ) + { + DdNode * bIntersect; + bIntersect = Cudd_bddIntersect( dd, bNext, pbOutputs[i] ); Cudd_Ref( bIntersect ); + assert( p->pSeqModel == NULL ); + p->pSeqModel = Aig_ManVerifyUsingBddsCountExample( p, dd, pbParts, + vOnionRings, bIntersect, i, pPars->fVerbose, pPars->fSilent ); + Cudd_RecursiveDeref( dd, bIntersect ); + if ( !pPars->fSilent ) + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", i, p->pName, Vec_PtrSize(vOnionRings) ); + Cudd_RecursiveDeref( dd, bReached ); + bReached = NULL; + pPars->iFrame = nIters; + break; + } + } + if ( i < Saig_ManPoNum(p) ) + break; + // get the new states + bCurrent = Cudd_bddAnd( dd, bNext, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); + Vec_PtrPush( vOnionRings, bCurrent ); Cudd_Ref( bCurrent ); + // minimize the new states with the reached states +// bCurrent = Cudd_bddConstrain( dd, bTemp = bCurrent, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); +// Cudd_RecursiveDeref( dd, bTemp ); + // add to the reached states + bReached = Cudd_bddOr( dd, bTemp = bReached, bNext ); Cudd_Ref( bReached ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bNext ); + if ( pPars->fVerbose ) + fprintf( stdout, "Frame = %3d. BDD = %5d. ", nIters, nBddSize ); + if ( fInternalReorder && pPars->fReorder && nBddSize > nThreshold ) + { + if ( pPars->fVerbose ) + fprintf( stdout, "Reordering... Before = %5d. ", Cudd_DagSize(bReached) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + Cudd_AutodynDisable( dd ); + if ( pPars->fVerbose ) + fprintf( stdout, "After = %5d.\r", Cudd_DagSize(bReached) ); + nThreshold *= 2; + } + if ( pPars->fVerbose ) +// fprintf( stdout, "\r" ); + fprintf( stdout, "\n" ); + + if ( pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(dd, bReached, Saig_ManRegNum(p) ); +// Extra_bddPrint( dd, bReached );printf( "\n" ); + fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p)) ); + fflush( stdout ); + } + + } + Cudd_RecursiveDeref( dd, bNext ); + // free the onion rings + Vec_PtrForEachEntry( DdNode *, vOnionRings, bTemp, i ) + Cudd_RecursiveDeref( dd, bTemp ); + Vec_PtrFree( vOnionRings ); + // undo the image tree + if ( pPars->fPartition ) + Bbr_bddImageTreeDelete( pTree ); + else + Bbr_bddImageTreeDelete2( pTree2 ); + if ( bReached == NULL ) + return 0; // proved reachable + // report the stats + if ( pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(dd, bReached, Saig_ManRegNum(p) ); + if ( nIters > pPars->nIterMax || nBddSize > pPars->nBddMax ) + fprintf( stdout, "Reachability analysis is stopped after %d frames.\n", nIters ); + else + fprintf( stdout, "Reachability analysis completed after %d frames.\n", nIters ); + fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p)) ); + fflush( stdout ); + } +//ABC_PRB( dd, bReached ); + Cudd_RecursiveDeref( dd, bReached ); + // SPG + // + if ( fixedPoint ) { + if ( !pPars->fSilent ) { + printf( "The miter is proved unreachable after %d iterations. ", nIters ); + } + pPars->iFrame = nIters - 1; + return 1; + } + assert(nIters >= pPars->nIterMax || nBddSize >= pPars->nBddMax); + if ( !pPars->fSilent ) + printf( "Verified only for states reachable in %d frames. ", nIters ); + pPars->iFrame = nIters - 1; + return -1; // undecided +} + +/**Function************************************************************* + + Synopsis [Performs reachability to see if any PO can be asserted.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Aig_ManVerifyUsingBdds_int( Aig_Man_t * p, Saig_ParBbr_t * pPars ) +{ + int fCheckOutputs = !pPars->fSkipOutCheck; + DdManager * dd; + DdNode ** pbParts, ** pbOutputs; + DdNode * bInitial, * bTemp; + int RetValue, i; + abctime clk = Abc_Clock(); + Vec_Ptr_t * vOnionRings; + + assert( Saig_ManRegNum(p) > 0 ); + + // compute the global BDDs of the latches + dd = Aig_ManComputeGlobalBdds( p, pPars->nBddMax, 1, pPars->fReorder, pPars->fVerbose ); + if ( dd == NULL ) + { + if ( !pPars->fSilent ) + printf( "The number of intermediate BDD nodes exceeded the limit (%d).\n", pPars->nBddMax ); + return -1; + } + if ( pPars->fVerbose ) + printf( "Shared BDD size is %6d nodes.\n", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + + // check the runtime limit + if ( pPars->TimeLimit && pPars->TimeLimit <= (Abc_Clock()-clk)/CLOCKS_PER_SEC ) + { + printf( "Reached timeout after constructing global BDDs (%d seconds).\n", pPars->TimeLimit ); + Cudd_Quit( dd ); + return -1; + } + + // start the onion rings + vOnionRings = Vec_PtrAlloc( 1000 ); + + // save outputs + pbOutputs = Aig_ManCreateOutputs( dd, p ); + + // create partitions + pbParts = Aig_ManCreatePartitions( dd, p, pPars->fReorder, pPars->fVerbose ); + + // create the initial state and the variable map + bInitial = Aig_ManInitStateVarMap( dd, p, pPars->fVerbose ); Cudd_Ref( bInitial ); + + // set reordering + if ( pPars->fReorderImage ) + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + + // check the result + RetValue = -1; + for ( i = 0; i < Saig_ManPoNum(p); i++ ) + { + if ( fCheckOutputs && !Cudd_bddLeq( dd, bInitial, Cudd_Not(pbOutputs[i]) ) ) + { + DdNode * bIntersect; + bIntersect = Cudd_bddIntersect( dd, bInitial, pbOutputs[i] ); Cudd_Ref( bIntersect ); + assert( p->pSeqModel == NULL ); + p->pSeqModel = Aig_ManVerifyUsingBddsCountExample( p, dd, pbParts, + vOnionRings, bIntersect, i, pPars->fVerbose, pPars->fSilent ); + Cudd_RecursiveDeref( dd, bIntersect ); + if ( !pPars->fSilent ) + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", i, p->pName, -1 ); + RetValue = 0; + break; + } + } + // free the onion rings + Vec_PtrForEachEntry( DdNode *, vOnionRings, bTemp, i ) + Cudd_RecursiveDeref( dd, bTemp ); + Vec_PtrFree( vOnionRings ); + // explore reachable states + if ( RetValue == -1 ) + RetValue = Aig_ManComputeReachable( dd, p, pbParts, bInitial, pbOutputs, pPars, fCheckOutputs ); + + // cleanup + Cudd_RecursiveDeref( dd, bInitial ); + for ( i = 0; i < Saig_ManRegNum(p); i++ ) + Cudd_RecursiveDeref( dd, pbParts[i] ); + ABC_FREE( pbParts ); + for ( i = 0; i < Saig_ManPoNum(p); i++ ) + Cudd_RecursiveDeref( dd, pbOutputs[i] ); + ABC_FREE( pbOutputs ); +// if ( RetValue == -1 ) + Cudd_Quit( dd ); +// else +// Bbr_StopManager( dd ); + + // report the runtime + if ( !pPars->fSilent ) + { + ABC_PRT( "Time", Abc_Clock() - clk ); + fflush( stdout ); + } + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Performs reachability to see if any PO can be asserted.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Aig_ManVerifyUsingBdds( Aig_Man_t * pInit, Saig_ParBbr_t * pPars ) +{ + Abc_Cex_t * pCexOld, * pCexNew; + Aig_Man_t * p; + Aig_Obj_t * pObj; + Vec_Int_t * vInputMap; + int i, k, Entry, iBitOld, iBitNew, RetValue; +// pPars->fVerbose = 1; + // check if there are PIs without fanout + Saig_ManForEachPi( pInit, pObj, i ) + if ( Aig_ObjRefs(pObj) == 0 ) + break; + if ( i == Saig_ManPiNum(pInit) ) + return Aig_ManVerifyUsingBdds_int( pInit, pPars ); + // create new AIG + p = Aig_ManDupTrim( pInit ); + assert( Aig_ManCiNum(p) < Aig_ManCiNum(pInit) ); + assert( Aig_ManRegNum(p) == Aig_ManRegNum(pInit) ); + RetValue = Aig_ManVerifyUsingBdds_int( p, pPars ); + if ( RetValue != 0 ) + { + Aig_ManStop( p ); + return RetValue; + } + // the problem is satisfiable - remap the pattern + pCexOld = p->pSeqModel; + assert( pCexOld != NULL ); + // create input map + vInputMap = Vec_IntAlloc( Saig_ManPiNum(pInit) ); + Saig_ManForEachPi( pInit, pObj, i ) + if ( pObj->pData != NULL ) + Vec_IntPush( vInputMap, Aig_ObjCioId((Aig_Obj_t *)pObj->pData) ); + else + Vec_IntPush( vInputMap, -1 ); + // create new pattern + pCexNew = Abc_CexAlloc( Saig_ManRegNum(pInit), Saig_ManPiNum(pInit), pCexOld->iFrame+1 ); + pCexNew->iFrame = pCexOld->iFrame; + pCexNew->iPo = pCexOld->iPo; + // copy the bit-data + for ( iBitOld = 0; iBitOld < pCexOld->nRegs; iBitOld++ ) + if ( Abc_InfoHasBit( pCexOld->pData, iBitOld ) ) + Abc_InfoSetBit( pCexNew->pData, iBitOld ); + // copy the primary input data + iBitNew = iBitOld; + for ( i = 0; i <= pCexNew->iFrame; i++ ) + { + Vec_IntForEachEntry( vInputMap, Entry, k ) + { + if ( Entry == -1 ) + continue; + if ( Abc_InfoHasBit( pCexOld->pData, iBitOld + Entry ) ) + Abc_InfoSetBit( pCexNew->pData, iBitNew + k ); + } + iBitOld += Saig_ManPiNum(p); + iBitNew += Saig_ManPiNum(pInit); + } + assert( iBitOld < iBitNew ); + assert( iBitOld == pCexOld->nBits ); + assert( iBitNew == pCexNew->nBits ); + Vec_IntFree( vInputMap ); + pInit->pSeqModel = pCexNew; + Aig_ManStop( p ); + return 0; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/bbr/bbr_.c b/src/bdd/bbr/bbr_.c new file mode 100644 index 00000000..df934f7d --- /dev/null +++ b/src/bdd/bbr/bbr_.c @@ -0,0 +1,52 @@ +/**CFile**************************************************************** + + FileName [.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: .c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "__Int.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/bbr/module.make b/src/bdd/bbr/module.make new file mode 100644 index 00000000..4bb1a292 --- /dev/null +++ b/src/bdd/bbr/module.make @@ -0,0 +1,4 @@ +SRC += src/bdd/bbr/bbrCex.c \ + src/bdd/bbr/bbrImage.c \ + src/bdd/bbr/bbrNtbdd.c \ + src/bdd/bbr/bbrReach.c diff --git a/src/bdd/extrab/extraBdd.h b/src/bdd/extrab/extraBdd.h new file mode 100644 index 00000000..3dbc6264 --- /dev/null +++ b/src/bdd/extrab/extraBdd.h @@ -0,0 +1,317 @@ +/**CFile**************************************************************** + + FileName [extraBdd.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [Various reusable software utilities.] + + Description [This library contains a number of operators and + traversal routines developed to extend the functionality of + CUDD v.2.3.x, by Fabio Somenzi (http://vlsi.colorado.edu/~fabio/) + To compile your code with the library, #include "extra.h" + in your source files and link your project to CUDD and this + library. Use the library at your own risk and with caution. + Note that debugging of some operators still continues.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraBdd.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef ABC__misc__extra__extra_bdd_h +#define ABC__misc__extra__extra_bdd_h + + +#ifdef _WIN32 +#define inline __inline // compatible with MS VS 6.0 +#endif + +/*---------------------------------------------------------------------------*/ +/* Nested includes */ +/*---------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +#include "misc/st/st.h" +#include "bdd/cudd/cuddInt.h" +#include "misc/extra/extra.h" + + +ABC_NAMESPACE_HEADER_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +/* constants of the manager */ +#define b0 Cudd_Not((dd)->one) +#define b1 (dd)->one +#define z0 (dd)->zero +#define z1 (dd)->one +#define a0 (dd)->zero +#define a1 (dd)->one + +// hash key macros +#define hashKey1(a,TSIZE) \ +((ABC_PTRUINT_T)(a) % TSIZE) + +#define hashKey2(a,b,TSIZE) \ +(((ABC_PTRUINT_T)(a) + (ABC_PTRUINT_T)(b) * DD_P1) % TSIZE) + +#define hashKey3(a,b,c,TSIZE) \ +(((((ABC_PTRUINT_T)(a) + (ABC_PTRUINT_T)(b)) * DD_P1 + (ABC_PTRUINT_T)(c)) * DD_P2 ) % TSIZE) + +#define hashKey4(a,b,c,d,TSIZE) \ +((((((ABC_PTRUINT_T)(a) + (ABC_PTRUINT_T)(b)) * DD_P1 + (ABC_PTRUINT_T)(c)) * DD_P2 + \ + (ABC_PTRUINT_T)(d)) * DD_P3) % TSIZE) + +#define hashKey5(a,b,c,d,e,TSIZE) \ +(((((((ABC_PTRUINT_T)(a) + (ABC_PTRUINT_T)(b)) * DD_P1 + (ABC_PTRUINT_T)(c)) * DD_P2 + \ + (ABC_PTRUINT_T)(d)) * DD_P3 + (ABC_PTRUINT_T)(e)) * DD_P1) % TSIZE) + +/*===========================================================================*/ +/* Various Utilities */ +/*===========================================================================*/ + +/*=== extraBddAuto.c ========================================================*/ + +extern DdNode * Extra_bddSpaceFromFunctionFast( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ); +extern DdNode * extraBddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ); +extern DdNode * Extra_bddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ); +extern DdNode * extraBddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ); +extern DdNode * extraBddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ); + +extern DdNode * Extra_bddSpaceCanonVars( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceCanonVars( DdManager * dd, DdNode * bSpace ); + +extern DdNode * Extra_bddSpaceEquations( DdManager * dd, DdNode * bSpace ); +extern DdNode * Extra_bddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ); +extern DdNode * Extra_bddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ); +extern DdNode * extraBddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ); + +extern DdNode * Extra_bddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ); +extern DdNode * extraBddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ); +extern DdNode * Extra_bddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ); +extern DdNode * extraBddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ); + +extern DdNode * Extra_bddSpaceReduce( DdManager * dd, DdNode * bFunc, DdNode * bCanonVars ); +extern DdNode ** Extra_bddSpaceExorGates( DdManager * dd, DdNode * bFuncRed, DdNode * zEquations ); + +/*=== extraBddCas.c =============================================================*/ + +/* performs the binary encoding of the set of function using the given vars */ +extern DdNode * Extra_bddEncodingBinary( DdManager * dd, DdNode ** pbFuncs, int nFuncs, DdNode ** pbVars, int nVars ); +/* solves the column encoding problem using a sophisticated method */ +extern DdNode * Extra_bddEncodingNonStrict( DdManager * dd, DdNode ** pbColumns, int nColumns, DdNode * bVarsCol, DdNode ** pCVars, int nMulti, int * pSimple ); +/* collects the nodes under the cut and, for each node, computes the sum of paths leading to it from the root */ +extern st__table * Extra_bddNodePathsUnderCut( DdManager * dd, DdNode * bFunc, int CutLevel ); +/* collects the nodes under the cut starting from the given set of ADD nodes */ +extern int Extra_bddNodePathsUnderCutArray( DdManager * dd, DdNode ** paNodes, DdNode ** pbCubes, int nNodes, DdNode ** paNodesRes, DdNode ** pbCubesRes, int CutLevel ); +/* find the profile of a DD (the number of edges crossing each level) */ +extern int Extra_ProfileWidth( DdManager * dd, DdNode * F, int * Profile, int CutLevel ); + +/*=== extraBddImage.c ================================================================*/ + +typedef struct Extra_ImageTree_t_ Extra_ImageTree_t; +extern Extra_ImageTree_t * Extra_bddImageStart( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int fVerbose ); +extern DdNode * Extra_bddImageCompute( Extra_ImageTree_t * pTree, DdNode * bCare ); +extern void Extra_bddImageTreeDelete( Extra_ImageTree_t * pTree ); +extern DdNode * Extra_bddImageRead( Extra_ImageTree_t * pTree ); + +typedef struct Extra_ImageTree2_t_ Extra_ImageTree2_t; +extern Extra_ImageTree2_t * Extra_bddImageStart2( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int fVerbose ); +extern DdNode * Extra_bddImageCompute2( Extra_ImageTree2_t * pTree, DdNode * bCare ); +extern void Extra_bddImageTreeDelete2( Extra_ImageTree2_t * pTree ); +extern DdNode * Extra_bddImageRead2( Extra_ImageTree2_t * pTree ); + +/*=== extraBddMisc.c ========================================================*/ + +extern DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute ); +extern DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f ); +extern DdNode * Extra_bddRemapUp( DdManager * dd, DdNode * bF ); +extern DdNode * Extra_bddMove( DdManager * dd, DdNode * bF, int nVars ); +extern DdNode * extraBddMove( DdManager * dd, DdNode * bF, DdNode * bFlag ); +extern void Extra_StopManager( DdManager * dd ); +extern void Extra_bddPrint( DdManager * dd, DdNode * F ); +extern void Extra_bddPrintSupport( DdManager * dd, DdNode * F ); +extern void extraDecomposeCover( DdManager* dd, DdNode* zC, DdNode** zC0, DdNode** zC1, DdNode** zC2 ); +extern int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp ); +extern int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar ); +extern int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 ); +extern int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax ); +extern int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall ); +extern int * Extra_SupportArray( DdManager * dd, DdNode * F, int * support ); +extern int * Extra_VectorSupportArray( DdManager * dd, DdNode ** F, int n, int * support ); +extern DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF ); +extern DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc ); +extern DdNode * Extra_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ); +extern DdNode * Extra_bddBitsToCube( DdManager * dd, int Code, int CodeWidth, DdNode ** pbVars, int fMsbFirst ); +extern DdNode * Extra_bddSupportNegativeCube( DdManager * dd, DdNode * f ); +extern int Extra_bddIsVar( DdNode * bFunc ); +extern DdNode * Extra_bddCreateAnd( DdManager * dd, int nVars ); +extern DdNode * Extra_bddCreateOr( DdManager * dd, int nVars ); +extern DdNode * Extra_bddCreateExor( DdManager * dd, int nVars ); +extern DdNode * Extra_zddPrimes( DdManager * dd, DdNode * F ); +extern void Extra_bddPermuteArray( DdManager * dd, DdNode ** bNodesIn, DdNode ** bNodesOut, int nNodes, int *permut ); +extern DdNode * Extra_bddComputeCube( DdManager * dd, DdNode ** bXVars, int nVars ); +extern DdNode * Extra_bddChangePolarity( DdManager * dd, DdNode * bFunc, DdNode * bVars ); +extern DdNode * extraBddChangePolarity( DdManager * dd, DdNode * bFunc, DdNode * bVars ); +extern int Extra_bddVarIsInCube( DdNode * bCube, int iVar ); +extern DdNode * Extra_bddAndPermute( DdManager * ddF, DdNode * bF, DdManager * ddG, DdNode * bG, int * pPermute ); +extern int Extra_bddCountCubes( DdManager * dd, DdNode ** pFuncs, int nFuncs, int fMode, int nLimit, int * pGuide ); +extern void Extra_zddDumpPla( DdManager * dd, DdNode * zCover, int nVars, char * pFileName ); + +#ifndef ABC_PRB +#define ABC_PRB(dd,f) printf("%s = ", #f); Extra_bddPrint(dd,f); printf("\n") +#endif + +/*=== extraBddKmap.c ================================================================*/ + +/* displays the Karnaugh Map of a function */ +extern void Extra_PrintKMap( FILE * pFile, DdManager * dd, DdNode * OnSet, DdNode * OffSet, int nVars, DdNode ** XVars, int fSuppType, char ** pVarNames ); +/* displays the Karnaugh Map of a relation */ +extern void Extra_PrintKMapRelation( FILE * pFile, DdManager * dd, DdNode * OnSet, DdNode * OffSet, int nXVars, int nYVars, DdNode ** XVars, DdNode ** YVars ); + +/*=== extraBddSymm.c =================================================================*/ + +typedef struct Extra_SymmInfo_t_ Extra_SymmInfo_t; +struct Extra_SymmInfo_t_ { + int nVars; // the number of variables in the support + int nVarsMax; // the number of variables in the DD manager + int nSymms; // the number of pair-wise symmetries + int nNodes; // the number of nodes in a ZDD (if applicable) + int * pVars; // the list of all variables present in the support + char ** pSymms; // the symmetry information +}; + +/* computes the classical symmetry information for the function - recursive */ +extern Extra_SymmInfo_t * Extra_SymmPairsCompute( DdManager * dd, DdNode * bFunc ); +/* computes the classical symmetry information for the function - using naive approach */ +extern Extra_SymmInfo_t * Extra_SymmPairsComputeNaive( DdManager * dd, DdNode * bFunc ); +extern int Extra_bddCheckVarsSymmetricNaive( DdManager * dd, DdNode * bF, int iVar1, int iVar2 ); + +/* allocates the data structure */ +extern Extra_SymmInfo_t * Extra_SymmPairsAllocate( int nVars ); +/* deallocates the data structure */ +extern void Extra_SymmPairsDissolve( Extra_SymmInfo_t * ); +/* print the contents the data structure */ +extern void Extra_SymmPairsPrint( Extra_SymmInfo_t * ); +/* converts the ZDD into the Extra_SymmInfo_t structure */ +extern Extra_SymmInfo_t * Extra_SymmPairsCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bVars ); + +/* computes the classical symmetry information as a ZDD */ +extern DdNode * Extra_zddSymmPairsCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +extern DdNode * extraZddSymmPairsCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +/* returns a singleton-set ZDD containing all variables that are symmetric with the given one */ +extern DdNode * Extra_zddGetSymmetricVars( DdManager * dd, DdNode * bF, DdNode * bG, DdNode * bVars ); +extern DdNode * extraZddGetSymmetricVars( DdManager * dd, DdNode * bF, DdNode * bG, DdNode * bVars ); +/* converts a set of variables into a set of singleton subsets */ +extern DdNode * Extra_zddGetSingletons( DdManager * dd, DdNode * bVars ); +extern DdNode * extraZddGetSingletons( DdManager * dd, DdNode * bVars ); +/* filters the set of variables using the support of the function */ +extern DdNode * Extra_bddReduceVarSet( DdManager * dd, DdNode * bVars, DdNode * bF ); +extern DdNode * extraBddReduceVarSet( DdManager * dd, DdNode * bVars, DdNode * bF ); + +/* checks the possibility that the two vars are symmetric */ +extern int Extra_bddCheckVarsSymmetric( DdManager * dd, DdNode * bF, int iVar1, int iVar2 ); +extern DdNode * extraBddCheckVarsSymmetric( DdManager * dd, DdNode * bF, DdNode * bVars ); + +/* build the set of all tuples of K variables out of N from the BDD cube */ +extern DdNode * Extra_zddTuplesFromBdd( DdManager * dd, int K, DdNode * bVarsN ); +extern DdNode * extraZddTuplesFromBdd( DdManager * dd, DdNode * bVarsK, DdNode * bVarsN ); +/* selects one subset from a ZDD representing the set of subsets */ +extern DdNode * Extra_zddSelectOneSubset( DdManager * dd, DdNode * zS ); +extern DdNode * extraZddSelectOneSubset( DdManager * dd, DdNode * zS ); + +/*=== extraBddUnate.c =================================================================*/ + +extern DdNode * Extra_bddAndTime( DdManager * dd, DdNode * f, DdNode * g, int TimeOut ); +extern DdNode * Extra_bddAndAbstractTime( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube, int TimeOut ); +extern DdNode * Extra_TransferPermuteTime( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute, int TimeOut ); + +/*=== extraBddUnate.c =================================================================*/ + +typedef struct Extra_UnateVar_t_ Extra_UnateVar_t; +struct Extra_UnateVar_t_ { + unsigned iVar : 30; // index of the variable + unsigned Pos : 1; // 1 if positive unate + unsigned Neg : 1; // 1 if negative unate +}; + +typedef struct Extra_UnateInfo_t_ Extra_UnateInfo_t; +struct Extra_UnateInfo_t_ { + int nVars; // the number of variables in the support + int nVarsMax; // the number of variables in the DD manager + int nUnate; // the number of unate variables + Extra_UnateVar_t * pVars; // the array of variables present in the support +}; + +/* allocates the data structure */ +extern Extra_UnateInfo_t * Extra_UnateInfoAllocate( int nVars ); +/* deallocates the data structure */ +extern void Extra_UnateInfoDissolve( Extra_UnateInfo_t * ); +/* print the contents the data structure */ +extern void Extra_UnateInfoPrint( Extra_UnateInfo_t * ); +/* converts the ZDD into the Extra_SymmInfo_t structure */ +extern Extra_UnateInfo_t * Extra_UnateInfoCreateFromZdd( DdManager * dd, DdNode * zUnate, DdNode * bVars ); +/* naive check of unateness of one variable */ +extern int Extra_bddCheckUnateNaive( DdManager * dd, DdNode * bF, int iVar ); + +/* computes the unateness information for the function */ +extern Extra_UnateInfo_t * Extra_UnateComputeFast( DdManager * dd, DdNode * bFunc ); +extern Extra_UnateInfo_t * Extra_UnateComputeSlow( DdManager * dd, DdNode * bFunc ); + +/* computes the classical symmetry information as a ZDD */ +extern DdNode * Extra_zddUnateInfoCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); +extern DdNode * extraZddUnateInfoCompute( DdManager * dd, DdNode * bF, DdNode * bVars ); + +/* converts a set of variables into a set of singleton subsets */ +extern DdNode * Extra_zddGetSingletonsBoth( DdManager * dd, DdNode * bVars ); +extern DdNode * extraZddGetSingletonsBoth( DdManager * dd, DdNode * bVars ); + +/**AutomaticEnd***************************************************************/ + + + +ABC_NAMESPACE_HEADER_END + + + +#endif /* __EXTRA_H__ */ diff --git a/src/bdd/extrab/extraBddAuto.c b/src/bdd/extrab/extraBddAuto.c new file mode 100644 index 00000000..5fb38aec --- /dev/null +++ b/src/bdd/extrab/extraBddAuto.c @@ -0,0 +1,1563 @@ +/**CFile**************************************************************** + + FileName [extraBddAuto.c] + + PackageName [extra] + + Synopsis [Computation of autosymmetries.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddAuto.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + + +/* + LinearSpace(f) = Space(f,f) + + Space(f,g) + { + if ( f = const ) + { + if ( f = g ) return 1; + else return 0; + } + if ( g = const ) return 0; + return x' * Space(fx',gx') * Space(fx,gx) + x * Space(fx',gx) * Space(fx,gx'); + } + + Equations(s) = Pos(s) + Neg(s); + + Pos(s) + { + if ( s = 0 ) return 1; + if ( s = 1 ) return 0; + if ( sx'= 0 ) return Pos(sx) + x; + if ( sx = 0 ) return Pos(sx'); + return 1 * [Pos(sx') & Pos(sx)] + x * [Pos(sx') & Neg(sx)]; + } + + Neg(s) + { + if ( s = 0 ) return 1; + if ( s = 1 ) return 0; + if ( sx'= 0 ) return Neg(sx); + if ( sx = 0 ) return Neg(sx') + x; + return 1 * [Neg(sx') & Neg(sx)] + x * [Neg(sx') & Pos(sx)]; + } + + + SpaceP(A) + { + if ( A = 0 ) return 1; + if ( A = 1 ) return 1; + return x' * SpaceP(Ax') * SpaceP(Ax) + x * SpaceP(Ax') * SpaceN(Ax); + } + + SpaceN(A) + { + if ( A = 0 ) return 1; + if ( A = 1 ) return 0; + return x' * SpaceN(Ax') * SpaceN(Ax) + x * SpaceN(Ax') * SpaceP(Ax); + } + + + LinInd(A) + { + if ( A = const ) return 1; + if ( !LinInd(Ax') ) return 0; + if ( !LinInd(Ax) ) return 0; + if ( LinSumOdd(Ax') & LinSumEven(Ax) != 0 ) return 0; + if ( LinSumEven(Ax') & LinSumEven(Ax) != 0 ) return 0; + return 1; + } + + LinSumOdd(A) + { + if ( A = 0 ) return 0; // Odd0 ---e-- Odd1 + if ( A = 1 ) return 1; // \ o + Odd0 = LinSumOdd(Ax'); // x is absent // \ + Even0 = LinSumEven(Ax'); // x is absent // / o + Odd1 = LinSumOdd(Ax); // x is present // Even0 ---e-- Even1 + Even1 = LinSumEven(Ax); // x is absent + return 1 * [Odd0 + ExorP(Odd0, Even1)] + x * [Odd1 + ExorP(Odd1, Even0)]; + } + + LinSumEven(A) + { + if ( A = 0 ) return 0; + if ( A = 1 ) return 0; + Odd0 = LinSumOdd(Ax'); // x is absent + Even0 = LinSumEven(Ax'); // x is absent + Odd1 = LinSumOdd(Ax); // x is present + Even1 = LinSumEven(Ax); // x is absent + return 1 * [Even0 + Even1 + ExorP(Even0, Even1)] + x * [ExorP(Odd0, Odd1)]; + } + +*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionFast( DdManager * dd, DdNode * bFunc ) +{ + int * pSupport; + int * pPermute; + int * pPermuteBack; + DdNode ** pCompose; + DdNode * bCube, * bTemp; + DdNode * bSpace, * bFunc1, * bFunc2, * bSpaceShift; + int nSupp, Counter; + int i, lev; + + // get the support + pSupport = ABC_ALLOC( int, ddMax(dd->size,dd->sizeZ) ); + Extra_SupportArray( dd, bFunc, pSupport ); + nSupp = 0; + for ( i = 0; i < dd->size; i++ ) + if ( pSupport[i] ) + nSupp++; + + // make sure the manager has enough variables + if ( 2*nSupp > dd->size ) + { + printf( "Cannot derive linear space, because DD manager does not have enough variables.\n" ); + fflush( stdout ); + ABC_FREE( pSupport ); + return NULL; + } + + // create the permutation arrays + pPermute = ABC_ALLOC( int, dd->size ); + pPermuteBack = ABC_ALLOC( int, dd->size ); + pCompose = ABC_ALLOC( DdNode *, dd->size ); + for ( i = 0; i < dd->size; i++ ) + { + pPermute[i] = i; + pPermuteBack[i] = i; + pCompose[i] = dd->vars[i]; Cudd_Ref( pCompose[i] ); + } + + // remap the function in such a way that the variables are interleaved + Counter = 0; + bCube = b1; Cudd_Ref( bCube ); + for ( lev = 0; lev < dd->size; lev++ ) + if ( pSupport[ dd->invperm[lev] ] ) + { // var "dd->invperm[lev]" on level "lev" should go to level 2*Counter; + pPermute[ dd->invperm[lev] ] = dd->invperm[2*Counter]; + // var from level 2*Counter+1 should go back to the place of this var + pPermuteBack[ dd->invperm[2*Counter+1] ] = dd->invperm[lev]; + // the permutation should be defined in such a way that variable + // on level 2*Counter is replaced by an EXOR of itself and var on the next level + Cudd_Deref( pCompose[ dd->invperm[2*Counter] ] ); + pCompose[ dd->invperm[2*Counter] ] = + Cudd_bddXor( dd, dd->vars[ dd->invperm[2*Counter] ], dd->vars[ dd->invperm[2*Counter+1] ] ); + Cudd_Ref( pCompose[ dd->invperm[2*Counter] ] ); + // add this variable to the cube + bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[ dd->invperm[2*Counter] ] ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + // increment the counter + Counter ++; + } + + // permute the functions + bFunc1 = Cudd_bddPermute( dd, bFunc, pPermute ); Cudd_Ref( bFunc1 ); + // compose to gate the function depending on both vars + bFunc2 = Cudd_bddVectorCompose( dd, bFunc1, pCompose ); Cudd_Ref( bFunc2 ); + // gate the vector space + // L(a) = ForAll x [ F(x) = F(x+a) ] = Not( Exist x [ F(x) (+) F(x+a) ] ) + bSpaceShift = Cudd_bddXorExistAbstract( dd, bFunc1, bFunc2, bCube ); Cudd_Ref( bSpaceShift ); + bSpaceShift = Cudd_Not( bSpaceShift ); + // permute the space back into the original mapping + bSpace = Cudd_bddPermute( dd, bSpaceShift, pPermuteBack ); Cudd_Ref( bSpace ); + Cudd_RecursiveDeref( dd, bFunc1 ); + Cudd_RecursiveDeref( dd, bFunc2 ); + Cudd_RecursiveDeref( dd, bSpaceShift ); + Cudd_RecursiveDeref( dd, bCube ); + + for ( i = 0; i < dd->size; i++ ) + Cudd_RecursiveDeref( dd, pCompose[i] ); + ABC_FREE( pPermute ); + ABC_FREE( pPermuteBack ); + ABC_FREE( pCompose ); + ABC_FREE( pSupport ); + + Cudd_Deref( bSpace ); + return bSpace; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunction( dd, bF, bG ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionPos( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunctionPos( dd, bFunc ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromFunctionNeg( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromFunctionNeg( dd, bFunc ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceCanonVars( DdManager * dd, DdNode * bSpace ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceCanonVars( dd, bSpace ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceReduce( DdManager * dd, DdNode * bFunc, DdNode * bCanonVars ) +{ + DdNode * bNegCube; + DdNode * bResult; + bNegCube = Extra_bddSupportNegativeCube( dd, bCanonVars ); Cudd_Ref( bNegCube ); + bResult = Cudd_Cofactor( dd, bFunc, bNegCube ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bNegCube ); + Cudd_Deref( bResult ); + return bResult; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquations( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + DdNode * zEquPos; + DdNode * zEquNeg; + zEquPos = Extra_bddSpaceEquationsPos( dd, bSpace ); Cudd_Ref( zEquPos ); + zEquNeg = Extra_bddSpaceEquationsNeg( dd, bSpace ); Cudd_Ref( zEquNeg ); + zRes = Cudd_zddUnion( dd, zEquPos, zEquNeg ); Cudd_Ref( zRes ); + Cudd_RecursiveDerefZdd( dd, zEquPos ); + Cudd_RecursiveDerefZdd( dd, zEquNeg ); + Cudd_Deref( zRes ); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquationsPos( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + do { + dd->reordered = 0; + zRes = extraBddSpaceEquationsPos( dd, bSpace ); + } while (dd->reordered == 1); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceEquationsNeg( DdManager * dd, DdNode * bSpace ) +{ + DdNode * zRes; + do { + dd->reordered = 0; + zRes = extraBddSpaceEquationsNeg( dd, bSpace ); + } while (dd->reordered == 1); + return zRes; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromMatrixPos( dd, zA ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + do { + dd->reordered = 0; + bRes = extraBddSpaceFromMatrixNeg( dd, zA ); + } while (dd->reordered == 1); + return bRes; +} + +/**Function************************************************************* + + Synopsis [Counts the number of literals in one combination.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_zddLitCountComb( DdManager * dd, DdNode * zComb ) +{ + int Counter; + if ( zComb == z0 ) + return 0; + Counter = 0; + for ( ; zComb != z1; zComb = cuddT(zComb) ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [] + + Description [Returns the array of ZDDs with the number equal to the number of + vars in the DD manager. If the given var is non-canonical, this array contains + the referenced ZDD representing literals in the corresponding EXOR equation.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode ** Extra_bddSpaceExorGates( DdManager * dd, DdNode * bFuncRed, DdNode * zEquations ) +{ + DdNode ** pzRes; + int * pVarsNonCan; + DdNode * zEquRem; + int iVarNonCan; + DdNode * zExor, * zTemp; + + // get the set of non-canonical variables + pVarsNonCan = ABC_ALLOC( int, ddMax(dd->size,dd->sizeZ) ); + Extra_SupportArray( dd, bFuncRed, pVarsNonCan ); + + // allocate storage for the EXOR sets + pzRes = ABC_ALLOC( DdNode *, dd->size ); + memset( pzRes, 0, sizeof(DdNode *) * dd->size ); + + // go through all the equations + zEquRem = zEquations; Cudd_Ref( zEquRem ); + while ( zEquRem != z0 ) + { + // extract one product + zExor = Extra_zddSelectOneSubset( dd, zEquRem ); Cudd_Ref( zExor ); + // remove it from the set + zEquRem = Cudd_zddDiff( dd, zTemp = zEquRem, zExor ); Cudd_Ref( zEquRem ); + Cudd_RecursiveDerefZdd( dd, zTemp ); + + // locate the non-canonical variable + iVarNonCan = -1; + for ( zTemp = zExor; zTemp != z1; zTemp = cuddT(zTemp) ) + { + if ( pVarsNonCan[zTemp->index/2] == 1 ) + { + assert( iVarNonCan == -1 ); + iVarNonCan = zTemp->index/2; + } + } + assert( iVarNonCan != -1 ); + + if ( Extra_zddLitCountComb( dd, zExor ) > 1 ) + pzRes[ iVarNonCan ] = zExor; // takes ref + else + Cudd_RecursiveDerefZdd( dd, zExor ); + } + Cudd_RecursiveDerefZdd( dd, zEquRem ); + + ABC_FREE( pVarsNonCan ); + return pzRes; +} + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the recursive steps of Extra_bddSpaceFromFunction.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ) +{ + DdNode * bRes; + DdNode * bFR, * bGR; + + bFR = Cudd_Regular( bF ); + bGR = Cudd_Regular( bG ); + if ( cuddIsConstant(bFR) ) + { + if ( bF == bG ) + return b1; + else + return b0; + } + if ( cuddIsConstant(bGR) ) + return b0; + // both bFunc and bCore are not constants + + // the operation is commutative - normalize the problem + if ( (unsigned)(ABC_PTRUINT_T)bF > (unsigned)(ABC_PTRUINT_T)bG ) + return extraBddSpaceFromFunction(dd, bG, bF); + + + if ( (bRes = cuddCacheLookup2(dd, extraBddSpaceFromFunction, bF, bG)) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bG0, * bG1; + DdNode * bTemp1, * bTemp2; + DdNode * bRes0, * bRes1; + int LevelF, LevelG; + int index; + + LevelF = dd->perm[bFR->index]; + LevelG = dd->perm[bGR->index]; + if ( LevelF <= LevelG ) + { + index = dd->invperm[LevelF]; + if ( bFR != bF ) + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + { + index = dd->invperm[LevelG]; + bF0 = bF1 = bF; + } + + if ( LevelG <= LevelF ) + { + if ( bGR != bG ) + { + bG0 = Cudd_Not( cuddE(bGR) ); + bG1 = Cudd_Not( cuddT(bGR) ); + } + else + { + bG0 = cuddE(bGR); + bG1 = cuddT(bGR); + } + } + else + bG0 = bG1 = bG; + + bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG0 ); + if ( bTemp1 == NULL ) + return NULL; + cuddRef( bTemp1 ); + + bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG1 ); + if ( bTemp2 == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp1 ); + return NULL; + } + cuddRef( bTemp2 ); + + + bRes0 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + + + bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG1 ); + if ( bTemp1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bTemp1 ); + + bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG0 ); + if ( bTemp2 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + return NULL; + } + cuddRef( bTemp2 ); + + bRes1 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bTemp1 ); + Cudd_RecursiveDeref( dd, bTemp2 ); + + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter(dd, index, Cudd_Not(bRes1), Cudd_Not(bRes0)); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + // insert the result into cache + cuddCacheInsert2(dd, extraBddSpaceFromFunction, bF, bG, bRes); + return bRes; + } +} /* end of extraBddSpaceFromFunction */ + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromFunctionPos( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return b1; + + if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromFunctionPos, bF)) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bPos0, * bPos1; + DdNode * bNeg0, * bNeg1; + DdNode * bRes0, * bRes1; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + + bPos0 = extraBddSpaceFromFunctionPos( dd, bF0 ); + if ( bPos0 == NULL ) + return NULL; + cuddRef( bPos0 ); + + bPos1 = extraBddSpaceFromFunctionPos( dd, bF1 ); + if ( bPos1 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + return NULL; + } + cuddRef( bPos1 ); + + bRes0 = cuddBddAndRecur( dd, bPos0, bPos1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + + + bNeg0 = extraBddSpaceFromFunctionNeg( dd, bF0 ); + if ( bNeg0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bNeg0 ); + + bNeg1 = extraBddSpaceFromFunctionNeg( dd, bF1 ); + if ( bNeg1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + return NULL; + } + cuddRef( bNeg1 ); + + bRes1 = cuddBddAndRecur( dd, bNeg0, bNeg1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromFunctionPos, bF, bRes ); + return bRes; + } +} + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromFunctionNeg( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return b0; + + if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromFunctionNeg, bF)) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bPos0, * bPos1; + DdNode * bNeg0, * bNeg1; + DdNode * bRes0, * bRes1; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + + bPos0 = extraBddSpaceFromFunctionNeg( dd, bF0 ); + if ( bPos0 == NULL ) + return NULL; + cuddRef( bPos0 ); + + bPos1 = extraBddSpaceFromFunctionNeg( dd, bF1 ); + if ( bPos1 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + return NULL; + } + cuddRef( bPos1 ); + + bRes0 = cuddBddAndRecur( dd, bPos0, bPos1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bPos0 ); + Cudd_RecursiveDeref( dd, bPos1 ); + + + bNeg0 = extraBddSpaceFromFunctionPos( dd, bF0 ); + if ( bNeg0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bNeg0 ); + + bNeg1 = extraBddSpaceFromFunctionPos( dd, bF1 ); + if ( bNeg1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + return NULL; + } + cuddRef( bNeg1 ); + + bRes1 = cuddBddAndRecur( dd, bNeg0, bNeg1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bNeg0 ); + Cudd_RecursiveDeref( dd, bNeg1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromFunctionNeg, bF, bRes ); + return bRes; + } +} + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceCanonVars().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceCanonVars( DdManager * dd, DdNode * bF ) +{ + DdNode * bRes, * bFR; + statLine( dd ); + + bFR = Cudd_Regular(bF); + if ( cuddIsConstant(bFR) ) + return bF; + + if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceCanonVars, bF)) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bRes, * bRes0; + + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + bRes = extraBddSpaceCanonVars( dd, bF1 ); + if ( bRes == NULL ) + return NULL; + } + else if ( bF1 == b0 ) + { + bRes = extraBddSpaceCanonVars( dd, bF0 ); + if ( bRes == NULL ) + return NULL; + } + else + { + bRes0 = extraBddSpaceCanonVars( dd, bF0 ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + + bRes = cuddUniqueInter( dd, bFR->index, bRes0, b0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd,bRes0 ); + return NULL; + } + cuddDeref( bRes0 ); + } + + cuddCacheInsert1( dd, extraBddSpaceCanonVars, bF, bRes ); + return bRes; + } +} + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceEquationsPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceEquationsPos( DdManager * dd, DdNode * bF ) +{ + DdNode * zRes; + statLine( dd ); + + if ( bF == b0 ) + return z1; + if ( bF == b1 ) + return z0; + + if ( (zRes = cuddCacheLookup1Zdd(dd, extraBddSpaceEquationsPos, bF)) ) + return zRes; + else + { + DdNode * bFR, * bF0, * bF1; + DdNode * zPos0, * zPos1, * zNeg1; + DdNode * zRes, * zRes0, * zRes1; + + bFR = Cudd_Regular(bF); + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + zRes1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zRes1 == NULL ) + return NULL; + cuddRef( zRes1 ); + + // add the current element to the set + zRes = cuddZddGetNode( dd, 2*bFR->index, z1, zRes1 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes1 ); + } + else if ( bF1 == b0 ) + { + zRes = extraBddSpaceEquationsPos( dd, bF0 ); + if ( zRes == NULL ) + return NULL; + } + else + { + zPos0 = extraBddSpaceEquationsPos( dd, bF0 ); + if ( zPos0 == NULL ) + return NULL; + cuddRef( zPos0 ); + + zPos1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zPos1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + return NULL; + } + cuddRef( zPos1 ); + + zNeg1 = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zNeg1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zNeg1 ); + + + zRes0 = cuddZddIntersect( dd, zPos0, zPos1 ); + if ( zRes0 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes0 ); + + zRes1 = cuddZddIntersect( dd, zPos0, zNeg1 ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes1 ); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + // only zRes0 and zRes1 are refed at this point + + zRes = cuddZddGetNode( dd, 2*bFR->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + } + + cuddCacheInsert1( dd, extraBddSpaceEquationsPos, bF, zRes ); + return zRes; + } +} + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceEquationsNev().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceEquationsNeg( DdManager * dd, DdNode * bF ) +{ + DdNode * zRes; + statLine( dd ); + + if ( bF == b0 ) + return z1; + if ( bF == b1 ) + return z0; + + if ( (zRes = cuddCacheLookup1Zdd(dd, extraBddSpaceEquationsNeg, bF)) ) + return zRes; + else + { + DdNode * bFR, * bF0, * bF1; + DdNode * zPos0, * zPos1, * zNeg1; + DdNode * zRes, * zRes0, * zRes1; + + bFR = Cudd_Regular(bF); + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( bF0 == b0 ) + { + zRes = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zRes == NULL ) + return NULL; + } + else if ( bF1 == b0 ) + { + zRes0 = extraBddSpaceEquationsNeg( dd, bF0 ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // add the current element to the set + zRes = cuddZddGetNode( dd, 2*bFR->index, z1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + return NULL; + } + cuddDeref( zRes0 ); + } + else + { + zPos0 = extraBddSpaceEquationsNeg( dd, bF0 ); + if ( zPos0 == NULL ) + return NULL; + cuddRef( zPos0 ); + + zPos1 = extraBddSpaceEquationsNeg( dd, bF1 ); + if ( zPos1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + return NULL; + } + cuddRef( zPos1 ); + + zNeg1 = extraBddSpaceEquationsPos( dd, bF1 ); + if ( zNeg1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zNeg1 ); + + + zRes0 = cuddZddIntersect( dd, zPos0, zPos1 ); + if ( zRes0 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes0 ); + + zRes1 = cuddZddIntersect( dd, zPos0, zNeg1 ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + return NULL; + } + cuddRef( zRes1 ); + Cudd_RecursiveDerefZdd(dd, zNeg1); + Cudd_RecursiveDerefZdd(dd, zPos0); + Cudd_RecursiveDerefZdd(dd, zPos1); + // only zRes0 and zRes1 are refed at this point + + zRes = cuddZddGetNode( dd, 2*bFR->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zRes0); + Cudd_RecursiveDerefZdd(dd, zRes1); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + } + + cuddCacheInsert1( dd, extraBddSpaceEquationsNeg, bF, zRes ); + return zRes; + } +} + + + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromMatrixPos( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + statLine( dd ); + + if ( zA == z0 ) + return b1; + if ( zA == z1 ) + return b1; + + if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromMatrixPos, zA)) ) + return bRes; + else + { + DdNode * bP0, * bP1; + DdNode * bN0, * bN1; + DdNode * bRes0, * bRes1; + + bP0 = extraBddSpaceFromMatrixPos( dd, cuddE(zA) ); + if ( bP0 == NULL ) + return NULL; + cuddRef( bP0 ); + + bP1 = extraBddSpaceFromMatrixPos( dd, cuddT(zA) ); + if ( bP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + return NULL; + } + cuddRef( bP1 ); + + bRes0 = cuddBddAndRecur( dd, bP0, bP1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + + + bN0 = extraBddSpaceFromMatrixPos( dd, cuddE(zA) ); + if ( bN0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bN0 ); + + bN1 = extraBddSpaceFromMatrixNeg( dd, cuddT(zA) ); + if ( bN1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + return NULL; + } + cuddRef( bN1 ); + + bRes1 = cuddBddAndRecur( dd, bN0, bN1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, zA->index/2, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, zA->index/2, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromMatrixPos, zA, bRes ); + return bRes; + } +} + + +/**Function************************************************************* + + Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ) +{ + DdNode * bRes; + statLine( dd ); + + if ( zA == z0 ) + return b1; + if ( zA == z1 ) + return b0; + + if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromMatrixNeg, zA)) ) + return bRes; + else + { + DdNode * bP0, * bP1; + DdNode * bN0, * bN1; + DdNode * bRes0, * bRes1; + + bP0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); + if ( bP0 == NULL ) + return NULL; + cuddRef( bP0 ); + + bP1 = extraBddSpaceFromMatrixNeg( dd, cuddT(zA) ); + if ( bP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + return NULL; + } + cuddRef( bP1 ); + + bRes0 = cuddBddAndRecur( dd, bP0, bP1 ); + if ( bRes0 == NULL ) + { + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + return NULL; + } + cuddRef( bRes0 ); + Cudd_RecursiveDeref( dd, bP0 ); + Cudd_RecursiveDeref( dd, bP1 ); + + + bN0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); + if ( bN0 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bN0 ); + + bN1 = extraBddSpaceFromMatrixPos( dd, cuddT(zA) ); + if ( bN1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + return NULL; + } + cuddRef( bN1 ); + + bRes1 = cuddBddAndRecur( dd, bN0, bN1 ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + return NULL; + } + cuddRef( bRes1 ); + Cudd_RecursiveDeref( dd, bN0 ); + Cudd_RecursiveDeref( dd, bN1 ); + + + // consider the case when Res0 and Res1 are the same node + if ( bRes0 == bRes1 ) + bRes = bRes1; + // consider the case when Res1 is complemented + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter( dd, zA->index/2, Cudd_Not(bRes1), Cudd_Not(bRes0) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, zA->index/2, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + + cuddCacheInsert1( dd, extraBddSpaceFromMatrixNeg, zA, bRes ); + return bRes; + } +} + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddCas.c b/src/bdd/extrab/extraBddCas.c new file mode 100644 index 00000000..024e4462 --- /dev/null +++ b/src/bdd/extrab/extraBddCas.c @@ -0,0 +1,1235 @@ +/**CFile**************************************************************** + + FileName [extraBddCas.c] + + PackageName [extra] + + Synopsis [Procedures related to LUT cascade synthesis.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddCas.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +// the table to store cofactor operations +#define _TABLESIZE_COF 51113 +typedef struct +{ + unsigned Sign; + DdNode * Arg1; +} _HashEntry_cof; +_HashEntry_cof HHTable1[_TABLESIZE_COF]; + +// the table to store the result of computation of the number of minterms +#define _TABLESIZE_MINT 15113 +typedef struct +{ + DdNode * Arg1; + unsigned Arg2; + unsigned Res; +} _HashEntry_mint; +_HashEntry_mint HHTable2[_TABLESIZE_MINT]; + +typedef struct +{ + int nEdges; // the number of in-coming edges of the node + DdNode * bSum; // the sum of paths of the incoming edges +} traventry; + +// the signature used for hashing +static unsigned s_Signature = 1; + +static int s_CutLevel = 0; + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +// because the proposed solution to the optimal encoding problem has exponential complexity +// we limit the depth of the branch and bound procedure to 5 levels +static int s_MaxDepth = 5; + +static int s_nVarsBest; // the number of vars in the best ordering +static int s_VarOrderBest[32]; // storing the best ordering of vars in the "simple encoding" +static int s_VarOrderCur[32]; // storing the current ordering of vars + +// the place to store the supports of the encoded function +static DdNode * s_Field[8][256]; // the size should be K, 2^K, where K is no less than MaxDepth +static DdNode * s_Encoded; // this is the original function +static DdNode * s_VarAll; // the set of all column variables +static int s_MultiStart; // the total number of encoding variables used +// the array field now stores the supports + +static DdNode ** s_pbTemp; // the temporary storage for the columns + +static int s_BackTracks; +static int s_BackTrackLimit = 100; + +static DdNode * s_Terminal; // the terminal value for counting minterms + + +static int s_EncodingVarsLevel; + + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars ); +static void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level ); +// functions called from EvaluateEncodings_rec() +static DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ); +static DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ); +unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll ); +static unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max ); + +static void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st__table * Visited ); +static void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st__table * Visited, st__table * CutNodes ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the binary encoding of the set of function using the given vars.] + + Description [Performs a straight binary encoding of the set of functions using + the variable cubes formed from the given set of variables. ] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * +Extra_bddEncodingBinary( + DdManager * dd, + DdNode ** pbFuncs, // pbFuncs is the array of columns to be encoded + int nFuncs, // nFuncs is the number of columns in the array + DdNode ** pbVars, // pbVars is the array of variables to use for the codes + int nVars ) // nVars is the column multiplicity, [log2(nFuncs)] +{ + int i; + DdNode * bResult; + DdNode * bCube, * bTemp, * bProd; + + assert( nVars >= Abc_Base2Log(nFuncs) ); + + bResult = b0; Cudd_Ref( bResult ); + for ( i = 0; i < nFuncs; i++ ) + { + bCube = Extra_bddBitsToCube( dd, i, nVars, pbVars, 1 ); Cudd_Ref( bCube ); + bProd = Cudd_bddAnd( dd, bCube, pbFuncs[i] ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bCube ); + + bResult = Cudd_bddOr( dd, bProd, bTemp = bResult ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + } + + Cudd_Deref( bResult ); + return bResult; +} /* end of Extra_bddEncodingBinary */ + + +/**Function******************************************************************** + + Synopsis [Solves the column encoding problem using a sophisticated method.] + + Description [The encoding is based on the idea of deriving functions which + depend on only one variable, which corresponds to the case of non-disjoint + decompostion. It is assumed that the variables pCVars are ordered below the variables + representing the solumns, and the first variable pCVars[0] is the topmost one.] + + SideEffects [] + + SeeAlso [Extra_bddEncodingBinary] + +******************************************************************************/ + +DdNode * +Extra_bddEncodingNonStrict( + DdManager * dd, + DdNode ** pbColumns, // pbColumns is the array of columns to be encoded; + int nColumns, // nColumns is the number of columns in the array + DdNode * bVarsCol, // bVarsCol is the cube of variables on which the columns depend + DdNode ** pCVars, // pCVars is the array of variables to use for the codes + int nMulti, // nMulti is the column multiplicity, [log2(nColumns)] + int * pSimple ) // pSimple gets the number of code variables taken from the input varibles without change +{ + DdNode * bEncoded, * bResult; + int nVarsCol = Cudd_SupportSize(dd,bVarsCol); + abctime clk; + + // cannot work with more that 32-bit codes + assert( nMulti < 32 ); + + // perform the preliminary encoding using the straight binary code + bEncoded = Extra_bddEncodingBinary( dd, pbColumns, nColumns, pCVars, nMulti ); Cudd_Ref( bEncoded ); + //printf( "Node count = %d", Cudd_DagSize(bEncoded) ); + + // set the backgroup value for counting minterms + s_Terminal = b0; + // set the level of the encoding variables + s_EncodingVarsLevel = dd->invperm[pCVars[0]->index]; + + // the current number of backtracks + s_BackTracks = 0; + // the variables that are cofactored on the topmost level where everything starts (no vars) + s_Field[0][0] = b1; + // the size of the best set of "simple" encoding variables found so far + s_nVarsBest = 0; + + // set the relation to be accessible to traversal procedures + s_Encoded = bEncoded; + // the set of all vars to be accessible to traversal procedures + s_VarAll = bVarsCol; + // the column multiplicity + s_MultiStart = nMulti; + + + clk = Abc_Clock(); + // find the simplest encoding + if ( nColumns > 2 ) + EvaluateEncodings_rec( dd, bVarsCol, nVarsCol, nMulti, 1 ); +// printf( "The number of backtracks = %d\n", s_BackTracks ); +// s_EncSearchTime += Abc_Clock() - clk; + + // allocate the temporary storage for the columns + s_pbTemp = (DdNode **)ABC_ALLOC( char, nColumns * sizeof(DdNode *) ); + +// clk = Abc_Clock(); + bResult = CreateTheCodes_rec( dd, bEncoded, 0, pCVars ); Cudd_Ref( bResult ); +// s_EncComputeTime += Abc_Clock() - clk; + + // delocate the preliminarily encoded set + Cudd_RecursiveDeref( dd, bEncoded ); +// Cudd_RecursiveDeref( dd, aEncoded ); + + ABC_FREE( s_pbTemp ); + + *pSimple = s_nVarsBest; + Cudd_Deref( bResult ); + return bResult; +} + +/**Function******************************************************************** + + Synopsis [Collects the nodes under the cut and, for each node, computes the sum of paths leading to it from the root.] + + Description [The table returned contains the set of BDD nodes pointed to under the cut + and, for each node, the BDD of the sum of paths leading to this node from the root + The sums of paths in the table are referenced. CutLevel is the first DD level + considered to be under the cut.] + + SideEffects [] + + SeeAlso [Extra_bddNodePaths] + +******************************************************************************/ + st__table * Extra_bddNodePathsUnderCut( DdManager * dd, DdNode * bFunc, int CutLevel ) +{ + st__table * Visited; // temporary table to remember the visited nodes + st__table * CutNodes; // the result goes here + st__table * Result; // the result goes here + DdNode * aFunc; + + s_CutLevel = CutLevel; + + Result = st__init_table( st__ptrcmp, st__ptrhash);; + // the terminal cases + if ( Cudd_IsConstant( bFunc ) ) + { + if ( bFunc == b1 ) + { + st__insert( Result, (char*)b1, (char*)b1 ); + Cudd_Ref( b1 ); + Cudd_Ref( b1 ); + } + else + { + st__insert( Result, (char*)b0, (char*)b0 ); + Cudd_Ref( b0 ); + Cudd_Ref( b0 ); + } + return Result; + } + + // create the ADD to simplify processing (no complemented edges) + aFunc = Cudd_BddToAdd( dd, bFunc ); Cudd_Ref( aFunc ); + + // Step 1: Start the tables and collect information about the nodes above the cut + // this information tells how many edges point to each node + Visited = st__init_table( st__ptrcmp, st__ptrhash);; + CutNodes = st__init_table( st__ptrcmp, st__ptrhash);; + + CountNodeVisits_rec( dd, aFunc, Visited ); + + // Step 2: Traverse the BDD using the visited table and compute the sum of paths + CollectNodesAndComputePaths_rec( dd, aFunc, b1, Visited, CutNodes ); + + // at this point the table of cut nodes is ready and the table of visited is useless + { + st__generator * gen; + DdNode * aNode; + traventry * p; + st__foreach_item( Visited, gen, (const char**)&aNode, (char**)&p ) + { + Cudd_RecursiveDeref( dd, p->bSum ); + ABC_FREE( p ); + } + st__free_table( Visited ); + } + + // go through the table CutNodes and create the BDD and the path to be returned + { + st__generator * gen; + DdNode * aNode, * bNode, * bSum; + st__foreach_item( CutNodes, gen, (const char**)&aNode, (char**)&bSum) + { + // aNode is not referenced, because aFunc is holding it + bNode = Cudd_addBddPattern( dd, aNode ); Cudd_Ref( bNode ); + st__insert( Result, (char*)bNode, (char*)bSum ); + // the new table takes both refs + } + st__free_table( CutNodes ); + } + + // dereference the ADD + Cudd_RecursiveDeref( dd, aFunc ); + + // return the table + return Result; + +} /* end of Extra_bddNodePathsUnderCut */ + +/**Function******************************************************************** + + Synopsis [Collects the nodes under the cut in the ADD starting from the given set of ADD nodes.] + + Description [Takes the array, paNodes, of ADD nodes to start the traversal, + the array, pbCubes, of BDD cubes to start the traversal with in each node, + and the number, nNodes, of ADD nodes and BDD cubes in paNodes and pbCubes. + Returns the number of columns found. Fills in paNodesRes (pbCubesRes) + with the set of ADD columns (BDD paths). These arrays should be allocated + by the user.] + + SideEffects [] + + SeeAlso [Extra_bddNodePaths] + +******************************************************************************/ +int Extra_bddNodePathsUnderCutArray( DdManager * dd, DdNode ** paNodes, DdNode ** pbCubes, int nNodes, DdNode ** paNodesRes, DdNode ** pbCubesRes, int CutLevel ) +{ + st__table * Visited; // temporary table to remember the visited nodes + st__table * CutNodes; // the nodes under the cut go here + int i, Counter; + + s_CutLevel = CutLevel; + + // there should be some nodes + assert( nNodes > 0 ); + if ( nNodes == 1 && Cudd_IsConstant( paNodes[0] ) ) + { + if ( paNodes[0] == a1 ) + { + paNodesRes[0] = a1; Cudd_Ref( a1 ); + pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] ); + } + else + { + paNodesRes[0] = a0; Cudd_Ref( a0 ); + pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] ); + } + return 1; + } + + // Step 1: Start the table and collect information about the nodes above the cut + // this information tells how many edges point to each node + CutNodes = st__init_table( st__ptrcmp, st__ptrhash);; + Visited = st__init_table( st__ptrcmp, st__ptrhash);; + + for ( i = 0; i < nNodes; i++ ) + CountNodeVisits_rec( dd, paNodes[i], Visited ); + + // Step 2: Traverse the BDD using the visited table and compute the sum of paths + for ( i = 0; i < nNodes; i++ ) + CollectNodesAndComputePaths_rec( dd, paNodes[i], pbCubes[i], Visited, CutNodes ); + + // at this point, the table of cut nodes is ready and the table of visited is useless + { + st__generator * gen; + DdNode * aNode; + traventry * p; + st__foreach_item( Visited, gen, (const char**)&aNode, (char**)&p ) + { + Cudd_RecursiveDeref( dd, p->bSum ); + ABC_FREE( p ); + } + st__free_table( Visited ); + } + + // go through the table CutNodes and create the BDD and the path to be returned + { + st__generator * gen; + DdNode * aNode, * bSum; + Counter = 0; + st__foreach_item( CutNodes, gen, (const char**)&aNode, (char**)&bSum) + { + paNodesRes[Counter] = aNode; Cudd_Ref( aNode ); + pbCubesRes[Counter] = bSum; + Counter++; + } + st__free_table( CutNodes ); + } + + // return the number of cofactors found + return Counter; + +} /* end of Extra_bddNodePathsUnderCutArray */ + +/**Function************************************************************* + + Synopsis [Collects all the BDD nodes into the table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void extraCollectNodes( DdNode * Func, st__table * tNodes ) +{ + DdNode * FuncR; + FuncR = Cudd_Regular(Func); + if ( st__find_or_add( tNodes, (char*)FuncR, NULL ) ) + return; + if ( cuddIsConstant(FuncR) ) + return; + extraCollectNodes( cuddE(FuncR), tNodes ); + extraCollectNodes( cuddT(FuncR), tNodes ); +} + +/**Function************************************************************* + + Synopsis [Collects all the nodes of one DD into the table.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + st__table * Extra_CollectNodes( DdNode * Func ) +{ + st__table * tNodes; + tNodes = st__init_table( st__ptrcmp, st__ptrhash ); + extraCollectNodes( Func, tNodes ); + return tNodes; +} + +/**Function************************************************************* + + Synopsis [Updates the topmost level from which the given node is referenced.] + + Description [Takes the table which maps each BDD nodes (including the constants) + into the topmost level on which this node counts as a cofactor. Takes the topmost + level, on which this node counts as a cofactor (see Extra_ProfileWidthFast(). + Takes the node, for which the table entry should be updated.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void extraProfileUpdateTopLevel( st__table * tNodeTopRef, int TopLevelNew, DdNode * node ) +{ + int * pTopLevel; + + if ( st__find_or_add( tNodeTopRef, (char*)node, (char***)&pTopLevel ) ) + { // the node is already referenced + // the current top level should be updated if it is larger than the new level + if ( *pTopLevel > TopLevelNew ) + *pTopLevel = TopLevelNew; + } + else + { // the node is not referenced + // its level should be set to the current new level + *pTopLevel = TopLevelNew; + } +} +/**Function************************************************************* + + Synopsis [Fast computation of the BDD profile.] + + Description [The array to store the profile is given by the user and should + contain at least as many entries as there is the maximum of the BDD/ZDD + size of the manager PLUS ONE. + When we say that the widths of the DD on level L is W, we mean the following. + Let us create the cut between the level L-1 and the level L and count the number + of different DD nodes pointed to across the cut. This number is the width W. + From this it follows the on level 0, the width is equal to the number of external + pointers to the considered DDs. If there is only one DD, then the profile on + level 0 is always 1. If this DD is rooted in the topmost variable, then the width + on level 1 is always 2, etc. The width at the level equal to dd->size is the + number of terminal nodes in the DD. (Because we consider the first level #0 + and the last level #dd->size, the profile array should contain dd->size+1 entries.) + ] + + SideEffects [This procedure will not work for BDDs w/ complement edges, only for ADDs and ZDDs] + + SeeAlso [] + +***********************************************************************/ +int Extra_ProfileWidth( DdManager * dd, DdNode * Func, int * pProfile, int CutLevel ) +{ + st__generator * gen; + st__table * tNodeTopRef; // this table stores the top level from which this node is pointed to + st__table * tNodes; + DdNode * node; + DdNode * nodeR; + int LevelStart, Limit; + int i, size; + int WidthMax; + + // start the mapping table + tNodeTopRef = st__init_table( st__ptrcmp, st__ptrhash);; + // add the topmost node to the profile + extraProfileUpdateTopLevel( tNodeTopRef, 0, Func ); + + // collect all nodes + tNodes = Extra_CollectNodes( Func ); + // go though all the nodes and set the top level the cofactors are pointed from +// Cudd_ForeachNode( dd, Func, genDD, node ) + st__foreach_item( tNodes, gen, (const char**)&node, NULL ) + { +// assert( Cudd_Regular(node) ); // this procedure works only with ADD/ZDD (not BDD w/ compl.edges) + nodeR = Cudd_Regular(node); + if ( cuddIsConstant(nodeR) ) + continue; + // this node is not a constant - consider its cofactors + extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddE(nodeR) ); + extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddT(nodeR) ); + } + st__free_table( tNodes ); + + // clean the profile + size = ddMax(dd->size, dd->sizeZ) + 1; + for ( i = 0; i < size; i++ ) + pProfile[i] = 0; + + // create the profile + st__foreach_item( tNodeTopRef, gen, (const char**)&node, (char**)&LevelStart ) + { + nodeR = Cudd_Regular(node); + Limit = (cuddIsConstant(nodeR))? dd->size: dd->perm[nodeR->index]; + for ( i = LevelStart; i <= Limit; i++ ) + pProfile[i]++; + } + + if ( CutLevel != -1 && CutLevel != 0 ) + size = CutLevel; + + // get the max width + WidthMax = 0; + for ( i = 0; i < size; i++ ) + if ( WidthMax < pProfile[i] ) + WidthMax = pProfile[i]; + + // deref the table + st__free_table( tNodeTopRef ); + + return WidthMax; +} /* end of Extra_ProfileWidth */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the non-strict codes when evaluation is finished.] + + Description [The information about the best code is stored in s_VarOrderBest, + which has s_nVarsBest entries.] + + SideEffects [None] + +******************************************************************************/ +DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars ) +// bEncoded is the preliminarily encoded set of columns +// Level is the current level in the recursion +// pCVars are the variables to be used for encoding +{ + DdNode * bRes; + if ( Level == s_nVarsBest ) + { // the terminal case, when we need to remap the encoded function + // from the preliminary encoded variables to the new ones + st__table * CutNodes; + int nCols; +// double nMints; +/* +#ifdef _DEBUG + + { + DdNode * bTemp; + // make sure that the given number of variables is enough + bTemp = Cudd_bddExistAbstract( dd, bEncoded, s_VarAll ); Cudd_Ref( bTemp ); +// nMints = Cudd_CountMinterm( dd, bTemp, s_MultiStart ); + nMints = Extra_CountMintermsSimple( bTemp, (1< Extra_Power2( s_MultiStart-Level ) ) + { // the number of minterms is too large to encode the columns + // using the given minimum number of encoding variables + assert( 0 ); + } + Cudd_RecursiveDeref( dd, bTemp ); + } +#endif +*/ + // get the columns to be re-encoded + CutNodes = Extra_bddNodePathsUnderCut( dd, bEncoded, s_EncodingVarsLevel ); + // LUT size is the cut level because because the temporary encoding variables + // are above the functional variables - this is not true!!! + // the temporary variables are below! + + // put the entries from the table into the temporary array + { + st__generator * gen; + DdNode * bColumn, * bCode; + nCols = 0; + st__foreach_item( CutNodes, gen, (const char**)&bCode, (char**)&bColumn ) + { + if ( bCode == b0 ) + { // the unused part of the columns + Cudd_RecursiveDeref( dd, bColumn ); + Cudd_RecursiveDeref( dd, bCode ); + continue; + } + else + { + s_pbTemp[ nCols ] = bColumn; // takes ref + Cudd_RecursiveDeref( dd, bCode ); + nCols++; + } + } + st__free_table( CutNodes ); +// assert( nCols == (int)nMints ); + } + + // encode the columns + if ( s_MultiStart-Level == 0 ) // we reached the bottom level of recursion + { + assert( nCols == 1 ); +// assert( (int)nMints == 1 ); + bRes = s_pbTemp[0]; Cudd_Ref( bRes ); + } + else + { + bRes = Extra_bddEncodingBinary( dd, s_pbTemp, nCols, pCVars+Level, s_MultiStart-Level ); Cudd_Ref( bRes ); + } + + // deref the columns + { + int i; + for ( i = 0; i < nCols; i++ ) + Cudd_RecursiveDeref( dd, s_pbTemp[i] ); + } + } + else + { + // cofactor the problem as specified in the best solution + DdNode * bCof0, * bCof1; + DdNode * bRes0, * bRes1; + DdNode * bProd0, * bProd1; + DdNode * bTemp; + DdNode * bVarNext = dd->vars[ s_VarOrderBest[Level] ]; + + bCof0 = Cudd_Cofactor( dd, bEncoded, Cudd_Not( bVarNext ) ); Cudd_Ref( bCof0 ); + bCof1 = Cudd_Cofactor( dd, bEncoded, bVarNext ); Cudd_Ref( bCof1 ); + + // call recursively + bRes0 = CreateTheCodes_rec( dd, bCof0, Level+1, pCVars ); Cudd_Ref( bRes0 ); + bRes1 = CreateTheCodes_rec( dd, bCof1, Level+1, pCVars ); Cudd_Ref( bRes1 ); + + Cudd_RecursiveDeref( dd, bCof0 ); + Cudd_RecursiveDeref( dd, bCof1 ); + + // compose the result using the identity (bVarNext <=> pCVars[Level]) - this is wrong! + // compose the result as follows: x'y'F0 + xyF1 + bProd0 = Cudd_bddAnd( dd, Cudd_Not(bVarNext), Cudd_Not(pCVars[Level]) ); Cudd_Ref( bProd0 ); + bProd1 = Cudd_bddAnd( dd, bVarNext , pCVars[Level] ); Cudd_Ref( bProd1 ); + + bProd0 = Cudd_bddAnd( dd, bTemp = bProd0, bRes0 ); Cudd_Ref( bProd0 ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bRes0 ); + + bProd1 = Cudd_bddAnd( dd, bTemp = bProd1, bRes1 ); Cudd_Ref( bProd1 ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bRes1 ); + + bRes = Cudd_bddOr( dd, bProd0, bProd1 ); Cudd_Ref( bRes ); + + Cudd_RecursiveDeref( dd, bProd0 ); + Cudd_RecursiveDeref( dd, bProd1 ); + } + Cudd_Deref( bRes ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [Old implementation.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level ) +// bVarsCol is the set of remaining variables +// nVarsCol is the number of remaining variables +// nMulti is the number of encoding variables to be used +// Level is the level of recursion, from which this function is called +// if we successfully finish this procedure, Level also stands for how many encoding variabled we saved +{ + int i, k; + int nEntries = (1<<(Level-1)); // the number of entries in the field of the previous level + DdNode * bVars0, * bVars1; // the cofactors + unsigned nMint0, nMint1; // the number of minterms + DdNode * bTempV; + DdNode * bVarTop; + int fBreak; + + + // there is no need to search above this level + if ( Level > s_MaxDepth ) + return; + + // if there are no variables left, quit the research + if ( bVarsCol == b1 ) + return; + + if ( s_BackTracks > s_BackTrackLimit ) + return; + + s_BackTracks++; + + // otherwise, go through the remaining variables + for ( bTempV = bVarsCol; bTempV != b1; bTempV = cuddT(bTempV) ) + { + // the currently tested variable + bVarTop = dd->vars[bTempV->index]; + + // put it into the array + s_VarOrderCur[Level-1] = bTempV->index; + + // go through the entries and fill them out by cofactoring + fBreak = 0; + for ( i = 0; i < nEntries; i++ ) + { + bVars0 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], Cudd_Not(bVarTop), &nMint0 ); + Cudd_Ref( bVars0 ); + + if ( nMint0 > Extra_Power2( nMulti-1 ) ) + { + // there is no way to encode - dereference and return + Cudd_RecursiveDeref( dd, bVars0 ); + fBreak = 1; + break; + } + + bVars1 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], bVarTop, &nMint1 ); + Cudd_Ref( bVars1 ); + + if ( nMint1 > Extra_Power2( nMulti-1 ) ) + { + // there is no way to encode - dereference and return + Cudd_RecursiveDeref( dd, bVars0 ); + Cudd_RecursiveDeref( dd, bVars1 ); + fBreak = 1; + break; + } + + // otherwise, add these two cofactors + s_Field[Level][2*i + 0] = bVars0; // takes ref + s_Field[Level][2*i + 1] = bVars1; // takes ref + } + + if ( !fBreak ) + { + DdNode * bVarsRem; + // if we ended up here, it means that the cofactors w.r.t. variable bVarTop satisfy the condition + // save this situation + if ( s_nVarsBest < Level ) + { + s_nVarsBest = Level; + // copy the variable assignment + for ( k = 0; k < Level; k++ ) + s_VarOrderBest[k] = s_VarOrderCur[k]; + } + + // call recursively + // get the new variable set + if ( nMulti-1 > 0 ) + { + bVarsRem = Cudd_bddExistAbstract( dd, bVarsCol, bVarTop ); Cudd_Ref( bVarsRem ); + EvaluateEncodings_rec( dd, bVarsRem, nVarsCol-1, nMulti-1, Level+1 ); + Cudd_RecursiveDeref( dd, bVarsRem ); + } + } + + // deref the contents of the array + for ( k = 0; k < i; k++ ) + { + Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 0] ); + Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 1] ); + } + + // if the solution is found, there is no need to continue + if ( s_nVarsBest == s_MaxDepth ) + return; + + // if the solution is found, there is no need to continue + if ( s_nVarsBest == s_MultiStart ) + return; + } + // at this point, we have tried all possible directions in the space of variables +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ) +// takes bVars - the variables cofactored so far (some of them may be in negative polarity) +// bVarTop - the topmost variable w.r.t. which to cofactor (may be in negative polarity) +// returns the cost and the new set of variables (bVars & bVarTop) +{ + DdNode * bVarsRes; + + // get the resulting set of variables + bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes ); + + // increment signature before calling Cudd_CountCofactorMinterms() + s_Signature++; + *Cost = Extra_CountCofactorMinterms( dd, s_Encoded, bVarsRes, s_VarAll ); + + Cudd_Deref( bVarsRes ); +// s_CountCalls++; + return bVarsRes; +} + +/**Function******************************************************************** + + Synopsis [Computes the current set of variables and counts the number of minterms.] + + Description [The old implementation, which is approximately 4 times slower.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost ) +{ + DdNode * bVarsRes; + DdNode * bCof, * bFun; + + bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes ); + + bCof = Cudd_Cofactor( dd, s_Encoded, bVarsRes ); Cudd_Ref( bCof ); + bFun = Cudd_bddExistAbstract( dd, bCof, s_VarAll ); Cudd_Ref( bFun ); + *Cost = (unsigned)Cudd_CountMinterm( dd, bFun, s_MultiStart ); + Cudd_RecursiveDeref( dd, bFun ); + Cudd_RecursiveDeref( dd, bCof ); + + Cudd_Deref( bVarsRes ); +// s_CountCalls++; + return bVarsRes; +} + + +/**Function******************************************************************** + + Synopsis [Counts the number of encoding minterms pointed to by the cofactor of the function.] + + Description [] + + SideEffects [None] + +******************************************************************************/ +unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll ) +// this function computes how many minterms depending on the encoding variables +// are there in the cofactor of bFunc w.r.t. variables bVarsCof +// bFunc is assumed to depend on variables s_VarsAll +// the variables s_VarsAll should be ordered above the encoding variables +{ + unsigned HKey; + DdNode * bFuncR; + + // if the function is zero, there are no minterms +// if ( bFunc == b0 ) +// return 0; + +// if ( st__lookup(Visited, (char*)bFunc, NULL) ) +// return 0; + +// HKey = hashKey2c( s_Signature, bFuncR ); +// if ( HHTable1[HKey].Sign == s_Signature && HHTable1[HKey].Arg1 == bFuncR ) // this node is visited +// return 0; + + + // check the hash-table + bFuncR = Cudd_Regular(bFunc); +// HKey = hashKey2( s_Signature, bFuncR, _TABLESIZE_COF ); + HKey = hashKey2( s_Signature, bFunc, _TABLESIZE_COF ); + for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF ) +// if ( HHTable1[HKey].Arg1 == bFuncR ) // this node is visited + if ( HHTable1[HKey].Arg1 == bFunc ) // this node is visited + return 0; + + + // if the function is already the code + if ( dd->perm[bFuncR->index] >= s_EncodingVarsLevel ) + { +// st__insert(Visited, (char*)bFunc, NULL); + +// HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + + assert( HHTable1[HKey].Sign != s_Signature ); + HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + HHTable1[HKey].Arg1 = bFunc; + + return Extra_CountMintermsSimple( bFunc, (1<perm[bFuncR->index]; + int LevelC = cuddI(dd,bVarsCofR->index); + int LevelA = dd->perm[bVarsAll->index]; + + int LevelTop = LevelF; + + if ( LevelTop > LevelC ) + LevelTop = LevelC; + + if ( LevelTop > LevelA ) + LevelTop = LevelA; + + // the top var in the function or in cofactoring vars always belongs to the set of all vars + assert( !( LevelTop == LevelF || LevelTop == LevelC ) || LevelTop == LevelA ); + + // cofactor the function + if ( LevelTop == LevelF ) + { + if ( bFuncR != bFunc ) // bFunc is complemented + { + bFunc0 = Cudd_Not( cuddE(bFuncR) ); + bFunc1 = Cudd_Not( cuddT(bFuncR) ); + } + else + { + bFunc0 = cuddE(bFuncR); + bFunc1 = cuddT(bFuncR); + } + } + else // bVars is higher in the variable order + bFunc0 = bFunc1 = bFunc; + + // cofactor the cube + if ( LevelTop == LevelC ) + { + if ( bVarsCofR != bVarsCof ) // bFunc is complemented + { + bVarsCof0 = Cudd_Not( cuddE(bVarsCofR) ); + bVarsCof1 = Cudd_Not( cuddT(bVarsCofR) ); + } + else + { + bVarsCof0 = cuddE(bVarsCofR); + bVarsCof1 = cuddT(bVarsCofR); + } + } + else // bVars is higher in the variable order + bVarsCof0 = bVarsCof1 = bVarsCof; + + // there are two cases: + // (1) the top variable belongs to the cofactoring variables + // (2) the top variable does not belong to the cofactoring variables + + // (1) the top variable belongs to the cofactoring variables + Res = 0; + if ( LevelTop == LevelC ) + { + if ( bVarsCof1 == b0 ) // this is a negative cofactor + { + if ( bFunc0 != b0 ) + Res = Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) ); + } + else // this is a positive cofactor + { + if ( bFunc1 != b0 ) + Res = Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) ); + } + } + else + { + if ( bFunc0 != b0 ) + Res += Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) ); + + if ( bFunc1 != b0 ) + Res += Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) ); + } + +// st__insert(Visited, (char*)bFunc, NULL); + +// HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + + // skip through the entries with the same signatures + // (these might have been created at the time of recursive calls) + for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF ); + assert( HHTable1[HKey].Sign != s_Signature ); + HHTable1[HKey].Sign = s_Signature; +// HHTable1[HKey].Arg1 = bFuncR; + HHTable1[HKey].Arg1 = bFunc; + + return Res; + } +} + +/**Function******************************************************************** + + Synopsis [Counts the number of minterms.] + + Description [This function counts minterms for functions up to 32 variables + using a local cache. The terminal value (s_Termina) should be adjusted for + BDDs and ADDs.] + + SideEffects [None] + +******************************************************************************/ +unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max ) +{ + unsigned HKey; + + // normalize + if ( Cudd_IsComplement(bFunc) ) + return max - Extra_CountMintermsSimple( Cudd_Not(bFunc), max ); + + // now it is known that the function is not complemented + if ( cuddIsConstant(bFunc) ) + return ((bFunc==s_Terminal)? 0: max); + + // check cache + HKey = hashKey2( bFunc, max, _TABLESIZE_MINT ); + if ( HHTable2[HKey].Arg1 == bFunc && HHTable2[HKey].Arg2 == max ) + return HHTable2[HKey].Res; + else + { + // min = min0/2 + min1/2; + unsigned min = (Extra_CountMintermsSimple( cuddE(bFunc), max ) >> 1) + + (Extra_CountMintermsSimple( cuddT(bFunc), max ) >> 1); + + HHTable2[HKey].Arg1 = bFunc; + HHTable2[HKey].Arg2 = max; + HHTable2[HKey].Res = min; + + return min; + } +} /* end of Extra_CountMintermsSimple */ + + +/**Function******************************************************************** + + Synopsis [Visits the nodes.] + + Description [Visits the nodes above the cut and the nodes pointed to below the cut; + collects the visited nodes, counts how many times each node is visited, and sets + the path-sum to be the constant zero BDD.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st__table * Visited ) + +{ + traventry * p; + char **slot; + if ( st__find_or_add(Visited, (char*)aFunc, &slot) ) + { // the entry already exists + p = (traventry*) *slot; + // increment the counter of incoming edges + p->nEdges++; + return; + } + // this node has not been visited + assert( !Cudd_IsComplement(aFunc) ); + + // create the new traversal entry + p = (traventry *) ABC_ALLOC( char, sizeof(traventry) ); + // set the initial sum of edges to zero BDD + p->bSum = b0; Cudd_Ref( b0 ); + // set the starting number of incoming edges + p->nEdges = 1; + // set this entry into the slot + *slot = (char*)p; + + // recur if the node is above the cut + if ( cuddI(dd,aFunc->index) < s_CutLevel ) + { + CountNodeVisits_rec( dd, cuddE(aFunc), Visited ); + CountNodeVisits_rec( dd, cuddT(aFunc), Visited ); + } +} /* end of CountNodeVisits_rec */ + + +/**Function******************************************************************** + + Synopsis [Revisits the nodes and computes the paths.] + + Description [This function visits the nodes above the cut having the goal of + summing all the incomming BDD edges; when this function comes across the node + below the cut, it saves this node in the CutNode table.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st__table * Visited, st__table * CutNodes ) +{ + // find the node in the visited table + DdNode * bTemp; + traventry * p; + char **slot; + if ( st__find_or_add(Visited, (char*)aFunc, &slot) ) + { // the node is found + // get the pointer to the traversal entry + p = (traventry*) *slot; + + // make sure that the counter of incoming edges is positive + assert( p->nEdges > 0 ); + + // add the cube to the currently accumulated cubes + p->bSum = Cudd_bddOr( dd, bTemp = p->bSum, bCube ); Cudd_Ref( p->bSum ); + Cudd_RecursiveDeref( dd, bTemp ); + + // decrement the number of visits + p->nEdges--; + + // if more visits to this node are expected, return + if ( p->nEdges ) + return; + else // if ( p->nEdges == 0 ) + { // this is the last visit - propagate the cube + + // check where this node is + if ( cuddI(dd,aFunc->index) < s_CutLevel ) + { // the node is above the cut + DdNode * bCube0, * bCube1; + + // get the top-most variable + DdNode * bVarTop = dd->vars[aFunc->index]; + + // compute the propagated cubes + bCube0 = Cudd_bddAnd( dd, p->bSum, Cudd_Not( bVarTop ) ); Cudd_Ref( bCube0 ); + bCube1 = Cudd_bddAnd( dd, p->bSum, bVarTop ); Cudd_Ref( bCube1 ); + + // call recursively + CollectNodesAndComputePaths_rec( dd, cuddE(aFunc), bCube0, Visited, CutNodes ); + CollectNodesAndComputePaths_rec( dd, cuddT(aFunc), bCube1, Visited, CutNodes ); + + // dereference the cubes + Cudd_RecursiveDeref( dd, bCube0 ); + Cudd_RecursiveDeref( dd, bCube1 ); + return; + } + else + { // the node is below the cut + // add this node to the cut node table, if it is not yet there + +// DdNode * bNode; +// bNode = Cudd_addBddPattern( dd, aFunc ); Cudd_Ref( bNode ); + if ( st__find_or_add(CutNodes, (char*)aFunc, &slot) ) + { // the node exists - should never happen + assert( 0 ); + } + *slot = (char*) p->bSum; Cudd_Ref( p->bSum ); + // the table takes the reference of bNode + return; + } + } + } + + // the node does not exist in the visited table - should never happen + assert(0); + +} /* end of CollectNodesAndComputePaths_rec */ + + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddImage.c b/src/bdd/extrab/extraBddImage.c new file mode 100644 index 00000000..46afb4f2 --- /dev/null +++ b/src/bdd/extrab/extraBddImage.c @@ -0,0 +1,1162 @@ +/**CFile**************************************************************** + + FileName [extraBddImage.c] + + PackageName [extra] + + Synopsis [Various reusable software utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - September 1, 2003.] + + Revision [$Id: extraBddImage.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/* + The ideas implemented in this file are inspired by the paper: + Pankaj Chauhan, Edmund Clarke, Somesh Jha, Jim Kukula, Tom Shiple, + Helmut Veith, Dong Wang. Non-linear Quantification Scheduling in + Image Computation. ICCAD, 2001. +*/ + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +typedef struct Extra_ImageNode_t_ Extra_ImageNode_t; +typedef struct Extra_ImagePart_t_ Extra_ImagePart_t; +typedef struct Extra_ImageVar_t_ Extra_ImageVar_t; + +struct Extra_ImageTree_t_ +{ + Extra_ImageNode_t * pRoot; // the root of quantification tree + Extra_ImageNode_t * pCare; // the leaf node with the care set + DdNode * bCareSupp; // the cube to quantify from the care + int fVerbose; // the verbosity flag + int nNodesMax; // the max number of nodes in one iter + int nNodesMaxT; // the overall max number of nodes + int nIter; // the number of iterations with this tree +}; + +struct Extra_ImageNode_t_ +{ + DdManager * dd; // the manager + DdNode * bCube; // the cube to quantify + DdNode * bImage; // the partial image + Extra_ImageNode_t * pNode1; // the first branch + Extra_ImageNode_t * pNode2; // the second branch + Extra_ImagePart_t * pPart; // the partition (temporary) +}; + +struct Extra_ImagePart_t_ +{ + DdNode * bFunc; // the partition + DdNode * bSupp; // the support of this partition + int nNodes; // the number of BDD nodes + short nSupp; // the number of support variables + short iPart; // the number of this partition +}; + +struct Extra_ImageVar_t_ +{ + int iNum; // the BDD index of this variable + DdNode * bParts; // the partition numbers + int nParts; // the number of partitions +}; + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticStart*************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static Extra_ImagePart_t ** Extra_CreateParts( DdManager * dd, + int nParts, DdNode ** pbParts, DdNode * bCare ); +static Extra_ImageVar_t ** Extra_CreateVars( DdManager * dd, + int nParts, Extra_ImagePart_t ** pParts, + int nVars, DdNode ** pbVarsNs ); +static Extra_ImageNode_t ** Extra_CreateNodes( DdManager * dd, + int nParts, Extra_ImagePart_t ** pParts, + int nVars, Extra_ImageVar_t ** pVars ); +static void Extra_DeleteParts_rec( Extra_ImageNode_t * pNode ); +static int Extra_BuildTreeNode( DdManager * dd, + int nNodes, Extra_ImageNode_t ** pNodes, + int nVars, Extra_ImageVar_t ** pVars ); +static Extra_ImageNode_t * Extra_MergeTopNodes( DdManager * dd, + int nNodes, Extra_ImageNode_t ** pNodes ); +static void Extra_bddImageTreeDelete_rec( Extra_ImageNode_t * pNode ); +static void Extra_bddImageCompute_rec( Extra_ImageTree_t * pTree, Extra_ImageNode_t * pNode ); +static int Extra_FindBestVariable( DdManager * dd, + int nNodes, Extra_ImageNode_t ** pNodes, + int nVars, Extra_ImageVar_t ** pVars ); +static void Extra_FindBestPartitions( DdManager * dd, DdNode * bParts, + int nNodes, Extra_ImageNode_t ** pNodes, + int * piNode1, int * piNode2 ); +static Extra_ImageNode_t * Extra_CombineTwoNodes( DdManager * dd, DdNode * bCube, + Extra_ImageNode_t * pNode1, Extra_ImageNode_t * pNode2 ); + +static void Extra_bddImagePrintLatchDependency( DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars ); +static void Extra_bddImagePrintLatchDependencyOne( DdManager * dd, DdNode * bFunc, + DdNode * bVarsCs, DdNode * bVarsNs, int iPart ); + +static void Extra_bddImagePrintTree( Extra_ImageTree_t * pTree ); +static void Extra_bddImagePrintTree_rec( Extra_ImageNode_t * pNode, int nOffset ); + + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Starts the image computation using tree-based scheduling.] + + Description [This procedure starts the image computation. It uses + the given care set to test-run the image computation and creates the + quantification tree by scheduling variable quantifications. The tree can + be used to compute images for other care sets without rescheduling. + In this case, Extra_bddImageCompute() should be called.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImageTree_t * Extra_bddImageStart( + DdManager * dd, DdNode * bCare, // the care set + int nParts, DdNode ** pbParts, // the partitions for image computation + int nVars, DdNode ** pbVars, int fVerbose ) // the NS and parameter variables (not quantified!) +{ + Extra_ImageTree_t * pTree; + Extra_ImagePart_t ** pParts; + Extra_ImageVar_t ** pVars; + Extra_ImageNode_t ** pNodes; + int v; + + if ( fVerbose && dd->size <= 80 ) + Extra_bddImagePrintLatchDependency( dd, bCare, nParts, pbParts, nVars, pbVars ); + + // create variables, partitions and leaf nodes + pParts = Extra_CreateParts( dd, nParts, pbParts, bCare ); + pVars = Extra_CreateVars( dd, nParts + 1, pParts, nVars, pbVars ); + pNodes = Extra_CreateNodes( dd, nParts + 1, pParts, dd->size, pVars ); + + // create the tree + pTree = ABC_ALLOC( Extra_ImageTree_t, 1 ); + memset( pTree, 0, sizeof(Extra_ImageTree_t) ); + pTree->pCare = pNodes[nParts]; + pTree->fVerbose = fVerbose; + + // process the nodes + while ( Extra_BuildTreeNode( dd, nParts + 1, pNodes, dd->size, pVars ) ); + + // make sure the variables are gone + for ( v = 0; v < dd->size; v++ ) + assert( pVars[v] == NULL ); + ABC_FREE( pVars ); + + // merge the topmost nodes + while ( (pTree->pRoot = Extra_MergeTopNodes( dd, nParts + 1, pNodes )) == NULL ); + + // make sure the nodes are gone + for ( v = 0; v < nParts + 1; v++ ) + assert( pNodes[v] == NULL ); + ABC_FREE( pNodes ); + +// if ( fVerbose ) +// Extra_bddImagePrintTree( pTree ); + + // set the support of the care set + pTree->bCareSupp = Cudd_Support( dd, bCare ); Cudd_Ref( pTree->bCareSupp ); + + // clean the partitions + Extra_DeleteParts_rec( pTree->pRoot ); + ABC_FREE( pParts ); + return pTree; +} + +/**Function************************************************************* + + Synopsis [Compute the image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddImageCompute( Extra_ImageTree_t * pTree, DdNode * bCare ) +{ + DdManager * dd = pTree->pCare->dd; + DdNode * bSupp, * bRem; + + pTree->nIter++; + + // make sure the supports are okay + bSupp = Cudd_Support( dd, bCare ); Cudd_Ref( bSupp ); + if ( bSupp != pTree->bCareSupp ) + { + bRem = Cudd_bddExistAbstract( dd, bSupp, pTree->bCareSupp ); Cudd_Ref( bRem ); + if ( bRem != b1 ) + { +printf( "Original care set support: " ); +ABC_PRB( dd, pTree->bCareSupp ); +printf( "Current care set support: " ); +ABC_PRB( dd, bSupp ); + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDeref( dd, bRem ); + printf( "The care set depends on some vars that were not in the care set during scheduling.\n" ); + return NULL; + } + Cudd_RecursiveDeref( dd, bRem ); + } + Cudd_RecursiveDeref( dd, bSupp ); + + // remove the previous image + Cudd_RecursiveDeref( dd, pTree->pCare->bImage ); + pTree->pCare->bImage = bCare; Cudd_Ref( bCare ); + + // compute the image + pTree->nNodesMax = 0; + Extra_bddImageCompute_rec( pTree, pTree->pRoot ); + if ( pTree->nNodesMaxT < pTree->nNodesMax ) + pTree->nNodesMaxT = pTree->nNodesMax; + +// if ( pTree->fVerbose ) +// printf( "Iter %2d : Max nodes = %5d.\n", pTree->nIter, pTree->nNodesMax ); + return pTree->pRoot->bImage; +} + +/**Function************************************************************* + + Synopsis [Delete the tree.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImageTreeDelete( Extra_ImageTree_t * pTree ) +{ + if ( pTree->bCareSupp ) + Cudd_RecursiveDeref( pTree->pRoot->dd, pTree->bCareSupp ); + Extra_bddImageTreeDelete_rec( pTree->pRoot ); + ABC_FREE( pTree ); +} + +/**Function************************************************************* + + Synopsis [Reads the image from the tree.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddImageRead( Extra_ImageTree_t * pTree ) +{ + return pTree->pRoot->bImage; +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + +/**Function************************************************************* + + Synopsis [Creates partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImagePart_t ** Extra_CreateParts( DdManager * dd, + int nParts, DdNode ** pbParts, DdNode * bCare ) +{ + Extra_ImagePart_t ** pParts; + int i; + + // start the partitions + pParts = ABC_ALLOC( Extra_ImagePart_t *, nParts + 1 ); + // create structures for each variable + for ( i = 0; i < nParts; i++ ) + { + pParts[i] = ABC_ALLOC( Extra_ImagePart_t, 1 ); + pParts[i]->bFunc = pbParts[i]; Cudd_Ref( pParts[i]->bFunc ); + pParts[i]->bSupp = Cudd_Support( dd, pParts[i]->bFunc ); Cudd_Ref( pParts[i]->bSupp ); + pParts[i]->nSupp = Extra_bddSuppSize( dd, pParts[i]->bSupp ); + pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); + pParts[i]->iPart = i; + } + // add the care set as the last partition + pParts[nParts] = ABC_ALLOC( Extra_ImagePart_t, 1 ); + pParts[nParts]->bFunc = bCare; Cudd_Ref( pParts[nParts]->bFunc ); + pParts[nParts]->bSupp = Cudd_Support( dd, pParts[nParts]->bFunc ); Cudd_Ref( pParts[nParts]->bSupp ); + pParts[nParts]->nSupp = Extra_bddSuppSize( dd, pParts[nParts]->bSupp ); + pParts[nParts]->nNodes = Cudd_DagSize( pParts[nParts]->bFunc ); + pParts[nParts]->iPart = nParts; + return pParts; +} + +/**Function************************************************************* + + Synopsis [Creates variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImageVar_t ** Extra_CreateVars( DdManager * dd, + int nParts, Extra_ImagePart_t ** pParts, + int nVars, DdNode ** pbVars ) +{ + Extra_ImageVar_t ** pVars; + DdNode ** pbFuncs; + DdNode * bCubeNs, * bSupp, * bParts, * bTemp, * bSuppTemp; + int nVarsTotal, iVar, p, Counter; + + // put all the functions into one array + pbFuncs = ABC_ALLOC( DdNode *, nParts ); + for ( p = 0; p < nParts; p++ ) + pbFuncs[p] = pParts[p]->bSupp; + bSupp = Cudd_VectorSupport( dd, pbFuncs, nParts ); Cudd_Ref( bSupp ); + ABC_FREE( pbFuncs ); + + // remove the NS vars + bCubeNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bCubeNs ); + bSupp = Cudd_bddExistAbstract( dd, bTemp = bSupp, bCubeNs ); Cudd_Ref( bSupp ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCubeNs ); + + // get the number of I and CS variables to be quantified + nVarsTotal = Extra_bddSuppSize( dd, bSupp ); + + // start the variables + pVars = ABC_ALLOC( Extra_ImageVar_t *, dd->size ); + memset( pVars, 0, sizeof(Extra_ImageVar_t *) * dd->size ); + // create structures for each variable + for ( bSuppTemp = bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) ) + { + iVar = bSuppTemp->index; + pVars[iVar] = ABC_ALLOC( Extra_ImageVar_t, 1 ); + pVars[iVar]->iNum = iVar; + // collect all the parts this var belongs to + Counter = 0; + bParts = b1; Cudd_Ref( bParts ); + for ( p = 0; p < nParts; p++ ) + if ( Cudd_bddLeq( dd, pParts[p]->bSupp, dd->vars[bSuppTemp->index] ) ) + { + bParts = Cudd_bddAnd( dd, bTemp = bParts, dd->vars[p] ); Cudd_Ref( bParts ); + Cudd_RecursiveDeref( dd, bTemp ); + Counter++; + } + pVars[iVar]->bParts = bParts; // takes ref + pVars[iVar]->nParts = Counter; + } + Cudd_RecursiveDeref( dd, bSupp ); + return pVars; +} + +/**Function************************************************************* + + Synopsis [Creates variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImageNode_t ** Extra_CreateNodes( DdManager * dd, + int nParts, Extra_ImagePart_t ** pParts, + int nVars, Extra_ImageVar_t ** pVars ) +{ + Extra_ImageNode_t ** pNodes; + Extra_ImageNode_t * pNode; + DdNode * bTemp; + int i, v, iPart; +/* + DdManager * dd; // the manager + DdNode * bCube; // the cube to quantify + DdNode * bImage; // the partial image + Extra_ImageNode_t * pNode1; // the first branch + Extra_ImageNode_t * pNode2; // the second branch + Extra_ImagePart_t * pPart; // the partition (temporary) +*/ + // start the partitions + pNodes = ABC_ALLOC( Extra_ImageNode_t *, nParts ); + // create structures for each leaf nodes + for ( i = 0; i < nParts; i++ ) + { + pNodes[i] = ABC_ALLOC( Extra_ImageNode_t, 1 ); + memset( pNodes[i], 0, sizeof(Extra_ImageNode_t) ); + pNodes[i]->dd = dd; + pNodes[i]->pPart = pParts[i]; + } + // find the quantification cubes for each leaf node + for ( v = 0; v < nVars; v++ ) + { + if ( pVars[v] == NULL ) + continue; + assert( pVars[v]->nParts > 0 ); + if ( pVars[v]->nParts > 1 ) + continue; + iPart = pVars[v]->bParts->index; + if ( pNodes[iPart]->bCube == NULL ) + { + pNodes[iPart]->bCube = dd->vars[v]; + Cudd_Ref( dd->vars[v] ); + } + else + { + pNodes[iPart]->bCube = Cudd_bddAnd( dd, bTemp = pNodes[iPart]->bCube, dd->vars[v] ); + Cudd_Ref( pNodes[iPart]->bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + // remove these variables + Cudd_RecursiveDeref( dd, pVars[v]->bParts ); + ABC_FREE( pVars[v] ); + } + + // assign the leaf node images + for ( i = 0; i < nParts; i++ ) + { + pNode = pNodes[i]; + if ( pNode->bCube ) + { + // update the partition + pParts[i]->bFunc = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bFunc, pNode->bCube ); + Cudd_Ref( pParts[i]->bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + // update the support the partition + pParts[i]->bSupp = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bSupp, pNode->bCube ); + Cudd_Ref( pParts[i]->bSupp ); + Cudd_RecursiveDeref( dd, bTemp ); + // update the numbers + pParts[i]->nSupp = Extra_bddSuppSize( dd, pParts[i]->bSupp ); + pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); + // get rid of the cube + // save the last (care set) quantification cube + if ( i < nParts - 1 ) + { + Cudd_RecursiveDeref( dd, pNode->bCube ); + pNode->bCube = NULL; + } + } + // copy the function + pNode->bImage = pParts[i]->bFunc; Cudd_Ref( pNode->bImage ); + } +/* + for ( i = 0; i < nParts; i++ ) + { + pNode = pNodes[i]; +ABC_PRB( dd, pNode->bCube ); +ABC_PRB( dd, pNode->pPart->bFunc ); +ABC_PRB( dd, pNode->pPart->bSupp ); +printf( "\n" ); + } +*/ + return pNodes; +} + + +/**Function************************************************************* + + Synopsis [Delete the partitions from the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_DeleteParts_rec( Extra_ImageNode_t * pNode ) +{ + Extra_ImagePart_t * pPart; + if ( pNode->pNode1 ) + Extra_DeleteParts_rec( pNode->pNode1 ); + if ( pNode->pNode2 ) + Extra_DeleteParts_rec( pNode->pNode2 ); + pPart = pNode->pPart; + Cudd_RecursiveDeref( pNode->dd, pPart->bFunc ); + Cudd_RecursiveDeref( pNode->dd, pPart->bSupp ); + ABC_FREE( pNode->pPart ); +} + +/**Function************************************************************* + + Synopsis [Delete the partitions from the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImageTreeDelete_rec( Extra_ImageNode_t * pNode ) +{ + if ( pNode->pNode1 ) + Extra_bddImageTreeDelete_rec( pNode->pNode1 ); + if ( pNode->pNode2 ) + Extra_bddImageTreeDelete_rec( pNode->pNode2 ); + if ( pNode->bCube ) + Cudd_RecursiveDeref( pNode->dd, pNode->bCube ); + if ( pNode->bImage ) + Cudd_RecursiveDeref( pNode->dd, pNode->bImage ); + assert( pNode->pPart == NULL ); + ABC_FREE( pNode ); +} + +/**Function************************************************************* + + Synopsis [Recompute the image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImageCompute_rec( Extra_ImageTree_t * pTree, Extra_ImageNode_t * pNode ) +{ + DdManager * dd = pNode->dd; + DdNode * bTemp; + int nNodes; + + // trivial case + if ( pNode->pNode1 == NULL ) + { + if ( pNode->bCube ) + { + pNode->bImage = Cudd_bddExistAbstract( dd, bTemp = pNode->bImage, pNode->bCube ); + Cudd_Ref( pNode->bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + } + return; + } + + // compute the children + if ( pNode->pNode1 ) + Extra_bddImageCompute_rec( pTree, pNode->pNode1 ); + if ( pNode->pNode2 ) + Extra_bddImageCompute_rec( pTree, pNode->pNode2 ); + + // clean the old image + if ( pNode->bImage ) + Cudd_RecursiveDeref( dd, pNode->bImage ); + pNode->bImage = NULL; + + // compute the new image + if ( pNode->bCube ) + pNode->bImage = Cudd_bddAndAbstract( dd, + pNode->pNode1->bImage, pNode->pNode2->bImage, pNode->bCube ); + else + pNode->bImage = Cudd_bddAnd( dd, pNode->pNode1->bImage, pNode->pNode2->bImage ); + Cudd_Ref( pNode->bImage ); + + if ( pTree->fVerbose ) + { + nNodes = Cudd_DagSize( pNode->bImage ); + if ( pTree->nNodesMax < nNodes ) + pTree->nNodesMax = nNodes; + } +} + +/**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; +} + + +/**Function************************************************************* + + Synopsis [Merges the nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImageNode_t * Extra_MergeTopNodes( + DdManager * dd, int nNodes, Extra_ImageNode_t ** pNodes ) +{ + Extra_ImageNode_t * pNode; + int n1 = -1, n2 = -1, n; + + // find the first and the second non-empty spots + for ( n = 0; n < nNodes; n++ ) + if ( pNodes[n] ) + { + if ( n1 == -1 ) + n1 = n; + else if ( n2 == -1 ) + { + n2 = n; + break; + } + } + assert( n1 != -1 ); + // check the situation when only one such node is detected + if ( n2 == -1 ) + { + // save the node + pNode = pNodes[n1]; + // clean the node + pNodes[n1] = NULL; + return pNode; + } + + // combines two nodes + pNode = Extra_CombineTwoNodes( dd, b1, pNodes[n1], pNodes[n2] ); + + // clean the old nodes + pNodes[n1] = pNode; + pNodes[n2] = NULL; + return NULL; +} + +/**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 [Computes the best variable.] + + Description [The variables is the best if the sum of squares of the + BDD sizes of the partitions, in which it participates, is the minimum.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_FindBestVariable( DdManager * dd, + int nNodes, Extra_ImageNode_t ** pNodes, + int nVars, Extra_ImageVar_t ** pVars ) +{ + DdNode * bTemp; + int iVarBest, v; + double CostBest, CostCur; + + CostBest = 100000000000000.0; + iVarBest = -1; + for ( v = 0; v < nVars; v++ ) + if ( pVars[v] ) + { + CostCur = 0; + for ( bTemp = pVars[v]->bParts; bTemp != b1; bTemp = cuddT(bTemp) ) + CostCur += pNodes[bTemp->index]->pPart->nNodes * + pNodes[bTemp->index]->pPart->nNodes; + if ( CostBest > CostCur ) + { + CostBest = CostCur; + iVarBest = v; + } + } + return iVarBest; +} + +/**Function************************************************************* + + Synopsis [Computes two smallest partions that have this var.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_FindBestPartitions( DdManager * dd, DdNode * bParts, + int nNodes, Extra_ImageNode_t ** pNodes, + int * piNode1, int * piNode2 ) +{ + DdNode * bTemp; + int iPart1, iPart2; + int CostMin1, CostMin2, Cost; + + // go through the partitions + iPart1 = iPart2 = -1; + CostMin1 = CostMin2 = 1000000; + for ( bTemp = bParts; bTemp != b1; bTemp = cuddT(bTemp) ) + { + Cost = pNodes[bTemp->index]->pPart->nNodes; + if ( CostMin1 > Cost ) + { + CostMin2 = CostMin1; iPart2 = iPart1; + CostMin1 = Cost; iPart1 = bTemp->index; + } + else if ( CostMin2 > Cost ) + { + CostMin2 = Cost; iPart2 = bTemp->index; + } + } + + *piNode1 = iPart1; + *piNode2 = iPart2; +} + +/**Function************************************************************* + + Synopsis [Prints the latch dependency matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImagePrintLatchDependency( + DdManager * dd, DdNode * bCare, // the care set + int nParts, DdNode ** pbParts, // the partitions for image computation + int nVars, DdNode ** pbVars ) // the NS and parameter variables (not quantified!) +{ + int i; + DdNode * bVarsCs, * bVarsNs; + + bVarsCs = Cudd_Support( dd, bCare ); Cudd_Ref( bVarsCs ); + bVarsNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bVarsNs ); + + printf( "The latch dependency matrix:\n" ); + printf( "Partitions = %d Variables: total = %d non-quantifiable = %d\n", + nParts, dd->size, nVars ); + printf( " : " ); + for ( i = 0; i < dd->size; i++ ) + printf( "%d", i % 10 ); + printf( "\n" ); + + for ( i = 0; i < nParts; i++ ) + Extra_bddImagePrintLatchDependencyOne( dd, pbParts[i], bVarsCs, bVarsNs, i ); + Extra_bddImagePrintLatchDependencyOne( dd, bCare, bVarsCs, bVarsNs, nParts ); + + Cudd_RecursiveDeref( dd, bVarsCs ); + Cudd_RecursiveDeref( dd, bVarsNs ); +} + +/**Function************************************************************* + + Synopsis [Prints one row of the latch dependency matrix.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImagePrintLatchDependencyOne( + DdManager * dd, DdNode * bFunc, // the function + DdNode * bVarsCs, DdNode * bVarsNs, // the current/next state vars + int iPart ) +{ + DdNode * bSupport; + int v; + bSupport = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupport ); + printf( " %3d : ", iPart ); + for ( v = 0; v < dd->size; v++ ) + { + if ( Cudd_bddLeq( dd, bSupport, dd->vars[v] ) ) + { + if ( Cudd_bddLeq( dd, bVarsCs, dd->vars[v] ) ) + printf( "c" ); + else if ( Cudd_bddLeq( dd, bVarsNs, dd->vars[v] ) ) + printf( "n" ); + else + printf( "i" ); + } + else + printf( "." ); + } + printf( "\n" ); + Cudd_RecursiveDeref( dd, bSupport ); +} + + +/**Function************************************************************* + + Synopsis [Prints the tree for quenstification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImagePrintTree( Extra_ImageTree_t * pTree ) +{ + printf( "The quantification scheduling tree:\n" ); + Extra_bddImagePrintTree_rec( pTree->pRoot, 1 ); +} + +/**Function************************************************************* + + Synopsis [Prints the tree for quenstification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImagePrintTree_rec( Extra_ImageNode_t * pNode, int Offset ) +{ + DdNode * Cube; + int i; + + Cube = pNode->bCube; + + if ( pNode->pNode1 == NULL ) + { + printf( "<%d> ", pNode->pPart->iPart ); + if ( Cube != NULL ) + { + ABC_PRB( pNode->dd, Cube ); + } + else + printf( "\n" ); + return; + } + + printf( "<*> " ); + if ( Cube != NULL ) + { + ABC_PRB( pNode->dd, Cube ); + } + else + printf( "\n" ); + + for ( i = 0; i < Offset; i++ ) + printf( " " ); + Extra_bddImagePrintTree_rec( pNode->pNode1, Offset + 1 ); + + for ( i = 0; i < Offset; i++ ) + printf( " " ); + Extra_bddImagePrintTree_rec( pNode->pNode2, Offset + 1 ); +} + + + + + +struct Extra_ImageTree2_t_ +{ + DdManager * dd; + DdNode * bRel; + DdNode * bCube; + DdNode * bImage; +}; + +/**Function************************************************************* + + Synopsis [Starts the monolithic image computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Extra_ImageTree2_t * Extra_bddImageStart2( + DdManager * dd, DdNode * bCare, + int nParts, DdNode ** pbParts, + int nVars, DdNode ** pbVars, int fVerbose ) +{ + Extra_ImageTree2_t * pTree; + DdNode * bCubeAll, * bCubeNot, * bTemp; + int i; + + pTree = ABC_ALLOC( Extra_ImageTree2_t, 1 ); + pTree->dd = dd; + pTree->bImage = NULL; + + bCubeAll = Extra_bddComputeCube( dd, dd->vars, dd->size ); Cudd_Ref( bCubeAll ); + bCubeNot = Extra_bddComputeCube( dd, pbVars, nVars ); Cudd_Ref( bCubeNot ); + pTree->bCube = Cudd_bddExistAbstract( dd, bCubeAll, bCubeNot ); Cudd_Ref( pTree->bCube ); + Cudd_RecursiveDeref( dd, bCubeAll ); + Cudd_RecursiveDeref( dd, bCubeNot ); + + // derive the monolithic relation + pTree->bRel = b1; Cudd_Ref( pTree->bRel ); + for ( i = 0; i < nParts; i++ ) + { + pTree->bRel = Cudd_bddAnd( dd, bTemp = pTree->bRel, pbParts[i] ); Cudd_Ref( pTree->bRel ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Extra_bddImageCompute2( pTree, bCare ); + return pTree; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddImageCompute2( Extra_ImageTree2_t * pTree, DdNode * bCare ) +{ + if ( pTree->bImage ) + Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); + pTree->bImage = Cudd_bddAndAbstract( pTree->dd, pTree->bRel, bCare, pTree->bCube ); + Cudd_Ref( pTree->bImage ); + return pTree->bImage; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_bddImageTreeDelete2( Extra_ImageTree2_t * pTree ) +{ + if ( pTree->bRel ) + Cudd_RecursiveDeref( pTree->dd, pTree->bRel ); + if ( pTree->bCube ) + Cudd_RecursiveDeref( pTree->dd, pTree->bCube ); + if ( pTree->bImage ) + Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); + ABC_FREE( pTree ); +} + +/**Function************************************************************* + + Synopsis [Returns the previously computed image.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddImageRead2( Extra_ImageTree2_t * pTree ) +{ + return pTree->bImage; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddKmap.c b/src/bdd/extrab/extraBddKmap.c new file mode 100644 index 00000000..aa5efe75 --- /dev/null +++ b/src/bdd/extrab/extraBddKmap.c @@ -0,0 +1,876 @@ +/**CFile**************************************************************** + + FileName [extraBddKmap.c] + + PackageName [extra] + + Synopsis [Visualizing the K-map.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddKmap.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +/// K-map visualization using pseudo graphics /// +/// Version 1.0. Started - August 20, 2000 /// +/// Version 2.0. Added to EXTRA - July 17, 2001 /// + +#include "extraBdd.h" + +#ifdef WIN32 +#include +#endif + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +// the maximum number of variables in the Karnaugh Map +#define MAXVARS 20 + +/* +// single line +#define SINGLE_VERTICAL (char)179 +#define SINGLE_HORIZONTAL (char)196 +#define SINGLE_TOP_LEFT (char)218 +#define SINGLE_TOP_RIGHT (char)191 +#define SINGLE_BOT_LEFT (char)192 +#define SINGLE_BOT_RIGHT (char)217 + +// double line +#define DOUBLE_VERTICAL (char)186 +#define DOUBLE_HORIZONTAL (char)205 +#define DOUBLE_TOP_LEFT (char)201 +#define DOUBLE_TOP_RIGHT (char)187 +#define DOUBLE_BOT_LEFT (char)200 +#define DOUBLE_BOT_RIGHT (char)188 + +// line intersections +#define SINGLES_CROSS (char)197 +#define DOUBLES_CROSS (char)206 +#define S_HOR_CROSS_D_VER (char)215 +#define S_VER_CROSS_D_HOR (char)216 + +// single line joining +#define S_JOINS_S_VER_LEFT (char)180 +#define S_JOINS_S_VER_RIGHT (char)195 +#define S_JOINS_S_HOR_TOP (char)193 +#define S_JOINS_S_HOR_BOT (char)194 + +// double line joining +#define D_JOINS_D_VER_LEFT (char)185 +#define D_JOINS_D_VER_RIGHT (char)204 +#define D_JOINS_D_HOR_TOP (char)202 +#define D_JOINS_D_HOR_BOT (char)203 + +// single line joining double line +#define S_JOINS_D_VER_LEFT (char)182 +#define S_JOINS_D_VER_RIGHT (char)199 +#define S_JOINS_D_HOR_TOP (char)207 +#define S_JOINS_D_HOR_BOT (char)209 +*/ + +// single line +#define SINGLE_VERTICAL (char)'|' +#define SINGLE_HORIZONTAL (char)'-' +#define SINGLE_TOP_LEFT (char)'+' +#define SINGLE_TOP_RIGHT (char)'+' +#define SINGLE_BOT_LEFT (char)'+' +#define SINGLE_BOT_RIGHT (char)'+' + +// double line +#define DOUBLE_VERTICAL (char)'|' +#define DOUBLE_HORIZONTAL (char)'-' +#define DOUBLE_TOP_LEFT (char)'+' +#define DOUBLE_TOP_RIGHT (char)'+' +#define DOUBLE_BOT_LEFT (char)'+' +#define DOUBLE_BOT_RIGHT (char)'+' + +// line intersections +#define SINGLES_CROSS (char)'+' +#define DOUBLES_CROSS (char)'+' +#define S_HOR_CROSS_D_VER (char)'+' +#define S_VER_CROSS_D_HOR (char)'+' + +// single line joining +#define S_JOINS_S_VER_LEFT (char)'+' +#define S_JOINS_S_VER_RIGHT (char)'+' +#define S_JOINS_S_HOR_TOP (char)'+' +#define S_JOINS_S_HOR_BOT (char)'+' + +// double line joining +#define D_JOINS_D_VER_LEFT (char)'+' +#define D_JOINS_D_VER_RIGHT (char)'+' +#define D_JOINS_D_HOR_TOP (char)'+' +#define D_JOINS_D_HOR_BOT (char)'+' + +// single line joining double line +#define S_JOINS_D_VER_LEFT (char)'+' +#define S_JOINS_D_VER_RIGHT (char)'+' +#define S_JOINS_D_HOR_TOP (char)'+' +#define S_JOINS_D_HOR_BOT (char)'+' + + +// other symbols +#define UNDERSCORE (char)95 +//#define SYMBOL_ZERO (char)248 // degree sign +//#define SYMBOL_ZERO (char)'o' +#ifdef WIN32 +#define SYMBOL_ZERO (char)'0' +#else +#define SYMBOL_ZERO (char)' ' +#endif +#define SYMBOL_ONE (char)'1' +#define SYMBOL_DC (char)'-' +#define SYMBOL_OVERLAP (char)'?' + +// full cells and half cells +#define CELL_FREE (char)32 +#define CELL_FULL (char)219 +#define HALF_UPPER (char)223 +#define HALF_LOWER (char)220 +#define HALF_LEFT (char)221 +#define HALF_RIGHT (char)222 + + +/*---------------------------------------------------------------------------*/ +/* Structure declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +// the array of BDD variables used internally +static DdNode * s_XVars[MAXVARS]; + +// flag which determines where the horizontal variable names are printed +static int fHorizontalVarNamesPrintedAbove = 1; + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +// Oleg's way of generating the gray code +static int GrayCode( int BinCode ); +static int BinCode ( int GrayCode ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Prints the K-map of the function.] + + Description [If the pointer to the array of variables XVars is NULL, + fSuppType determines how the support will be determined. + fSuppType == 0 -- takes the first nVars of the manager + fSuppType == 1 -- takes the topmost nVars of the manager + fSuppType == 2 -- determines support from the on-set and the offset + ] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_PrintKMap( + FILE * Output, /* the output stream */ + DdManager * dd, + DdNode * OnSet, + DdNode * OffSet, + int nVars, + DdNode ** XVars, + int fSuppType, /* the flag which determines how support is computed */ + char ** pVarNames ) +{ + int fPrintTruth = 1; + int d, p, n, s, v, h, w; + int nVarsVer; + int nVarsHor; + int nCellsVer; + int nCellsHor; + int nSkipSpaces; + + // make sure that on-set and off-set do not overlap + if ( !Cudd_bddLeq( dd, OnSet, Cudd_Not(OffSet) ) ) + { + fprintf( Output, "PrintKMap(): The on-set and the off-set overlap\n" ); + return; + } + if ( nVars == 0 ) + { printf( "Function is constant %d.\n", !Cudd_IsComplement(OnSet) ); return; } + + // print truth table for debugging + if ( fPrintTruth ) + { + DdNode * bCube, * bPart; + printf( "Truth table: " ); + if ( nVars == 0 ) + printf( "Constant" ); + else if ( nVars == 1 ) + printf( "1-var function" ); + else + { +// printf( "0x" ); + for ( d = (1<<(nVars-2)) - 1; d >= 0; d-- ) + { + int Value = 0; + for ( s = 0; s < 4; s++ ) + { + bCube = Extra_bddBitsToCube( dd, 4*d+s, nVars, dd->vars, 0 ); Cudd_Ref( bCube ); + bPart = Cudd_Cofactor( dd, OnSet, bCube ); Cudd_Ref( bPart ); + Value |= ((int)(bPart == b1) << s); + Cudd_RecursiveDeref( dd, bPart ); + Cudd_RecursiveDeref( dd, bCube ); + } + if ( Value < 10 ) + fprintf( stdout, "%d", Value ); + else + fprintf( stdout, "%c", 'a' + Value-10 ); + } + } + printf( "\n" ); + } + + +/* + if ( OnSet == b1 ) + { + fprintf( Output, "PrintKMap(): Constant 1\n" ); + return; + } + if ( OffSet == b1 ) + { + fprintf( Output, "PrintKMap(): Constant 0\n" ); + return; + } +*/ + if ( nVars < 0 || nVars > MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS ); + return; + } + + // determine the support if it is not given + if ( XVars == NULL ) + { + if ( fSuppType == 0 ) + { // assume that the support includes the first nVars of the manager + assert( nVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = Cudd_bddIthVar( dd, v ); + } + else if ( fSuppType == 1 ) + { // assume that the support includes the topmost nVars of the manager + assert( nVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = Cudd_bddIthVar( dd, dd->invperm[v] ); + } + else // determine the support + { + DdNode * SuppOn, * SuppOff, * Supp; + int cVars = 0; + DdNode * TempSupp; + + // determine support + SuppOn = Cudd_Support( dd, OnSet ); Cudd_Ref( SuppOn ); + SuppOff = Cudd_Support( dd, OffSet ); Cudd_Ref( SuppOff ); + Supp = Cudd_bddAnd( dd, SuppOn, SuppOff ); Cudd_Ref( Supp ); + Cudd_RecursiveDeref( dd, SuppOn ); + Cudd_RecursiveDeref( dd, SuppOff ); + + nVars = Cudd_SupportSize( dd, Supp ); + if ( nVars > MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is more than %d\n", MAXVARS ); + Cudd_RecursiveDeref( dd, Supp ); + return; + } + + // assign variables + for ( TempSupp = Supp; TempSupp != dd->one; TempSupp = Cudd_T(TempSupp), cVars++ ) + s_XVars[cVars] = Cudd_bddIthVar( dd, TempSupp->index ); + + Cudd_RecursiveDeref( dd, TempSupp ); + } + } + else + { + // copy variables + assert( XVars ); + for ( v = 0; v < nVars; v++ ) + s_XVars[v] = XVars[v]; + } + + //////////////////////////////////////////////////////////////////// + // determine the Karnaugh map parameters + nVarsVer = nVars/2; + nVarsHor = nVars - nVarsVer; + + nCellsVer = (1< MAXVARS ) + { + fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS ); + return; + } + + + //////////////////////////////////////////////////////////////////// + // determine the Karnaugh map parameters + nVarsVer = nXVars; + nVarsHor = nYVars; + nCellsVer = (1<> 1 ); +} + +/**Function******************************************************************** + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int BinCode ( int GrayCode ) +{ + int bc = GrayCode; + while( GrayCode >>= 1 ) bc ^= GrayCode; + return bc; +} + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddMisc.c b/src/bdd/extrab/extraBddMisc.c new file mode 100644 index 00000000..a2ba4036 --- /dev/null +++ b/src/bdd/extrab/extraBddMisc.c @@ -0,0 +1,2342 @@ +/**CFile**************************************************************** + + FileName [extraBddMisc.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [DD-based utilities.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: extraBddMisc.c,v 1.4 2005/10/04 00:19:54 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +// file "extraDdTransfer.c" +static DdNode * extraTransferPermuteRecur( DdManager * ddS, DdManager * ddD, DdNode * f, st__table * table, int * Permute ); +static DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute ); +static DdNode * cuddBddPermuteRecur ARGS( ( DdManager * manager, DdHashTable * table, DdNode * node, int *permut ) ); + +static DdNode * extraBddAndPermute( DdHashTable * table, DdManager * ddF, DdNode * bF, DdManager * ddG, DdNode * bG, int * pPermute ); + +// file "cuddUtils.c" +static void ddSupportStep(DdNode *f, int *support); +static void ddClearFlag(DdNode *f); + +static DdNode* extraZddPrimes( DdManager *dd, DdNode* F ); + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Convert a {A,B}DD from a manager to another with variable remapping.] + + Description [Convert a {A,B}DD from a manager to another one. The orders of the + variables in the two managers may be different. Returns a + pointer to the {A,B}DD in the destination manager if successful; NULL + otherwise. The i-th entry in the array Permute tells what is the index + of the i-th variable from the old manager in the new manager.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_TransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute ) +{ + DdNode * bRes; + do + { + ddDestination->reordered = 0; + bRes = extraTransferPermute( ddSource, ddDestination, f, Permute ); + } + while ( ddDestination->reordered == 1 ); + return ( bRes ); + +} /* end of Extra_TransferPermute */ + +/**Function******************************************************************** + + Synopsis [Transfers the BDD from one manager into another level by level.] + + Description [Transfers the BDD from one manager into another while + preserving the correspondence between variables level by level.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_TransferLevelByLevel( DdManager * ddSource, DdManager * ddDestination, DdNode * f ) +{ + DdNode * bRes; + int * pPermute; + int nMin, nMax, i; + + nMin = ddMin(ddSource->size, ddDestination->size); + nMax = ddMax(ddSource->size, ddDestination->size); + pPermute = ABC_ALLOC( int, nMax ); + // set up the variable permutation + for ( i = 0; i < nMin; i++ ) + pPermute[ ddSource->invperm[i] ] = ddDestination->invperm[i]; + if ( ddSource->size > ddDestination->size ) + { + for ( ; i < nMax; i++ ) + pPermute[ ddSource->invperm[i] ] = -1; + } + bRes = Extra_TransferPermute( ddSource, ddDestination, f, pPermute ); + ABC_FREE( pPermute ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Remaps the function to depend on the topmost variables on the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddRemapUp( + DdManager * dd, + DdNode * bF ) +{ + int * pPermute; + DdNode * bSupp, * bTemp, * bRes; + int Counter; + + pPermute = ABC_ALLOC( int, dd->size ); + + // get support + bSupp = Cudd_Support( dd, bF ); Cudd_Ref( bSupp ); + + // create the variable map + // to remap the DD into the upper part of the manager + Counter = 0; + for ( bTemp = bSupp; bTemp != dd->one; bTemp = cuddT(bTemp) ) + pPermute[bTemp->index] = dd->invperm[Counter++]; + + // transfer the BDD and remap it + bRes = Cudd_bddPermute( dd, bF, pPermute ); Cudd_Ref( bRes ); + + // remove support + Cudd_RecursiveDeref( dd, bSupp ); + + // return + Cudd_Deref( bRes ); + ABC_FREE( pPermute ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Moves the BDD by the given number of variables up or down.] + + Description [] + + SideEffects [] + + SeeAlso [Extra_bddShift] + +******************************************************************************/ +DdNode * Extra_bddMove( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int nVars) +{ + DdNode * res; + DdNode * bVars; + if ( nVars == 0 ) + return bF; + if ( Cudd_IsConstant(bF) ) + return bF; + assert( nVars <= dd->size ); + if ( nVars > 0 ) + bVars = dd->vars[nVars]; + else + bVars = Cudd_Not(dd->vars[-nVars]); + + do { + dd->reordered = 0; + res = extraBddMove( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddMove */ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_StopManager( DdManager * dd ) +{ + int RetValue; + // check for remaining references in the package + RetValue = Cudd_CheckZeroRef( dd ); + if ( RetValue > 10 ) +// if ( RetValue ) + printf( "\nThe number of referenced nodes = %d\n\n", RetValue ); +// Cudd_PrintInfo( dd, stdout ); + Cudd_Quit( dd ); +} + +/**Function******************************************************************** + + Synopsis [Outputs the BDD in a readable format.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +void Extra_bddPrint( DdManager * dd, DdNode * F ) +{ + DdGen * Gen; + int * Cube; + CUDD_VALUE_TYPE Value; + int nVars = dd->size; + int fFirstCube = 1; + int i; + + if ( F == NULL ) + { + printf("NULL"); + return; + } + if ( F == b0 ) + { + printf("Constant 0"); + return; + } + if ( F == b1 ) + { + printf("Constant 1"); + return; + } + + Cudd_ForeachCube( dd, F, Gen, Cube, Value ) + { + if ( fFirstCube ) + fFirstCube = 0; + else +// Output << " + "; + printf( " + " ); + + for ( i = 0; i < nVars; i++ ) + if ( Cube[i] == 0 ) + printf( "[%d]'", i ); +// printf( "%c'", (char)('a'+i) ); + else if ( Cube[i] == 1 ) + printf( "[%d]", i ); +// printf( "%c", (char)('a'+i) ); + } + +// printf("\n"); +} + +/**Function******************************************************************** + + Synopsis [Outputs the BDD in a readable format.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +void Extra_bddPrintSupport( DdManager * dd, DdNode * F ) +{ + DdNode * bSupp; + bSupp = Cudd_Support( dd, F ); Cudd_Ref( bSupp ); + Extra_bddPrint( dd, bSupp ); + Cudd_RecursiveDeref( dd, bSupp ); +} + +/**Function******************************************************************** + + Synopsis [Returns the size of the support.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppSize( DdManager * dd, DdNode * bSupp ) +{ + int Counter = 0; + while ( bSupp != b1 ) + { + assert( !Cudd_IsComplement(bSupp) ); + assert( cuddE(bSupp) == b0 ); + + bSupp = cuddT(bSupp); + Counter++; + } + return Counter; +} + +/**Function******************************************************************** + + Synopsis [Returns 1 if the support contains the given BDD variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppContainVar( DdManager * dd, DdNode * bS, DdNode * bVar ) +{ + for( ; bS != b1; bS = cuddT(bS) ) + if ( bS->index == bVar->index ) + return 1; + return 0; +} + +/**Function******************************************************************** + + Synopsis [Returns 1 if two supports represented as BDD cubes are overlapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppOverlapping( DdManager * dd, DdNode * S1, DdNode * S2 ) +{ + while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX ) + { + // if the top vars are the same, they intersect + if ( S1->index == S2->index ) + return 1; + // if the top vars are different, skip the one, which is higher + if ( dd->perm[S1->index] < dd->perm[S2->index] ) + S1 = cuddT(S1); + else + S2 = cuddT(S2); + } + return 0; +} + +/**Function******************************************************************** + + Synopsis [Returns the number of different vars in two supports.] + + Description [Counts the number of variables that appear in one support and + does not appear in other support. If the number exceeds DiffMax, returns DiffMax.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppDifferentVars( DdManager * dd, DdNode * S1, DdNode * S2, int DiffMax ) +{ + int Result = 0; + while ( S1->index != CUDD_CONST_INDEX && S2->index != CUDD_CONST_INDEX ) + { + // if the top vars are the same, this var is the same + if ( S1->index == S2->index ) + { + S1 = cuddT(S1); + S2 = cuddT(S2); + continue; + } + // the top var is different + Result++; + + if ( Result >= DiffMax ) + return DiffMax; + + // if the top vars are different, skip the one, which is higher + if ( dd->perm[S1->index] < dd->perm[S2->index] ) + S1 = cuddT(S1); + else + S2 = cuddT(S2); + } + + // consider the remaining variables + if ( S1->index != CUDD_CONST_INDEX ) + Result += Extra_bddSuppSize(dd,S1); + else if ( S2->index != CUDD_CONST_INDEX ) + Result += Extra_bddSuppSize(dd,S2); + + if ( Result >= DiffMax ) + return DiffMax; + return Result; +} + + +/**Function******************************************************************** + + Synopsis [Checks the support containment.] + + Description [This function returns 1 if one support is contained in another. + In this case, bLarge (bSmall) is assigned to point to the larger (smaller) support. + If the supports are identical, return 0 and does not assign the supports!] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddSuppCheckContainment( DdManager * dd, DdNode * bL, DdNode * bH, DdNode ** bLarge, DdNode ** bSmall ) +{ + DdNode * bSL = bL; + DdNode * bSH = bH; + int fLcontainsH = 1; + int fHcontainsL = 1; + int TopVar; + + if ( bSL == bSH ) + return 0; + + while ( bSL != b1 || bSH != b1 ) + { + if ( bSL == b1 ) + { // Low component has no vars; High components has some vars + fLcontainsH = 0; + if ( fHcontainsL == 0 ) + return 0; + else + break; + } + + if ( bSH == b1 ) + { // similarly + fHcontainsL = 0; + if ( fLcontainsH == 0 ) + return 0; + else + break; + } + + // determine the topmost var of the supports by comparing their levels + if ( dd->perm[bSL->index] < dd->perm[bSH->index] ) + TopVar = bSL->index; + else + TopVar = bSH->index; + + if ( TopVar == bSL->index && TopVar == bSH->index ) + { // they are on the same level + // it does not tell us anything about their containment + // skip this var + bSL = cuddT(bSL); + bSH = cuddT(bSH); + } + else if ( TopVar == bSL->index ) // and TopVar != bSH->index + { // Low components is higher and contains more vars + // it is not possible that High component contains Low + fHcontainsL = 0; + // skip this var + bSL = cuddT(bSL); + } + else // if ( TopVar == bSH->index ) // and TopVar != bSL->index + { // similarly + fLcontainsH = 0; + // skip this var + bSH = cuddT(bSH); + } + + // check the stopping condition + if ( !fHcontainsL && !fLcontainsH ) + return 0; + } + // only one of them can be true at the same time + assert( !fHcontainsL || !fLcontainsH ); + if ( fHcontainsL ) + { + *bLarge = bH; + *bSmall = bL; + } + else // fLcontainsH + { + *bLarge = bL; + *bSmall = bH; + } + return 1; +} + + +/**Function******************************************************************** + + Synopsis [Finds variables on which the DD depends and returns them as am array.] + + Description [Finds the variables on which the DD depends. Returns an array + with entries set to 1 for those variables that belong to the support; + NULL otherwise. The array is allocated by the user and should have at least + as many entries as the maximum number of variables in BDD and ZDD parts of + the manager.] + + SideEffects [None] + + SeeAlso [Cudd_Support Cudd_VectorSupport Cudd_ClassifySupport] + +******************************************************************************/ +int * +Extra_SupportArray( + DdManager * dd, /* manager */ + DdNode * f, /* DD whose support is sought */ + int * support ) /* array allocated by the user */ +{ + int i, size; + + /* Initialize support array for ddSupportStep. */ + size = ddMax(dd->size, dd->sizeZ); + for (i = 0; i < size; i++) + support[i] = 0; + + /* Compute support and clean up markers. */ + ddSupportStep(Cudd_Regular(f),support); + ddClearFlag(Cudd_Regular(f)); + + return(support); + +} /* end of Extra_SupportArray */ + +/**Function******************************************************************** + + Synopsis [Finds the variables on which a set of DDs depends.] + + Description [Finds the variables on which a set of DDs depends. + The set must contain either BDDs and ADDs, or ZDDs. + Returns a BDD consisting of the product of the variables if + successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_Support Cudd_ClassifySupport] + +******************************************************************************/ +int * +Extra_VectorSupportArray( + DdManager * dd, /* manager */ + DdNode ** F, /* array of DDs whose support is sought */ + int n, /* size of the array */ + int * support ) /* array allocated by the user */ +{ + int i, size; + + /* Allocate and initialize support array for ddSupportStep. */ + size = ddMax( dd->size, dd->sizeZ ); + for ( i = 0; i < size; i++ ) + support[i] = 0; + + /* Compute support and clean up markers. */ + for ( i = 0; i < n; i++ ) + ddSupportStep( Cudd_Regular(F[i]), support ); + for ( i = 0; i < n; i++ ) + ddClearFlag( Cudd_Regular(F[i]) ); + + return support; +} + +/**Function******************************************************************** + + Synopsis [Find any cube belonging to the on-set of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddFindOneCube( DdManager * dd, DdNode * bF ) +{ + char * s_Temp; + DdNode * bCube, * bTemp; + int v; + + // get the vector of variables in the cube + s_Temp = ABC_ALLOC( char, dd->size ); + Cudd_bddPickOneCube( dd, bF, s_Temp ); + + // start the cube + bCube = b1; Cudd_Ref( bCube ); + for ( v = 0; v < dd->size; v++ ) + if ( s_Temp[v] == 0 ) + { +// Cube &= !s_XVars[v]; + bCube = Cudd_bddAnd( dd, bTemp = bCube, Cudd_Not(dd->vars[v]) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + else if ( s_Temp[v] == 1 ) + { +// Cube &= s_XVars[v]; + bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[v] ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref(bCube); + ABC_FREE( s_Temp ); + return bCube; +} + +/**Function******************************************************************** + + Synopsis [Returns one cube contained in the given BDD.] + + Description [This function returns the cube with the smallest + bits-to-integer value.] + + SideEffects [] + +******************************************************************************/ +DdNode * Extra_bddGetOneCube( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bFuncR, * bFunc0, * bFunc1; + DdNode * bRes0, * bRes1, * bRes; + + bFuncR = Cudd_Regular(bFunc); + if ( cuddIsConstant(bFuncR) ) + return bFunc; + + // cofactor + if ( Cudd_IsComplement(bFunc) ) + { + bFunc0 = Cudd_Not( cuddE(bFuncR) ); + bFunc1 = Cudd_Not( cuddT(bFuncR) ); + } + else + { + bFunc0 = cuddE(bFuncR); + bFunc1 = cuddT(bFuncR); + } + + // try to find the cube with the negative literal + bRes0 = Extra_bddGetOneCube( dd, bFunc0 ); Cudd_Ref( bRes0 ); + + if ( bRes0 != b0 ) + { + bRes = Cudd_bddAnd( dd, bRes0, Cudd_Not(dd->vars[bFuncR->index]) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bRes0 ); + } + else + { + Cudd_RecursiveDeref( dd, bRes0 ); + // try to find the cube with the positive literal + bRes1 = Extra_bddGetOneCube( dd, bFunc1 ); Cudd_Ref( bRes1 ); + assert( bRes1 != b0 ); + bRes = Cudd_bddAnd( dd, bRes1, dd->vars[bFuncR->index] ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bRes1 ); + } + + Cudd_Deref( bRes ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddMove().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddComputeRangeCube( DdManager * dd, int iStart, int iStop ) +{ + DdNode * bTemp, * bProd; + int i; + assert( iStart <= iStop ); + assert( iStart >= 0 && iStart <= dd->size ); + assert( iStop >= 0 && iStop <= dd->size ); + bProd = b1; Cudd_Ref( bProd ); + for ( i = iStart; i < iStop; i++ ) + { + bProd = Cudd_bddAnd( dd, bTemp = bProd, dd->vars[i] ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bProd ); + return bProd; +} + +/**Function******************************************************************** + + Synopsis [Computes the cube of BDD variables corresponding to bits it the bit-code] + + Description [Returns a bdd composed of elementary bdds found in array BddVars[] such + that the bdd vars encode the number Value of bit length CodeWidth (if fMsbFirst is 1, + the most significant bit is encoded with the first bdd variable). If the variables + BddVars are not specified, takes the first CodeWidth variables of the manager] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddBitsToCube( DdManager * dd, int Code, int CodeWidth, DdNode ** pbVars, int fMsbFirst ) +{ + int z; + DdNode * bTemp, * bVar, * bVarBdd, * bResult; + + bResult = b1; Cudd_Ref( bResult ); + for ( z = 0; z < CodeWidth; z++ ) + { + bVarBdd = (pbVars)? pbVars[z]: dd->vars[z]; + if ( fMsbFirst ) + bVar = Cudd_NotCond( bVarBdd, (Code & (1 << (CodeWidth-1-z)))==0 ); + else + bVar = Cudd_NotCond( bVarBdd, (Code & (1 << (z)))==0 ); + bResult = Cudd_bddAnd( dd, bTemp = bResult, bVar ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bResult ); + + return bResult; +} /* end of Extra_bddBitsToCube */ + +/**Function******************************************************************** + + Synopsis [Finds the support as a negative polarity cube.] + + Description [Finds the variables on which a DD depends. Returns a BDD + consisting of the product of the variables in the negative polarity + if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_VectorSupport Cudd_Support] + +******************************************************************************/ +DdNode * Extra_bddSupportNegativeCube( DdManager * dd, DdNode * f ) +{ + int *support; + DdNode *res, *tmp, *var; + int i, j; + int size; + + /* Allocate and initialize support array for ddSupportStep. */ + size = ddMax( dd->size, dd->sizeZ ); + support = ABC_ALLOC( int, size ); + if ( support == NULL ) + { + dd->errorCode = CUDD_MEMORY_OUT; + return ( NULL ); + } + for ( i = 0; i < size; i++ ) + { + support[i] = 0; + } + + /* Compute support and clean up markers. */ + ddSupportStep( Cudd_Regular( f ), support ); + ddClearFlag( Cudd_Regular( f ) ); + + /* Transform support from array to cube. */ + do + { + dd->reordered = 0; + res = DD_ONE( dd ); + cuddRef( res ); + for ( j = size - 1; j >= 0; j-- ) + { /* for each level bottom-up */ + i = ( j >= dd->size ) ? j : dd->invperm[j]; + if ( support[i] == 1 ) + { + var = cuddUniqueInter( dd, i, dd->one, Cudd_Not( dd->one ) ); + ////////////////////////////////////////////////////////////////// + var = Cudd_Not(var); + ////////////////////////////////////////////////////////////////// + cuddRef( var ); + tmp = cuddBddAndRecur( dd, res, var ); + if ( tmp == NULL ) + { + Cudd_RecursiveDeref( dd, res ); + Cudd_RecursiveDeref( dd, var ); + res = NULL; + break; + } + cuddRef( tmp ); + Cudd_RecursiveDeref( dd, res ); + Cudd_RecursiveDeref( dd, var ); + res = tmp; + } + } + } + while ( dd->reordered == 1 ); + + ABC_FREE( support ); + if ( res != NULL ) + cuddDeref( res ); + return ( res ); + +} /* end of Extra_SupportNeg */ + +/**Function******************************************************************** + + Synopsis [Returns 1 if the BDD is the BDD of elementary variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddIsVar( DdNode * bFunc ) +{ + bFunc = Cudd_Regular( bFunc ); + if ( cuddIsConstant(bFunc) ) + return 0; + return cuddIsConstant( cuddT(bFunc) ) && cuddIsConstant( Cudd_Regular(cuddE(bFunc)) ); +} + +/**Function******************************************************************** + + Synopsis [Creates AND composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateAnd( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadOne(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddAnd( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Creates OR composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateOr( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadLogicZero(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddOr( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Creates EXOR composed of the first nVars of the manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddCreateExor( DdManager * dd, int nVars ) +{ + DdNode * bFunc, * bTemp; + int i; + bFunc = Cudd_ReadLogicZero(dd); Cudd_Ref( bFunc ); + for ( i = 0; i < nVars; i++ ) + { + bFunc = Cudd_bddXor( dd, bTemp = bFunc, Cudd_bddIthVar(dd,i) ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function******************************************************************** + + Synopsis [Computes the set of primes as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddPrimes( DdManager * dd, DdNode * F ) +{ + DdNode *res; + do { + dd->reordered = 0; + res = extraZddPrimes(dd, F); + if ( dd->reordered == 1 ) + printf("\nReordering in Extra_zddPrimes()\n"); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddPrimes */ + +/**Function******************************************************************** + + Synopsis [Permutes the variables of the array of BDDs.] + + Description [Given a permutation in array permut, creates a new BDD + with permuted variables. There should be an entry in array permut + for each variable in the manager. The i-th entry of permut holds the + index of the variable that is to substitute the i-th variable. + The DDs in the resulting array are already referenced.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute Cudd_bddSwapVariables] + +******************************************************************************/ +void Extra_bddPermuteArray( DdManager * manager, DdNode ** bNodesIn, DdNode ** bNodesOut, int nNodes, int *permut ) +{ + DdHashTable *table; + int i, k; + do + { + manager->reordered = 0; + table = cuddHashTableInit( manager, 1, 2 ); + + /* permute the output functions one-by-one */ + for ( i = 0; i < nNodes; i++ ) + { + bNodesOut[i] = cuddBddPermuteRecur( manager, table, bNodesIn[i], permut ); + if ( bNodesOut[i] == NULL ) + { + /* deref the array of the already computed outputs */ + for ( k = 0; k < i; k++ ) + Cudd_RecursiveDeref( manager, bNodesOut[k] ); + break; + } + cuddRef( bNodesOut[i] ); + } + /* Dispose of local cache. */ + cuddHashTableQuit( table ); + } + while ( manager->reordered == 1 ); +} /* end of Extra_bddPermuteArray */ + + +/**Function******************************************************************** + + Synopsis [Computes the positive polarty cube composed of the first vars in the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddComputeCube( DdManager * dd, DdNode ** bXVars, int nVars ) +{ + DdNode * bRes; + DdNode * bTemp; + int i; + + bRes = b1; Cudd_Ref( bRes ); + for ( i = 0; i < nVars; i++ ) + { + bRes = Cudd_bddAnd( dd, bTemp = bRes, bXVars[i] ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + + Cudd_Deref( bRes ); + return bRes; +} + +/**Function******************************************************************** + + Synopsis [Changes the polarity of vars listed in the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddChangePolarity( + DdManager * dd, /* the DD manager */ + DdNode * bFunc, + DdNode * bVars) +{ + DdNode *res; + do { + dd->reordered = 0; + res = extraBddChangePolarity( dd, bFunc, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddChangePolarity */ + + +/**Function************************************************************* + + Synopsis [Checks if the given variable belongs to the cube.] + + Description [Return -1 if the var does not appear in the cube. + Otherwise, returns polarity (0 or 1) of the var in the cube.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Extra_bddVarIsInCube( DdNode * bCube, int iVar ) +{ + DdNode * bCube0, * bCube1; + while ( Cudd_Regular(bCube)->index != CUDD_CONST_INDEX ) + { + bCube0 = Cudd_NotCond( cuddE(Cudd_Regular(bCube)), Cudd_IsComplement(bCube) ); + bCube1 = Cudd_NotCond( cuddT(Cudd_Regular(bCube)), Cudd_IsComplement(bCube) ); + // make sure it is a cube + assert( (Cudd_IsComplement(bCube0) && Cudd_Regular(bCube0)->index == CUDD_CONST_INDEX) || // bCube0 == 0 + (Cudd_IsComplement(bCube1) && Cudd_Regular(bCube1)->index == CUDD_CONST_INDEX) ); // bCube1 == 0 + // quit if it is the last one + if ( Cudd_Regular(bCube)->index == iVar ) + return (int)(Cudd_IsComplement(bCube0) && Cudd_Regular(bCube0)->index == CUDD_CONST_INDEX); + // get the next cube + if ( (Cudd_IsComplement(bCube0) && Cudd_Regular(bCube0)->index == CUDD_CONST_INDEX) ) + bCube = bCube1; + else + bCube = bCube0; + } + return -1; +} + +/**Function************************************************************* + + Synopsis [Computes the AND of two BDD with different orders.] + + Description [Derives the result of Boolean AND of bF and bG in ddF. + The array pPermute gives the mapping of variables of ddG into that of ddF.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Extra_bddAndPermute( DdManager * ddF, DdNode * bF, DdManager * ddG, DdNode * bG, int * pPermute ) +{ + DdHashTable * table; + DdNode * bRes; + do + { + ddF->reordered = 0; + table = cuddHashTableInit( ddF, 2, 256 ); + if (table == NULL) return NULL; + bRes = extraBddAndPermute( table, ddF, bF, ddG, bG, pPermute ); + if ( bRes ) cuddRef( bRes ); + cuddHashTableQuit( table ); + if ( bRes ) cuddDeref( bRes ); +//if ( ddF->reordered == 1 ) +//printf( "Reordering happened\n" ); + } + while ( ddF->reordered == 1 ); +//printf( "|F| =%6d |G| =%6d |H| =%6d |F|*|G| =%9d\n", +// Cudd_DagSize(bF), Cudd_DagSize(bG), Cudd_DagSize(bRes), +// Cudd_DagSize(bF) * Cudd_DagSize(bG) ); + return ( bRes ); +} + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddMove().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddMove( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bDist) +{ + DdNode * bRes; + + if ( Cudd_IsConstant(bF) ) + return bF; + + if ( (bRes = cuddCacheLookup2(dd, extraBddMove, bF, bDist)) ) + return bRes; + else + { + DdNode * bRes0, * bRes1; + DdNode * bF0, * bF1; + DdNode * bFR = Cudd_Regular(bF); + int VarNew; + + if ( Cudd_IsComplement(bDist) ) + VarNew = bFR->index - Cudd_Not(bDist)->index; + else + VarNew = bFR->index + bDist->index; + assert( VarNew < dd->size ); + + // cofactor the functions + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + bRes0 = extraBddMove( dd, bF0, bDist ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + + bRes1 = extraBddMove( dd, bF1, bDist ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bRes1 ); + + /* only bRes0 and bRes1 are referenced at this point */ + bRes = cuddBddIteRecur( dd, dd->vars[VarNew], bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bRes1 ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bRes0 ); + Cudd_RecursiveDeref( dd, bRes1 ); + + /* insert the result into cache */ + cuddCacheInsert2( dd, extraBddMove, bF, bDist, bRes ); + cuddDeref( bRes ); + return bRes; + } +} /* end of extraBddMove */ + + +/**Function******************************************************************** + + Synopsis [Finds three cofactors of the cover w.r.t. to the topmost variable.] + + Description [Finds three cofactors of the cover w.r.t. to the topmost variable. + Does not check the cover for being a constant. Assumes that ZDD variables encoding + positive and negative polarities are adjacent in the variable order. Is different + from cuddZddGetCofactors3() in that it does not compute the cofactors w.r.t. the + given variable but takes the cofactors with respent to the topmost variable. + This function is more efficient when used in recursive procedures because it does + not require referencing of the resulting cofactors (compare cuddZddProduct() + and extraZddPrimeProduct()).] + + SideEffects [None] + + SeeAlso [cuddZddGetCofactors3] + +******************************************************************************/ +void +extraDecomposeCover( + DdManager* dd, /* the manager */ + DdNode* zC, /* the cover */ + DdNode** zC0, /* the pointer to the negative var cofactor */ + DdNode** zC1, /* the pointer to the positive var cofactor */ + DdNode** zC2 ) /* the pointer to the cofactor without var */ +{ + if ( (zC->index & 1) == 0 ) + { /* the top variable is present in positive polarity and maybe in negative */ + + DdNode *Temp = cuddE( zC ); + *zC1 = cuddT( zC ); + if ( cuddIZ(dd,Temp->index) == cuddIZ(dd,zC->index) + 1 ) + { /* Temp is not a terminal node + * top var is present in negative polarity */ + *zC2 = cuddE( Temp ); + *zC0 = cuddT( Temp ); + } + else + { /* top var is not present in negative polarity */ + *zC2 = Temp; + *zC0 = dd->zero; + } + } + else + { /* the top variable is present only in negative */ + *zC1 = dd->zero; + *zC2 = cuddE( zC ); + *zC0 = cuddT( zC ); + } +} /* extraDecomposeCover */ + + + +/**Function******************************************************************** + + Synopsis [Counts the total number of cubes in the ISOPs of the functions.] + + Description [Returns -1 if the number of cubes exceeds the limit.] + + SideEffects [None] + + SeeAlso [Extra_TransferPermute] + +******************************************************************************/ +static DdNode * extraBddCountCubes( DdManager * dd, DdNode * L, DdNode * U, st__table *table, int * pnCubes, int Limit ) +{ + DdNode *one = DD_ONE(dd); + DdNode *zero = Cudd_Not(one); + int v, top_l, top_u; + DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud; + DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1; + DdNode *Isub0, *Isub1, *Id; + DdNode *x; + DdNode *term0, *term1, *sum; + DdNode *Lv, *Uv, *Lnv, *Unv; + DdNode *r; + int index; + int Count0 = 0, Count1 = 0, Count2 = 0; + + statLine(dd); + if (L == zero) + { + *pnCubes = 0; + return(zero); + } + if (U == one) + { + *pnCubes = 1; + return(one); + } + + /* Check cache */ + r = cuddCacheLookup2(dd, cuddBddIsop, L, U); + if (r) + { + int nCubes = 0; + if ( st__lookup( table, (char *)r, (char **)&nCubes ) ) + *pnCubes = nCubes; + else assert( 0 ); + return r; + } + + top_l = dd->perm[Cudd_Regular(L)->index]; + top_u = dd->perm[Cudd_Regular(U)->index]; + v = ddMin(top_l, top_u); + + /* Compute cofactors */ + if (top_l == v) { + index = Cudd_Regular(L)->index; + Lv = Cudd_T(L); + Lnv = Cudd_E(L); + if (Cudd_IsComplement(L)) { + Lv = Cudd_Not(Lv); + Lnv = Cudd_Not(Lnv); + } + } + else { + index = Cudd_Regular(U)->index; + Lv = Lnv = L; + } + + if (top_u == v) { + Uv = Cudd_T(U); + Unv = Cudd_E(U); + if (Cudd_IsComplement(U)) { + Uv = Cudd_Not(Uv); + Unv = Cudd_Not(Unv); + } + } + else { + Uv = Unv = U; + } + + Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv)); + if (Lsub0 == NULL) + return(NULL); + Cudd_Ref(Lsub0); + Usub0 = Unv; + Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv)); + if (Lsub1 == NULL) { + Cudd_RecursiveDeref(dd, Lsub0); + return(NULL); + } + Cudd_Ref(Lsub1); + Usub1 = Uv; + + Isub0 = extraBddCountCubes(dd, Lsub0, Usub0, table, &Count0, Limit); + if (Isub0 == NULL) { + Cudd_RecursiveDeref(dd, Lsub0); + Cudd_RecursiveDeref(dd, Lsub1); + return(NULL); + } + Cudd_Ref(Isub0); + Isub1 = extraBddCountCubes(dd, Lsub1, Usub1, table, &Count1, Limit); + if (Isub1 == NULL) { + Cudd_RecursiveDeref(dd, Lsub0); + Cudd_RecursiveDeref(dd, Lsub1); + Cudd_RecursiveDeref(dd, Isub0); + return(NULL); + } + Cudd_Ref(Isub1); + Cudd_RecursiveDeref(dd, Lsub0); + Cudd_RecursiveDeref(dd, Lsub1); + + Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0)); + if (Lsuper0 == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + return(NULL); + } + Cudd_Ref(Lsuper0); + Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1)); + if (Lsuper1 == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Lsuper0); + return(NULL); + } + Cudd_Ref(Lsuper1); + Usuper0 = Unv; + Usuper1 = Uv; + + /* Ld = Lsuper0 + Lsuper1 */ + Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1)); + Ld = Cudd_NotCond(Ld, Ld != NULL); + if (Ld == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Lsuper0); + Cudd_RecursiveDeref(dd, Lsuper1); + return(NULL); + } + Cudd_Ref(Ld); + Ud = cuddBddAndRecur(dd, Usuper0, Usuper1); + if (Ud == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Lsuper0); + Cudd_RecursiveDeref(dd, Lsuper1); + Cudd_RecursiveDeref(dd, Ld); + return(NULL); + } + Cudd_Ref(Ud); + Cudd_RecursiveDeref(dd, Lsuper0); + Cudd_RecursiveDeref(dd, Lsuper1); + + Id = extraBddCountCubes(dd, Ld, Ud, table, &Count2, Limit); + if (Id == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Ld); + Cudd_RecursiveDeref(dd, Ud); + return(NULL); + } + Cudd_Ref(Id); + Cudd_RecursiveDeref(dd, Ld); + Cudd_RecursiveDeref(dd, Ud); + + x = cuddUniqueInter(dd, index, one, zero); + if (x == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Id); + return(NULL); + } + Cudd_Ref(x); + term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0); + if (term0 == NULL) { + Cudd_RecursiveDeref(dd, Isub0); + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Id); + Cudd_RecursiveDeref(dd, x); + return(NULL); + } + Cudd_Ref(term0); + Cudd_RecursiveDeref(dd, Isub0); + term1 = cuddBddAndRecur(dd, x, Isub1); + if (term1 == NULL) { + Cudd_RecursiveDeref(dd, Isub1); + Cudd_RecursiveDeref(dd, Id); + Cudd_RecursiveDeref(dd, x); + Cudd_RecursiveDeref(dd, term0); + return(NULL); + } + Cudd_Ref(term1); + Cudd_RecursiveDeref(dd, x); + Cudd_RecursiveDeref(dd, Isub1); + /* sum = term0 + term1 */ + sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1)); + sum = Cudd_NotCond(sum, sum != NULL); + if (sum == NULL) { + Cudd_RecursiveDeref(dd, Id); + Cudd_RecursiveDeref(dd, term0); + Cudd_RecursiveDeref(dd, term1); + return(NULL); + } + Cudd_Ref(sum); + Cudd_RecursiveDeref(dd, term0); + Cudd_RecursiveDeref(dd, term1); + /* r = sum + Id */ + r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id)); + r = Cudd_NotCond(r, r != NULL); + if (r == NULL) { + Cudd_RecursiveDeref(dd, Id); + Cudd_RecursiveDeref(dd, sum); + return(NULL); + } + Cudd_Ref(r); + Cudd_RecursiveDeref(dd, sum); + Cudd_RecursiveDeref(dd, Id); + + cuddCacheInsert2(dd, cuddBddIsop, L, U, r); + *pnCubes = Count0 + Count1 + Count2; + if ( st__add_direct( table, (char *)r, (char *)(ABC_PTRINT_T)*pnCubes ) == st__OUT_OF_MEM ) + { + Cudd_RecursiveDeref( dd, r ); + return NULL; + } + if ( *pnCubes > Limit ) + { + Cudd_RecursiveDeref( dd, r ); + return NULL; + } + //printf( "%d ", *pnCubes ); + Cudd_Deref(r); + return r; +} +int Extra_bddCountCubes( DdManager * dd, DdNode ** pFuncs, int nFuncs, int fMode, int nLimit, int * pGuide ) +{ + DdNode * pF0, * pF1; + int i, Count, Count0, Count1, CounterAll = 0; + st__table *table = st__init_table( st__ptrcmp, st__ptrhash ); + unsigned int saveLimit = dd->maxLive; + dd->maxLive = dd->keys - dd->dead + 1000000; // limit on intermediate BDD nodes + for ( i = 0; i < nFuncs; i++ ) + { + if ( !pFuncs[i] ) + continue; + pF1 = pF0 = NULL; + Count0 = Count1 = nLimit; + if ( fMode == -1 || fMode == 1 ) // both or pos + pF1 = extraBddCountCubes( dd, pFuncs[i], pFuncs[i], table, &Count1, nLimit ); + pFuncs[i] = Cudd_Not( pFuncs[i] ); + if ( fMode == -1 || fMode == 0 ) // both or neg + pF0 = extraBddCountCubes( dd, pFuncs[i], pFuncs[i], table, &Count0, Count1 ); + pFuncs[i] = Cudd_Not( pFuncs[i] ); + if ( !pF1 && !pF0 ) + break; + if ( !pF0 ) pGuide[i] = 1, Count = Count1; // use pos + else if ( !pF1 ) pGuide[i] = 0, Count = Count0; // use neg + else if ( Count1 <= Count0 ) pGuide[i] = 1, Count = Count1; // use pos + else pGuide[i] = 0, Count = Count0; // use neg + CounterAll += Count; + //printf( "Output %5d has %5d cubes (%d) (%5d and %5d)\n", nOuts++, Count, pGuide[i], Count1, Count0 ); + } + dd->maxLive = saveLimit; + st__free_table( table ); + return i == nFuncs ? CounterAll : -1; +} /* end of Extra_bddCountCubes */ + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Convert a BDD from a manager to another one.] + + Description [Convert a BDD from a manager to another one. Returns a + pointer to the BDD in the destination manager if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Extra_TransferPermute] + +******************************************************************************/ +DdNode * extraTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute ) +{ + DdNode *res; + st__table *table = NULL; + st__generator *gen = NULL; + DdNode *key, *value; + + table = st__init_table( st__ptrcmp, st__ptrhash ); + if ( table == NULL ) + goto failure; + res = extraTransferPermuteRecur( ddS, ddD, f, table, Permute ); + if ( res != NULL ) + cuddRef( res ); + + /* Dereference all elements in the table and dispose of the table. + ** This must be done also if res is NULL to avoid leaks in case of + ** reordering. */ + gen = st__init_gen( table ); + if ( gen == NULL ) + goto failure; + while ( st__gen( gen, ( const char ** ) &key, ( char ** ) &value ) ) + { + Cudd_RecursiveDeref( ddD, value ); + } + st__free_gen( gen ); + gen = NULL; + st__free_table( table ); + table = NULL; + + if ( res != NULL ) + cuddDeref( res ); + return ( res ); + + failure: + if ( table != NULL ) + st__free_table( table ); + if ( gen != NULL ) + st__free_gen( gen ); + return ( NULL ); + +} /* end of extraTransferPermute */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_TransferPermute.] + + Description [Performs the recursive step of Extra_TransferPermute. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [extraTransferPermute] + +******************************************************************************/ +static DdNode * +extraTransferPermuteRecur( + DdManager * ddS, + DdManager * ddD, + DdNode * f, + st__table * table, + int * Permute ) +{ + DdNode *ft, *fe, *t, *e, *var, *res; + DdNode *one, *zero; + int index; + int comple = 0; + + statLine( ddD ); + one = DD_ONE( ddD ); + comple = Cudd_IsComplement( f ); + + /* Trivial cases. */ + if ( Cudd_IsConstant( f ) ) + return ( Cudd_NotCond( one, comple ) ); + + + /* Make canonical to increase the utilization of the cache. */ + f = Cudd_NotCond( f, comple ); + /* Now f is a regular pointer to a non-constant node. */ + + /* Check the cache. */ + if ( st__lookup( table, ( char * ) f, ( char ** ) &res ) ) + return ( Cudd_NotCond( res, comple ) ); + + if ( ddS->TimeStop && Abc_Clock() > ddS->TimeStop ) + return NULL; + if ( ddD->TimeStop && Abc_Clock() > ddD->TimeStop ) + return NULL; + + /* Recursive step. */ + if ( Permute ) + index = Permute[f->index]; + else + index = f->index; + + ft = cuddT( f ); + fe = cuddE( f ); + + t = extraTransferPermuteRecur( ddS, ddD, ft, table, Permute ); + if ( t == NULL ) + { + return ( NULL ); + } + cuddRef( t ); + + e = extraTransferPermuteRecur( ddS, ddD, fe, table, Permute ); + if ( e == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + return ( NULL ); + } + cuddRef( e ); + + zero = Cudd_Not(ddD->one); + var = cuddUniqueInter( ddD, index, one, zero ); + if ( var == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + res = cuddBddIteRecur( ddD, var, t, e ); + + if ( res == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + cuddRef( res ); + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + + if ( st__add_direct( table, ( char * ) f, ( char * ) res ) == + st__OUT_OF_MEM ) + { + Cudd_RecursiveDeref( ddD, res ); + return ( NULL ); + } + return ( Cudd_NotCond( res, comple ) ); + +} /* end of extraTransferPermuteRecur */ + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_Support.] + + Description [Performs the recursive step of Cudd_Support. Performs a + DFS from f. The support is accumulated in supp as a side effect. Uses + the LSB of the then pointer as visited flag.] + + SideEffects [None] + + SeeAlso [ddClearFlag] + +******************************************************************************/ +static void +ddSupportStep( + DdNode * f, + int * support) +{ + if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) { + return; + } + + support[f->index] = 1; + ddSupportStep(cuddT(f),support); + ddSupportStep(Cudd_Regular(cuddE(f)),support); + /* Mark as visited. */ + f->next = Cudd_Not(f->next); + return; + +} /* end of ddSupportStep */ + + +/**Function******************************************************************** + + Synopsis [Performs a DFS from f, clearing the LSB of the next + pointers.] + + Description [] + + SideEffects [None] + + SeeAlso [ddSupportStep ddDagInt] + +******************************************************************************/ +static void +ddClearFlag( + DdNode * f) +{ + if (!Cudd_IsComplement(f->next)) { + return; + } + /* Clear visited flag. */ + f->next = Cudd_Regular(f->next); + if (cuddIsConstant(f)) { + return; + } + ddClearFlag(cuddT(f)); + ddClearFlag(Cudd_Regular(cuddE(f))); + return; + +} /* end of ddClearFlag */ + + +/**Function******************************************************************** + + Synopsis [Composed three subcovers into one ZDD.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * +extraComposeCover( + DdManager* dd, /* the manager */ + DdNode* zC0, /* the pointer to the negative var cofactor */ + DdNode* zC1, /* the pointer to the positive var cofactor */ + DdNode* zC2, /* the pointer to the cofactor without var */ + int TopVar) /* the index of the positive ZDD var */ +{ + DdNode * zRes, * zTemp; + /* compose with-neg-var and without-var using the neg ZDD var */ + zTemp = cuddZddGetNode( dd, 2*TopVar + 1, zC0, zC2 ); + if ( zTemp == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zC0); + Cudd_RecursiveDerefZdd(dd, zC1); + Cudd_RecursiveDerefZdd(dd, zC2); + return NULL; + } + cuddRef( zTemp ); + cuddDeref( zC0 ); + cuddDeref( zC2 ); + + /* compose with-pos-var and previous result using the pos ZDD var */ + zRes = cuddZddGetNode( dd, 2*TopVar, zC1, zTemp ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd(dd, zC1); + Cudd_RecursiveDerefZdd(dd, zTemp); + return NULL; + } + cuddDeref( zC1 ); + cuddDeref( zTemp ); + return zRes; +} /* extraComposeCover */ + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of prime computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode* extraZddPrimes( DdManager *dd, DdNode* F ) +{ + DdNode *zRes; + + if ( F == Cudd_Not( dd->one ) ) + return dd->zero; + if ( F == dd->one ) + return dd->one; + + /* check cache */ + zRes = cuddCacheLookup1Zdd(dd, extraZddPrimes, F); + if (zRes) + return(zRes); + { + /* temporary variables */ + DdNode *bF01, *zP0, *zP1; + /* three components of the prime set */ + DdNode *zResE, *zResP, *zResN; + int fIsComp = Cudd_IsComplement( F ); + + /* find cofactors of F */ + DdNode * bF0 = Cudd_NotCond( Cudd_E( F ), fIsComp ); + DdNode * bF1 = Cudd_NotCond( Cudd_T( F ), fIsComp ); + + /* find the intersection of cofactors */ + bF01 = cuddBddAndRecur( dd, bF0, bF1 ); + if ( bF01 == NULL ) return NULL; + cuddRef( bF01 ); + + /* solve the problems for cofactors */ + zP0 = extraZddPrimes( dd, bF0 ); + if ( zP0 == NULL ) + { + Cudd_RecursiveDeref( dd, bF01 ); + return NULL; + } + cuddRef( zP0 ); + + zP1 = extraZddPrimes( dd, bF1 ); + if ( zP1 == NULL ) + { + Cudd_RecursiveDeref( dd, bF01 ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + return NULL; + } + cuddRef( zP1 ); + + /* check for local unateness */ + if ( bF01 == bF0 ) /* unate increasing */ + { + /* intersection is useless */ + cuddDeref( bF01 ); + /* the primes of intersection are the primes of F0 */ + zResE = zP0; + /* there are no primes with negative var */ + zResN = dd->zero; + cuddRef( zResN ); + /* primes with positive var are primes of F1 that are not primes of F01 */ + zResP = cuddZddDiff( dd, zP1, zP0 ); + if ( zResP == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResN ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResP ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + } + else if ( bF01 == bF1 ) /* unate decreasing */ + { + /* intersection is useless */ + cuddDeref( bF01 ); + /* the primes of intersection are the primes of F1 */ + zResE = zP1; + /* there are no primes with positive var */ + zResP = dd->zero; + cuddRef( zResP ); + /* primes with negative var are primes of F0 that are not primes of F01 */ + zResN = cuddZddDiff( dd, zP0, zP1 ); + if ( zResN == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResP ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + return NULL; + } + cuddRef( zResN ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + } + else /* not unate */ + { + /* primes without the top var are primes of F10 */ + zResE = extraZddPrimes( dd, bF01 ); + if ( zResE == NULL ) + { + Cudd_RecursiveDerefZdd( dd, bF01 ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResE ); + Cudd_RecursiveDeref( dd, bF01 ); + + /* primes with the negative top var are those of P0 that are not in F10 */ + zResN = cuddZddDiff( dd, zP0, zResE ); + if ( zResN == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResN ); + Cudd_RecursiveDerefZdd( dd, zP0 ); + + /* primes with the positive top var are those of P1 that are not in F10 */ + zResP = cuddZddDiff( dd, zP1, zResE ); + if ( zResP == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zResE ); + Cudd_RecursiveDerefZdd( dd, zResN ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + return NULL; + } + cuddRef( zResP ); + Cudd_RecursiveDerefZdd( dd, zP1 ); + } + + zRes = extraComposeCover( dd, zResN, zResP, zResE, Cudd_Regular(F)->index ); + if ( zRes == NULL ) return NULL; + + /* insert the result into cache */ + cuddCacheInsert1(dd, extraZddPrimes, F, zRes); + return zRes; + } +} /* end of extraZddPrimes */ + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddPermute.] + + Description [ Recursively puts the BDD in the order given in the array permut. + Checks for trivial cases to terminate recursion, then splits on the + children of this node. Once the solutions for the children are + obtained, it puts into the current position the node from the rest of + the BDD that should be here. Then returns this BDD. + The key here is that the node being visited is NOT put in its proper + place by this instance, but rather is switched when its proper position + is reached in the recursion tree.

+ The DdNode * that is returned is the same BDD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute cuddAddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddBddPermuteRecur( DdManager * manager /* DD manager */ , + DdHashTable * table /* computed table */ , + DdNode * node /* BDD to be reordered */ , + int *permut /* permutation array */ ) +{ + DdNode *N, *T, *E; + DdNode *res; + int index; + + statLine( manager ); + N = Cudd_Regular( node ); + + /* Check for terminal case of constant node. */ + if ( cuddIsConstant( N ) ) + { + return ( node ); + } + + /* If problem already solved, look up answer and return. */ + if ( N->ref != 1 && ( res = cuddHashTableLookup1( table, N ) ) != NULL ) + { + return ( Cudd_NotCond( res, N != node ) ); + } + + /* Split and recur on children of this node. */ + T = cuddBddPermuteRecur( manager, table, cuddT( N ), permut ); + if ( T == NULL ) + return ( NULL ); + cuddRef( T ); + E = cuddBddPermuteRecur( manager, table, cuddE( N ), permut ); + if ( E == NULL ) + { + Cudd_IterDerefBdd( manager, T ); + return ( NULL ); + } + cuddRef( E ); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = permut[N->index]; + res = cuddBddIteRecur( manager, manager->vars[index], T, E ); + if ( res == NULL ) + { + Cudd_IterDerefBdd( manager, T ); + Cudd_IterDerefBdd( manager, E ); + return ( NULL ); + } + cuddRef( res ); + Cudd_IterDerefBdd( manager, T ); + Cudd_IterDerefBdd( manager, E ); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if ( N->ref != 1 ) + { + ptrint fanout = ( ptrint ) N->ref; + cuddSatDec( fanout ); + if ( !cuddHashTableInsert1( table, N, res, fanout ) ) + { + Cudd_IterDerefBdd( manager, res ); + return ( NULL ); + } + } + cuddDeref( res ); + return ( Cudd_NotCond( res, N != node ) ); + +} /* end of cuddBddPermuteRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_bddChangePolarity().] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddChangePolarity( + DdManager * dd, /* the DD manager */ + DdNode * bFunc, + DdNode * bVars) +{ + DdNode * bRes; + + if ( bVars == b1 ) + return bFunc; + if ( Cudd_IsConstant(bFunc) ) + return bFunc; + + if ( (bRes = cuddCacheLookup2(dd, extraBddChangePolarity, bFunc, bVars)) ) + return bRes; + else + { + DdNode * bFR = Cudd_Regular(bFunc); + int LevelF = dd->perm[bFR->index]; + int LevelV = dd->perm[bVars->index]; + + if ( LevelV < LevelF ) + bRes = extraBddChangePolarity( dd, bFunc, cuddT(bVars) ); + else // if ( LevelF <= LevelV ) + { + DdNode * bRes0, * bRes1; + DdNode * bF0, * bF1; + DdNode * bVarsNext; + + // cofactor the functions + if ( bFR != bFunc ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + if ( LevelF == LevelV ) + bVarsNext = cuddT(bVars); + else + bVarsNext = bVars; + + bRes0 = extraBddChangePolarity( dd, bF0, bVarsNext ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + + bRes1 = extraBddChangePolarity( dd, bF1, bVarsNext ); + if ( bRes1 == NULL ) + { + Cudd_RecursiveDeref( dd, bRes0 ); + return NULL; + } + cuddRef( bRes1 ); + + if ( LevelF == LevelV ) + { // swap the cofactors + DdNode * bTemp; + bTemp = bRes0; + bRes0 = bRes1; + bRes1 = bTemp; + } + + /* only aRes0 and aRes1 are referenced at this point */ + + /* consider the case when Res0 and Res1 are the same node */ + if ( bRes0 == bRes1 ) + bRes = bRes1; + /* consider the case when Res1 is complemented */ + else if ( Cudd_IsComplement(bRes1) ) + { + bRes = cuddUniqueInter(dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0)); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + bRes = Cudd_Not(bRes); + } + else + { + bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref(dd,bRes0); + Cudd_RecursiveDeref(dd,bRes1); + return NULL; + } + } + cuddDeref( bRes0 ); + cuddDeref( bRes1 ); + } + + /* insert the result into cache */ + cuddCacheInsert2(dd, extraBddChangePolarity, bFunc, bVars, bRes); + return bRes; + } +} /* end of extraBddChangePolarity */ + + + +static int Counter = 0; + +/**Function************************************************************* + + Synopsis [Computes the AND of two BDD with different orders.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * extraBddAndPermute( DdHashTable * table, DdManager * ddF, DdNode * bF, DdManager * ddG, DdNode * bG, int * pPermute ) +{ + DdNode * bF0, * bF1, * bG0, * bG1, * bRes0, * bRes1, * bRes, * bVar; + int LevF, LevG, Lev; + + // if F == 0, return 0 + if ( bF == Cudd_Not(ddF->one) ) + return Cudd_Not(ddF->one); + // if G == 0, return 0 + if ( bG == Cudd_Not(ddG->one) ) + return Cudd_Not(ddF->one); + // if G == 1, return F + if ( bG == ddG->one ) + return bF; + // cannot use F == 1, because the var order of G has to be changed + + // check cache + if ( //(Cudd_Regular(bF)->ref != 1 || Cudd_Regular(bG)->ref != 1) && + (bRes = cuddHashTableLookup2(table, bF, bG)) ) + return bRes; + Counter++; + + if ( ddF->TimeStop && Abc_Clock() > ddF->TimeStop ) + return NULL; + if ( ddG->TimeStop && Abc_Clock() > ddG->TimeStop ) + return NULL; + + // find the topmost variable in F and G using var order of F + LevF = cuddI( ddF, Cudd_Regular(bF)->index ); + LevG = cuddI( ddF, pPermute ? pPermute[Cudd_Regular(bG)->index] : Cudd_Regular(bG)->index ); + Lev = Abc_MinInt( LevF, LevG ); + assert( Lev < ddF->size ); + bVar = ddF->vars[ddF->invperm[Lev]]; + + // cofactor + bF0 = (Lev < LevF) ? bF : Cudd_NotCond( cuddE(Cudd_Regular(bF)), Cudd_IsComplement(bF) ); + bF1 = (Lev < LevF) ? bF : Cudd_NotCond( cuddT(Cudd_Regular(bF)), Cudd_IsComplement(bF) ); + bG0 = (Lev < LevG) ? bG : Cudd_NotCond( cuddE(Cudd_Regular(bG)), Cudd_IsComplement(bG) ); + bG1 = (Lev < LevG) ? bG : Cudd_NotCond( cuddT(Cudd_Regular(bG)), Cudd_IsComplement(bG) ); + + // call for cofactors + bRes0 = extraBddAndPermute( table, ddF, bF0, ddG, bG0, pPermute ); + if ( bRes0 == NULL ) + return NULL; + cuddRef( bRes0 ); + // call for cofactors + bRes1 = extraBddAndPermute( table, ddF, bF1, ddG, bG1, pPermute ); + if ( bRes1 == NULL ) + { + Cudd_IterDerefBdd( ddF, bRes0 ); + return NULL; + } + cuddRef( bRes1 ); + + // compose the result + bRes = cuddBddIteRecur( ddF, bVar, bRes1, bRes0 ); + if ( bRes == NULL ) + { + Cudd_IterDerefBdd( ddF, bRes0 ); + Cudd_IterDerefBdd( ddF, bRes1 ); + return NULL; + } + cuddRef( bRes ); + Cudd_IterDerefBdd( ddF, bRes0 ); + Cudd_IterDerefBdd( ddF, bRes1 ); + + // cache the result +// if ( Cudd_Regular(bF)->ref != 1 || Cudd_Regular(bG)->ref != 1 ) + { + ptrint fanout = (ptrint)Cudd_Regular(bF)->ref * Cudd_Regular(bG)->ref; + cuddSatDec(fanout); + cuddHashTableInsert2( table, bF, bG, bRes, fanout ); + } + cuddDeref( bRes ); + return bRes; +} + +/**Function************************************************************* + + Synopsis [Testbench.] + + Description [This procedure takes BDD manager ddF and two BDDs + in this manager (bF and bG). It creates a new manager ddG, + transfers bG into it and then reorders it, resulting in bG2. + Then it tries to compute the product of bF and bG2 in ddF.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_TestAndPerm( DdManager * ddF, DdNode * bF, DdNode * bG ) +{ + DdManager * ddG; + DdNode * bG2, * bRes1, * bRes2; + abctime clk; + // disable variable ordering in ddF + Cudd_AutodynDisable( ddF ); + + // create new BDD manager + ddG = Cudd_Init( ddF->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + // transfer BDD into it + Cudd_ShuffleHeap( ddG, ddF->invperm ); + bG2 = Extra_TransferLevelByLevel( ddF, ddG, bG ); Cudd_Ref( bG2 ); + // reorder the new manager + Cudd_ReduceHeap( ddG, CUDD_REORDER_SYMM_SIFT, 1 ); + + // compute the result +clk = Abc_Clock(); + bRes1 = Cudd_bddAnd( ddF, bF, bG ); Cudd_Ref( bRes1 ); +Abc_PrintTime( 1, "Runtime of Cudd_bddAnd ", Abc_Clock() - clk ); + + // compute the result +Counter = 0; +clk = Abc_Clock(); + bRes2 = Extra_bddAndPermute( ddF, bF, ddG, bG2, NULL ); Cudd_Ref( bRes2 ); +Abc_PrintTime( 1, "Runtime of new procedure", Abc_Clock() - clk ); +printf( "Recursive calls = %d\n", Counter ); +printf( "|F| =%6d |G| =%6d |H| =%6d |F|*|G| =%9d ", + Cudd_DagSize(bF), Cudd_DagSize(bG), Cudd_DagSize(bRes2), + Cudd_DagSize(bF) * Cudd_DagSize(bG) ); + + if ( bRes1 == bRes2 ) + printf( "Result verified.\n\n" ); + else + printf( "Result is incorrect.\n\n" ); + + Cudd_RecursiveDeref( ddF, bRes1 ); + Cudd_RecursiveDeref( ddF, bRes2 ); + // quit the new manager + Cudd_RecursiveDeref( ddG, bG2 ); + Extra_StopManager( ddG ); + + // re-enable variable ordering in ddF + Cudd_AutodynEnable( ddF, CUDD_REORDER_SYMM_SIFT ); +} + +/**Function************************************************************* + + Synopsis [Writes ZDD into a PLA file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Extra_zddDumpPla( DdManager * dd, DdNode * F, int nVars, char * pFileName ) +{ + DdGen *gen; + char * pCube; + int * pPath, i; + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + { + printf( "Cannot open file \"%s\" for writing.\n", pFileName ); + return; + } + fprintf( pFile, "# PLA file dumped by Extra_zddDumpPla() in ABC\n" ); + fprintf( pFile, ".i %d\n", nVars ); + fprintf( pFile, ".o 1\n" ); + pCube = ABC_CALLOC( char, dd->sizeZ ); + Cudd_zddForeachPath( dd, F, gen, pPath ) + { + for ( i = 0; i < nVars; i++ ) + pCube[i] = '-'; + for ( i = 0; i < nVars; i++ ) + if ( pPath[2*i] == 1 || pPath[2*i+1] == 1 ) + pCube[i] = '0' + (pPath[2*i] == 1); + fprintf( pFile, "%s 1\n", pCube ); + } + fprintf( pFile, ".e\n\n" ); + fclose( pFile ); + ABC_FREE( pCube ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddSymm.c b/src/bdd/extrab/extraBddSymm.c new file mode 100644 index 00000000..9dd2c8e5 --- /dev/null +++ b/src/bdd/extrab/extraBddSymm.c @@ -0,0 +1,1474 @@ +/**CFile**************************************************************** + + FileName [extraBddSymm.c] + + PackageName [extra] + + Synopsis [Efficient methods to compute the information about + symmetric variables using the algorithm presented in the paper: + A. Mishchenko. Fast Computation of Symmetries in Boolean Functions. + Transactions on CAD, Nov. 2003.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddSymm.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +#define DD_GET_SYMM_VARS_TAG 0x0a /* former DD_BDD_XOR_EXIST_ABSTRACT_TAG */ + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information for the function.] + + Description [Returns the symmetry information in the form of Extra_SymmInfo_t structure.] + + SideEffects [If the ZDD variables are not derived from BDD variables with + multiplicity 2, this function may derive them in a wrong way.] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsCompute( + DdManager * dd, /* the manager */ + DdNode * bFunc) /* the function whose symmetries are computed */ +{ + DdNode * bSupp; + DdNode * zRes; + Extra_SymmInfo_t * p; + + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + zRes = Extra_zddSymmPairsCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes ); + + p = Extra_SymmPairsCreateFromZdd( dd, zRes, bSupp ); + + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDerefZdd( dd, zRes ); + + return p; + +} /* end of Extra_SymmPairsCompute */ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddSymmPairsCompute( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddSymmPairsCompute( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddSymmPairsCompute */ + +/**Function******************************************************************** + + Synopsis [Returns a singleton-set ZDD containing all variables that are symmetric with the given one.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSymmetricVars( + DdManager * dd, /* the DD manager */ + DdNode * bF, /* the first function - originally, the positive cofactor */ + DdNode * bG, /* the second fucntion - originally, the negative cofactor */ + DdNode * bVars) /* the set of variables, on which F and G depend */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSymmetricVars( dd, bF, bG, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSymmetricVars */ + + +/**Function******************************************************************** + + Synopsis [Converts a set of variables into a set of singleton subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSingletons( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSingletons( dd, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSingletons */ + +/**Function******************************************************************** + + Synopsis [Filters the set of variables using the support of the function.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_bddReduceVarSet( + DdManager * dd, /* the DD manager */ + DdNode * bVars, /* the set of variables to be reduced */ + DdNode * bF) /* the function whose support is used for reduction */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraBddReduceVarSet( dd, bVars, bF ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddReduceVarSet */ + + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_SymmInfo_t * Extra_SymmPairsAllocate( int nVars ) +{ + int i; + Extra_SymmInfo_t * p; + + // allocate and clean the storage for symmetry info + p = ABC_ALLOC( Extra_SymmInfo_t, 1 ); + memset( p, 0, sizeof(Extra_SymmInfo_t) ); + p->nVars = nVars; + p->pVars = ABC_ALLOC( int, nVars ); + p->pSymms = ABC_ALLOC( char *, nVars ); + p->pSymms[0] = ABC_ALLOC( char , nVars * nVars ); + memset( p->pSymms[0], 0, nVars * nVars * sizeof(char) ); + + for ( i = 1; i < nVars; i++ ) + p->pSymms[i] = p->pSymms[i-1] + nVars; + + return p; +} /* end of Extra_SymmPairsAllocate */ + +/**Function******************************************************************** + + Synopsis [Deallocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_SymmPairsDissolve( Extra_SymmInfo_t * p ) +{ + ABC_FREE( p->pVars ); + ABC_FREE( p->pSymms[0] ); + ABC_FREE( p->pSymms ); + ABC_FREE( p ); +} /* end of Extra_SymmPairsDissolve */ + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_SymmPairsPrint( Extra_SymmInfo_t * p ) +{ + int i, k; + printf( "\n" ); + for ( i = 0; i < p->nVars; i++ ) + { + for ( k = 0; k <= i; k++ ) + printf( " " ); + for ( k = i+1; k < p->nVars; k++ ) + if ( p->pSymms[i][k] ) + printf( "1" ); + else + printf( "." ); + printf( "\n" ); + } +} /* end of Extra_SymmPairsPrint */ + + +/**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 [Checks the possibility of two variables being symmetric.] + + Description [Returns 0 if vars are not symmetric. Return 1 if vars can be symmetric.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckVarsSymmetric( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar1, + int iVar2) +{ + DdNode * bVars; + int Res; + +// return 1; + + assert( iVar1 != iVar2 ); + assert( iVar1 < dd->size ); + assert( iVar2 < dd->size ); + + bVars = Cudd_bddAnd( dd, dd->vars[iVar1], dd->vars[iVar2] ); Cudd_Ref( bVars ); + + Res = (int)( extraBddCheckVarsSymmetric( dd, bF, bVars ) == b1 ); + + Cudd_RecursiveDeref( dd, bVars ); + + return Res; +} /* end of Extra_bddCheckVarsSymmetric */ + + +/**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 [Checks if the two variables are symmetric.] + + Description [Returns 0 if vars are not symmetric. Return 1 if vars are symmetric.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckVarsSymmetricNaive( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar1, + int iVar2) +{ + DdNode * bCube1, * bCube2; + DdNode * bCof01, * bCof10; + int Res; + + assert( iVar1 != iVar2 ); + assert( iVar1 < dd->size ); + assert( iVar2 < dd->size ); + + bCube1 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar1] ), dd->vars[iVar2] ); Cudd_Ref( bCube1 ); + bCube2 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar2] ), dd->vars[iVar1] ); Cudd_Ref( bCube2 ); + + bCof01 = Cudd_Cofactor( dd, bF, bCube1 ); Cudd_Ref( bCof01 ); + bCof10 = Cudd_Cofactor( dd, bF, bCube2 ); Cudd_Ref( bCof10 ); + + Res = (int)( bCof10 == bCof01 ); + + Cudd_RecursiveDeref( dd, bCof01 ); + Cudd_RecursiveDeref( dd, bCof10 ); + Cudd_RecursiveDeref( dd, bCube1 ); + Cudd_RecursiveDeref( dd, bCube2 ); + + return Res; +} /* end of Extra_bddCheckVarsSymmetricNaive */ + + +/**Function******************************************************************** + + Synopsis [Builds ZDD representing the set of fixed-size variable tuples.] + + Description [Creates ZDD of all combinations of variables in Support that + is represented by a BDD.] + + SideEffects [New ZDD variables are created if indices of the variables + present in the combination are larger than the currently + allocated number of ZDD variables.] + + SeeAlso [] + +******************************************************************************/ +DdNode* Extra_zddTuplesFromBdd( + DdManager * dd, /* the DD manager */ + int K, /* the number of variables in tuples */ + DdNode * bVarsN) /* the set of all variables represented as a BDD */ +{ + DdNode *zRes; + int autoDynZ; + + autoDynZ = dd->autoDynZ; + dd->autoDynZ = 0; + + do { + /* transform the numeric arguments (K) into a DdNode* argument; + * this allows us to use the standard internal CUDD cache */ + DdNode *bVarSet = bVarsN, *bVarsK = bVarsN; + int nVars = 0, i; + + /* determine the number of variables in VarSet */ + while ( bVarSet != b1 ) + { + nVars++; + /* make sure that the VarSet is a cube */ + if ( cuddE( bVarSet ) != b0 ) + return NULL; + bVarSet = cuddT( bVarSet ); + } + /* make sure that the number of variables in VarSet is less or equal + that the number of variables that should be present in the tuples + */ + if ( K > nVars ) + return NULL; + + /* the second argument in the recursive call stannds for ; + * reate the first argument, which stands for + * as when we are talking about the tuple of out of */ + for ( i = 0; i < nVars-K; i++ ) + bVarsK = cuddT( bVarsK ); + + dd->reordered = 0; + zRes = extraZddTuplesFromBdd(dd, bVarsK, bVarsN ); + + } while (dd->reordered == 1); + dd->autoDynZ = autoDynZ; + return zRes; + +} /* end of Extra_zddTuplesFromBdd */ + +/**Function******************************************************************** + + Synopsis [Selects one subset from the set of subsets represented by a ZDD.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode* Extra_zddSelectOneSubset( + DdManager * dd, /* the DD manager */ + DdNode * zS) /* the ZDD */ +{ + DdNode *res; + do { + dd->reordered = 0; + res = extraZddSelectOneSubset(dd, zS); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddSelectOneSubset */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**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 [Performs a recursive step of Extra_zddGetSymmetricVars.] + + Description [Returns the set of ZDD singletons, containing those positive + ZDD variables that correspond to BDD variables x, for which it is true + that bF(x=0) == bG(x=1).] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSymmetricVars( + DdManager * dd, /* the DD manager */ + DdNode * bF, /* the first function - originally, the positive cofactor */ + DdNode * bG, /* the second function - originally, the negative cofactor */ + DdNode * bVars) /* the set of variables, on which F and G depend */ +{ + DdNode * zRes; + DdNode * bFR = Cudd_Regular(bF); + DdNode * bGR = Cudd_Regular(bG); + + if ( cuddIsConstant(bFR) && cuddIsConstant(bGR) ) + { + if ( bF == bG ) + return extraZddGetSingletons( dd, bVars ); + else + return z0; + } + assert( bVars != b1 ); + + if ( (zRes = cuddCacheLookupZdd(dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars)) ) + return zRes; + else + { + DdNode * zRes0, * zRes1; + DdNode * zPlus, * zTemp; + DdNode * bF0, * bF1; + DdNode * bG0, * bG1; + DdNode * bVarsNew; + + int LevelF = cuddI(dd,bFR->index); + int LevelG = cuddI(dd,bGR->index); + int LevelFG; + + if ( LevelF < LevelG ) + LevelFG = LevelF; + else + LevelFG = LevelG; + + // at least one of the arguments is not a constant + assert( LevelFG < dd->size ); + + // every variable in bF and bG should be also in bVars, therefore LevelFG cannot be above LevelV + // if LevelFG is below LevelV, scroll through the vars in bVars to the same level as LevelFG + for ( bVarsNew = bVars; LevelFG > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ); + assert( LevelFG == dd->perm[bVarsNew->index] ); + + // cofactor the functions + if ( LevelF == LevelFG ) + { + if ( bFR != bF ) // bF is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + bF0 = bF1 = bF; + + if ( LevelG == LevelFG ) + { + if ( bGR != bG ) // bG is complemented + { + bG0 = Cudd_Not( cuddE(bGR) ); + bG1 = Cudd_Not( cuddT(bGR) ); + } + else + { + bG0 = cuddE(bGR); + bG1 = cuddT(bGR); + } + } + else + bG0 = bG1 = bG; + + // solve subproblems + zRes0 = extraZddGetSymmetricVars( dd, bF0, bG0, cuddT(bVarsNew) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + // if there is not symmetries in the negative cofactor + // there is no need to test the positive cofactor + if ( zRes0 == z0 ) + zRes = zRes0; // zRes takes reference + else + { + zRes1 = extraZddGetSymmetricVars( dd, bF1, bG1, cuddT(bVarsNew) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + + // only those variables should belong to the resulting set + // for which the property is true for both cofactors + 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 ); + } + + // add one more singleton if the property is true for this variable + if ( bF0 == bG1 ) + { + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + } + + if ( bF == bG && bVars != bVarsNew ) + { + // if the functions are equal, so are their cofactors + // add those variables from V that are above F and G + + DdNode * bVarsExtra; + + assert( LevelFG > dd->perm[bVars->index] ); + + // create the BDD of the extra variables + bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsNew ); + if ( bVarsExtra == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( bVarsExtra ); + + zPlus = extraZddGetSingletons( dd, 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 ); + + cuddCacheInsert( dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSymmetricVars */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_zddGetSingletons.] + + Description [Returns the set of ZDD singletons, containing those positive + polarity ZDD variables that correspond to the BDD variables in bVars.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSingletons( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * zRes; + + if ( bVars == b1 ) +// if ( bVars == b0 ) // bug fixed by Jin Zhang, Jan 23, 2004 + return z1; + + if ( (zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletons, bVars)) ) + return zRes; + else + { + DdNode * zTemp, * zPlus; + + // solve subproblem + zRes = extraZddGetSingletons( dd, cuddT(bVars) ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + + cuddCacheInsert1( dd, extraZddGetSingletons, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSingletons */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_bddReduceVarSet.] + + Description [Returns the set of all variables in the given set that are not in the + support of the given function.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddReduceVarSet( + DdManager * dd, /* the DD manager */ + DdNode * bVars, /* the set of variables to be reduced */ + DdNode * bF) /* the function whose support is used for reduction */ +{ + DdNode * bRes; + DdNode * bFR = Cudd_Regular(bF); + + if ( cuddIsConstant(bFR) || bVars == b1 ) + return bVars; + + if ( (bRes = cuddCacheLookup2(dd, extraBddReduceVarSet, bVars, bF)) ) + return bRes; + else + { + DdNode * bF0, * bF1; + DdNode * bVarsThis, * bVarsLower, * bTemp; + int LevelF; + + // if LevelF is below LevelV, scroll through the vars in bVars + LevelF = dd->perm[bFR->index]; + for ( bVarsThis = bVars; LevelF > cuddI(dd,bVarsThis->index); bVarsThis = cuddT(bVarsThis) ); + // scroll also through the current var, because it should be not be added + if ( LevelF == cuddI(dd,bVarsThis->index) ) + bVarsLower = cuddT(bVarsThis); + else + bVarsLower = bVarsThis; + + // cofactor the function + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + + // solve subproblems + bRes = extraBddReduceVarSet( dd, bVarsLower, bF0 ); + if ( bRes == NULL ) + return NULL; + cuddRef( bRes ); + + bRes = extraBddReduceVarSet( dd, bTemp = bRes, bF1 ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + + // the current var should not be added + // add the skipped vars + if ( bVarsThis != bVars ) + { + DdNode * bVarsExtra; + + // extract the skipped variables + bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsThis ); + if ( bVarsExtra == NULL ) + { + Cudd_RecursiveDeref( dd, bRes ); + return NULL; + } + cuddRef( bVarsExtra ); + + // add these variables + bRes = cuddBddAndRecur( dd, bTemp = bRes, bVarsExtra ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + return NULL; + } + cuddRef( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bVarsExtra ); + } + cuddDeref( bRes ); + + cuddCacheInsert2( dd, extraBddReduceVarSet, bVars, bF, bRes ); + return bRes; + } +} /* end of extraBddReduceVarSet */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_bddCheckVarsSymmetric().] + + Description [Returns b0 if the variables are not symmetric. Returns b1 if the + variables can be symmetric. The variables are represented in the form of a + two-variable cube. In case the cube contains one variable (below Var1 level), + the cube's pointer is complemented if the variable Var1 occurred on the + current path; otherwise, the cube's pointer is regular. Uses additional + complemented bit (Hash_Not) to mark the result if in the BDD rooted that this + node there is a branch passing though the node labeled with Var2.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraBddCheckVarsSymmetric( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * bRes; + + if ( bF == b0 ) + return b1; + + assert( bVars != b1 ); + + if ( (bRes = cuddCacheLookup2(dd, extraBddCheckVarsSymmetric, bF, bVars)) ) + return bRes; + else + { + DdNode * bRes0, * bRes1; + DdNode * bF0, * bF1; + DdNode * bFR = Cudd_Regular(bF); + int LevelF = cuddI(dd,bFR->index); + + DdNode * bVarsR = Cudd_Regular(bVars); + int fVar1Pres; + int iLev1; + int iLev2; + + if ( bVarsR != bVars ) // cube's pointer is complemented + { + assert( cuddT(bVarsR) == b1 ); + fVar1Pres = 1; // the first var is present on the path + iLev1 = -1; // we are already below the first var level + iLev2 = dd->perm[bVarsR->index]; // the level of the second var + } + else // cube's pointer is NOT complemented + { + fVar1Pres = 0; // the first var is absent on the path + if ( cuddT(bVars) == b1 ) + { + iLev1 = -1; // we are already below the first var level + iLev2 = dd->perm[bVars->index]; // the level of the second var + } + else + { + assert( cuddT(cuddT(bVars)) == b1 ); + iLev1 = dd->perm[bVars->index]; // the level of the first var + iLev2 = dd->perm[cuddT(bVars)->index]; // the level of the second var + } + } + + // cofactor the function + // the cofactors are needed only if we are above the second level + if ( LevelF < iLev2 ) + { + if ( bFR != bF ) // bFunc is complemented + { + bF0 = Cudd_Not( cuddE(bFR) ); + bF1 = Cudd_Not( cuddT(bFR) ); + } + else + { + bF0 = cuddE(bFR); + bF1 = cuddT(bFR); + } + } + else + bF0 = bF1 = NULL; + + // consider five cases: + // (1) F is above iLev1 + // (2) F is on the level iLev1 + // (3) F is between iLev1 and iLev2 + // (4) F is on the level iLev2 + // (5) F is below iLev2 + + // (1) F is above iLev1 + if ( LevelF < iLev1 ) + { + // the returned result cannot have the hash attribute + // because we still did not reach the level of Var1; + // the attribute never travels above the level of Var1 + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); +// assert( !Hash_IsComplement( bRes0 ) ); + assert( bRes0 != z0 ); + if ( bRes0 == b0 ) + bRes = b0; + else + bRes = extraBddCheckVarsSymmetric( dd, bF1, bVars ); +// assert( !Hash_IsComplement( bRes ) ); + assert( bRes != z0 ); + } + // (2) F is on the level iLev1 + else if ( LevelF == iLev1 ) + { + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, Cudd_Not( cuddT(bVars) ) ); + if ( bRes0 == b0 ) + bRes = b0; + else + { + bRes1 = extraBddCheckVarsSymmetric( dd, bF1, Cudd_Not( cuddT(bVars) ) ); + if ( bRes1 == b0 ) + bRes = b0; + else + { +// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) + if ( bRes0 == z0 || bRes1 == z0 ) + bRes = b1; + else + bRes = b0; + } + } + } + // (3) F is between iLev1 and iLev2 + else if ( LevelF < iLev2 ) + { + bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); + if ( bRes0 == b0 ) + bRes = b0; + else + { + bRes1 = extraBddCheckVarsSymmetric( dd, bF1, bVars ); + if ( bRes1 == b0 ) + bRes = b0; + else + { +// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) +// bRes = Hash_Not( b1 ); + if ( bRes0 == z0 || bRes1 == z0 ) + bRes = z0; + else + bRes = b1; + } + } + } + // (4) F is on the level iLev2 + else if ( LevelF == iLev2 ) + { + // this is the only place where the hash attribute (Hash_Not) can be added + // to the result; it can be added only if the path came through the node + // lebeled with Var1; therefore, the hash attribute cannot be returned + // to the caller function + if ( fVar1Pres ) +// bRes = Hash_Not( b1 ); + bRes = z0; + else + bRes = b0; + } + // (5) F is below iLev2 + else // if ( LevelF > iLev2 ) + { + // it is possible that the path goes through the node labeled by Var1 + // and still everything is okay; we do not label with Hash_Not here + // because the path does not go through node labeled by Var2 + bRes = b1; + } + + cuddCacheInsert2(dd, extraBddCheckVarsSymmetric, bF, bVars, bRes); + return bRes; + } +} /* end of extraBddCheckVarsSymmetric */ + +/**Function******************************************************************** + + Synopsis [Performs the reordering-sensitive step of Extra_zddTupleFromBdd().] + + Description [Generates in a bottom-up fashion ZDD for all combinations + composed of k variables out of variables belonging to Support.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode* extraZddTuplesFromBdd( + DdManager * dd, /* the DD manager */ + DdNode * bVarsK, /* the number of variables in tuples */ + DdNode * bVarsN) /* the set of all variables */ +{ + DdNode *zRes, *zRes0, *zRes1; + statLine(dd); + + /* terminal cases */ +/* if ( k < 0 || k > n ) + * return dd->zero; + * if ( n == 0 ) + * return dd->one; + */ + if ( cuddI( dd, bVarsK->index ) < cuddI( dd, bVarsN->index ) ) + return z0; + if ( bVarsN == b1 ) + return z1; + + /* check cache */ + zRes = cuddCacheLookup2Zdd(dd, extraZddTuplesFromBdd, bVarsK, bVarsN); + if (zRes) + return(zRes); + + /* ZDD in which this variable is 0 */ +/* zRes0 = extraZddTuplesFromBdd( dd, k, n-1 ); */ + zRes0 = extraZddTuplesFromBdd( dd, bVarsK, cuddT(bVarsN) ); + if ( zRes0 == NULL ) + return NULL; + cuddRef( zRes0 ); + + /* ZDD in which this variable is 1 */ +/* zRes1 = extraZddTuplesFromBdd( dd, k-1, n-1 ); */ + if ( bVarsK == b1 ) + { + zRes1 = z0; + cuddRef( zRes1 ); + } + else + { + zRes1 = extraZddTuplesFromBdd( dd, cuddT(bVarsK), cuddT(bVarsN) ); + if ( zRes1 == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + return NULL; + } + cuddRef( zRes1 ); + } + + /* compose Res0 and Res1 with the given ZDD variable */ + zRes = cuddZddGetNode( dd, 2*bVarsN->index, zRes1, zRes0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes0 ); + Cudd_RecursiveDerefZdd( dd, zRes1 ); + return NULL; + } + cuddDeref( zRes0 ); + cuddDeref( zRes1 ); + + /* insert the result into cache */ + cuddCacheInsert2(dd, extraZddTuplesFromBdd, bVarsK, bVarsN, zRes); + return zRes; + +} /* end of extraZddTuplesFromBdd */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_zddSelectOneSubset.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddSelectOneSubset( + DdManager * dd, + DdNode * zS ) +// selects one subset from the ZDD zS +// returns z0 if and only if zS is an empty set of cubes +{ + DdNode * zRes; + + if ( zS == z0 ) return z0; + if ( zS == z1 ) return z1; + + // check cache + if ( (zRes = cuddCacheLookup1Zdd( dd, extraZddSelectOneSubset, zS )) ) + return zRes; + else + { + DdNode * zS0, * zS1, * zTemp; + + zS0 = cuddE(zS); + zS1 = cuddT(zS); + + if ( zS0 != z0 ) + { + zRes = extraZddSelectOneSubset( dd, zS0 ); + if ( zRes == NULL ) + return NULL; + } + else // if ( zS0 == z0 ) + { + assert( zS1 != z0 ); + zRes = extraZddSelectOneSubset( dd, zS1 ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + zRes = cuddZddGetNode( dd, zS->index, zTemp = zRes, z0 ); + if ( zRes == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zTemp ); + return NULL; + } + cuddDeref( zTemp ); + } + + // insert the result into cache + cuddCacheInsert1( dd, extraZddSelectOneSubset, zS, zRes ); + return zRes; + } +} /* end of extraZddSelectOneSubset */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddTime.c b/src/bdd/extrab/extraBddTime.c new file mode 100644 index 00000000..dc9ff147 --- /dev/null +++ b/src/bdd/extrab/extraBddTime.c @@ -0,0 +1,660 @@ +/**CFile**************************************************************** + + FileName [extraBddTime.c] + + PackageName [extra] + + Synopsis [Procedures to control runtime in BDD operators.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddTime.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +#define CHECK_FACTOR 10 + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + + + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static DdNode * cuddBddAndRecurTime( DdManager * manager, DdNode * f, DdNode * g, int * pRecCalls, int TimeOut ); +static DdNode * cuddBddAndAbstractRecurTime( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube, int * pRecCalls, int TimeOut ); +static DdNode * extraTransferPermuteTime( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute, int TimeOut ); +static DdNode * extraTransferPermuteRecurTime( DdManager * ddS, DdManager * ddD, DdNode * f, st__table * table, int * Permute, int TimeOut ); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Computes the conjunction of two BDDs f and g.] + + Description [Computes the conjunction of two BDDs f and g. Returns a + pointer to the resulting BDD if successful; NULL if the intermediate + result blows up.] + + SideEffects [None] + + SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAndAbstract Cudd_bddIntersect + Cudd_bddOr Cudd_bddNand Cudd_bddNor Cudd_bddXor Cudd_bddXnor] + +******************************************************************************/ +DdNode * +Extra_bddAndTime( + DdManager * dd, + DdNode * f, + DdNode * g, + int TimeOut) +{ + DdNode *res; + int Counter = 0; + + do { + dd->reordered = 0; + res = cuddBddAndRecurTime(dd,f,g, &Counter, TimeOut); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_bddAndTime */ + +/**Function******************************************************************** + + Synopsis [Takes the AND of two BDDs and simultaneously abstracts the + variables in cube.] + + Description [Takes the AND of two BDDs and simultaneously abstracts + the variables in cube. The variables are existentially abstracted. + Returns a pointer to the result is successful; NULL otherwise. + Cudd_bddAndAbstract implements the semiring matrix multiplication + algorithm for the boolean semiring.] + + SideEffects [None] + + SeeAlso [Cudd_addMatrixMultiply Cudd_addTriangle Cudd_bddAnd] + +******************************************************************************/ +DdNode * +Extra_bddAndAbstractTime( + DdManager * manager, + DdNode * f, + DdNode * g, + DdNode * cube, + int TimeOut) +{ + DdNode *res; + int Counter = 0; + + do { + manager->reordered = 0; + res = cuddBddAndAbstractRecurTime(manager, f, g, cube, &Counter, TimeOut); + } while (manager->reordered == 1); + return(res); + +} /* end of Extra_bddAndAbstractTime */ + +/**Function******************************************************************** + + Synopsis [Convert a {A,B}DD from a manager to another with variable remapping.] + + Description [Convert a {A,B}DD from a manager to another one. The orders of the + variables in the two managers may be different. Returns a + pointer to the {A,B}DD in the destination manager if successful; NULL + otherwise. The i-th entry in the array Permute tells what is the index + of the i-th variable from the old manager in the new manager.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_TransferPermuteTime( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute, int TimeOut ) +{ + DdNode * bRes; + do + { + ddDestination->reordered = 0; + bRes = extraTransferPermuteTime( ddSource, ddDestination, f, Permute, TimeOut ); + } + while ( ddDestination->reordered == 1 ); + return ( bRes ); + +} /* end of Extra_TransferPermuteTime */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddAnd.] + + Description [Implements the recursive step of Cudd_bddAnd by taking + the conjunction of two BDDs. Returns a pointer to the result is + successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddAnd] + +******************************************************************************/ +DdNode * +cuddBddAndRecurTime( + DdManager * manager, + DdNode * f, + DdNode * g, + int * pRecCalls, + int TimeOut) +{ + DdNode *F, *fv, *fnv, *G, *gv, *gnv; + DdNode *one, *r, *t, *e; + unsigned int topf, topg, index; + + statLine(manager); + one = DD_ONE(manager); + + /* Terminal cases. */ + F = Cudd_Regular(f); + G = Cudd_Regular(g); + if (F == G) { + if (f == g) return(f); + else return(Cudd_Not(one)); + } + if (F == one) { + if (f == one) return(g); + else return(f); + } + if (G == one) { + if (g == one) return(f); + else return(g); + } + + /* At this point f and g are not constant. */ + if (f > g) { /* Try to increase cache efficiency. */ + DdNode *tmp = f; + f = g; + g = tmp; + F = Cudd_Regular(f); + G = Cudd_Regular(g); + } + + /* Check cache. */ + if (F->ref != 1 || G->ref != 1) { + r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g); + if (r != NULL) return(r); + } + +// if ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < Abc_Clock() ) + if ( TimeOut && Abc_Clock() > TimeOut ) + return NULL; + + /* Here we can skip the use of cuddI, because the operands are known + ** to be non-constant. + */ + topf = manager->perm[F->index]; + topg = manager->perm[G->index]; + + /* Compute cofactors. */ + if (topf <= topg) { + index = F->index; + fv = cuddT(F); + fnv = cuddE(F); + if (Cudd_IsComplement(f)) { + fv = Cudd_Not(fv); + fnv = Cudd_Not(fnv); + } + } else { + index = G->index; + fv = fnv = f; + } + + if (topg <= topf) { + gv = cuddT(G); + gnv = cuddE(G); + if (Cudd_IsComplement(g)) { + gv = Cudd_Not(gv); + gnv = Cudd_Not(gnv); + } + } else { + gv = gnv = g; + } + + t = cuddBddAndRecurTime(manager, fv, gv, pRecCalls, TimeOut); + if (t == NULL) return(NULL); + cuddRef(t); + + e = cuddBddAndRecurTime(manager, fnv, gnv, pRecCalls, TimeOut); + if (e == NULL) { + Cudd_IterDerefBdd(manager, t); + return(NULL); + } + cuddRef(e); + + if (t == e) { + r = t; + } else { + if (Cudd_IsComplement(t)) { + r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); + if (r == NULL) { + Cudd_IterDerefBdd(manager, t); + Cudd_IterDerefBdd(manager, e); + return(NULL); + } + r = Cudd_Not(r); + } else { + r = cuddUniqueInter(manager,(int)index,t,e); + if (r == NULL) { + Cudd_IterDerefBdd(manager, t); + Cudd_IterDerefBdd(manager, e); + return(NULL); + } + } + } + cuddDeref(e); + cuddDeref(t); + if (F->ref != 1 || G->ref != 1) + cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r); + return(r); + +} /* end of cuddBddAndRecur */ + + +/**Function******************************************************************** + + Synopsis [Takes the AND of two BDDs and simultaneously abstracts the + variables in cube.] + + Description [Takes the AND of two BDDs and simultaneously abstracts + the variables in cube. The variables are existentially abstracted. + Returns a pointer to the result is successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddAndAbstract] + +******************************************************************************/ +DdNode * +cuddBddAndAbstractRecurTime( + DdManager * manager, + DdNode * f, + DdNode * g, + DdNode * cube, + int * pRecCalls, + int TimeOut) +{ + DdNode *F, *ft, *fe, *G, *gt, *ge; + DdNode *one, *zero, *r, *t, *e; + unsigned int topf, topg, topcube, top, index; + + statLine(manager); + one = DD_ONE(manager); + zero = Cudd_Not(one); + + /* Terminal cases. */ + if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); + if (f == one && g == one) return(one); + + if (cube == one) { + return(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); + } + if (f == one || f == g) { + return(cuddBddExistAbstractRecur(manager, g, cube)); + } + if (g == one) { + return(cuddBddExistAbstractRecur(manager, f, cube)); + } + /* At this point f, g, and cube are not constant. */ + + if (f > g) { /* Try to increase cache efficiency. */ + DdNode *tmp = f; + f = g; + g = tmp; + } + + /* Here we can skip the use of cuddI, because the operands are known + ** to be non-constant. + */ + F = Cudd_Regular(f); + G = Cudd_Regular(g); + topf = manager->perm[F->index]; + topg = manager->perm[G->index]; + top = ddMin(topf, topg); + topcube = manager->perm[cube->index]; + + while (topcube < top) { + cube = cuddT(cube); + if (cube == one) { + return(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); + } + topcube = manager->perm[cube->index]; + } + /* Now, topcube >= top. */ + + /* Check cache. */ + if (F->ref != 1 || G->ref != 1) { + r = cuddCacheLookup(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube); + if (r != NULL) { + return(r); + } + } + +// if ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < Abc_Clock() ) + if ( TimeOut && Abc_Clock() > TimeOut ) + return NULL; + + if (topf == top) { + index = F->index; + ft = cuddT(F); + fe = cuddE(F); + if (Cudd_IsComplement(f)) { + ft = Cudd_Not(ft); + fe = Cudd_Not(fe); + } + } else { + index = G->index; + ft = fe = f; + } + + if (topg == top) { + gt = cuddT(G); + ge = cuddE(G); + if (Cudd_IsComplement(g)) { + gt = Cudd_Not(gt); + ge = Cudd_Not(ge); + } + } else { + gt = ge = g; + } + + if (topcube == top) { /* quantify */ + DdNode *Cube = cuddT(cube); + t = cuddBddAndAbstractRecurTime(manager, ft, gt, Cube, pRecCalls, TimeOut); + if (t == NULL) return(NULL); + /* Special case: 1 OR anything = 1. Hence, no need to compute + ** the else branch if t is 1. Likewise t + t * anything == t. + ** Notice that t == fe implies that fe does not depend on the + ** variables in Cube. Likewise for t == ge. + */ + if (t == one || t == fe || t == ge) { + if (F->ref != 1 || G->ref != 1) + cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, + f, g, cube, t); + return(t); + } + cuddRef(t); + /* Special case: t + !t * anything == t + anything. */ + if (t == Cudd_Not(fe)) { + e = cuddBddExistAbstractRecur(manager, ge, Cube); + } else if (t == Cudd_Not(ge)) { + e = cuddBddExistAbstractRecur(manager, fe, Cube); + } else { + e = cuddBddAndAbstractRecurTime(manager, fe, ge, Cube, pRecCalls, TimeOut); + } + if (e == NULL) { + Cudd_IterDerefBdd(manager, t); + return(NULL); + } + if (t == e) { + r = t; + cuddDeref(t); + } else { + cuddRef(e); + r = cuddBddAndRecurTime(manager, Cudd_Not(t), Cudd_Not(e), pRecCalls, TimeOut); + if (r == NULL) { + Cudd_IterDerefBdd(manager, t); + Cudd_IterDerefBdd(manager, e); + return(NULL); + } + r = Cudd_Not(r); + cuddRef(r); + Cudd_DelayedDerefBdd(manager, t); + Cudd_DelayedDerefBdd(manager, e); + cuddDeref(r); + } + } else { + t = cuddBddAndAbstractRecurTime(manager, ft, gt, cube, pRecCalls, TimeOut); + if (t == NULL) return(NULL); + cuddRef(t); + e = cuddBddAndAbstractRecurTime(manager, fe, ge, cube, pRecCalls, TimeOut); + if (e == NULL) { + Cudd_IterDerefBdd(manager, t); + return(NULL); + } + if (t == e) { + r = t; + cuddDeref(t); + } else { + cuddRef(e); + if (Cudd_IsComplement(t)) { + r = cuddUniqueInter(manager, (int) index, + Cudd_Not(t), Cudd_Not(e)); + if (r == NULL) { + Cudd_IterDerefBdd(manager, t); + Cudd_IterDerefBdd(manager, e); + return(NULL); + } + r = Cudd_Not(r); + } else { + r = cuddUniqueInter(manager,(int)index,t,e); + if (r == NULL) { + Cudd_IterDerefBdd(manager, t); + Cudd_IterDerefBdd(manager, e); + return(NULL); + } + } + cuddDeref(e); + cuddDeref(t); + } + } + + if (F->ref != 1 || G->ref != 1) + cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, r); + return (r); + +} /* end of cuddBddAndAbstractRecur */ + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Convert a BDD from a manager to another one.] + + Description [Convert a BDD from a manager to another one. Returns a + pointer to the BDD in the destination manager if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Extra_TransferPermute] + +******************************************************************************/ +DdNode * extraTransferPermuteTime( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute, int TimeOut ) +{ + DdNode *res; + st__table *table = NULL; + st__generator *gen = NULL; + DdNode *key, *value; + + table = st__init_table( st__ptrcmp, st__ptrhash ); + if ( table == NULL ) + goto failure; + res = extraTransferPermuteRecurTime( ddS, ddD, f, table, Permute, TimeOut ); + if ( res != NULL ) + cuddRef( res ); + + /* Dereference all elements in the table and dispose of the table. + ** This must be done also if res is NULL to avoid leaks in case of + ** reordering. */ + gen = st__init_gen( table ); + if ( gen == NULL ) + goto failure; + while ( st__gen( gen, ( const char ** ) &key, ( char ** ) &value ) ) + { + Cudd_RecursiveDeref( ddD, value ); + } + st__free_gen( gen ); + gen = NULL; + st__free_table( table ); + table = NULL; + + if ( res != NULL ) + cuddDeref( res ); + return ( res ); + + failure: + if ( table != NULL ) + st__free_table( table ); + if ( gen != NULL ) + st__free_gen( gen ); + return ( NULL ); + +} /* end of extraTransferPermuteTime */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Extra_TransferPermute.] + + Description [Performs the recursive step of Extra_TransferPermute. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [extraTransferPermuteTime] + +******************************************************************************/ +static DdNode * +extraTransferPermuteRecurTime( + DdManager * ddS, + DdManager * ddD, + DdNode * f, + st__table * table, + int * Permute, + int TimeOut ) +{ + DdNode *ft, *fe, *t, *e, *var, *res; + DdNode *one, *zero; + int index; + int comple = 0; + + statLine( ddD ); + one = DD_ONE( ddD ); + comple = Cudd_IsComplement( f ); + + /* Trivial cases. */ + if ( Cudd_IsConstant( f ) ) + return ( Cudd_NotCond( one, comple ) ); + + + /* Make canonical to increase the utilization of the cache. */ + f = Cudd_NotCond( f, comple ); + /* Now f is a regular pointer to a non-constant node. */ + + /* Check the cache. */ + if ( st__lookup( table, ( char * ) f, ( char ** ) &res ) ) + return ( Cudd_NotCond( res, comple ) ); + + if ( TimeOut && Abc_Clock() > TimeOut ) + return NULL; + + /* Recursive step. */ + if ( Permute ) + index = Permute[f->index]; + else + index = f->index; + + ft = cuddT( f ); + fe = cuddE( f ); + + t = extraTransferPermuteRecurTime( ddS, ddD, ft, table, Permute, TimeOut ); + if ( t == NULL ) + { + return ( NULL ); + } + cuddRef( t ); + + e = extraTransferPermuteRecurTime( ddS, ddD, fe, table, Permute, TimeOut ); + if ( e == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + return ( NULL ); + } + cuddRef( e ); + + zero = Cudd_Not(ddD->one); + var = cuddUniqueInter( ddD, index, one, zero ); + if ( var == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + res = cuddBddIteRecur( ddD, var, t, e ); + + if ( res == NULL ) + { + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + return ( NULL ); + } + cuddRef( res ); + Cudd_RecursiveDeref( ddD, t ); + Cudd_RecursiveDeref( ddD, e ); + + if ( st__add_direct( table, ( char * ) f, ( char * ) res ) == + st__OUT_OF_MEM ) + { + Cudd_RecursiveDeref( ddD, res ); + return ( NULL ); + } + return ( Cudd_NotCond( res, comple ) ); + +} /* end of extraTransferPermuteRecurTime */ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/extraBddUnate.c b/src/bdd/extrab/extraBddUnate.c new file mode 100644 index 00000000..9ebdd4e5 --- /dev/null +++ b/src/bdd/extrab/extraBddUnate.c @@ -0,0 +1,646 @@ +/**CFile**************************************************************** + + FileName [extraBddUnate.c] + + PackageName [extra] + + Synopsis [Efficient methods to compute the information about + unate variables using an algorithm that is conceptually similar to + the algorithm for two-variable symmetry computation presented in: + A. Mishchenko. Fast Computation of Symmetries in Boolean Functions. + Transactions on CAD, Nov. 2003.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 2.0. Started - September 1, 2003.] + + Revision [$Id: extraBddUnate.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "extraBdd.h" + +ABC_NAMESPACE_IMPL_START + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +/**AutomaticEnd***************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information for the function.] + + Description [Returns the symmetry information in the form of Extra_UnateInfo_t structure.] + + SideEffects [If the ZDD variables are not derived from BDD variables with + multiplicity 2, this function may derive them in a wrong way.] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateComputeFast( + DdManager * dd, /* the manager */ + DdNode * bFunc) /* the function whose symmetries are computed */ +{ + DdNode * bSupp; + DdNode * zRes; + Extra_UnateInfo_t * p; + + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + zRes = Extra_zddUnateInfoCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes ); + + p = Extra_UnateInfoCreateFromZdd( dd, zRes, bSupp ); + + Cudd_RecursiveDeref( dd, bSupp ); + Cudd_RecursiveDerefZdd( dd, zRes ); + + return p; + +} /* end of Extra_UnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Computes the classical symmetry information as a ZDD.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddUnateInfoCompute( + DdManager * dd, /* the DD manager */ + DdNode * bF, + DdNode * bVars) +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddUnateInfoCompute( dd, bF, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddUnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Converts a set of variables into a set of singleton subsets.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * Extra_zddGetSingletonsBoth( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * res; + do { + dd->reordered = 0; + res = extraZddGetSingletonsBoth( dd, bVars ); + } while (dd->reordered == 1); + return(res); + +} /* end of Extra_zddGetSingletonsBoth */ + +/**Function******************************************************************** + + Synopsis [Allocates unateness information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateInfoAllocate( int nVars ) +{ + Extra_UnateInfo_t * p; + // allocate and clean the storage for unateness info + p = ABC_ALLOC( Extra_UnateInfo_t, 1 ); + memset( p, 0, sizeof(Extra_UnateInfo_t) ); + p->nVars = nVars; + p->pVars = ABC_ALLOC( Extra_UnateVar_t, nVars ); + memset( p->pVars, 0, nVars * sizeof(Extra_UnateVar_t) ); + return p; +} /* end of Extra_UnateInfoAllocate */ + +/**Function******************************************************************** + + Synopsis [Deallocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_UnateInfoDissolve( Extra_UnateInfo_t * p ) +{ + ABC_FREE( p->pVars ); + ABC_FREE( p ); +} /* end of Extra_UnateInfoDissolve */ + +/**Function******************************************************************** + + Synopsis [Allocates symmetry information structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +void Extra_UnateInfoPrint( Extra_UnateInfo_t * p ) +{ + char * pBuffer; + int i; + pBuffer = ABC_ALLOC( char, p->nVarsMax+1 ); + memset( pBuffer, ' ', p->nVarsMax ); + pBuffer[p->nVarsMax] = 0; + for ( i = 0; i < p->nVars; i++ ) + if ( p->pVars[i].Neg ) + pBuffer[ p->pVars[i].iVar ] = 'n'; + else if ( p->pVars[i].Pos ) + pBuffer[ p->pVars[i].iVar ] = 'p'; + else + pBuffer[ p->pVars[i].iVar ] = '.'; + printf( "%s\n", pBuffer ); + ABC_FREE( pBuffer ); +} /* end of Extra_UnateInfoPrint */ + + +/**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_UnateInfo_t * Extra_UnateInfoCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp ) +{ + Extra_UnateInfo_t * p; + DdNode * bTemp, * zSet, * zCube, * zTemp; + int * pMapVars2Nums; + int i, nSuppSize; + + nSuppSize = Extra_bddSuppSize( dd, bSupp ); + + // allocate and clean the storage for symmetry info + p = Extra_UnateInfoAllocate( 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; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + { + p->pVars[i].iVar = bTemp->index; + pMapVars2Nums[bTemp->index] = i; + } + + // write the symmetry info into the structure + zSet = zPairs; Cudd_Ref( zSet ); +// Cudd_zddPrintCover( dd, zPairs ); printf( "\n" ); + while ( zSet != z0 ) + { + // get the next cube + zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube ); + + // add this var to the data structure + assert( cuddT(zCube) == z1 && cuddE(zCube) == z0 ); + if ( zCube->index & 1 ) // neg + p->pVars[ pMapVars2Nums[zCube->index/2] ].Neg = 1; + else + p->pVars[ pMapVars2Nums[zCube->index/2] ].Pos = 1; + // count the unate vars + p->nUnate++; + + // 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_UnateInfoCreateFromZdd */ + + + +/**Function******************************************************************** + + Synopsis [Computes the classical unateness information for the function.] + + Description [Uses the naive way of comparing cofactors.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +Extra_UnateInfo_t * Extra_UnateComputeSlow( DdManager * dd, DdNode * bFunc ) +{ + int nSuppSize; + DdNode * bSupp, * bTemp; + Extra_UnateInfo_t * p; + int i, Res; + + // 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_UnateInfoAllocate( nSuppSize ); + + // assign the variables + p->nVarsMax = dd->size; + for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) + { + Res = Extra_bddCheckUnateNaive( dd, bFunc, bTemp->index ); + p->pVars[i].iVar = bTemp->index; + if ( Res == -1 ) + p->pVars[i].Neg = 1; + else if ( Res == 1 ) + p->pVars[i].Pos = 1; + p->nUnate += (Res != 0); + } + Cudd_RecursiveDeref( dd, bSupp ); + return p; + +} /* end of Extra_UnateComputeSlow */ + +/**Function******************************************************************** + + Synopsis [Checks if the two variables are symmetric.] + + Description [Returns 0 if vars are not unate. Return -1/+1 if the var is neg/pos unate.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Extra_bddCheckUnateNaive( + DdManager * dd, /* the DD manager */ + DdNode * bF, + int iVar) +{ + DdNode * bCof0, * bCof1; + int Res; + + assert( iVar < dd->size ); + + bCof0 = Cudd_Cofactor( dd, bF, Cudd_Not(Cudd_bddIthVar(dd,iVar)) ); Cudd_Ref( bCof0 ); + bCof1 = Cudd_Cofactor( dd, bF, Cudd_bddIthVar(dd,iVar) ); Cudd_Ref( bCof1 ); + + if ( Cudd_bddLeq( dd, bCof0, bCof1 ) ) + Res = 1; + else if ( Cudd_bddLeq( dd, bCof1, bCof0 ) ) + Res =-1; + else + Res = 0; + + Cudd_RecursiveDeref( dd, bCof0 ); + Cudd_RecursiveDeref( dd, bCof1 ); + return Res; +} /* end of Extra_bddCheckUnateNaive */ + + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_UnateInfoCompute.] + + 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 * +extraZddUnateInfoCompute( + 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) ) + { + if ( cuddIsConstant(bVars) ) + return z0; + return extraZddGetSingletonsBoth( dd, bVars ); + } + assert( bVars != b1 ); + + if ( (zRes = cuddCacheLookup2Zdd(dd, extraZddUnateInfoCompute, bFunc, bVars)) ) + return zRes; + else + { + DdNode * zRes0, * zRes1; + DdNode * zTemp, * zPlus; + DdNode * bF0, * bF1; + DdNode * bVarsNew; + int nVarsExtra; + int LevelF; + int AddVar; + + // 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 = extraZddUnateInfoCompute( 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 = extraZddUnateInfoCompute( 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 + AddVar = -1; + if ( Cudd_bddLeq( dd, bF0, bF1 ) ) // pos + AddVar = 0; + else if ( Cudd_bddLeq( dd, bF1, bF0 ) ) // neg + AddVar = 1; + if ( AddVar >= 0 ) + { + // create the singleton + zPlus = cuddZddGetNode( dd, 2*bFR->index + AddVar, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + } + // 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 + for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) + { + // create the negative singleton + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index+1, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + + + // create the positive singleton + zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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, extraZddUnateInfoCompute, bFunc, bVars, zRes); + return zRes; + } +} /* end of extraZddUnateInfoCompute */ + + +/**Function******************************************************************** + + Synopsis [Performs a recursive step of Extra_zddGetSingletons.] + + Description [Returns the set of ZDD singletons, containing those pos/neg + polarity ZDD variables that correspond to the BDD variables in bVars.] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +DdNode * extraZddGetSingletonsBoth( + DdManager * dd, /* the DD manager */ + DdNode * bVars) /* the set of variables */ +{ + DdNode * zRes; + + if ( bVars == b1 ) + return z1; + + if ( (zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletonsBoth, bVars)) ) + return zRes; + else + { + DdNode * zTemp, * zPlus; + + // solve subproblem + zRes = extraZddGetSingletonsBoth( dd, cuddT(bVars) ); + if ( zRes == NULL ) + return NULL; + cuddRef( zRes ); + + + // create the negative singleton + zPlus = cuddZddGetNode( dd, 2*bVars->index+1, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + + + // create the positive singleton + zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 ); + if ( zPlus == NULL ) + { + Cudd_RecursiveDerefZdd( dd, zRes ); + return NULL; + } + cuddRef( zPlus ); + + // 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 ); + cuddCacheInsert1( dd, extraZddGetSingletonsBoth, bVars, zRes ); + return zRes; + } +} /* end of extraZddGetSingletonsBoth */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static Functions */ +/*---------------------------------------------------------------------------*/ +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/extrab/module.make b/src/bdd/extrab/module.make new file mode 100644 index 00000000..38cdddb6 --- /dev/null +++ b/src/bdd/extrab/module.make @@ -0,0 +1,8 @@ +SRC += src/bdd/extrab/extraBddAuto.c \ + src/bdd/extrab/extraBddCas.c \ + src/bdd/extrab/extraBddImage.c \ + src/bdd/extrab/extraBddKmap.c \ + src/bdd/extrab/extraBddMisc.c \ + src/bdd/extrab/extraBddSymm.c \ + src/bdd/extrab/extraBddTime.c \ + src/bdd/extrab/extraBddUnate.c diff --git a/src/bdd/llb/llb.c b/src/bdd/llb/llb.c new file mode 100644 index 00000000..348c0622 --- /dev/null +++ b/src/bdd/llb/llb.c @@ -0,0 +1,52 @@ +/**CFile**************************************************************** + + FileName [llb.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb.h b/src/bdd/llb/llb.h new file mode 100644 index 00000000..f465359d --- /dev/null +++ b/src/bdd/llb/llb.h @@ -0,0 +1,96 @@ +/**CFile**************************************************************** + + FileName [llb.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 8, 2010.] + + Revision [$Id: llb.h,v 1.00 2010/05/08 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef ABC__aig__llb__llb_h +#define ABC__aig__llb__llb_h + + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_HEADER_START + + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Gia_ParLlb_t_ Gia_ParLlb_t; +struct Gia_ParLlb_t_ +{ + int nBddMax; // maximum BDD size + int nIterMax; // maximum iteration count + int nClusterMax; // maximum cluster size + int nHintDepth; // the number of times to cofactor + int HintFirst; // the number of first hint to use + int fUseFlow; // use flow computation + int nVolumeMax; // the largest volume + int nVolumeMin; // the smallest volume + int nPartValue; // partitioning value + int fBackward; // enable backward reachability + int fReorder; // enable dynamic variable reordering + int fIndConstr; // extract inductive constraints + int fUsePivots; // use internal pivot variables + int fCluster; // use partition clustering + int fSchedule; // use cluster scheduling + int fDumpReached; // dump reached states into a file + int fVerbose; // print verbose information + int fVeryVerbose; // print dependency matrices + int fSilent; // do not print any infomation + int fSkipReach; // skip reachability (preparation phase only) + int fSkipOutCheck; // does not check the property output + int TimeLimit; // time limit for one reachability run + int TimeLimitGlo; // time limit for all reachability runs + // internal parameters + abctime TimeTarget; // the time to stop + int iFrame; // explored up to this frame +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== llbCore.c ==========================================================*/ +extern void Llb_ManSetDefaultParams( Gia_ParLlb_t * pPars ); +/*=== llb4Nonlin.c ==========================================================*/ +extern int Llb_Nonlin4CoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ); + + + +ABC_NAMESPACE_HEADER_END + + + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/bdd/llb/llb1Cluster.c b/src/bdd/llb/llb1Cluster.c new file mode 100644 index 00000000..1356e484 --- /dev/null +++ b/src/bdd/llb/llb1Cluster.c @@ -0,0 +1,356 @@ +/**CFile**************************************************************** + + FileName [llb1Cluster.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Clustering algorithm.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Cluster.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManComputeCommonQuant( Llb_Mtr_t * p, int iCol1, int iCol2 ) +{ + int iVar, Weight = 0; + for ( iVar = 0; iVar < p->nRows - p->nFfs; iVar++ ) + { + // count each removed variable as 2 + if ( p->pMatrix[iCol1][iVar] == 1 && p->pMatrix[iCol2][iVar] == 1 && p->pRowSums[iVar] == 2 ) + Weight += 2; + // count each added variale as -1 + else if ( (p->pMatrix[iCol1][iVar] == 1 && p->pMatrix[iCol2][iVar] == 0) || + (p->pMatrix[iCol1][iVar] == 0 && p->pMatrix[iCol2][iVar] == 1) ) + Weight--; + } + return Weight; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManComputeBestQuant( Llb_Mtr_t * p ) +{ + int i, k, WeightBest = -100000, WeightCur, RetValue = -1; + for ( i = 1; i < p->nCols-1; i++ ) + for ( k = i+1; k < p->nCols-1; k++ ) + { + if ( p->pColSums[i] == 0 || p->pColSums[i] > p->pMan->pPars->nClusterMax ) + continue; + if ( p->pColSums[k] == 0 || p->pColSums[k] > p->pMan->pPars->nClusterMax ) + continue; + + WeightCur = Llb_ManComputeCommonQuant( p, i, k ); + if ( WeightCur <= 0 ) + continue; + if ( WeightBest < WeightCur ) + { + WeightBest = WeightCur; + RetValue = (i << 16) | k; + } + } +// printf( "Choosing best quant Weight %4d\n", WeightCur ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float ** Llb_ManComputeQuant( Llb_Mtr_t * p ) +{ + float ** pCosts; + int i, k; + // alloc and clean + pCosts = (float **)Extra_ArrayAlloc( p->nCols, p->nCols, sizeof(float) ); + for ( i = 0; i < p->nCols; i++ ) + for ( k = 0; k < p->nCols; k++ ) + pCosts[i][i] = 0.0; + // fill up + for ( i = 1; i < p->nCols-1; i++ ) + for ( k = i+1; k < p->nCols-1; k++ ) + pCosts[i][k] = pCosts[k][i] = Llb_ManComputeCommonQuant( p, i, k ); + return pCosts; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float Llb_ManComputeCommonAttr( Llb_Mtr_t * p, int iCol1, int iCol2 ) +{ + int iVar, CountComm = 0, CountDiff = 0; + for ( iVar = 0; iVar < p->nRows - p->nFfs; iVar++ ) + { + if ( p->pMatrix[iCol1][iVar] == 1 && p->pMatrix[iCol2][iVar] == 1 ) + CountComm++; + else if ( p->pMatrix[iCol1][iVar] == 1 || p->pMatrix[iCol2][iVar] == 1 ) + CountDiff++; + } +/* + printf( "Attr cost for %4d and %4d: %4d %4d (%5.2f)\n", + iCol1, iCol2, + CountDiff, CountComm, + -1.0 * CountDiff / ( CountComm + CountDiff ) ); +*/ + return -1.0 * CountDiff / ( CountComm + CountDiff ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManComputeBestAttr( Llb_Mtr_t * p ) +{ + float WeightBest = -100000, WeightCur; + int i, k, RetValue = -1; + for ( i = 1; i < p->nCols-1; i++ ) + for ( k = i+1; k < p->nCols-1; k++ ) + { + if ( p->pColSums[i] == 0 || p->pColSums[i] > p->pMan->pPars->nClusterMax ) + continue; + if ( p->pColSums[k] == 0 || p->pColSums[k] > p->pMan->pPars->nClusterMax ) + continue; + WeightCur = Llb_ManComputeCommonAttr( p, i, k ); + if ( WeightBest < WeightCur ) + { + WeightBest = WeightCur; + RetValue = (i << 16) | k; + } + } + return RetValue; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float ** Llb_ManComputeAttr( Llb_Mtr_t * p ) +{ + float ** pCosts; + int i, k; + // alloc and clean + pCosts = (float **)Extra_ArrayAlloc( p->nCols, p->nCols, sizeof(float) ); + for ( i = 0; i < p->nCols; i++ ) + for ( k = 0; k < p->nCols; k++ ) + pCosts[i][i] = 0.0; + // fill up + for ( i = 1; i < p->nCols-1; i++ ) + for ( k = i+1; k < p->nCols-1; k++ ) + pCosts[i][k] = pCosts[k][i] = Llb_ManComputeCommonAttr( p, i, k ); + return pCosts; +} + + +/**Function************************************************************* + + Synopsis [Returns the number of variables that will be saved.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrCombineSelectedColumns( Llb_Mtr_t * p, int iGrp1, int iGrp2 ) +{ + int iVar; + assert( iGrp1 >= 1 && iGrp1 < p->nCols - 1 ); + assert( iGrp2 >= 1 && iGrp2 < p->nCols - 1 ); + assert( p->pColGrps[iGrp1] != NULL ); + assert( p->pColGrps[iGrp2] != NULL ); + for ( iVar = 0; iVar < p->nRows; iVar++ ) + { + if ( p->pMatrix[iGrp1][iVar] == 1 && p->pMatrix[iGrp2][iVar] == 1 ) + p->pRowSums[iVar]--; + if ( p->pMatrix[iGrp1][iVar] == 0 && p->pMatrix[iGrp2][iVar] == 1 ) + { + p->pMatrix[iGrp1][iVar] = 1; + p->pColSums[iGrp1]++; + } + if ( p->pMatrix[iGrp2][iVar] == 1 ) + p->pMatrix[iGrp2][iVar] = 0; + } + p->pColSums[iGrp2] = 0; +} + + +/**Function************************************************************* + + Synopsis [Combines one pair of columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManClusterOne( Llb_Mtr_t * p, int iCol1, int iCol2 ) +{ + int fVerbose = 0; + Llb_Grp_t * pGrp; + int iVar; + + if ( fVerbose ) + { + printf( "Combining %d and %d\n", iCol1, iCol2 ); + for ( iVar = 0; iVar < p->nRows; iVar++ ) + { + if ( p->pMatrix[iCol1][iVar] == 0 && p->pMatrix[iCol2][iVar] == 0 ) + continue; + printf( "%3d : %c%c\n", iVar, + p->pMatrix[iCol1][iVar]? '*':' ', + p->pMatrix[iCol2][iVar]? '*':' ' ); + } + } + pGrp = Llb_ManGroupsCombine( p->pColGrps[iCol1], p->pColGrps[iCol2] ); + Llb_MtrCombineSelectedColumns( p, iCol1, iCol2 ); + p->pColGrps[iCol1] = pGrp; + p->pColGrps[iCol2] = NULL; +} + +/**Function************************************************************* + + Synopsis [Removes empty columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManClusterCompress( Llb_Mtr_t * p ) +{ + int i, k = 0; + for ( i = 0; i < p->nCols; i++ ) + { + if ( p->pColGrps[i] == NULL ) + { + assert( p->pColSums[i] == 0 ); + assert( p->pMatrix[i] != NULL ); + ABC_FREE( p->pMatrix[i] ); + continue; + } + p->pMatrix[k] = p->pMatrix[i]; + p->pColGrps[k] = p->pColGrps[i]; + p->pColSums[k] = p->pColSums[i]; + k++; + } + p->nCols = k; +} + +/**Function************************************************************* + + Synopsis [Combines one pair of columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManCluster( Llb_Mtr_t * p ) +{ + int RetValue; + do + { + do { + RetValue = Llb_ManComputeBestQuant( p ); + if ( RetValue > 0 ) + Llb_ManClusterOne( p, RetValue >> 16, RetValue & 0xffff ); + } + while ( RetValue > 0 ); + + RetValue = Llb_ManComputeBestAttr( p ); + if ( RetValue > 0 ) + Llb_ManClusterOne( p, RetValue >> 16, RetValue & 0xffff ); + + Llb_MtrVerifyMatrix( p ); + } + while ( RetValue > 0 ); + + Llb_ManClusterCompress( p ); + + Llb_MtrVerifyMatrix( p ); +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Constr.c b/src/bdd/llb/llb1Constr.c new file mode 100644 index 00000000..1ef4ce14 --- /dev/null +++ b/src/bdd/llb/llb1Constr.c @@ -0,0 +1,313 @@ +/**CFile**************************************************************** + + FileName [llb1Constr.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Computing inductive constraints.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Constr.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns the array of constraint candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCountEntries( Vec_Int_t * vCands ) +{ + int i, Entry, Counter = 0; + Vec_IntForEachEntry( vCands, Entry, i ) + Counter += ((Entry == 0) || (Entry == 1)); + return Counter; +} + +/**Function************************************************************* + + Synopsis [Returns the array of constraint candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrintEntries( Aig_Man_t * p, Vec_Int_t * vCands ) +{ + int i, Entry; + if ( vCands == NULL ) + { + printf( "There is no hints.\n" ); + return; + } + Entry = Llb_ManCountEntries(vCands); + printf( "\n*** Using %d hint%s:\n", Entry, (Entry != 1 ? "s":"") ); + Vec_IntForEachEntry( vCands, Entry, i ) + { + if ( Entry != 0 && Entry != 1 ) + continue; + printf( "%c", Entry ? '+' : '-' ); + printf( "%-6d : ", i ); + Aig_ObjPrint( p, Aig_ManObj(p, i) ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Dereference BDD nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManDerefenceBdds( Aig_Man_t * p, DdManager * dd ) +{ + Aig_Obj_t * pObj; + int i; + Aig_ManForEachObj( p, pObj, i ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); +} + +/**Function************************************************************* + + Synopsis [Returns the array of constraint candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManComputeIndCase_rec( Aig_Man_t * p, Aig_Obj_t * pObj, DdManager * dd, Vec_Ptr_t * vBdds ) +{ + DdNode * bBdd0, * bBdd1; + DdNode * bFunc = (DdNode *)Vec_PtrEntry( vBdds, Aig_ObjId(pObj) ); + if ( bFunc != NULL ) + return bFunc; + assert( Aig_ObjIsNode(pObj) ); + bBdd0 = Llb_ManComputeIndCase_rec( p, Aig_ObjFanin0(pObj), dd, vBdds ); + bBdd1 = Llb_ManComputeIndCase_rec( p, Aig_ObjFanin1(pObj), dd, vBdds ); + bBdd0 = Cudd_NotCond( bBdd0, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( bBdd1, Aig_ObjFaninC1(pObj) ); + bFunc = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( bFunc ); + Vec_PtrWriteEntry( vBdds, Aig_ObjId(pObj), bFunc ); + return bFunc; +} + +/**Function************************************************************* + + Synopsis [Returns the array of constraint candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManComputeIndCase( Aig_Man_t * p, DdManager * dd, Vec_Int_t * vNodes ) +{ + Vec_Ptr_t * vBdds; + Aig_Obj_t * pObj; + DdNode * bFunc; + int i, Entry; + vBdds = Vec_PtrStart( Aig_ManObjNumMax(p) ); + bFunc = Cudd_ReadOne(dd); Cudd_Ref( bFunc ); + Vec_PtrWriteEntry( vBdds, Aig_ObjId(Aig_ManConst1(p)), bFunc ); + Saig_ManForEachPi( p, pObj, i ) + { + bFunc = Cudd_bddIthVar( dd, Aig_ManCiNum(p) + i ); Cudd_Ref( bFunc ); + Vec_PtrWriteEntry( vBdds, Aig_ObjId(pObj), bFunc ); + } + Saig_ManForEachLi( p, pObj, i ) + { + bFunc = (DdNode *)pObj->pData; Cudd_Ref( bFunc ); + Vec_PtrWriteEntry( vBdds, Aig_ObjId(Saig_ObjLiToLo(p, pObj)), bFunc ); + } + Vec_IntForEachEntry( vNodes, Entry, i ) + { + if ( Entry != 0 && Entry != 1 ) + continue; + pObj = Aig_ManObj( p, i ); + bFunc = Llb_ManComputeIndCase_rec( p, pObj, dd, vBdds ); + if ( Entry == 0 ) + { +// Extra_bddPrint( dd, Cudd_Not(pObj->pData) ); printf( "\n" ); +// Extra_bddPrint( dd, Cudd_Not(bFunc) ); printf( "\n" ); + if ( !Cudd_bddLeq( dd, Cudd_Not(pObj->pData), Cudd_Not(bFunc) ) ) + Vec_IntWriteEntry( vNodes, i, -1 ); + } + else if ( Entry == 1 ) + { +// Extra_bddPrint( dd, pObj->pData ); printf( "\n" ); +// Extra_bddPrint( dd, bFunc ); printf( "\n" ); + if ( !Cudd_bddLeq( dd, (DdNode *)pObj->pData, bFunc ) ) + Vec_IntWriteEntry( vNodes, i, -1 ); + } + } + Vec_PtrForEachEntry( DdNode *, vBdds, bFunc, i ) + if ( bFunc ) + Cudd_RecursiveDeref( dd, bFunc ); + Vec_PtrFree( vBdds ); +} + +/**Function************************************************************* + + Synopsis [Returns the array of constraint candidates.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_ManComputeBaseCase( Aig_Man_t * p, DdManager * dd ) +{ + Vec_Int_t * vNodes; + Aig_Obj_t * pObj, * pRoot; + int i; + pRoot = Aig_ManCo( p, 0 ); + vNodes = Vec_IntStartFull( Aig_ManObjNumMax(p) ); + Aig_ManForEachObj( p, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) ) + continue; + if ( Cudd_bddLeq( dd, (DdNode *)pObj->pData, Cudd_Not(pRoot->pData) ) ) + Vec_IntWriteEntry( vNodes, i, 1 ); + else if ( Cudd_bddLeq( dd, Cudd_Not((DdNode *)pObj->pData), Cudd_Not(pRoot->pData) ) ) + Vec_IntWriteEntry( vNodes, i, 0 ); + } + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Constructs global BDDs for each object in the AIG manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb_ManConstructGlobalBdds( Aig_Man_t * p ) +{ + DdManager * dd; + DdNode * bBdd0, * bBdd1; + Aig_Obj_t * pObj; + int i; + dd = Cudd_Init( Aig_ManCiNum(p), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + pObj = Aig_ManConst1(p); + pObj->pData = Cudd_ReadOne(dd); Cudd_Ref( (DdNode *)pObj->pData ); + Aig_ManForEachCi( p, pObj, i ) + { + pObj->pData = Cudd_bddIthVar(dd, i); Cudd_Ref( (DdNode *)pObj->pData ); + } + Aig_ManForEachNode( p, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( (DdNode *)pObj->pData ); + } + Aig_ManForEachCo( p, pObj, i ) + { + pObj->pData = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); Cudd_Ref( (DdNode *)pObj->pData ); + } + return dd; +} + +/**Function************************************************************* + + Synopsis [Derives inductive constraints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_ManDeriveConstraints( Aig_Man_t * p ) +{ + DdManager * dd; + Vec_Int_t * vNodes; + if ( Saig_ManPoNum(p) != 1 ) + { + printf( "The AIG has %d property outputs.\n", Saig_ManPoNum(p) ); + return NULL; + } + assert( Saig_ManPoNum(p) == 1 ); + dd = Llb_ManConstructGlobalBdds( p ); + vNodes = Llb_ManComputeBaseCase( p, dd ); + if ( Llb_ManCountEntries(vNodes) > 0 ) + Llb_ManComputeIndCase( p, dd, vNodes ); + if ( Llb_ManCountEntries(vNodes) == 0 ) + Vec_IntFreeP( &vNodes ); + Llb_ManDerefenceBdds( p, dd ); + Extra_StopManager( dd ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Tests derived constraints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManConstrTest( Aig_Man_t * p ) +{ + Vec_Int_t * vNodes; + vNodes = Llb_ManDeriveConstraints( p ); + Llb_ManPrintEntries( p, vNodes ); + Vec_IntFreeP( &vNodes ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Core.c b/src/bdd/llb/llb1Core.c new file mode 100644 index 00000000..213f2cd9 --- /dev/null +++ b/src/bdd/llb/llb1Core.c @@ -0,0 +1,222 @@ +/**CFile**************************************************************** + + FileName [llb1Core.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Top-level procedure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Core.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" +#include "aig/gia/gia.h" +#include "aig/gia/giaAig.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManSetDefaultParams( Gia_ParLlb_t * p ) +{ + memset( p, 0, sizeof(Gia_ParLlb_t) ); + p->nBddMax = 10000000; + p->nIterMax = 10000000; + p->nClusterMax = 20; + p->nHintDepth = 0; + p->HintFirst = 0; + p->fUseFlow = 0; // use flow + p->nVolumeMax = 100; // max volume + p->nVolumeMin = 30; // min volume + p->nPartValue = 5; // partitioning value + p->fBackward = 0; // forward by default + p->fReorder = 1; + p->fIndConstr = 0; + p->fUsePivots = 0; + p->fCluster = 0; + p->fSchedule = 0; + p->fDumpReached = 0; + p->fVerbose = 0; + p->fVeryVerbose = 0; + p->fSilent = 0; + p->TimeLimit = 0; +// p->TimeLimit = 0; + p->TimeLimitGlo = 0; + p->TimeTarget = 0; + p->iFrame = -1; +} + + +/**Function************************************************************* + + Synopsis [Prints statistics about MFFCs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrintAig( Llb_Man_t * p ) +{ + Abc_Print( 1, "pi =%3d ", Saig_ManPiNum(p->pAig) ); + Abc_Print( 1, "po =%3d ", Saig_ManPoNum(p->pAig) ); + Abc_Print( 1, "ff =%3d ", Saig_ManRegNum(p->pAig) ); + Abc_Print( 1, "int =%5d ", Vec_IntSize(p->vVar2Obj)-Aig_ManCiNum(p->pAig)-Saig_ManRegNum(p->pAig) ); + Abc_Print( 1, "var =%5d ", Vec_IntSize(p->vVar2Obj) ); + Abc_Print( 1, "part =%5d ", Vec_PtrSize(p->vGroups)-2 ); + Abc_Print( 1, "and =%5d ", Aig_ManNodeNum(p->pAig) ); + Abc_Print( 1, "lev =%4d ", Aig_ManLevelNum(p->pAig) ); +// Abc_Print( 1, "cut =%4d ", Llb_ManCrossCut(p->pAig) ); + Abc_Print( 1, "\n" ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManModelCheckAig( Aig_Man_t * pAigGlo, Gia_ParLlb_t * pPars, Vec_Int_t * vHints, DdManager ** pddGlo ) +{ + Llb_Man_t * p = NULL; + Aig_Man_t * pAig; + int RetValue = -1; + abctime clk = Abc_Clock(); + + if ( pPars->fIndConstr ) + { + assert( vHints == NULL ); + vHints = Llb_ManDeriveConstraints( pAigGlo ); + } + + // derive AIG for hints + if ( vHints == NULL ) + pAig = Aig_ManDupSimple( pAigGlo ); + else + { + if ( pPars->fVerbose ) + Llb_ManPrintEntries( pAigGlo, vHints ); + pAig = Aig_ManDupSimpleWithHints( pAigGlo, vHints ); + } + + + if ( pPars->fUseFlow ) + { +// p = Llb_ManStartFlow( pAigGlo, pAig, pPars ); + } + else + { + p = Llb_ManStart( pAigGlo, pAig, pPars ); + if ( pPars->fVerbose ) + { + Llb_ManPrintAig( p ); + printf( "Original matrix: " ); + Llb_MtrPrintMatrixStats( p->pMatrix ); + if ( pPars->fVeryVerbose ) + Llb_MtrPrint( p->pMatrix, 1 ); + } + if ( pPars->fCluster ) + { + Llb_ManCluster( p->pMatrix ); + if ( pPars->fVerbose ) + { + printf( "Matrix after clustering: " ); + Llb_MtrPrintMatrixStats( p->pMatrix ); + if ( pPars->fVeryVerbose ) + Llb_MtrPrint( p->pMatrix, 1 ); + } + } + if ( pPars->fSchedule ) + { + Llb_MtrSchedule( p->pMatrix ); + if ( pPars->fVerbose ) + { + printf( "Matrix after scheduling: " ); + Llb_MtrPrintMatrixStats( p->pMatrix ); + if ( pPars->fVeryVerbose ) + Llb_MtrPrint( p->pMatrix, 1 ); + } + } + } + + if ( !p->pPars->fSkipReach ) + RetValue = Llb_ManReachability( p, vHints, pddGlo ); + Llb_ManStop( p ); + + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + + if ( pPars->fIndConstr ) + Vec_IntFreeP( &vHints ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManModelCheckGia( Gia_Man_t * pGia, Gia_ParLlb_t * pPars ) +{ + Gia_Man_t * pGia2; + Aig_Man_t * pAig; + int RetValue = -1; + pGia2 = Gia_ManDupDfs( pGia ); + pAig = Gia_ManToAigSimple( pGia2 ); + Gia_ManStop( pGia2 ); +//Aig_ManShow( pAig, 0, NULL ); + + if ( pPars->nHintDepth == 0 ) + RetValue = Llb_ManModelCheckAig( pAig, pPars, NULL, NULL ); + else + RetValue = Llb_ManModelCheckAigWithHints( pAig, pPars ); + pGia->pCexSeq = pAig->pSeqModel; pAig->pSeqModel = NULL; + Aig_ManStop( pAig ); + return RetValue; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Group.c b/src/bdd/llb/llb1Group.c new file mode 100644 index 00000000..1099b2cd --- /dev/null +++ b/src/bdd/llb/llb1Group.c @@ -0,0 +1,474 @@ +/**CFile**************************************************************** + + FileName [llb1Group.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Initial partition computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Group.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupAlloc( Llb_Man_t * pMan ) +{ + Llb_Grp_t * p; + p = ABC_CALLOC( Llb_Grp_t, 1 ); + p->pMan = pMan; + p->vIns = Vec_PtrAlloc( 8 ); + p->vOuts = Vec_PtrAlloc( 8 ); + p->Id = Vec_PtrSize( pMan->vGroups ); + Vec_PtrPush( pMan->vGroups, p ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManGroupStop( Llb_Grp_t * p ) +{ + if ( p == NULL ) + return; + Vec_PtrWriteEntry( p->pMan->vGroups, p->Id, NULL ); + Vec_PtrFreeP( &p->vIns ); + Vec_PtrFreeP( &p->vOuts ); + Vec_PtrFreeP( &p->vNodes ); + ABC_FREE( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManGroupCollect_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes ) +{ + if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) + return; + Aig_ObjSetTravIdCurrent(pAig, pObj); + if ( Aig_ObjIsConst1(pObj) ) + return; + if ( Aig_ObjIsCo(pObj) ) + { + Llb_ManGroupCollect_rec( pAig, Aig_ObjFanin0(pObj), vNodes ); + return; + } + assert( Aig_ObjIsAnd(pObj) ); + Llb_ManGroupCollect_rec( pAig, Aig_ObjFanin0(pObj), vNodes ); + Llb_ManGroupCollect_rec( pAig, Aig_ObjFanin1(pObj), vNodes ); + Vec_PtrPush( vNodes, pObj ); +} + +/**Function************************************************************* + + Synopsis [Collects the support of MFFC.] + + Description [Returns the number of internal nodes in the MFFC.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManGroupCollect( Llb_Grp_t * pGroup ) +{ + Vec_Ptr_t * vNodes; + Aig_Obj_t * pObj; + int i; + vNodes = Vec_PtrAlloc( 100 ); + Aig_ManIncrementTravId( pGroup->pMan->pAig ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + Aig_ObjSetTravIdCurrent( pGroup->pMan->pAig, pObj ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + Aig_ObjSetTravIdPrevious( pGroup->pMan->pAig, pObj ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + Llb_ManGroupCollect_rec( pGroup->pMan->pAig, pObj, vNodes ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManGroupCreate_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Ptr_t * vSupp ) +{ + if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) + return; + Aig_ObjSetTravIdCurrent(pAig, pObj); + if ( Aig_ObjIsConst1(pObj) ) + return; + if ( pObj->fMarkA ) + { + Vec_PtrPush( vSupp, pObj ); + return; + } + assert( Aig_ObjIsAnd(pObj) ); + Llb_ManGroupCreate_rec( pAig, Aig_ObjFanin0(pObj), vSupp ); + Llb_ManGroupCreate_rec( pAig, Aig_ObjFanin1(pObj), vSupp ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupCreate( Llb_Man_t * pMan, Aig_Obj_t * pObj ) +{ + Llb_Grp_t * p; + assert( pObj->fMarkA == 1 ); + // derive group + p = Llb_ManGroupAlloc( pMan ); + Vec_PtrPush( p->vOuts, pObj ); + Aig_ManIncrementTravId( pMan->pAig ); + if ( Aig_ObjIsCo(pObj) ) + Llb_ManGroupCreate_rec( pMan->pAig, Aig_ObjFanin0(pObj), p->vIns ); + else + { + Llb_ManGroupCreate_rec( pMan->pAig, Aig_ObjFanin0(pObj), p->vIns ); + Llb_ManGroupCreate_rec( pMan->pAig, Aig_ObjFanin1(pObj), p->vIns ); + } + // derive internal objects + assert( p->vNodes == NULL ); + p->vNodes = Llb_ManGroupCollect( p ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupCreateFirst( Llb_Man_t * pMan ) +{ + Llb_Grp_t * p; + Aig_Obj_t * pObj; + int i; + p = Llb_ManGroupAlloc( pMan ); + Saig_ManForEachLo( pMan->pAig, pObj, i ) + Vec_PtrPush( p->vOuts, pObj ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupCreateLast( Llb_Man_t * pMan ) +{ + Llb_Grp_t * p; + Aig_Obj_t * pObj; + int i; + p = Llb_ManGroupAlloc( pMan ); + Saig_ManForEachLi( pMan->pAig, pObj, i ) + Vec_PtrPush( p->vIns, pObj ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupsCombine( Llb_Grp_t * p1, Llb_Grp_t * p2 ) +{ + Llb_Grp_t * p; + Aig_Obj_t * pObj; + int i; + p = Llb_ManGroupAlloc( p1->pMan ); + // create inputs + Vec_PtrForEachEntry( Aig_Obj_t *, p1->vIns, pObj, i ) + Vec_PtrPush( p->vIns, pObj ); + Vec_PtrForEachEntry( Aig_Obj_t *, p2->vIns, pObj, i ) + Vec_PtrPushUnique( p->vIns, pObj ); + // create outputs + Vec_PtrForEachEntry( Aig_Obj_t *, p1->vOuts, pObj, i ) + Vec_PtrPush( p->vOuts, pObj ); + Vec_PtrForEachEntry( Aig_Obj_t *, p2->vOuts, pObj, i ) + Vec_PtrPushUnique( p->vOuts, pObj ); + + // derive internal objects + assert( p->vNodes == NULL ); + p->vNodes = Llb_ManGroupCollect( p ); + return p; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManGroupMarkNodes_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return; + if ( Aig_ObjIsTravIdPrevious(p, pObj) ) + { + Aig_ObjSetTravIdCurrent(p, pObj); + return; + } + Aig_ObjSetTravIdCurrent(p, pObj); + assert( Aig_ObjIsNode(pObj) ); + Llb_ManGroupMarkNodes_rec( p, Aig_ObjFanin0(pObj) ); + Llb_ManGroupMarkNodes_rec( p, Aig_ObjFanin1(pObj) ); +} + +/**Function************************************************************* + + Synopsis [Creates group from two cuts derived by the flow computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Grp_t * Llb_ManGroupCreateFromCuts( Llb_Man_t * pMan, Vec_Int_t * vCut1, Vec_Int_t * vCut2 ) +{ + Llb_Grp_t * p; + Aig_Obj_t * pObj; + int i; + p = Llb_ManGroupAlloc( pMan ); + + // mark Cut1 + Aig_ManIncrementTravId( pMan->pAig ); + Aig_ManForEachObjVec( vCut1, pMan->pAig, pObj, i ) + Aig_ObjSetTravIdCurrent( pMan->pAig, pObj ); + // collect unmarked Cut2 + Aig_ManForEachObjVec( vCut2, pMan->pAig, pObj, i ) + if ( !Aig_ObjIsTravIdCurrent( pMan->pAig, pObj ) ) + Vec_PtrPush( p->vOuts, pObj ); + + // mark nodes reachable from Cut2 + Aig_ManIncrementTravId( pMan->pAig ); + Aig_ManForEachObjVec( vCut2, pMan->pAig, pObj, i ) + Llb_ManGroupMarkNodes_rec( pMan->pAig, pObj ); + // collect marked Cut1 + Aig_ManForEachObjVec( vCut1, pMan->pAig, pObj, i ) + if ( Aig_ObjIsTravIdCurrent( pMan->pAig, pObj ) ) + Vec_PtrPush( p->vIns, pObj ); + + // derive internal objects + assert( p->vNodes == NULL ); + p->vNodes = Llb_ManGroupCollect( p ); + return p; +} + + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrepareGroups( Llb_Man_t * pMan ) +{ + Aig_Obj_t * pObj; + int i; + assert( pMan->vGroups == NULL ); + pMan->vGroups = Vec_PtrAlloc( 1000 ); + Llb_ManGroupCreateFirst( pMan ); + Aig_ManForEachNode( pMan->pAig, pObj, i ) + { + if ( pObj->fMarkA ) + Llb_ManGroupCreate( pMan, pObj ); + } + Saig_ManForEachLi( pMan->pAig, pObj, i ) + { + if ( pObj->fMarkA ) + Llb_ManGroupCreate( pMan, pObj ); + } + Llb_ManGroupCreateLast( pMan ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrintSpan( Llb_Man_t * p ) +{ + Llb_Grp_t * pGroup; + Aig_Obj_t * pVar; + int i, k, Span = 0, SpanMax = 0; + Vec_PtrForEachEntry( Llb_Grp_t *, p->vGroups, pGroup, i ) + { + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pVar, k ) + if ( Vec_IntEntry(p->vVarBegs, pVar->Id) == i ) + Span++; + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pVar, k ) + if ( Vec_IntEntry(p->vVarBegs, pVar->Id) == i ) + Span++; + + SpanMax = Abc_MaxInt( SpanMax, Span ); +printf( "%d ", Span ); + + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pVar, k ) + if ( Vec_IntEntry(p->vVarEnds, pVar->Id) == i ) + Span--; + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pVar, k ) + if ( Vec_IntEntry(p->vVarEnds, pVar->Id) == i ) + Span--; + } +printf( "\n" ); +printf( "Max = %d\n", SpanMax ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManGroupHasVar( Llb_Man_t * p, int iGroup, int iVar ) +{ + Llb_Grp_t * pGroup = (Llb_Grp_t *)Vec_PtrEntry( p->vGroups, iGroup ); + Aig_Obj_t * pObj; + int i; + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + if ( pObj->Id == iVar ) + return 1; + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + if ( pObj->Id == iVar ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrintHisto( Llb_Man_t * p ) +{ + Aig_Obj_t * pObj; + int i, k; + Aig_ManForEachObj( p->pAig, pObj, i ) + { + if ( Vec_IntEntry(p->vObj2Var, i) < 0 ) + continue; + printf( "%3d :", i ); + for ( k = 0; k < Vec_IntEntry(p->vVarBegs, i); k++ ) + printf( " " ); + for ( ; k <= Vec_IntEntry(p->vVarEnds, i); k++ ) + printf( "%c", Llb_ManGroupHasVar(p, k, i)? '*':'-' ); + printf( "\n" ); + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Hint.c b/src/bdd/llb/llb1Hint.c new file mode 100644 index 00000000..353b4c69 --- /dev/null +++ b/src/bdd/llb/llb1Hint.c @@ -0,0 +1,226 @@ +/**CFile**************************************************************** + + FileName [llb1Hint.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Cofactors the circuit w.r.t. the high-fanout variables.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Hint.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns CI index with the largest number of fanouts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManMaxFanoutCi( Aig_Man_t * pAig ) +{ + Aig_Obj_t * pObj; + int i, WeightMax = -ABC_INFINITY, iInput = -1; + Aig_ManForEachCi( pAig, pObj, i ) + if ( WeightMax < Aig_ObjRefs(pObj) ) + { + WeightMax = Aig_ObjRefs(pObj); + iInput = i; + } + assert( iInput >= 0 ); + return iInput; +} + +/**Function************************************************************* + + Synopsis [Derives AIG whose PI is substituted by a constant.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Aig_Man_t * Llb_ManPerformHints( Aig_Man_t * pAig, int nHintDepth ) +{ + Aig_Man_t * pNew, * pTemp; + int i, iInput; + pNew = Aig_ManDupDfs( pAig ); + for ( i = 0; i < nHintDepth; i++ ) + { + iInput = Llb_ManMaxFanoutCi( pNew ); + Abc_Print( 1, "%d %3d\n", i, iInput ); + pNew = Aig_ManDupCof( pTemp = pNew, iInput, 1 ); + Aig_ManStop( pTemp ); + } + return pNew; +} + +/**Function************************************************************* + + Synopsis [Returns CI index with the largest number of fanouts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_ManCollectHighFanoutObjects( Aig_Man_t * pAig, int nCandMax, int fCisOnly ) +{ + Vec_Int_t * vFanouts, * vResult; + Aig_Obj_t * pObj; + int i, fChanges, PivotValue; +// int Entry; + // collect fanout counts + vFanouts = Vec_IntAlloc( 100 ); + Aig_ManForEachObj( pAig, pObj, i ) + { +// if ( !Aig_ObjIsCi(pObj) && (fCisOnly || !Aig_ObjIsNode(pObj)) ) + if ( !Saig_ObjIsLo(pAig,pObj) && (fCisOnly || !Aig_ObjIsNode(pObj)) ) + continue; + Vec_IntPush( vFanouts, Aig_ObjRefs(pObj) ); + } + Vec_IntSort( vFanouts, 1 ); + // pick the separator + nCandMax = Abc_MinInt( nCandMax, Vec_IntSize(vFanouts) - 1 ); + PivotValue = Vec_IntEntry( vFanouts, nCandMax ); + Vec_IntFree( vFanouts ); + // collect obj satisfying the constraints + vResult = Vec_IntAlloc( 100 ); + Aig_ManForEachObj( pAig, pObj, i ) + { +// if ( !Aig_ObjIsCi(pObj) && (fCisOnly || !Aig_ObjIsNode(pObj)) ) + if ( !Saig_ObjIsLo(pAig,pObj) && (fCisOnly || !Aig_ObjIsNode(pObj)) ) + continue; + if ( Aig_ObjRefs(pObj) < PivotValue ) + continue; + Vec_IntPush( vResult, Aig_ObjId(pObj) ); + } + assert( Vec_IntSize(vResult) >= nCandMax ); + // order in the decreasing order of fanouts + do + { + fChanges = 0; + for ( i = 0; i < Vec_IntSize(vResult) - 1; i++ ) + if ( Aig_ObjRefs(Aig_ManObj(pAig, Vec_IntEntry(vResult, i))) < + Aig_ObjRefs(Aig_ManObj(pAig, Vec_IntEntry(vResult, i+1))) ) + { + int Temp = Vec_IntEntry( vResult, i ); + Vec_IntWriteEntry( vResult, i, Vec_IntEntry(vResult, i+1) ); + Vec_IntWriteEntry( vResult, i+1, Temp ); + fChanges = 1; + } + } + while ( fChanges ); +/* + Vec_IntForEachEntry( vResult, Entry, i ) + printf( "%d ", Aig_ObjRefs(Aig_ManObj(pAig, Entry)) ); +printf( "\n" ); +*/ + return vResult; +} + +/**Function************************************************************* + + Synopsis [Derives AIG whose PI is substituted by a constant.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManModelCheckAigWithHints( Aig_Man_t * pAigGlo, Gia_ParLlb_t * pPars ) +{ + DdManager * ddGlo = NULL; + Vec_Int_t * vHints; + Vec_Int_t * vHFCands; + int i, Entry, RetValue = -1; + abctime clk = Abc_Clock(); + assert( pPars->nHintDepth > 0 ); +/* + // perform reachability without hints + RetValue = Llb_ManModelCheckAig( pAigGlo, pPars, NULL, NULL ); + if ( RetValue >= 0 ) + return RetValue; +*/ + // create hints representation + vHFCands = Llb_ManCollectHighFanoutObjects( pAigGlo, pPars->nHintDepth+pPars->HintFirst, 1 ); + vHints = Vec_IntStartFull( Aig_ManObjNumMax(pAigGlo) ); + // add one hint at a time till the problem is solved + Vec_IntForEachEntryStart( vHFCands, Entry, i, pPars->HintFirst ) + { + Vec_IntWriteEntry( vHints, Entry, 1 ); // change to 1 to start from zero cof!!! + // solve under hints + RetValue = Llb_ManModelCheckAig( pAigGlo, pPars, vHints, &ddGlo ); + if ( RetValue == 0 ) + goto Finish; + if ( RetValue == 1 ) + break; + } + if ( RetValue == -1 ) + goto Finish; + // undo the hints one at a time + for ( ; i >= pPars->HintFirst; i-- ) + { + Entry = Vec_IntEntry( vHFCands, i ); + Vec_IntWriteEntry( vHints, Entry, -1 ); + // solve under relaxed hints + RetValue = Llb_ManModelCheckAig( pAigGlo, pPars, vHints, &ddGlo ); + if ( RetValue == 0 ) + goto Finish; + if ( RetValue == 1 ) + continue; + break; + } +Finish: + if ( ddGlo ) + { + if ( ddGlo->bFunc ) + Cudd_RecursiveDeref( ddGlo, ddGlo->bFunc ); + Extra_StopManager( ddGlo ); + } + Vec_IntFreeP( &vHFCands ); + Vec_IntFreeP( &vHints ); + if ( pPars->fVerbose ) + Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clk ); + return RetValue; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Man.c b/src/bdd/llb/llb1Man.c new file mode 100644 index 00000000..f5de25e0 --- /dev/null +++ b/src/bdd/llb/llb1Man.c @@ -0,0 +1,218 @@ +/**CFile**************************************************************** + + FileName [llb1Man.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Reachability manager.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Man.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrepareVarMap( Llb_Man_t * p ) +{ + Aig_Obj_t * pObjLi, * pObjLo; + int i, iVarLi, iVarLo; + assert( p->vNs2Glo == NULL ); + assert( p->vCs2Glo == NULL ); + assert( p->vGlo2Cs == NULL ); + assert( p->vGlo2Ns == NULL ); + p->vNs2Glo = Vec_IntStartFull( Vec_IntSize(p->vVar2Obj) ); + p->vCs2Glo = Vec_IntStartFull( Vec_IntSize(p->vVar2Obj) ); + p->vGlo2Cs = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + p->vGlo2Ns = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + Saig_ManForEachLiLo( p->pAig, pObjLi, pObjLo, i ) + { + iVarLi = Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObjLi)); + iVarLo = Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObjLo)); + assert( iVarLi >= 0 && iVarLi < Vec_IntSize(p->vVar2Obj) ); + assert( iVarLo >= 0 && iVarLo < Vec_IntSize(p->vVar2Obj) ); + Vec_IntWriteEntry( p->vNs2Glo, iVarLi, i ); + Vec_IntWriteEntry( p->vCs2Glo, iVarLo, i ); + Vec_IntWriteEntry( p->vGlo2Cs, i, iVarLo ); + Vec_IntWriteEntry( p->vGlo2Ns, i, iVarLi ); + } + // add mapping of the PIs + Saig_ManForEachPi( p->pAig, pObjLo, i ) + { + iVarLo = Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObjLo)); + Vec_IntWriteEntry( p->vCs2Glo, iVarLo, Aig_ManRegNum(p->pAig)+i ); + Vec_IntWriteEntry( p->vNs2Glo, iVarLo, Aig_ManRegNum(p->pAig)+i ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManPrepareVarLimits( Llb_Man_t * p ) +{ + Llb_Grp_t * pGroup; + Aig_Obj_t * pVar; + int i, k; + assert( p->vVarBegs == NULL ); + assert( p->vVarEnds == NULL ); + p->vVarEnds = Vec_IntStart( Aig_ManObjNumMax(p->pAig) ); + p->vVarBegs = Vec_IntStart( Aig_ManObjNumMax(p->pAig) ); + Vec_IntFill( p->vVarBegs, Aig_ManObjNumMax(p->pAig), p->pMatrix->nCols ); + + for ( i = 0; i < p->pMatrix->nCols; i++ ) + { + pGroup = p->pMatrix->pColGrps[i]; + + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pVar, k ) + if ( Vec_IntEntry(p->vVarBegs, pVar->Id) > i ) + Vec_IntWriteEntry( p->vVarBegs, pVar->Id, i ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pVar, k ) + if ( Vec_IntEntry(p->vVarBegs, pVar->Id) > i ) + Vec_IntWriteEntry( p->vVarBegs, pVar->Id, i ); + + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pVar, k ) + if ( Vec_IntEntry(p->vVarEnds, pVar->Id) < i ) + Vec_IntWriteEntry( p->vVarEnds, pVar->Id, i ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pVar, k ) + if ( Vec_IntEntry(p->vVarEnds, pVar->Id) < i ) + Vec_IntWriteEntry( p->vVarEnds, pVar->Id, i ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManStop( Llb_Man_t * p ) +{ + Llb_Grp_t * pGrp; + DdNode * bTemp; + int i; + +// Vec_IntFreeP( &p->vMem ); +// Vec_PtrFreeP( &p->vTops ); +// Vec_PtrFreeP( &p->vBots ); +// Vec_VecFreeP( (Vec_Vec_t **)&p->vCuts ); + + if ( p->pMatrix ) + Llb_MtrFree( p->pMatrix ); + Vec_PtrForEachEntry( Llb_Grp_t *, p->vGroups, pGrp, i ) + Llb_ManGroupStop( pGrp ); + if ( p->dd ) + { +// printf( "Manager dd\n" ); + Extra_StopManager( p->dd ); + } + if ( p->ddG ) + { +// printf( "Manager ddG\n" ); + if ( p->ddG->bFunc ) + Cudd_RecursiveDeref( p->ddG, p->ddG->bFunc ); + Extra_StopManager( p->ddG ); + } + if ( p->ddR ) + { +// printf( "Manager ddR\n" ); + if ( p->ddR->bFunc ) + Cudd_RecursiveDeref( p->ddR, p->ddR->bFunc ); + Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i ) + Cudd_RecursiveDeref( p->ddR, bTemp ); + Extra_StopManager( p->ddR ); + } + Aig_ManStop( p->pAig ); + Vec_PtrFreeP( &p->vGroups ); + Vec_IntFreeP( &p->vVar2Obj ); + Vec_IntFreeP( &p->vObj2Var ); + Vec_IntFreeP( &p->vVarBegs ); + Vec_IntFreeP( &p->vVarEnds ); + Vec_PtrFreeP( &p->vRings ); + Vec_IntFreeP( &p->vNs2Glo ); + Vec_IntFreeP( &p->vCs2Glo ); + Vec_IntFreeP( &p->vGlo2Cs ); + Vec_IntFreeP( &p->vGlo2Ns ); +// Vec_IntFreeP( &p->vHints ); + ABC_FREE( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Man_t * Llb_ManStart( Aig_Man_t * pAigGlo, Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Man_t * p; + Aig_ManCleanMarkA( pAig ); + p = ABC_CALLOC( Llb_Man_t, 1 ); + p->pAigGlo = pAigGlo; + p->pPars = pPars; + p->pAig = pAig; + p->vVar2Obj = Llb_ManMarkPivotNodes( p->pAig, pPars->fUsePivots ); + p->vObj2Var = Vec_IntInvert( p->vVar2Obj, -1 ); + p->vRings = Vec_PtrAlloc( 100 ); + Llb_ManPrepareVarMap( p ); + Llb_ManPrepareGroups( p ); + Aig_ManCleanMarkA( pAig ); + p->pMatrix = Llb_MtrCreate( p ); + p->pMatrix->pMan = p; + return p; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Matrix.c b/src/bdd/llb/llb1Matrix.c new file mode 100644 index 00000000..7aa9c744 --- /dev/null +++ b/src/bdd/llb/llb1Matrix.c @@ -0,0 +1,430 @@ +/**CFile**************************************************************** + + FileName [llb1Matrix.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Partition clustering as a matrix problem.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Matrix.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// 0123 nCols +// +---------------------> +// pi 0 | 111 row0 pRowSums[0] +// pi 1 | 1 11 row1 pRowSums[1] +// pi 2 | 1 11 row2 pRowSums[2] +// CS |1 1 +// CS |1 111 +// CS |111 111 +// int | 11111 +// int | 111 +// int | 111 +// int | 111 +// NS | 11 11 +// NS | 11 1 +// NS | 111 +// nRows | +// v +// cccc pColSums[0] +// oooo pColSums[1] +// llll pColSums[2] +// 0123 pColSums[3] + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Verify columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrVerifyRowsAll( Llb_Mtr_t * p ) +{ + int iRow, iCol, Counter; + for ( iCol = 0; iCol < p->nCols; iCol++ ) + { + Counter = 0; + for ( iRow = 0; iRow < p->nRows; iRow++ ) + if ( p->pMatrix[iCol][iRow] == 1 ) + Counter++; + assert( Counter == p->pColSums[iCol] ); + } +} + +/**Function************************************************************* + + Synopsis [Verify columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrVerifyColumnsAll( Llb_Mtr_t * p ) +{ + int iRow, iCol, Counter; + for ( iRow = 0; iRow < p->nRows; iRow++ ) + { + Counter = 0; + for ( iCol = 0; iCol < p->nCols; iCol++ ) + if ( p->pMatrix[iCol][iRow] == 1 ) + Counter++; + assert( Counter == p->pRowSums[iRow] ); + } +} + +/**Function************************************************************* + + Synopsis [Verify columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrVerifyMatrix( Llb_Mtr_t * p ) +{ + Llb_MtrVerifyRowsAll( p ); + Llb_MtrVerifyColumnsAll( p ); +} + +/**Function************************************************************* + + Synopsis [Sort variables in the order of removal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int * Llb_MtrFindVarOrder( Llb_Mtr_t * p ) +{ + int * pOrder, * pLast; + int i, k, fChanges, Temp; + pOrder = ABC_CALLOC( int, p->nRows ); + pLast = ABC_CALLOC( int, p->nRows ); + for ( i = 0; i < p->nRows; i++ ) + { + pOrder[i] = i; + for ( k = p->nCols - 1; k >= 0; k-- ) + if ( p->pMatrix[k][i] ) + { + pLast[i] = k; + break; + } + } + do + { + fChanges = 0; + for ( i = 0; i < p->nRows - 1; i++ ) + if ( pLast[i] > pLast[i+1] ) + { + Temp = pOrder[i]; + pOrder[i] = pOrder[i+1]; + pOrder[i+1] = Temp; + + Temp = pLast[i]; + pLast[i] = pLast[i+1]; + pLast[i+1] = Temp; + + fChanges = 1; + } + } + while ( fChanges ); + ABC_FREE( pLast ); + return pOrder; +} + +/**Function************************************************************* + + Synopsis [Returns type of a variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Llb_MtrVarName( Llb_Mtr_t * p, int iVar ) +{ + static char Buffer[10]; + if ( iVar < p->nPis ) + strcpy( Buffer, "pi" ); + else if ( iVar < p->nPis + p->nFfs ) + strcpy( Buffer, "CS" ); + else if ( iVar >= p->nRows - p->nFfs ) + strcpy( Buffer, "NS" ); + else + strcpy( Buffer, "int" ); + return Buffer; +} + +/**Function************************************************************* + + Synopsis [Creates one column with vars in the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrPrint( Llb_Mtr_t * p, int fOrder ) +{ + int * pOrder = NULL; + int i, iRow, iCol; + if ( fOrder ) + pOrder = Llb_MtrFindVarOrder( p ); + for ( i = 0; i < p->nRows; i++ ) + { + iRow = pOrder ? pOrder[i] : i; + printf( "%3d : ", iRow ); + printf( "%3d ", p->pRowSums[iRow] ); + printf( "%3s ", Llb_MtrVarName(p, iRow) ); + for ( iCol = 0; iCol < p->nCols; iCol++ ) + printf( "%c", p->pMatrix[iCol][iRow] ? '*' : ' ' ); + printf( "\n" ); + } + ABC_FREE( pOrder ); +} + +/**Function************************************************************* + + Synopsis [Verify columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrPrintMatrixStats( Llb_Mtr_t * p ) +{ + int iVar, iGrp, iGrp1, iGrp2, Span = 0, nCutSize = 0, nCutSizeMax = 0; + int * pGrp1 = ABC_CALLOC( int, p->nRows ); + int * pGrp2 = ABC_CALLOC( int, p->nRows ); + for ( iVar = 0; iVar < p->nRows; iVar++ ) + { + if ( p->pRowSums[iVar] == 0 ) + continue; + for ( iGrp1 = 0; iGrp1 < p->nCols; iGrp1++ ) + if ( p->pMatrix[iGrp1][iVar] == 1 ) + break; + for ( iGrp2 = p->nCols - 1; iGrp2 >= 0; iGrp2-- ) + if ( p->pMatrix[iGrp2][iVar] == 1 ) + break; + assert( iGrp1 <= iGrp2 ); + pGrp1[iVar] = iGrp1; + pGrp2[iVar] = iGrp2; + Span += iGrp2 - iGrp1; + } + // compute span + for ( iGrp = 0; iGrp < p->nCols; iGrp++ ) + { + for ( iVar = 0; iVar < p->nRows; iVar++ ) + if ( pGrp1[iVar] == iGrp ) + nCutSize++; + if ( nCutSizeMax < nCutSize ) + nCutSizeMax = nCutSize; + for ( iVar = 0; iVar < p->nRows; iVar++ ) + if ( pGrp2[iVar] == iGrp ) + nCutSize--; + } + ABC_FREE( pGrp1 ); + ABC_FREE( pGrp2 ); + printf( "[%4d x %4d] Life-span =%6.2f Max-cut =%5d\n", + p->nCols, p->nRows, 1.0*Span/p->nRows, nCutSizeMax ); + if ( nCutSize ) + Abc_Print( -1, "Cut size is not zero (%d).\n", nCutSize ); +} + + + +/**Function************************************************************* + + Synopsis [Starts the matrix representation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mtr_t * Llb_MtrAlloc( int nPis, int nFfs, int nCols, int nRows ) +{ + Llb_Mtr_t * p; + int i; + p = ABC_CALLOC( Llb_Mtr_t, 1 ); + p->nPis = nPis; + p->nFfs = nFfs; + p->nRows = nRows; + p->nCols = nCols; + p->pRowSums = ABC_CALLOC( int, nRows ); + p->pColSums = ABC_CALLOC( int, nCols ); + p->pColGrps = ABC_CALLOC( Llb_Grp_t *, nCols ); + p->pMatrix = ABC_CALLOC( char *, nCols ); + for ( i = 0; i < nCols; i++ ) + p->pMatrix[i] = ABC_CALLOC( char, nRows ); + // partial product + p->pProdVars = ABC_CALLOC( char, nRows ); // variables in the partial product + p->pProdNums = ABC_CALLOC( int, nRows ); // var counts in the remaining partitions + return p; +} + +/**Function************************************************************* + + Synopsis [Stops the matrix representation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrFree( Llb_Mtr_t * p ) +{ + int i; + ABC_FREE( p->pProdVars ); + ABC_FREE( p->pProdNums ); + for ( i = 0; i < p->nCols; i++ ) + ABC_FREE( p->pMatrix[i] ); + ABC_FREE( p->pRowSums ); + ABC_FREE( p->pColSums ); + ABC_FREE( p->pMatrix ); + ABC_FREE( p->pColGrps ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Creates one column with vars in the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrAddColumn( Llb_Mtr_t * p, Llb_Grp_t * pGrp ) +{ + Aig_Obj_t * pVar; + int i, iRow, iCol = pGrp->Id; + assert( iCol >= 0 && iCol < p->nCols ); + p->pColGrps[iCol] = pGrp; + Vec_PtrForEachEntry( Aig_Obj_t *, pGrp->vIns, pVar, i ) + { + iRow = Vec_IntEntry( pGrp->pMan->vObj2Var, Aig_ObjId(pVar) ); + assert( iRow >= 0 && iRow < p->nRows ); + p->pMatrix[iCol][iRow] = 1; + p->pColSums[iCol]++; + p->pRowSums[iRow]++; + } + Vec_PtrForEachEntry( Aig_Obj_t *, pGrp->vOuts, pVar, i ) + { + iRow = Vec_IntEntry( pGrp->pMan->vObj2Var, Aig_ObjId(pVar) ); + assert( iRow >= 0 && iRow < p->nRows ); + p->pMatrix[iCol][iRow] = 1; + p->pColSums[iCol]++; + p->pRowSums[iRow]++; + } +} + +/**Function************************************************************* + + Synopsis [Matrix reduce.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrRemoveSingletonRows( Llb_Mtr_t * p ) +{ + int i, k; + for ( i = 0; i < p->nRows; i++ ) + if ( p->pRowSums[i] < 2 ) + { + p->pRowSums[i] = 0; + for ( k = 0; k < p->nCols; k++ ) + { + if ( p->pMatrix[k][i] == 1 ) + { + p->pMatrix[k][i] = 0; + p->pColSums[k]--; + } + } + } +} + +/**Function************************************************************* + + Synopsis [Matrix reduce.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mtr_t * Llb_MtrCreate( Llb_Man_t * p ) +{ + Llb_Mtr_t * pMatrix; + Llb_Grp_t * pGroup; + int i; + pMatrix = Llb_MtrAlloc( Saig_ManPiNum(p->pAig), Saig_ManRegNum(p->pAig), + Vec_PtrSize(p->vGroups), Vec_IntSize(p->vVar2Obj) ); + Vec_PtrForEachEntry( Llb_Grp_t *, p->vGroups, pGroup, i ) + Llb_MtrAddColumn( pMatrix, pGroup ); +// Llb_MtrRemoveSingletonRows( pMatrix ); + return pMatrix; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Pivot.c b/src/bdd/llb/llb1Pivot.c new file mode 100644 index 00000000..7a5bb66f --- /dev/null +++ b/src/bdd/llb/llb1Pivot.c @@ -0,0 +1,254 @@ +/**CFile**************************************************************** + + FileName [llb1Pivot.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Determining pivot variables.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Pivot.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManTracePaths_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Aig_Obj_t * pPivot ) +{ + Aig_Obj_t * pFanout; + int k, iFan = -1; + if ( Aig_ObjIsTravIdPrevious(p, pObj) ) + return 0; + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return 1; + if ( Saig_ObjIsLi(p, pObj) ) + return 0; + if ( Saig_ObjIsPo(p, pObj) ) + return 0; + if ( pObj == pPivot ) + return 1; + assert( Aig_ObjIsCand(pObj) ); + Aig_ObjForEachFanout( p, pObj, pFanout, iFan, k ) + if ( !Llb_ManTracePaths_rec( p, pFanout, pPivot ) ) + { + Aig_ObjSetTravIdPrevious(p, pObj); + return 0; + } + Aig_ObjSetTravIdCurrent(p, pObj); + return 1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManTracePaths( Aig_Man_t * p, Aig_Obj_t * pPivot ) +{ + Aig_Obj_t * pObj; + int i, Counter = 0; + Aig_ManIncrementTravId( p ); // prev = visited with path to LI (value 0) + Aig_ManIncrementTravId( p ); // cur = visited w/o path to LI (value 1) + Saig_ManForEachLo( p, pObj, i ) + Counter += Llb_ManTracePaths_rec( p, pObj, pPivot ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManTestCuts( Aig_Man_t * p ) +{ + Aig_Obj_t * pObj; + int i, Count; + Aig_ManFanoutStart( p ); + Aig_ManForEachNode( p, pObj, i ) + { + if ( Aig_ObjRefs(pObj) <= 1 ) + continue; + Count = Llb_ManTracePaths( p, pObj ); + printf( "Obj =%5d. Lev =%3d. Fanout =%5d. Count = %3d.\n", + i, Aig_ObjLevel(pObj), Aig_ObjRefs(pObj), Count ); + } + Aig_ManFanoutStop( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManLabelLiCones_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + if ( pObj->fMarkB ) + return; + pObj->fMarkB = 1; + assert( Aig_ObjIsNode(pObj) ); + Llb_ManLabelLiCones_rec( p, Aig_ObjFanin0(pObj) ); + Llb_ManLabelLiCones_rec( p, Aig_ObjFanin1(pObj) ); +} + +/**Function************************************************************* + + Synopsis [Determine starting cut-points.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManLabelLiCones( Aig_Man_t * p ) +{ + Aig_Obj_t * pObj; + int i; + // mark const and PIs + Aig_ManConst1(p)->fMarkB = 1; + Aig_ManForEachCi( p, pObj, i ) + pObj->fMarkB = 1; + // mark cones + Saig_ManForEachLi( p, pObj, i ) + Llb_ManLabelLiCones_rec( p, Aig_ObjFanin0(pObj) ); +} + +/**Function************************************************************* + + Synopsis [Determine starting cut-points.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManMarkInternalPivots( Aig_Man_t * p ) +{ + Vec_Ptr_t * vMuxes; + Aig_Obj_t * pObj; + int i, Counter = 0; + + // remove refs due to MUXes + vMuxes = Aig_ManMuxesCollect( p ); + Aig_ManMuxesDeref( p, vMuxes ); + + // mark nodes feeding into LIs + Aig_ManCleanMarkB( p ); + Llb_ManLabelLiCones( p ); + + // mark internal nodes + Aig_ManFanoutStart( p ); + Aig_ManForEachNode( p, pObj, i ) + if ( pObj->fMarkB && pObj->nRefs > 1 ) + { + if ( Llb_ManTracePaths(p, pObj) > 0 ) + pObj->fMarkA = 1; + Counter++; + } + Aig_ManFanoutStop( p ); +// printf( "TracePath tried = %d.\n", Counter ); + + // mark nodes feeding into LIs + Aig_ManCleanMarkB( p ); + + // add refs due to MUXes + Aig_ManMuxesRef( p, vMuxes ); + Vec_PtrFree( vMuxes ); +} + +/**Function************************************************************* + + Synopsis [Determine starting cut-points.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_ManMarkPivotNodes( Aig_Man_t * p, int fUseInternal ) +{ + Vec_Int_t * vVar2Obj; + Aig_Obj_t * pObj; + int i; + // mark inputs/outputs + Aig_ManForEachCi( p, pObj, i ) + pObj->fMarkA = 1; + Saig_ManForEachLi( p, pObj, i ) + pObj->fMarkA = 1; + + // mark internal pivot nodes + if ( fUseInternal ) + Llb_ManMarkInternalPivots( p ); + + // assign variable numbers + Aig_ManConst1(p)->fMarkA = 0; + vVar2Obj = Vec_IntAlloc( 100 ); + Aig_ManForEachCi( p, pObj, i ) + Vec_IntPush( vVar2Obj, Aig_ObjId(pObj) ); + Aig_ManForEachNode( p, pObj, i ) + if ( pObj->fMarkA ) + Vec_IntPush( vVar2Obj, Aig_ObjId(pObj) ); + Saig_ManForEachLi( p, pObj, i ) + Vec_IntPush( vVar2Obj, Aig_ObjId(pObj) ); + return vVar2Obj; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Reach.c b/src/bdd/llb/llb1Reach.c new file mode 100644 index 00000000..fae7bee2 --- /dev/null +++ b/src/bdd/llb/llb1Reach.c @@ -0,0 +1,904 @@ +/**CFile**************************************************************** + + FileName [llb1Reach.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Reachability analysis.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Reach.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Derives global BDD for the node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManConstructOutBdd( Aig_Man_t * pAig, Aig_Obj_t * pNode, DdManager * dd ) +{ + DdNode * bBdd0, * bBdd1, * bFunc; + Vec_Ptr_t * vNodes; + Aig_Obj_t * pObj = NULL; + int i; + abctime TimeStop; + if ( Aig_ObjFanin0(pNode) == Aig_ManConst1(pAig) ) + return Cudd_NotCond( Cudd_ReadOne(dd), Aig_ObjFaninC0(pNode) ); + TimeStop = dd->TimeStop; dd->TimeStop = 0; + vNodes = Aig_ManDfsNodes( pAig, &pNode, 1 ); + assert( Vec_PtrSize(vNodes) > 0 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) ) + continue; + bBdd0 = Cudd_NotCond( Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( (DdNode *)pObj->pData ); + } + bFunc = (DdNode *)pObj->pData; Cudd_Ref( bFunc ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) ) + continue; + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + } + Vec_PtrFree( vNodes ); + if ( Aig_ObjIsCo(pNode) ) + bFunc = Cudd_NotCond( bFunc, Aig_ObjFaninC0(pNode) ); + Cudd_Deref( bFunc ); + dd->TimeStop = TimeStop; + return bFunc; +} + +/**Function************************************************************* + + Synopsis [Derives BDD for the group.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManConstructGroupBdd( Llb_Man_t * p, Llb_Grp_t * pGroup ) +{ + Aig_Obj_t * pObj; + DdNode * bBdd0, * bBdd1, * bRes, * bXor, * bTemp; + int i, k; + Aig_ManConst1(p->pAig)->pData = Cudd_ReadOne( p->dd ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + pObj->pData = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vNodes, pObj, i ) + { + bBdd0 = Cudd_NotCond( Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); +// pObj->pData = Extra_bddAndTime( p->dd, bBdd0, bBdd1, p->pPars->TimeTarget ); + pObj->pData = Cudd_bddAnd( p->dd, bBdd0, bBdd1 ); + if ( pObj->pData == NULL ) + { + Vec_PtrForEachEntryStop( Aig_Obj_t *, pGroup->vNodes, pObj, k, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( p->dd, (DdNode *)pObj->pData ); + return NULL; + } + Cudd_Ref( (DdNode *)pObj->pData ); + } + bRes = Cudd_ReadOne( p->dd ); Cudd_Ref( bRes ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + { + if ( Aig_ObjIsCo(pObj) ) + bBdd0 = Cudd_NotCond( Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + else + bBdd0 = (DdNode *)pObj->pData; + bBdd1 = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bXor = Cudd_bddXor( p->dd, bBdd0, bBdd1 ); Cudd_Ref( bXor ); +// bRes = Extra_bddAndTime( p->dd, bTemp = bRes, Cudd_Not(bXor), p->pPars->TimeTarget ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, Cudd_Not(bXor) ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bXor ); + Vec_PtrForEachEntryStop( Aig_Obj_t *, pGroup->vNodes, pObj, k, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( p->dd, (DdNode *)pObj->pData ); + return NULL; + } + Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bXor ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vNodes, pObj, i ) + Cudd_RecursiveDeref( p->dd, (DdNode *)pObj->pData ); + Cudd_Deref( bRes ); + return bRes; +} + +/**Function************************************************************* + + Synopsis [Derives quantification cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManConstructQuantCubeIntern( Llb_Man_t * p, Llb_Grp_t * pGroup, int iGrpPlace, int fBackward ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bTemp, * bVar; + int i, iGroupFirst, iGroupLast; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bRes = Cudd_ReadOne( p->dd ); Cudd_Ref( bRes ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + { + if ( fBackward && Saig_ObjIsPi(p->pAig, pObj) ) + continue; + iGroupFirst = Vec_IntEntry(p->vVarBegs, Aig_ObjId(pObj)); + iGroupLast = Vec_IntEntry(p->vVarEnds, Aig_ObjId(pObj)); + assert( iGroupFirst <= iGroupLast ); + if ( iGroupFirst < iGroupLast ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + { + if ( fBackward && Saig_ObjIsPi(p->pAig, pObj) ) + continue; + iGroupFirst = Vec_IntEntry(p->vVarBegs, Aig_ObjId(pObj)); + iGroupLast = Vec_IntEntry(p->vVarEnds, Aig_ObjId(pObj)); + assert( iGroupFirst <= iGroupLast ); + if ( iGroupFirst < iGroupLast ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Cudd_Deref( bRes ); + p->dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [Derives quantification cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManConstructQuantCubeFwd( Llb_Man_t * p, Llb_Grp_t * pGroup, int iGrpPlace ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bTemp, * bVar; + int i, iGroupLast; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bRes = Cudd_ReadOne( p->dd ); Cudd_Ref( bRes ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + { + iGroupLast = Vec_IntEntry(p->vVarEnds, Aig_ObjId(pObj)); + assert( iGroupLast >= iGrpPlace ); + if ( iGroupLast > iGrpPlace ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + { + iGroupLast = Vec_IntEntry(p->vVarEnds, Aig_ObjId(pObj)); + assert( iGroupLast >= iGrpPlace ); + if ( iGroupLast > iGrpPlace ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Cudd_Deref( bRes ); + p->dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [Derives quantification cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManConstructQuantCubeBwd( Llb_Man_t * p, Llb_Grp_t * pGroup, int iGrpPlace ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bTemp, * bVar; + int i, iGroupFirst; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bRes = Cudd_ReadOne( p->dd ); Cudd_Ref( bRes ); + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vIns, pObj, i ) + { + if ( Saig_ObjIsPi(p->pAig, pObj) ) + continue; + iGroupFirst = Vec_IntEntry(p->vVarBegs, Aig_ObjId(pObj)); + assert( iGroupFirst <= iGrpPlace ); + if ( iGroupFirst < iGrpPlace ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, pGroup->vOuts, pObj, i ) + { + if ( Saig_ObjIsPi(p->pAig, pObj) ) + continue; + iGroupFirst = Vec_IntEntry(p->vVarBegs, Aig_ObjId(pObj)); + assert( iGroupFirst <= iGrpPlace ); + if ( iGroupFirst < iGrpPlace ) + continue; + bVar = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)) ); + bRes = Cudd_bddAnd( p->dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Cudd_Deref( bRes ); + p->dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManComputeInitState( Llb_Man_t * p, DdManager * dd ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bVar, * bTemp; + int i, iVar; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Saig_ManForEachLo( p->pAig, pObj, i ) + { + iVar = (dd == p->ddG) ? i : Vec_IntEntry(p->vObj2Var, Aig_ObjId(pObj)); + bVar = Cudd_bddIthVar( dd, iVar ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, Cudd_Not(bVar) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManComputeImage( Llb_Man_t * p, DdNode * bInit, int fBackward ) +{ + int fCheckSupport = 0; + Llb_Grp_t * pGroup; + DdNode * bImage, * bGroup, * bCube, * bTemp; + int k, Index; + bImage = bInit; Cudd_Ref( bImage ); + for ( k = 1; k < p->pMatrix->nCols-1; k++ ) + { + if ( fBackward ) + Index = p->pMatrix->nCols - 1 - k; + else + Index = k; + + // compute group BDD + pGroup = p->pMatrix->pColGrps[Index]; + bGroup = Llb_ManConstructGroupBdd( p, pGroup ); + if ( bGroup == NULL ) + { + Cudd_RecursiveDeref( p->dd, bImage ); + return NULL; + } + Cudd_Ref( bGroup ); + // quantify variables appearing only in this group + bCube = Llb_ManConstructQuantCubeIntern( p, pGroup, Index, fBackward ); Cudd_Ref( bCube ); + bGroup = Cudd_bddExistAbstract( p->dd, bTemp = bGroup, bCube ); + if ( bGroup == NULL ) + { + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bCube ); + return NULL; + } + Cudd_Ref( bGroup ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bCube ); + // perform partial product + if ( fBackward ) + bCube = Llb_ManConstructQuantCubeBwd( p, pGroup, Index ); + else + bCube = Llb_ManConstructQuantCubeFwd( p, pGroup, Index ); + Cudd_Ref( bCube ); +// bImage = Extra_bddAndAbstractTime( p->dd, bTemp = bImage, bGroup, bCube, p->pPars->TimeTarget ); + bImage = Cudd_bddAndAbstract( p->dd, bTemp = bImage, bGroup, bCube ); + if ( bImage == NULL ) + { + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bGroup ); + Cudd_RecursiveDeref( p->dd, bCube ); + return NULL; + } + Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bGroup ); + Cudd_RecursiveDeref( p->dd, bCube ); + } + + // make sure image depends on next state vars + if ( fCheckSupport ) + { + bCube = Cudd_Support( p->dd, bImage ); Cudd_Ref( bCube ); + for ( bTemp = bCube; bTemp != p->dd->one; bTemp = cuddT(bTemp) ) + { + int ObjId = Vec_IntEntry( p->vVar2Obj, bTemp->index ); + Aig_Obj_t * pObj = Aig_ManObj( p->pAig, ObjId ); + if ( !Saig_ObjIsLi(p->pAig, pObj) ) + printf( "Var %d assigned to obj %d that is not LI\n", bTemp->index, ObjId ); + } + Cudd_RecursiveDeref( p->dd, bCube ); + } + Cudd_Deref( bImage ); + return bImage; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ManCreateConstraints( Llb_Man_t * p, Vec_Int_t * vHints, int fUseNsVars ) +{ + DdNode * bConstr, * bFunc, * bTemp; + Aig_Obj_t * pObj; + int i, Entry; + abctime TimeStop; + if ( vHints == NULL ) + return Cudd_ReadOne( p->dd ); + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + assert( Aig_ManCiNum(p->pAig) == Aig_ManCiNum(p->pAigGlo) ); + // assign const and PI nodes to the original AIG + Aig_ManCleanData( p->pAig ); + Aig_ManConst1( p->pAig )->pData = Cudd_ReadOne( p->dd ); + Saig_ManForEachPi( p->pAig, pObj, i ) + pObj->pData = Cudd_bddIthVar( p->dd, Vec_IntEntry(p->vObj2Var,Aig_ObjId(pObj)) ); + Saig_ManForEachLo( p->pAig, pObj, i ) + { + if ( fUseNsVars ) + Entry = Vec_IntEntry( p->vObj2Var, Aig_ObjId(Saig_ObjLoToLi(p->pAig, pObj)) ); + else + Entry = Vec_IntEntry( p->vObj2Var, Aig_ObjId(pObj) ); + pObj->pData = Cudd_bddIthVar( p->dd, Entry ); + } + // transfer them to the global AIG + Aig_ManCleanData( p->pAigGlo ); + Aig_ManConst1( p->pAigGlo )->pData = Cudd_ReadOne( p->dd ); + Aig_ManForEachCi( p->pAigGlo, pObj, i ) + pObj->pData = Aig_ManCi(p->pAig, i)->pData; + // derive consraints + bConstr = Cudd_ReadOne( p->dd ); Cudd_Ref( bConstr ); + Vec_IntForEachEntry( vHints, Entry, i ) + { + if ( Entry != 0 && Entry != 1 ) + continue; + bFunc = Llb_ManConstructOutBdd( p->pAigGlo, Aig_ManObj(p->pAigGlo, i), p->dd ); Cudd_Ref( bFunc ); + bFunc = Cudd_NotCond( bFunc, Entry ); // restrict to not constraint + // make the product + bConstr = Cudd_bddAnd( p->dd, bTemp = bConstr, bFunc ); Cudd_Ref( bConstr ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bFunc ); + } + Cudd_Deref( bConstr ); + p->dd->TimeStop = TimeStop; + return bConstr; +} + +/**Function************************************************************* + + Synopsis [Perform reachability with hints and returns reached states in ppGlo.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Llb_ManReachDeriveCex( Llb_Man_t * p ) +{ + Abc_Cex_t * pCex; + Aig_Obj_t * pObj; + DdNode * bState = NULL, * bImage, * bOneCube, * bTemp, * bRing; + int i, v, RetValue, nPiOffset; + char * pValues = ABC_ALLOC( char, Cudd_ReadSize(p->ddR) ); + assert( Vec_PtrSize(p->vRings) > 0 ); + + p->dd->TimeStop = 0; + p->ddR->TimeStop = 0; + +/* + Saig_ManForEachLo( p->pAig, pObj, i ) + printf( "%d ", pObj->Id ); + printf( "\n" ); + Saig_ManForEachLi( p->pAig, pObj, i ) + printf( "%d(%d) ", pObj->Id, Aig_ObjFaninId0(pObj) ); + printf( "\n" ); +*/ + // allocate room for the counter-example + pCex = Abc_CexAlloc( Saig_ManRegNum(p->pAig), Saig_ManPiNum(p->pAig), Vec_PtrSize(p->vRings) ); + pCex->iFrame = Vec_PtrSize(p->vRings) - 1; + pCex->iPo = -1; + + // get the last cube + bOneCube = Cudd_bddIntersect( p->ddR, (DdNode *)Vec_PtrEntryLast(p->vRings), p->ddR->bFunc ); Cudd_Ref( bOneCube ); + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); + + // write PIs of counter-example + nPiOffset = Saig_ManRegNum(p->pAig) + Saig_ManPiNum(p->pAig) * (Vec_PtrSize(p->vRings) - 1); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // write state in terms of NS variables + if ( Vec_PtrSize(p->vRings) > 1 ) + { + bState = Llb_CoreComputeCube( p->dd, p->vGlo2Ns, 1, pValues ); Cudd_Ref( bState ); + } + // perform backward analysis + Vec_PtrForEachEntryReverse( DdNode *, p->vRings, bRing, v ) + { + if ( v == Vec_PtrSize(p->vRings) - 1 ) + continue; +//Extra_bddPrintSupport( p->dd, bState ); printf( "\n" ); +//Extra_bddPrintSupport( p->dd, bRing ); printf( "\n" ); + // compute the next states + bImage = Llb_ManComputeImage( p, bState, 1 ); + assert( bImage != NULL ); + Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bState ); +//Extra_bddPrintSupport( p->dd, bImage ); printf( "\n" ); + + // move reached states into ring manager + bImage = Extra_TransferPermute( p->dd, p->ddR, bTemp = bImage, Vec_IntArray(p->vCs2Glo) ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bTemp ); +//Extra_bddPrintSupport( p->ddR, bImage ); printf( "\n" ); + + // intersect with the previous set + bOneCube = Cudd_bddIntersect( p->ddR, bImage, bRing ); Cudd_Ref( bOneCube ); + Cudd_RecursiveDeref( p->ddR, bImage ); + + // find any assignment of the BDD + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); +/* + for ( i = 0; i < p->ddR->size; i++ ) + printf( "%d ", pValues[i] ); + printf( "\n" ); +*/ + // write PIs of counter-example + nPiOffset -= Saig_ManPiNum(p->pAig); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // check that we get the init state + if ( v == 0 ) + { + Saig_ManForEachLo( p->pAig, pObj, i ) + assert( pValues[i] == 0 ); + break; + } + + // write state in terms of NS variables + bState = Llb_CoreComputeCube( p->dd, p->vGlo2Ns, 1, pValues ); Cudd_Ref( bState ); + } + assert( nPiOffset == Saig_ManRegNum(p->pAig) ); + // update the output number +//Abc_CexPrint( pCex ); + RetValue = Saig_ManFindFailedPoCex( p->pAigGlo, pCex ); + assert( RetValue >= 0 && RetValue < Saig_ManPoNum(p->pAigGlo) ); // invalid CEX!!! + pCex->iPo = RetValue; + // cleanup + ABC_FREE( pValues ); + return pCex; +} + +/**Function************************************************************* + + Synopsis [Perform reachability with hints and returns reached states in ppGlo.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManReachability( Llb_Man_t * p, Vec_Int_t * vHints, DdManager ** pddGlo ) +{ + int * pNs2Glo = Vec_IntArray( p->vNs2Glo ); + int * pCs2Glo = Vec_IntArray( p->vCs2Glo ); + int * pGlo2Cs = Vec_IntArray( p->vGlo2Cs ); + DdNode * bCurrent, * bReached, * bNext, * bTemp, * bCube; + DdNode * bConstrCs, * bConstrNs; + abctime clk2, clk = Abc_Clock(); + int nIters, nBddSize = 0; +// int nThreshold = 10000; + + // compute time to stop + p->pPars->TimeTarget = p->pPars->TimeLimit ? p->pPars->TimeLimit * CLOCKS_PER_SEC + Abc_Clock(): 0; + + // define variable limits + Llb_ManPrepareVarLimits( p ); + + // start the managers + assert( p->dd == NULL ); + assert( p->ddG == NULL ); + assert( p->ddR == NULL ); + p->dd = Cudd_Init( Vec_IntSize(p->vVar2Obj), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + p->ddR = Cudd_Init( Aig_ManCiNum(p->pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + if ( pddGlo && *pddGlo ) + p->ddG = *pddGlo, *pddGlo = NULL; + else + p->ddG = Cudd_Init( Aig_ManRegNum(p->pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + + if ( p->pPars->fReorder ) + { + Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddG, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddR, CUDD_REORDER_SYMM_SIFT ); + } + else + { + Cudd_AutodynDisable( p->dd ); + Cudd_AutodynDisable( p->ddG ); + Cudd_AutodynDisable( p->ddR ); + } + + // set the stop time parameter + p->dd->TimeStop = p->pPars->TimeTarget; + p->ddG->TimeStop = p->pPars->TimeTarget; + p->ddR->TimeStop = p->pPars->TimeTarget; + + // create bad state in the ring manager + p->ddR->bFunc = Llb_BddComputeBad( p->pAigGlo, p->ddR, p->pPars->TimeTarget ); + if ( p->ddR->bFunc == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->ddR->bFunc ); + + // derive constraints + bConstrCs = Llb_ManCreateConstraints( p, vHints, 0 ); Cudd_Ref( bConstrCs ); + bConstrNs = Llb_ManCreateConstraints( p, vHints, 1 ); Cudd_Ref( bConstrNs ); +//Extra_bddPrint( p->dd, bConstrCs ); printf( "\n" ); +//Extra_bddPrint( p->dd, bConstrNs ); printf( "\n" ); + + // perform reachability analysis + // compute the starting set of states + if ( p->ddG->bFunc ) + { + bReached = p->ddG->bFunc; p->ddG->bFunc = NULL; + bCurrent = Extra_TransferPermute( p->ddG, p->dd, bReached, pGlo2Cs ); Cudd_Ref( bCurrent ); + } + else + { + bReached = Llb_ManComputeInitState( p, p->ddG ); Cudd_Ref( bReached ); + bCurrent = Llb_ManComputeInitState( p, p->dd ); Cudd_Ref( bCurrent ); + } +//Extra_bddPrintSupport( p->ddG, bReached ); printf( "\n" ); +//Extra_bddPrintSupport( p->dd, bCurrent ); printf( "\n" ); + +//Extra_bddPrintSupport( p->dd, bCurrent ); printf( "\n" ); + for ( nIters = 0; nIters < p->pPars->nIterMax; nIters++ ) + { + clk2 = Abc_Clock(); + // check the runtime limit + if ( p->pPars->TimeLimit && Abc_Clock() > p->pPars->TimeTarget ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout during image computation (%d seconds).\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + + // save the onion ring + bTemp = Extra_TransferPermute( p->dd, p->ddR, bCurrent, pCs2Glo ); + if ( bTemp == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during ring transfer.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bTemp ); + Vec_PtrPush( p->vRings, bTemp ); + + // check it for bad states + if ( !p->pPars->fSkipOutCheck && !Cudd_bddLeq( p->ddR, bTemp, Cudd_Not(p->ddR->bFunc) ) ) + { + assert( p->pAigGlo->pSeqModel == NULL ); + if ( !p->pPars->fBackward ) + p->pAigGlo->pSeqModel = Llb_ManReachDeriveCex( p ); + if ( !p->pPars->fSilent ) + { + if ( !p->pPars->fBackward ) + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", p->pAigGlo->pSeqModel->iPo, p->pAigGlo->pName, p->pAigGlo->pName, nIters ); + else + Abc_Print( 1, "Output ??? of miter \"%s\" was asserted in frame %d (counter-example is not produced). ", p->pAigGlo->pName, nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return 0; + } + + // restrict reachable states using constraints + if ( vHints ) + { + bCurrent = Cudd_bddAnd( p->dd, bTemp = bCurrent, bConstrCs ); Cudd_Ref( bCurrent ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + + // quantify variables appearing only in the init state + bCube = Llb_ManConstructQuantCubeIntern( p, (Llb_Grp_t *)Vec_PtrEntry(p->vGroups,0), 0, 0 ); Cudd_Ref( bCube ); + bCurrent = Cudd_bddExistAbstract( p->dd, bTemp = bCurrent, bCube ); Cudd_Ref( bCurrent ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bCube ); + + // compute the next states + bNext = Llb_ManComputeImage( p, bCurrent, 0 ); + if ( bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bNext ); + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + + // restrict reachable states using constraints + if ( vHints ) + { + bNext = Cudd_bddAnd( p->dd, bTemp = bNext, bConstrNs ); Cudd_Ref( bNext ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } +//Extra_bddPrintSupport( p->dd, bNext ); printf( "\n" ); + + // remap these states into the current state vars +// bNext = Extra_TransferPermute( p->dd, p->ddG, bTemp = bNext, pNs2Glo ); Cudd_Ref( bNext ); +// Cudd_RecursiveDeref( p->dd, bTemp ); +// bNext = Extra_TransferPermuteTime( p->dd, p->ddG, bTemp = bNext, pNs2Glo, p->pPars->TimeTarget ); + bNext = Extra_TransferPermute( p->dd, p->ddG, bTemp = bNext, pNs2Glo ); + if ( bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bNext ); + Cudd_RecursiveDeref( p->dd, bTemp ); + + + // check if there are any new states + if ( Cudd_bddLeq( p->ddG, bNext, bReached ) ) // implication = no new states + { + Cudd_RecursiveDeref( p->ddG, bNext ); bNext = NULL; + break; + } + + // check the BDD size + nBddSize = Cudd_DagSize(bNext); + if ( nBddSize > p->pPars->nBddMax ) + { + Cudd_RecursiveDeref( p->ddG, bNext ); bNext = NULL; + break; + } + + // get the new states + bCurrent = Cudd_bddAnd( p->ddG, bNext, Cudd_Not(bReached) ); + if ( bCurrent == NULL ) + { + Cudd_RecursiveDeref( p->ddG, bNext ); bNext = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + break; + } + Cudd_Ref( bCurrent ); + // minimize the new states with the reached states +// bCurrent = Cudd_bddConstrain( p->ddG, bTemp = bCurrent, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); +// bCurrent = Cudd_bddRestrict( p->ddG, bTemp = bCurrent, Cudd_Not(bReached) ); Cudd_Ref( bCurrent ); +// Cudd_RecursiveDeref( p->ddG, bTemp ); +//printf( "Initial BDD =%7d. Constrained BDD =%7d.\n", Cudd_DagSize(bTemp), Cudd_DagSize(bCurrent) ); + + // remap these states into the current state vars +// bCurrent = Extra_TransferPermute( p->ddG, p->dd, bTemp = bCurrent, pGlo2Cs ); Cudd_Ref( bCurrent ); +// Cudd_RecursiveDeref( p->ddG, bTemp ); +// bCurrent = Extra_TransferPermuteTime( p->ddG, p->dd, bTemp = bCurrent, pGlo2Cs, p->pPars->TimeTarget ); + bCurrent = Extra_TransferPermute( p->ddG, p->dd, bTemp = bCurrent, pGlo2Cs ); + if ( bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 2.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->ddG, bTemp ); + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bCurrent ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + + + // add to the reached states + bReached = Cudd_bddOr( p->ddG, bTemp = bReached, bNext ); + if ( bReached == NULL ) + { + Cudd_RecursiveDeref( p->ddG, bTemp ); bTemp = NULL; + Cudd_RecursiveDeref( p->ddG, bNext ); bNext = NULL; + break; + } + Cudd_Ref( bReached ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + Cudd_RecursiveDeref( p->ddG, bNext ); + bNext = NULL; + + if ( p->pPars->fVerbose ) + { + fprintf( stdout, "F =%5d : ", nIters ); + fprintf( stdout, "Im =%6d ", nBddSize ); + fprintf( stdout, "(%4d %3d) ", Cudd_ReadReorderings(p->dd), Cudd_ReadGarbageCollections(p->dd) ); + fprintf( stdout, "Rea =%6d ", Cudd_DagSize(bReached) ); + fprintf( stdout, "(%4d%4d) ", Cudd_ReadReorderings(p->ddG), Cudd_ReadGarbageCollections(p->ddG) ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk2 ); + } +/* + if ( p->pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->ddG, bReached, Saig_ManRegNum(p->pAig) ); +// Extra_bddPrint( p->ddG, bReached );printf( "\n" ); + fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } +*/ + } + Cudd_RecursiveDeref( p->dd, bConstrCs ); bConstrCs = NULL; + Cudd_RecursiveDeref( p->dd, bConstrNs ); bConstrNs = NULL; + if ( bReached == NULL ) + { + p->pPars->iFrame = nIters - 1; + return 0; // reachable + } +// assert( bCurrent == NULL ); + if ( bCurrent ) + Cudd_RecursiveDeref( p->dd, bCurrent ); + // report the stats + if ( p->pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->ddG, bReached, Saig_ManRegNum(p->pAig) ); + if ( nIters >= p->pPars->nIterMax || nBddSize > p->pPars->nBddMax ) + fprintf( stdout, "Reachability analysis is stopped after %d frames.\n", nIters ); + else + fprintf( stdout, "Reachability analysis completed after %d frames.\n", nIters ); + fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } + if ( nIters >= p->pPars->nIterMax || nBddSize > p->pPars->nBddMax ) + { + if ( !p->pPars->fSilent ) + printf( "Verified only for states reachable in %d frames. ", nIters ); + p->pPars->iFrame = p->pPars->nIterMax; + Cudd_RecursiveDeref( p->ddG, bReached ); + return -1; // undecided + } + if ( pddGlo ) + { + assert( p->ddG->bFunc == NULL ); + p->ddG->bFunc = bReached; bReached = NULL; + assert( *pddGlo == NULL ); + *pddGlo = p->ddG; p->ddG = NULL; + } + else + Cudd_RecursiveDeref( p->ddG, bReached ); + if ( !p->pPars->fSilent ) + printf( "The miter is proved unreachable after %d iterations. ", nIters ); + p->pPars->iFrame = nIters - 1; + return 1; // unreachable +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb1Sched.c b/src/bdd/llb/llb1Sched.c new file mode 100644 index 00000000..51de973a --- /dev/null +++ b/src/bdd/llb/llb1Sched.c @@ -0,0 +1,257 @@ +/**CFile**************************************************************** + + FileName [llb1Sched.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Partition scheduling algorithm.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb1Sched.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Swaps two rows.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrSwapColumns( Llb_Mtr_t * p, int iCol1, int iCol2 ) +{ + Llb_Grp_t * pGemp; + char * pTemp; + int iTemp; + assert( iCol1 >= 0 && iCol1 < p->nCols ); + assert( iCol2 >= 0 && iCol2 < p->nCols ); + if ( iCol1 == iCol2 ) + return; + assert( iCol1 != iCol2 ); + // swap col groups + pGemp = p->pColGrps[iCol1]; + p->pColGrps[iCol1] = p->pColGrps[iCol2]; + p->pColGrps[iCol2] = pGemp; + // swap col vectors + pTemp = p->pMatrix[iCol1]; + p->pMatrix[iCol1] = p->pMatrix[iCol2]; + p->pMatrix[iCol2] = pTemp; + // swap col sums + iTemp = p->pColSums[iCol1]; + p->pColSums[iCol1] = p->pColSums[iCol2]; + p->pColSums[iCol2] = iTemp; +} + +/**Function************************************************************* + + Synopsis [Find columns which brings as few vars as possible.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_MtrFindBestColumn( Llb_Mtr_t * p, int iGrpStart ) +{ + int Cost, Cost2, CostBest = ABC_INFINITY, Cost2Best = ABC_INFINITY; + int WeightCur, WeightBest = -ABC_INFINITY, iGrp = -1, iGrpBest = -1; + int k, c, iVar, Counter; + // find partition that reduces partial product as much as possible + for ( iVar = 0; iVar < p->nRows - p->nFfs; iVar++ ) + { + if ( p->pRowSums[iVar] < 2 ) + continue; + // look at present variables that can be quantified + if ( !(p->pProdVars[iVar] == 1 && p->pProdNums[iVar] == 1) ) + continue; + // check that it appears in one partition only + Counter = 0; + for ( c = iGrpStart; c < p->nCols-1; c++ ) + if ( p->pMatrix[c][iVar] == 1 ) + { + iGrp = c; + Counter++; + } + assert( Counter == 1 ); + if ( Counter != 1 ) + Abc_Print( -1, "Llb_MtrFindBestColumn() Internal error!\n" ); + // find weight of this column + WeightCur = 0; + for ( k = 0; k < p->nRows; k++ ) + { + // increase weight if variable k will be quantified from partial product + if ( p->pProdVars[k] == 1 && p->pMatrix[iGrp][k] == 1 && p->pProdNums[k] == 1 ) + WeightCur += 2; + // decrease weight if variable k will be added to partial product + if ( p->pProdVars[k] == 0 && p->pMatrix[iGrp][k] == 1 ) + WeightCur--; + } + if ( WeightCur > 0 && WeightBest < WeightCur ) + { + WeightBest = WeightCur; + iGrpBest = iGrp; + } + } + if ( iGrpBest >= 0 ) + return iGrpBest; + // could not find the group with any vars to quantify + // select the group that contains as few extra variables as possible + // if there is a tie, select variables that appear in less groups than others + for ( iGrp = iGrpStart; iGrp < p->nCols-1; iGrp++ ) + { + Cost = Cost2 = 0; + for ( k = 0; k < p->nRows; k++ ) + if ( p->pProdVars[k] == 0 && p->pMatrix[iGrp][k] == 1 ) + { + Cost++; + Cost2 += p->pProdNums[k]; + } + if ( CostBest > Cost || + (CostBest == Cost && Cost2 > Cost2Best) ) + { + CostBest = Cost; + Cost2Best = Cost2; + iGrpBest = iGrp; + } + } + return iGrpBest; +} + +/**Function************************************************************* + + Synopsis [Returns the number of variables that will be saved.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrUseSelectedColumn( Llb_Mtr_t * p, int iCol ) +{ + int iVar; + assert( iCol >= 1 && iCol < p->nCols - 1 ); + for ( iVar = 0; iVar < p->nRows; iVar++ ) + { + if ( p->pMatrix[iCol][iVar] == 0 ) + continue; + if ( p->pProdVars[iVar] == 1 && p->pProdNums[iVar] == 1 ) + { + p->pProdVars[iVar] = 0; + p->pProdNums[iVar] = 0; + continue; + } + if ( p->pProdVars[iVar] == 0 ) + { + p->pProdVars[iVar] = 1; + p->pProdNums[iVar] = p->pRowSums[iVar]; + } + p->pProdNums[iVar]--; + assert( p->pProdNums[iVar] >= 0 ); + if ( p->pProdNums[iVar] < 0 ) + Abc_Print( -1, "Llb_MtrUseSelectedColumn() Internal error!\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Verify columns.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrVerifyColumns( Llb_Mtr_t * p, int iGrpStart ) +{ + int iVar, iGrp, Counter; + for ( iVar = 0; iVar < p->nRows; iVar++ ) + { + if ( p->pProdVars[iVar] == 0 ) + continue; + Counter = 0; + for ( iGrp = iGrpStart; iGrp < p->nCols; iGrp++ ) + if ( p->pMatrix[iGrp][iVar] == 1 ) + Counter++; + assert( Counter == p->pProdNums[iVar] ); + if ( Counter != p->pProdNums[iVar] ) + Abc_Print( -1, "Llb_MtrVerifyColumns(): Internal error.\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Matrix reduce.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MtrSchedule( Llb_Mtr_t * p ) +{ + int iGrp, iGrpBest, i; + // start partial product + for ( i = 0; i < p->nRows; i++ ) + { + if ( i >= p->nPis && i < p->nPis + p->nFfs ) + { + p->pProdVars[i] = 1; + p->pProdNums[i] = p->pRowSums[i] - 1; + } + else + { + p->pProdVars[i] = 0; + p->pProdNums[i] = p->pRowSums[i]; + } + } + // order the partitions + Llb_MtrVerifyMatrix( p ); + for ( iGrp = 1; iGrp < p->nCols-1; iGrp++ ) + { + Llb_MtrVerifyColumns( p, iGrp ); + iGrpBest = Llb_MtrFindBestColumn( p, iGrp ); + Llb_MtrUseSelectedColumn( p, iGrpBest ); + Llb_MtrSwapColumns( p, iGrp, iGrpBest ); + } + Llb_MtrVerifyMatrix( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Bad.c b/src/bdd/llb/llb2Bad.c new file mode 100644 index 00000000..ac04b563 --- /dev/null +++ b/src/bdd/llb/llb2Bad.c @@ -0,0 +1,138 @@ +/**CFile**************************************************************** + + FileName [llb2Bad.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Computing bad states.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Bad.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes bad in working manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd, abctime TimeOut ) +{ + Vec_Ptr_t * vNodes; + DdNode * bBdd0, * bBdd1, * bTemp, * bResult; + Aig_Obj_t * pObj; + int i, k; + assert( Cudd_ReadSize(dd) == Aig_ManCiNum(pInit) ); + // initialize elementary variables + Aig_ManConst1(pInit)->pData = Cudd_ReadOne( dd ); + Saig_ManForEachLo( pInit, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, i ); + Saig_ManForEachPi( pInit, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Aig_ManRegNum(pInit) + i ); + // compute internal nodes + vNodes = Aig_ManDfsNodes( pInit, (Aig_Obj_t **)Vec_PtrArray(pInit->vCos), Saig_ManPoNum(pInit) ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) ) + continue; + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); +// pObj->pData = Extra_bddAndTime( dd, bBdd0, bBdd1, TimeOut ); + pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); + if ( pObj->pData == NULL ) + { + Vec_PtrForEachEntryStop( Aig_Obj_t *, vNodes, pObj, k, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Vec_PtrFree( vNodes ); + return NULL; + } + Cudd_Ref( (DdNode *)pObj->pData ); + } + // quantify PIs of each PO + bResult = Cudd_ReadLogicZero( dd ); Cudd_Ref( bResult ); + Saig_ManForEachPo( pInit, pObj, i ) + { + bBdd0 = Cudd_NotCond( Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bResult = Cudd_bddOr( dd, bTemp = bResult, bBdd0 ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + } + // deref + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) ) + continue; + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + } + Vec_PtrFree( vNodes ); + Cudd_Deref( bResult ); + return bResult; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_BddQuantifyPis( Aig_Man_t * pInit, DdManager * dd, DdNode * bFunc ) +{ + DdNode * bVar, * bCube, * bTemp; + Aig_Obj_t * pObj; + int i; + abctime TimeStop; + assert( Cudd_ReadSize(dd) == Aig_ManCiNum(pInit) ); + TimeStop = dd->TimeStop; dd->TimeStop = 0; + // create PI cube + bCube = Cudd_ReadOne( dd ); Cudd_Ref( bCube ); + Saig_ManForEachPi( pInit, pObj, i ) { + bVar = Cudd_bddIthVar( dd, Aig_ManRegNum(pInit) + i ); + bCube = Cudd_bddAnd( dd, bTemp = bCube, bVar ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + // quantify PI cube + bFunc = Cudd_bddExistAbstract( dd, bFunc, bCube ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( dd, bCube ); + Cudd_Deref( bFunc ); + dd->TimeStop = TimeStop; + return bFunc; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Core.c b/src/bdd/llb/llb2Core.c new file mode 100644 index 00000000..3d62b322 --- /dev/null +++ b/src/bdd/llb/llb2Core.c @@ -0,0 +1,777 @@ +/**CFile**************************************************************** + + FileName [llb2Core.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Core procedure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Core.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Img_t_ Llb_Img_t; +struct Llb_Img_t_ +{ + Aig_Man_t * pInit; // AIG manager + Aig_Man_t * pAig; // AIG manager + Gia_ParLlb_t * pPars; // parameters + + DdManager * dd; // BDD manager + DdManager * ddG; // BDD manager + DdManager * ddR; // BDD manager + Vec_Ptr_t * vDdMans; // BDD managers for each partition + Vec_Ptr_t * vRings; // onion rings in ddR + + Vec_Int_t * vDriRefs; // driver references + Vec_Int_t * vVarsCs; // cur state variables + Vec_Int_t * vVarsNs; // next state variables + + Vec_Int_t * vCs2Glo; // cur state variables into global variables + Vec_Int_t * vNs2Glo; // next state variables into global variables + Vec_Int_t * vGlo2Cs; // global variables into cur state variables + Vec_Int_t * vGlo2Ns; // global variables into next state variables +}; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes cube composed of given variables with given values.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_CoreComputeCube( DdManager * dd, Vec_Int_t * vVars, int fUseVarIndex, char * pValues ) +{ + DdNode * bRes, * bVar, * bTemp; + int i, iVar, Index; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Vec_IntForEachEntry( vVars, Index, i ) + { + iVar = fUseVarIndex ? Index : i; + bVar = Cudd_NotCond( Cudd_bddIthVar(dd, iVar), (int)(pValues == NULL || pValues[i] != 1) ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [Derives counter-example by backward reachability.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Llb_CoreDeriveCex( Llb_Img_t * p ) +{ + Abc_Cex_t * pCex; + Aig_Obj_t * pObj; + Vec_Ptr_t * vSupps, * vQuant0, * vQuant1; + DdNode * bState = NULL, * bImage, * bOneCube, * bTemp, * bRing; + int i, v, RetValue, nPiOffset; + char * pValues = ABC_ALLOC( char, Cudd_ReadSize(p->ddR) ); + assert( Vec_PtrSize(p->vRings) > 0 ); + + p->dd->TimeStop = 0; + p->ddR->TimeStop = 0; + + // get supports and quantified variables + Vec_PtrReverseOrder( p->vDdMans ); + vSupps = Llb_ImgSupports( p->pAig, p->vDdMans, p->vVarsNs, p->vVarsCs, 1, 0 ); + Llb_ImgSchedule( vSupps, &vQuant0, &vQuant1, 0 ); + Vec_VecFree( (Vec_Vec_t *)vSupps ); + Llb_ImgQuantifyReset( p->vDdMans ); +// Llb_ImgQuantifyFirst( p->pAig, p->vDdMans, vQuant0 ); + + // allocate room for the counter-example + pCex = Abc_CexAlloc( Saig_ManRegNum(p->pAig), Saig_ManPiNum(p->pAig), Vec_PtrSize(p->vRings) ); + pCex->iFrame = Vec_PtrSize(p->vRings) - 1; + pCex->iPo = -1; + + // get the last cube + bOneCube = Cudd_bddIntersect( p->ddR, (DdNode *)Vec_PtrEntryLast(p->vRings), p->ddR->bFunc ); Cudd_Ref( bOneCube ); + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); + + // write PIs of counter-example + nPiOffset = Saig_ManRegNum(p->pAig) + Saig_ManPiNum(p->pAig) * (Vec_PtrSize(p->vRings) - 1); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // write state in terms of NS variables + if ( Vec_PtrSize(p->vRings) > 1 ) + { + bState = Llb_CoreComputeCube( p->dd, p->vVarsNs, 1, pValues ); Cudd_Ref( bState ); + } + // perform backward analysis + Vec_PtrForEachEntryReverse( DdNode *, p->vRings, bRing, v ) + { + if ( v == Vec_PtrSize(p->vRings) - 1 ) + continue; + // compute the next states + bImage = Llb_ImgComputeImage( p->pAig, p->vDdMans, p->dd, bState, + vQuant0, vQuant1, p->vDriRefs, p->pPars->TimeTarget, 1, 0, 0 ); + assert( bImage != NULL ); + Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bState ); +//Extra_bddPrintSupport( p->dd, bImage ); printf( "\n" ); + + // move reached states into ring manager + bImage = Extra_TransferPermute( p->dd, p->ddR, bTemp = bImage, Vec_IntArray(p->vCs2Glo) ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bTemp ); + + // intersect with the previous set + bOneCube = Cudd_bddIntersect( p->ddR, bImage, bRing ); Cudd_Ref( bOneCube ); + Cudd_RecursiveDeref( p->ddR, bImage ); + + // find any assignment of the BDD + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); + + // write PIs of counter-example + nPiOffset -= Saig_ManPiNum(p->pAig); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // check that we get the init state + if ( v == 0 ) + { + Saig_ManForEachLo( p->pAig, pObj, i ) + assert( pValues[i] == 0 ); + break; + } + + // write state in terms of NS variables + bState = Llb_CoreComputeCube( p->dd, p->vVarsNs, 1, pValues ); Cudd_Ref( bState ); + } + assert( nPiOffset == Saig_ManRegNum(p->pAig) ); + // update the output number + RetValue = Saig_ManFindFailedPoCex( p->pInit, pCex ); + assert( RetValue >= 0 && RetValue < Saig_ManPoNum(p->pInit) ); // invalid CEX!!! + pCex->iPo = RetValue; + // cleanup + ABC_FREE( pValues ); + Vec_VecFree( (Vec_Vec_t *)vQuant0 ); + Vec_VecFree( (Vec_Vec_t *)vQuant1 ); + return pCex; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_CoreReachability_int( Llb_Img_t * p, Vec_Ptr_t * vQuant0, Vec_Ptr_t * vQuant1 ) +{ + int * pLoc2Glo = p->pPars->fBackward? Vec_IntArray( p->vCs2Glo ) : Vec_IntArray( p->vNs2Glo ); + int * pLoc2GloR = p->pPars->fBackward? Vec_IntArray( p->vNs2Glo ) : Vec_IntArray( p->vCs2Glo ); + int * pGlo2Loc = p->pPars->fBackward? Vec_IntArray( p->vGlo2Ns ) : Vec_IntArray( p->vGlo2Cs ); + DdNode * bCurrent, * bReached, * bNext, * bTemp; + abctime clk2, clk = Abc_Clock(); + int nIters, nBddSize;//, iOutFail = -1; +/* + // compute time to stop + if ( p->pPars->TimeLimit ) + p->pPars->TimeTarget = Abc_Clock() + p->pPars->TimeLimit * CLOCKS_PER_SEC; + else + p->pPars->TimeTarget = 0; +*/ + + if ( Abc_Clock() > p->pPars->TimeTarget ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) before image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + + // set the stop time parameter + p->dd->TimeStop = p->pPars->TimeTarget; + p->ddG->TimeStop = p->pPars->TimeTarget; + p->ddR->TimeStop = p->pPars->TimeTarget; + + // compute initial states + if ( p->pPars->fBackward ) + { + // create init state in the global manager + bTemp = Llb_BddComputeBad( p->pInit, p->ddR, p->pPars->TimeTarget ); + if ( bTemp == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) while computing bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( bTemp ); + // create bad state in the ring manager + p->ddR->bFunc = Llb_CoreComputeCube( p->ddR, p->vVarsCs, 0, NULL ); Cudd_Ref( p->ddR->bFunc ); + bCurrent = Llb_BddQuantifyPis( p->pInit, p->ddR, bTemp ); Cudd_Ref( bCurrent ); + Cudd_RecursiveDeref( p->ddR, bTemp ); + bReached = Cudd_bddTransfer( p->ddR, p->ddG, bCurrent ); Cudd_Ref( bReached ); + Cudd_RecursiveDeref( p->ddR, bCurrent ); + // move init state to the working manager + bCurrent = Extra_TransferPermute( p->ddG, p->dd, bReached, pGlo2Loc ); + if ( bCurrent == NULL ) + { + Cudd_RecursiveDeref( p->ddG, bReached ); + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during transfer 0.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( bCurrent ); + } + else + { + // create bad state in the ring manager + p->ddR->bFunc = Llb_BddComputeBad( p->pInit, p->ddR, p->pPars->TimeTarget ); + if ( p->ddR->bFunc == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) while computing bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->ddR->bFunc ); + // create init state in the working and global manager + bCurrent = Llb_CoreComputeCube( p->dd, p->vVarsCs, 1, NULL ); Cudd_Ref( bCurrent ); + bReached = Llb_CoreComputeCube( p->ddG, p->vVarsCs, 0, NULL ); Cudd_Ref( bReached ); +//Extra_bddPrint( p->dd, bCurrent ); printf( "\n" ); +//Extra_bddPrint( p->ddG, bReached ); printf( "\n" ); + } + + // compute onion rings + for ( nIters = 0; nIters < p->pPars->nIterMax; nIters++ ) + { + clk2 = Abc_Clock(); + // check the runtime limit + if ( p->pPars->TimeLimit && Abc_Clock() > p->pPars->TimeTarget ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + + // save the onion ring + bTemp = Extra_TransferPermute( p->dd, p->ddR, bCurrent, pLoc2GloR ); + if ( bTemp == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bTemp ); + Vec_PtrPush( p->vRings, bTemp ); + + // check it for bad states + if ( !p->pPars->fSkipOutCheck && !Cudd_bddLeq( p->ddR, bTemp, Cudd_Not(p->ddR->bFunc) ) ) + { + assert( p->pInit->pSeqModel == NULL ); + if ( !p->pPars->fBackward ) + p->pInit->pSeqModel = Llb_CoreDeriveCex( p ); + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + if ( !p->pPars->fSilent ) + { + if ( !p->pPars->fBackward ) + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", p->pInit->pSeqModel->iPo, p->pInit->pName, nIters ); + else + Abc_Print( 1, "Output ??? was asserted in frame %d (counter-example is not produced). ", nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = nIters - 1; + return 0; + } + + // compute the next states + bNext = Llb_ImgComputeImage( p->pAig, p->vDdMans, p->dd, bCurrent, + vQuant0, vQuant1, p->vDriRefs, p->pPars->TimeTarget, + p->pPars->fBackward, p->pPars->fReorder, p->pPars->fVeryVerbose ); + if ( bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bNext ); + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; +//Extra_bddPrintSupport( p->dd, bNext ); printf( "\n" ); + + // remap these states into the global manager +// bNext = Extra_TransferPermute( p->dd, p->ddG, bTemp = bNext, pLoc2Glo ); Cudd_Ref( bNext ); +// Cudd_RecursiveDeref( p->dd, bTemp ); + +// bNext = Extra_TransferPermuteTime( p->dd, p->ddG, bTemp = bNext, pLoc2Glo, p->pPars->TimeTarget ); + bNext = Extra_TransferPermute( p->dd, p->ddG, bTemp = bNext, pLoc2Glo ); + if ( bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bNext ); + Cudd_RecursiveDeref( p->dd, bTemp ); + + nBddSize = Cudd_DagSize(bNext); + // check if there are any new states + if ( Cudd_bddLeq( p->ddG, bNext, bReached ) ) // implication = no new states + { + Cudd_RecursiveDeref( p->ddG, bNext ); bNext = NULL; + break; + } + + // get the new states + bCurrent = Cudd_bddAnd( p->ddG, bNext, Cudd_Not(bReached) ); + if ( bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 2.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->ddG, bNext ); + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bCurrent ); + + // remap these states into the current state vars +// bCurrent = Extra_TransferPermute( p->ddG, p->dd, bTemp = bCurrent, pGlo2Loc ); Cudd_Ref( bCurrent ); +// Cudd_RecursiveDeref( p->ddG, bTemp ); + +// bCurrent = Extra_TransferPermuteTime( p->ddG, p->dd, bTemp = bCurrent, pGlo2Loc, p->pPars->TimeTarget ); + bCurrent = Extra_TransferPermute( p->ddG, p->dd, bTemp = bCurrent, pGlo2Loc ); + if ( bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 2.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->ddG, bTemp ); + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + Cudd_Ref( bCurrent ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + + // add to the reached states + bReached = Cudd_bddOr( p->ddG, bTemp = bReached, bNext ); Cudd_Ref( bReached ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + Cudd_RecursiveDeref( p->ddG, bNext ); + bNext = NULL; + + if ( p->pPars->fVeryVerbose ) + { + double nMints = Cudd_CountMinterm(p->ddG, bReached, Saig_ManRegNum(p->pAig) ); +// Extra_bddPrint( p->ddG, bReached );printf( "\n" ); + fprintf( stdout, " Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } + if ( p->pPars->fVerbose ) + { + fprintf( stdout, "F =%3d : ", nIters ); + fprintf( stdout, "Image =%6d ", nBddSize ); + fprintf( stdout, "(%4d%4d) ", + Cudd_ReadReorderings(p->dd), Cudd_ReadGarbageCollections(p->dd) ); + fprintf( stdout, "Reach =%6d ", Cudd_DagSize(bReached) ); + fprintf( stdout, "(%4d%4d) ", + Cudd_ReadReorderings(p->ddG), Cudd_ReadGarbageCollections(p->ddG) ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk2 ); + } + + // check timeframe limit + if ( nIters == p->pPars->nIterMax - 1 ) + { + if ( !p->pPars->fSilent ) + printf( "Reached limit on the number of timeframes (%d).\n", p->pPars->nIterMax ); + p->pPars->iFrame = nIters; + Cudd_RecursiveDeref( p->dd, bCurrent ); bCurrent = NULL; + Cudd_RecursiveDeref( p->ddG, bReached ); bReached = NULL; + return -1; + } + } + if ( bReached == NULL ) + { + p->pPars->iFrame = nIters - 1; + return 0; // reachable + } + if ( bCurrent ) + Cudd_RecursiveDeref( p->dd, bCurrent ); + // report the stats + if ( p->pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->ddG, bReached, Saig_ManRegNum(p->pAig) ); + if ( nIters >= p->pPars->nIterMax ) + fprintf( stdout, "Reachability analysis is stopped after %d frames.\n", nIters ); + else + fprintf( stdout, "Reachability analysis completed after %d frames.\n", nIters ); + fprintf( stdout, "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } + if ( p->pPars->fDumpReached ) + { + Llb_ManDumpReached( p->ddG, bReached, p->pAig->pName, "reached.blif" ); + printf( "Reached states with %d BDD nodes are dumpted into file \"reached.blif\".\n", Cudd_DagSize(bReached) ); + } + Cudd_RecursiveDeref( p->ddG, bReached ); + if ( nIters >= p->pPars->nIterMax ) + { + if ( !p->pPars->fSilent ) + { + printf( "Verified only for states reachable in %d frames. ", nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = p->pPars->nIterMax; + return -1; // undecided + } + if ( !p->pPars->fSilent ) + { + printf( "The miter is proved unreachable after %d iterations. ", nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = nIters - 1; + return 1; // unreachable +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_CoreReachability( Llb_Img_t * p ) +{ + Vec_Ptr_t * vSupps, * vQuant0, * vQuant1; + int RetValue; + // get supports and quantified variables + if ( p->pPars->fBackward ) + { + Vec_PtrReverseOrder( p->vDdMans ); + vSupps = Llb_ImgSupports( p->pAig, p->vDdMans, p->vVarsNs, p->vVarsCs, 0, p->pPars->fVeryVerbose ); + } + else + vSupps = Llb_ImgSupports( p->pAig, p->vDdMans, p->vVarsCs, p->vVarsNs, 0, p->pPars->fVeryVerbose ); + Llb_ImgSchedule( vSupps, &vQuant0, &vQuant1, p->pPars->fVeryVerbose ); + Vec_VecFree( (Vec_Vec_t *)vSupps ); + // remove variables + Llb_ImgQuantifyFirst( p->pAig, p->vDdMans, vQuant0, p->pPars->fVeryVerbose ); + // perform reachability + RetValue = Llb_CoreReachability_int( p, vQuant0, vQuant1 ); + Vec_VecFree( (Vec_Vec_t *)vQuant0 ); + Vec_VecFree( (Vec_Vec_t *)vQuant1 ); + return RetValue; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_CoreConstructAll( Aig_Man_t * p, Vec_Ptr_t * vResult, Vec_Int_t * vVarsNs, abctime TimeTarget ) +{ + DdManager * dd; + Vec_Ptr_t * vDdMans; + Vec_Ptr_t * vLower, * vUpper = NULL; + int i; + vDdMans = Vec_PtrStart( Vec_PtrSize(vResult) ); + Vec_PtrForEachEntryReverse( Vec_Ptr_t *, vResult, vLower, i ) + { + if ( i < Vec_PtrSize(vResult) - 1 ) + dd = Llb_ImgPartition( p, vLower, vUpper, TimeTarget ); + else + dd = Llb_DriverLastPartition( p, vVarsNs, TimeTarget ); + if ( dd == NULL ) + { + Vec_PtrForEachEntry( DdManager *, vDdMans, dd, i ) + { + if ( dd == NULL ) + continue; + if ( dd->bFunc ) + Cudd_RecursiveDeref( dd, dd->bFunc ); + Extra_StopManager( dd ); + } + Vec_PtrFree( vDdMans ); + return NULL; + } + Vec_PtrWriteEntry( vDdMans, i, dd ); + vUpper = vLower; + } + return vDdMans; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_CoreSetVarMaps( Llb_Img_t * p ) +{ + Aig_Obj_t * pObj; + int i, iVarCs, iVarNs; + assert( p->vVarsCs != NULL ); + assert( p->vVarsNs != NULL ); + assert( p->vCs2Glo == NULL ); + assert( p->vNs2Glo == NULL ); + assert( p->vGlo2Cs == NULL ); + assert( p->vGlo2Ns == NULL ); + p->vCs2Glo = Vec_IntStartFull( Aig_ManObjNumMax(p->pAig) ); + p->vNs2Glo = Vec_IntStartFull( Aig_ManObjNumMax(p->pAig) ); + p->vGlo2Cs = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + p->vGlo2Ns = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + for ( i = 0; i < Aig_ManRegNum(p->pAig); i++ ) + { + iVarCs = Vec_IntEntry( p->vVarsCs, i ); + iVarNs = Vec_IntEntry( p->vVarsNs, i ); + assert( iVarCs >= 0 && iVarCs < Aig_ManObjNumMax(p->pAig) ); + assert( iVarNs >= 0 && iVarNs < Aig_ManObjNumMax(p->pAig) ); + Vec_IntWriteEntry( p->vCs2Glo, iVarCs, i ); + Vec_IntWriteEntry( p->vNs2Glo, iVarNs, i ); + Vec_IntWriteEntry( p->vGlo2Cs, i, iVarCs ); + Vec_IntWriteEntry( p->vGlo2Ns, i, iVarNs ); + } + // add mapping of the PIs + Saig_ManForEachPi( p->pAig, pObj, i ) + Vec_IntWriteEntry( p->vCs2Glo, Aig_ObjId(pObj), Aig_ManRegNum(p->pAig)+i ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Img_t * Llb_CoreStart( Aig_Man_t * pInit, Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Img_t * p; + p = ABC_CALLOC( Llb_Img_t, 1 ); + p->pInit = pInit; + p->pAig = pAig; + p->pPars = pPars; + p->dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + p->ddG = Cudd_Init( Aig_ManRegNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + p->ddR = Cudd_Init( Aig_ManCiNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddG, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddR, CUDD_REORDER_SYMM_SIFT ); + p->vRings = Vec_PtrAlloc( 100 ); + p->vDriRefs = Llb_DriverCountRefs( pAig ); + p->vVarsCs = Llb_DriverCollectCs( pAig ); + p->vVarsNs = Llb_DriverCollectNs( pAig, p->vDriRefs ); + Llb_CoreSetVarMaps( p ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_CoreStop( Llb_Img_t * p ) +{ + DdManager * dd; + DdNode * bTemp; + int i; + if ( p->vDdMans ) + Vec_PtrForEachEntry( DdManager *, p->vDdMans, dd, i ) + { + if ( dd->bFunc ) + Cudd_RecursiveDeref( dd, dd->bFunc ); + if ( dd->bFunc2 ) + Cudd_RecursiveDeref( dd, dd->bFunc2 ); + Extra_StopManager( dd ); + } + Vec_PtrFreeP( &p->vDdMans ); + if ( p->ddR->bFunc ) + Cudd_RecursiveDeref( p->ddR, p->ddR->bFunc ); + Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i ) + Cudd_RecursiveDeref( p->ddR, bTemp ); + Vec_PtrFree( p->vRings ); + Extra_StopManager( p->dd ); + Extra_StopManager( p->ddG ); + Extra_StopManager( p->ddR ); + Vec_IntFreeP( &p->vDriRefs ); + Vec_IntFreeP( &p->vVarsCs ); + Vec_IntFreeP( &p->vVarsNs ); + Vec_IntFreeP( &p->vCs2Glo ); + Vec_IntFreeP( &p->vNs2Glo ); + Vec_IntFreeP( &p->vGlo2Cs ); + Vec_IntFreeP( &p->vGlo2Ns ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_CoreExperiment( Aig_Man_t * pInit, Aig_Man_t * pAig, Gia_ParLlb_t * pPars, Vec_Ptr_t * vResult, abctime TimeTarget ) +{ + int RetValue; + Llb_Img_t * p; +// printf( "\n" ); +// pPars->fVerbose = 1; + p = Llb_CoreStart( pInit, pAig, pPars ); + p->vDdMans = Llb_CoreConstructAll( pAig, vResult, p->vVarsNs, TimeTarget ); + if ( p->vDdMans == NULL ) + { + if ( !pPars->fSilent ) + printf( "Reached timeout (%d seconds) while deriving the partitions.\n", pPars->TimeLimit ); + Llb_CoreStop( p ); + return -1; + } + RetValue = Llb_CoreReachability( p ); + Llb_CoreStop( p ); + return RetValue; +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManReachMinCut( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + extern Vec_Ptr_t * Llb_ManComputeCuts( Aig_Man_t * p, int Num, int fVerbose, int fVeryVerbose ); + Vec_Ptr_t * vResult; + Aig_Man_t * p; + int RetValue = -1; + abctime clk = Abc_Clock(); + + // compute time to stop + pPars->TimeTarget = pPars->TimeLimit ? pPars->TimeLimit * CLOCKS_PER_SEC + Abc_Clock(): 0; + + p = Aig_ManDupFlopsOnly( pAig ); +//Aig_ManShow( p, 0, NULL ); + if ( pPars->fVerbose ) + Aig_ManPrintStats( pAig ); + if ( pPars->fVerbose ) + Aig_ManPrintStats( p ); + Aig_ManFanoutStart( p ); + + vResult = Llb_ManComputeCuts( p, pPars->nPartValue, pPars->fVerbose, pPars->fVeryVerbose ); + + if ( pPars->TimeLimit && Abc_Clock() > pPars->TimeTarget ) + { + if ( !pPars->fSilent ) + printf( "Reached timeout (%d seconds) after partitioning.\n", pPars->TimeLimit ); + + Vec_VecFree( (Vec_Vec_t *)vResult ); + Aig_ManFanoutStop( p ); + Aig_ManCleanMarkAB( p ); + Aig_ManStop( p ); + return RetValue; + } + + if ( !pPars->fSkipReach ) + RetValue = Llb_CoreExperiment( pAig, p, pPars, vResult, pPars->TimeTarget ); + + Vec_VecFree( (Vec_Vec_t *)vResult ); + Aig_ManFanoutStop( p ); + Aig_ManCleanMarkAB( p ); + Aig_ManStop( p ); + + if ( RetValue == -1 ) + Abc_PrintTime( 1, "Total runtime of the min-cut-based reachability engine", Abc_Clock() - clk ); + return RetValue; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Driver.c b/src/bdd/llb/llb2Driver.c new file mode 100644 index 00000000..1471f377 --- /dev/null +++ b/src/bdd/llb/llb2Driver.c @@ -0,0 +1,222 @@ +/**CFile**************************************************************** + + FileName [llb2Driver.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Procedures working with flop drivers.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Driver.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +// driver issue:arises when creating +// - driver ref-counter array +// - Ns2Glo maps +// - final partition +// - change-phase cube + +// LI variable is used when +// - driver drives more than one LI +// - driver is a PI +// - driver is a constant + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns the array of times each flop driver is referenced.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_DriverCountRefs( Aig_Man_t * p ) +{ + Vec_Int_t * vCounts; + Aig_Obj_t * pObj; + int i; + vCounts = Vec_IntStart( Aig_ManObjNumMax(p) ); + Saig_ManForEachLi( p, pObj, i ) + Vec_IntAddToEntry( vCounts, Aig_ObjFaninId0(pObj), 1 ); + return vCounts; +} + +/**Function************************************************************* + + Synopsis [Returns array of NS variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_DriverCollectNs( Aig_Man_t * pAig, Vec_Int_t * vDriRefs ) +{ + Vec_Int_t * vVars; + Aig_Obj_t * pObj, * pDri; + int i; + vVars = Vec_IntAlloc( Aig_ManRegNum(pAig) ); + Saig_ManForEachLi( pAig, pObj, i ) + { + pDri = Aig_ObjFanin0(pObj); + if ( Vec_IntEntry( vDriRefs, Aig_ObjId(pDri) ) != 1 || Saig_ObjIsPi(pAig, pDri) || Aig_ObjIsConst1(pDri) ) + Vec_IntPush( vVars, Aig_ObjId(pObj) ); + else + Vec_IntPush( vVars, Aig_ObjId(pDri) ); + } + return vVars; +} + +/**Function************************************************************* + + Synopsis [Returns array of CS variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_DriverCollectCs( Aig_Man_t * pAig ) +{ + Vec_Int_t * vVars; + Aig_Obj_t * pObj; + int i; + vVars = Vec_IntAlloc( Aig_ManRegNum(pAig) ); + Saig_ManForEachLo( pAig, pObj, i ) + Vec_IntPush( vVars, Aig_ObjId(pObj) ); + return vVars; +} + +/**Function************************************************************* + + Synopsis [Create cube for phase swapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_DriverPhaseCube( Aig_Man_t * pAig, Vec_Int_t * vDriRefs, DdManager * dd ) +{ + DdNode * bCube, * bVar, * bTemp; + Aig_Obj_t * pObj; + int i; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bCube = Cudd_ReadOne( dd ); Cudd_Ref( bCube ); + Saig_ManForEachLi( pAig, pObj, i ) + { + assert( Vec_IntEntry( vDriRefs, Aig_ObjFaninId0(pObj) ) >= 1 ); + if ( Vec_IntEntry( vDriRefs, Aig_ObjFaninId0(pObj) ) != 1 ) + continue; + if ( !Aig_ObjFaninC0(pObj) ) + continue; + bVar = Cudd_bddIthVar( dd, Aig_ObjFaninId0(pObj) ); + bCube = Cudd_bddAnd( dd, bTemp = bCube, bVar ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bCube ); + dd->TimeStop = TimeStop; + return bCube; +} + +/**Function************************************************************* + + Synopsis [Compute the last partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb_DriverLastPartition( Aig_Man_t * p, Vec_Int_t * vVarsNs, abctime TimeTarget ) +{ +// int fVerbose = 1; + DdManager * dd; + DdNode * bVar1, * bVar2, * bProd, * bRes, * bTemp; + Aig_Obj_t * pObj; + int i; + dd = Cudd_Init( Aig_ManObjNumMax(p), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + dd->TimeStop = TimeTarget; + bRes = Cudd_ReadOne(dd); Cudd_Ref( bRes ); + + // mark the duplicated flop inputs + Aig_ManForEachObjVec( vVarsNs, p, pObj, i ) + { + if ( !Saig_ObjIsLi(p, pObj) ) + continue; + bVar1 = Cudd_bddIthVar( dd, Aig_ObjId(pObj) ); + bVar2 = Cudd_bddIthVar( dd, Aig_ObjFaninId0(pObj) ); + if ( Aig_ObjIsConst1(Aig_ObjFanin0(pObj)) ) + bVar2 = Cudd_ReadOne(dd); + bVar2 = Cudd_NotCond( bVar2, Aig_ObjFaninC0(pObj) ); + bProd = Cudd_bddXnor( dd, bVar1, bVar2 ); Cudd_Ref( bProd ); +// bRes = Cudd_bddAnd( dd, bTemp = bRes, bProd ); Cudd_Ref( bRes ); +// bRes = Extra_bddAndTime( dd, bTemp = bRes, bProd, TimeTarget ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, bProd ); + if ( bRes == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + return NULL; + } + Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + } + +/* + Saig_ManForEachLi( p, pObj, i ) + printf( "%d ", Aig_ObjId(pObj) ); + printf( "\n" ); + Saig_ManForEachLi( p, pObj, i ) + printf( "%c%d ", Aig_ObjFaninC0(pObj)? '-':'+', Aig_ObjFaninId0(pObj) ); + printf( "\n" ); +*/ + Cudd_AutodynDisable( dd ); +// Cudd_RecursiveDeref( dd, bRes ); +// Extra_StopManager( dd ); + dd->bFunc = bRes; + dd->TimeStop = 0; + return dd; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Dump.c b/src/bdd/llb/llb2Dump.c new file mode 100644 index 00000000..74f07922 --- /dev/null +++ b/src/bdd/llb/llb2Dump.c @@ -0,0 +1,104 @@ +/**CFile**************************************************************** + + FileName [llb2Dump.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Dumps the BDD of reached states into a file.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Dump.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns a dummy name.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +char * Llb_ManGetDummyName( char * pPrefix, int Num, int nDigits ) +{ + static char Buffer[2000]; + sprintf( Buffer, "%s%0*d", pPrefix, nDigits, Num ); + return Buffer; +} + +/**Function************************************************************* + + Synopsis [Writes reached state BDD into a BLIF file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManDumpReached( DdManager * ddG, DdNode * bReached, char * pModel, char * pFileName ) +{ + FILE * pFile; + Vec_Ptr_t * vNamesIn, * vNamesOut; + char * pName; + int i, nDigits; + // reorder the BDD + Cudd_ReduceHeap( ddG, CUDD_REORDER_SYMM_SIFT, 1 ); + + // create input names + nDigits = Abc_Base10Log( Cudd_ReadSize(ddG) ); + vNamesIn = Vec_PtrAlloc( Cudd_ReadSize(ddG) ); + for ( i = 0; i < Cudd_ReadSize(ddG); i++ ) + { + pName = Llb_ManGetDummyName( "ff", i, nDigits ); + Vec_PtrPush( vNamesIn, Extra_UtilStrsav(pName) ); + } + // create output names + vNamesOut = Vec_PtrAlloc( 1 ); + Vec_PtrPush( vNamesOut, Extra_UtilStrsav("Reached") ); + + // write the file + pFile = fopen( pFileName, "wb" ); + Cudd_DumpBlif( ddG, 1, &bReached, (char **)Vec_PtrArray(vNamesIn), (char **)Vec_PtrArray(vNamesOut), pModel, pFile, 0 ); + fclose( pFile ); + + // cleanup + Vec_PtrForEachEntry( char *, vNamesIn, pName, i ) + ABC_FREE( pName ); + Vec_PtrForEachEntry( char *, vNamesOut, pName, i ) + ABC_FREE( pName ); + Vec_PtrFree( vNamesIn ); + Vec_PtrFree( vNamesOut ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Flow.c b/src/bdd/llb/llb2Flow.c new file mode 100644 index 00000000..64db32b3 --- /dev/null +++ b/src/bdd/llb/llb2Flow.c @@ -0,0 +1,1376 @@ +/**CFile**************************************************************** + + FileName [llb2Flow.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Flow computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Flow.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline int Llb_ObjSetPath( Aig_Obj_t * pObj, Aig_Obj_t * pNext ) { pObj->pData = (void *)pNext; return 1; } +static inline Aig_Obj_t * Llb_ObjGetPath( Aig_Obj_t * pObj ) { return (Aig_Obj_t *)pObj->pData; } +static inline Aig_Obj_t * Llb_ObjGetFanoutPath( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + Aig_Obj_t * pFanout; + int i, iFanout = -1; + assert( Llb_ObjGetPath(pObj) ); + Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, i ) + if ( Llb_ObjGetPath(pFanout) == pObj ) + return pFanout; + return NULL; +} + +extern Vec_Ptr_t * Llb_ManCutSupp( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + + +/**Function************************************************************* + + Synopsis [For each cut, returns PIs that can be quantified.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManCutSupps( Aig_Man_t * p, Vec_Ptr_t * vResult ) +{ + Vec_Ptr_t * vSupps, * vOne, * vLower, * vUpper; + int i; + vSupps = Vec_PtrAlloc( 100 ); + Vec_PtrPush( vSupps, Vec_PtrAlloc(0) ); + vLower = (Vec_Ptr_t *)Vec_PtrEntry( vResult, 0 ); + Vec_PtrForEachEntryStart( Vec_Ptr_t *, vResult, vUpper, i, 1 ) + { + vOne = Llb_ManCutSupp( p, vLower, vUpper ); + Vec_PtrPush( vSupps, vOne ); + vLower = vUpper; + } + assert( Vec_PtrSize(vSupps) == Vec_PtrSize(vResult) ); + return vSupps; +} + +/**Function************************************************************* + + Synopsis [For each cut, returns PIs that can be quantified.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManCutMap( Aig_Man_t * p, Vec_Ptr_t * vResult, Vec_Ptr_t * vSupps ) +{ + int fShowMatrix = 1; + Vec_Ptr_t * vMaps, * vOne; + Vec_Int_t * vMap, * vPrev, * vNext; + Aig_Obj_t * pObj; + int * piFirst, * piLast; + int i, k, CounterPlus, CounterMinus, Counter; + + vMaps = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Vec_Ptr_t *, vResult, vOne, i ) + { + vMap = Vec_IntStart( Aig_ManObjNumMax(p) ); + Vec_PtrForEachEntry( Aig_Obj_t *, vOne, pObj, k ) + { + if ( !Saig_ObjIsPi(p, pObj) ) + Vec_IntWriteEntry( vMap, pObj->Id, 1 ); +// else +//printf( "*" ); +//printf( "%d ", pObj->Id ); + } + Vec_PtrPush( vMaps, vMap ); +//printf( "\n" ); + } + Vec_PtrPush( vMaps, Vec_IntStart( Aig_ManObjNumMax(p) ) ); + assert( Vec_PtrSize(vMaps) == Vec_PtrSize(vResult)+1 ); + + // collect the first and last PIs + piFirst = ABC_ALLOC( int, Saig_ManPiNum(p) ); + piLast = ABC_ALLOC( int, Saig_ManPiNum(p) ); + Saig_ManForEachPi( p, pObj, i ) + piFirst[i] = piLast[i] = -1; + Vec_PtrForEachEntry( Vec_Ptr_t *, vSupps, vOne, i ) + { + Vec_PtrForEachEntry( Aig_Obj_t *, vOne, pObj, k ) + { + if ( !Saig_ObjIsPi(p, pObj) ) + continue; + if ( piFirst[Aig_ObjCioId(pObj)] == -1 ) + piFirst[Aig_ObjCioId(pObj)] = i; + piLast[Aig_ObjCioId(pObj)] = i; + } + } + // PIs feeding into the flops should be extended to the last frame + Saig_ManForEachLi( p, pObj, i ) + { + if ( !Saig_ObjIsPi(p, Aig_ObjFanin0(pObj)) ) + continue; + piLast[Aig_ObjCioId(Aig_ObjFanin0(pObj))] = Vec_PtrSize(vMaps)-1; + } + + // set the PI map + Saig_ManForEachPi( p, pObj, i ) + { + if ( piFirst[i] == -1 ) + continue; + if ( piFirst[i] == piLast[i] ) + { + vMap = (Vec_Int_t *)Vec_PtrEntry( vMaps, piFirst[i] ); + Vec_IntWriteEntry( vMap, pObj->Id, 2 ); + continue; + } + + // set support for all in between + for ( k = piFirst[i]; k <= piLast[i]; k++ ) + { + vMap = (Vec_Int_t *)Vec_PtrEntry( vMaps, k ); + Vec_IntWriteEntry( vMap, pObj->Id, 1 ); + } + } + ABC_FREE( piFirst ); + ABC_FREE( piLast ); + + + // find all that will appear here + Counter = Aig_ManRegNum(p); + printf( "%d ", Counter ); + Vec_PtrForEachEntryStart( Vec_Int_t *, vMaps, vMap, i, 1 ) + { + vPrev = (Vec_Int_t *)Vec_PtrEntry( vMaps, i-1 ); + vNext = (i == Vec_PtrSize(vMaps)-1)? NULL: (Vec_Int_t *)Vec_PtrEntry( vMaps, i+1 ); + + CounterPlus = CounterMinus = 0; + Aig_ManForEachObj( p, pObj, k ) + { + if ( Saig_ObjIsPi(p, pObj) ) + { + if ( Vec_IntEntry(vPrev, k) == 0 && Vec_IntEntry(vMap, k) == 1 ) + CounterPlus++; + if ( Vec_IntEntry(vMap, k) == 1 && (vNext == NULL || Vec_IntEntry(vNext, k) == 0) ) + CounterMinus++; + } + else + { + if ( Vec_IntEntry(vPrev, k) == 0 && Vec_IntEntry(vMap, k) == 1 ) + CounterPlus++; + if ( Vec_IntEntry(vPrev, k) == 1 && Vec_IntEntry(vMap, k) == 0 ) + CounterMinus++; + } + } + Counter = Counter + CounterPlus - CounterMinus; + printf( "%d=%d ", i, Counter ); + } + printf( "\n" ); + + if ( !fShowMatrix ) + return vMaps; + Aig_ManForEachObj( p, pObj, i ) + { + if ( !Aig_ObjIsCi(pObj) && !Aig_ObjIsNode(pObj) ) + continue; + Vec_PtrForEachEntry( Vec_Int_t *, vMaps, vMap, k ) + if ( Vec_IntEntry(vMap, i) ) + break; + if ( k == Vec_PtrSize(vMaps) ) + continue; + printf( "Obj = %4d : ", i ); + if ( Saig_ObjIsPi(p,pObj) ) + printf( "pi " ); + else if ( Saig_ObjIsLo(p,pObj) ) + printf( "lo " ); + else if ( Aig_ObjIsNode(pObj) ) + printf( "and " ); + + Vec_PtrForEachEntry( Vec_Int_t *, vMaps, vMap, k ) + printf( "%d", Vec_IntEntry(vMap, i) ); + printf( "\n" ); + } + return vMaps; +} + +/**Function************************************************************* + + Synopsis [Counts the number of PIs in the cut] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCutPiNum( Aig_Man_t * p, Vec_Ptr_t * vMinCut ) +{ + Aig_Obj_t * pObj; + int i, Counter = 0; + Vec_PtrForEachEntry( Aig_Obj_t *, vMinCut, pObj, i ) + if ( Saig_ObjIsPi(p,pObj) ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Counts the number of LOs in the cut] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCutLoNum( Aig_Man_t * p, Vec_Ptr_t * vMinCut ) +{ + Aig_Obj_t * pObj; + int i, Counter = 0; + Vec_PtrForEachEntry( Aig_Obj_t *, vMinCut, pObj, i ) + if ( Saig_ObjIsLo(p,pObj) ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Counts the number of LIs in the cut] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCutLiNum( Aig_Man_t * p, Vec_Ptr_t * vMinCut ) +{ + Aig_Obj_t * pFanout; + Aig_Obj_t * pObj; + int i, k, iFanout = -1, Counter = 0; + Vec_PtrForEachEntry( Aig_Obj_t *, vMinCut, pObj, i ) + { + if ( Aig_ObjIsCi(pObj) ) + continue; + Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, k ) + { + if ( Saig_ObjIsLi(p, pFanout) ) + { + Counter++; + break; + } + } + } + return Counter; +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCutVolume_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return 0; + Aig_ObjSetTravIdCurrent(p, pObj); + assert( Aig_ObjIsNode(pObj) ); + return 1 + Llb_ManCutVolume_rec(p, Aig_ObjFanin0(pObj)) + + Llb_ManCutVolume_rec(p, Aig_ObjFanin1(pObj)); +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManCutVolume( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Aig_Obj_t * pObj; + int i, Counter = 0; + // mark the lower cut with the traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // count the upper cut + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + Counter += Llb_ManCutVolume_rec( p, pObj ); + return Counter; +} + + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManCutNodes_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return; + Aig_ObjSetTravIdCurrent(p, pObj); + assert( Aig_ObjIsNode(pObj) ); + Llb_ManCutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); + Llb_ManCutNodes_rec(p, Aig_ObjFanin1(pObj), vNodes); + Vec_PtrPush( vNodes, pObj ); +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManCutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vNodes; + Aig_Obj_t * pObj; + int i; + // mark the lower cut with the traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // count the upper cut + vNodes = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + Llb_ManCutNodes_rec( p, pObj, vNodes ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManCutSupp( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vNodes, * vSupp; + Aig_Obj_t * pObj; + int i; + vNodes = Llb_ManCutNodes( p, vLower, vUpper ); + // mark support of the nodes + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + assert( Aig_ObjIsNode(pObj) ); + Aig_ObjSetTravIdCurrent( p, Aig_ObjFanin0(pObj) ); + Aig_ObjSetTravIdCurrent( p, Aig_ObjFanin1(pObj) ); + } + Vec_PtrFree( vNodes ); + // collect the support nodes + vSupp = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + Vec_PtrPush( vSupp, pObj ); + return vSupp; + +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManCutRange( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vRange; + Aig_Obj_t * pObj; + int i; + // mark the lower cut with the traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // collect the upper ones that are not marked + vRange = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + if ( !Aig_ObjIsTravIdCurrent(p, pObj) ) + Vec_PtrPush( vRange, pObj ); + return vRange; +} + + + + +/**Function************************************************************* + + Synopsis [Prints the given cluster.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManCutPrint( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vSupp, * vRange; + int Pis, Ffs, And; + + Pis = Llb_ManCutPiNum(p, vLower); + Ffs = Llb_ManCutLoNum(p, vLower); + And = Vec_PtrSize(vLower) - Pis - Ffs; + printf( "Leaf: %3d=%3d+%3d+%3d ", Vec_PtrSize(vLower), Pis, Ffs, And ); + + Pis = Llb_ManCutPiNum(p, vUpper); + Ffs = Llb_ManCutLiNum(p, vUpper); + And = Vec_PtrSize(vUpper) - Pis - Ffs; + printf( "Root: %3d=%3d+%3d+%3d ", Vec_PtrSize(vUpper), Pis, Ffs, And ); + + vSupp = Llb_ManCutSupp( p, vLower, vUpper ); + Pis = Llb_ManCutPiNum(p, vSupp); + Ffs = Llb_ManCutLoNum(p, vSupp); + And = Vec_PtrSize(vSupp) - Pis - Ffs; + printf( "Supp: %3d=%3d+%3d+%3d ", Vec_PtrSize(vSupp), Pis, Ffs, And ); + + vRange = Llb_ManCutRange( p, vLower, vUpper ); + Pis = Llb_ManCutPiNum(p, vRange); + Ffs = Llb_ManCutLiNum(p, vRange); + And = Vec_PtrSize(vRange) - Pis - Ffs; + printf( "Range: %3d=%3d+%3d+%3d ", Vec_PtrSize(vRange), Pis, Ffs, And ); + + printf( "S =%3d. V =%3d.\n", + Vec_PtrSize(vSupp)+Vec_PtrSize(vRange), Llb_ManCutVolume(p, vLower, vUpper) ); + Vec_PtrFree( vSupp ); + Vec_PtrFree( vRange ); +/* + { + Aig_Obj_t * pObj; + int i; + printf( "Lower: " ); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + printf( " %d", pObj->Id ); + printf( " " ); + printf( "Upper: " ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + printf( " %d", pObj->Id ); + printf( "\n" ); + } +*/ +} + +/**Function************************************************************* + + Synopsis [Prints the given cluster.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManResultPrint( Aig_Man_t * p, Vec_Ptr_t * vResult ) +{ + Vec_Ptr_t * vLower, * vUpper = NULL; + int i; + Vec_PtrForEachEntryReverse( Vec_Ptr_t *, vResult, vLower, i ) + { + if ( i < Vec_PtrSize(vResult) - 1 ) + Llb_ManCutPrint( p, vLower, vUpper ); + vUpper = vLower; + } +} + +/**Function************************************************************* + + Synopsis [Tries to find an augmenting path originating in this node.] + + Description [This procedure works for directed graphs only!] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManFlowBwdPath2_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + Aig_Obj_t * pFanout; + assert( Aig_ObjIsNode(pObj) || Aig_ObjIsCi(pObj) || Aig_ObjIsConst1(pObj) ); + // skip visited nodes + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return 0; + Aig_ObjSetTravIdCurrent(p, pObj); + // process node without flow + if ( !Llb_ObjGetPath(pObj) ) + { + // start the path if we reached a terminal node + if ( pObj->fMarkA ) + return Llb_ObjSetPath( pObj, (Aig_Obj_t *)1 ); + // explore the fanins +// Abc_ObjForEachFanin( pObj, pFanin, i ) +// if ( Abc_NtkMaxFlowBwdPath2_rec(pFanin) ) +// return Abc_ObjSetPath( pObj, pFanin ); + if ( Aig_ObjIsNode(pObj) ) + { + if ( Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pObj) ) ) + return Llb_ObjSetPath( pObj, Aig_ObjFanin0(pObj) ); + if ( Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pObj) ) ) + return Llb_ObjSetPath( pObj, Aig_ObjFanin1(pObj) ); + } + return 0; + } + // pObj has flow - find the fanout with flow + pFanout = Llb_ObjGetFanoutPath( p, pObj ); + if ( pFanout == NULL ) + return 0; + // go through the fanins of the fanout with flow +// Abc_ObjForEachFanin( pFanout, pFanin, i ) +// if ( Abc_NtkMaxFlowBwdPath2_rec( pFanin ) ) +// return Abc_ObjSetPath( pFanout, pFanin ); + assert( Aig_ObjIsNode(pFanout) ); + if ( Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pFanout) ) ) + return Llb_ObjSetPath( pFanout, Aig_ObjFanin0(pFanout) ); + if ( Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pFanout) ) ) + return Llb_ObjSetPath( pFanout, Aig_ObjFanin1(pFanout) ); + // try the fanout + if ( Llb_ManFlowBwdPath2_rec( p, pFanout ) ) + return Llb_ObjSetPath( pFanout, NULL ); + return 0; +} + + +/**Function************************************************************* + + Synopsis [Cleans markB.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowLabelTfi_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return; + Aig_ObjSetTravIdCurrent(p, pObj); + if ( Aig_ObjIsCi(pObj) || Aig_ObjIsConst1(pObj) ) + return; + assert( Aig_ObjIsNode(pObj) ); + Llb_ManFlowLabelTfi_rec( p, Aig_ObjFanin0(pObj) ); + Llb_ManFlowLabelTfi_rec( p, Aig_ObjFanin1(pObj) ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowUpdateCut( Aig_Man_t * p, Vec_Ptr_t * vMinCut ) +{ + Aig_Obj_t * pObj; + int i; + // label the TFI of the cut nodes + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vMinCut, pObj, i ) + Llb_ManFlowLabelTfi_rec( p, pObj ); + // collect labeled fanins of non-labeled nodes + Vec_PtrClear( vMinCut ); + Aig_ManIncrementTravId(p); + Aig_ManForEachObj( p, pObj, i ) + { + if ( !Aig_ObjIsCo(pObj) && !Aig_ObjIsNode(pObj) ) + continue; + if ( Aig_ObjIsTravIdCurrent(p, pObj) || Aig_ObjIsTravIdPrevious(p, pObj) ) + continue; + if ( Aig_ObjIsTravIdPrevious(p, Aig_ObjFanin0(pObj)) ) + { + Aig_ObjSetTravIdCurrent(p, Aig_ObjFanin0(pObj)); + Vec_PtrPush( vMinCut, Aig_ObjFanin0(pObj) ); + } + if ( Aig_ObjIsNode(pObj) && Aig_ObjIsTravIdPrevious(p, Aig_ObjFanin1(pObj)) ) + { + Aig_ObjSetTravIdCurrent(p, Aig_ObjFanin1(pObj)); + Vec_PtrPush( vMinCut, Aig_ObjFanin1(pObj) ); + } + } +} + +/**Function************************************************************* + + Synopsis [Find minimum-volume minumum cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManFlowMinCut( Aig_Man_t * p ) +{ + Vec_Ptr_t * vMinCut; + Aig_Obj_t * pObj; + int i; + // collect the cut nodes + vMinCut = Vec_PtrAlloc( Aig_ManRegNum(p) ); + Aig_ManForEachObj( p, pObj, i ) + { + // node without flow is not a cut node + if ( !Llb_ObjGetPath(pObj) ) + continue; + // unvisited node is below the cut + if ( !Aig_ObjIsTravIdCurrent(p, pObj) ) + continue; + // add terminal with flow or node whose path is not visited + if ( pObj->fMarkA || !Aig_ObjIsTravIdCurrent( p, Llb_ObjGetPath(pObj) ) ) + Vec_PtrPush( vMinCut, pObj ); + } + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Verifies the min-cut is indeed a cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManFlowVerifyCut_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) +{ + // skip visited nodes + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return 1; + Aig_ObjSetTravIdCurrent(p, pObj); + // visit the node + if ( Aig_ObjIsConst1(pObj) ) + return 1; + if ( Aig_ObjIsCi(pObj) ) + return 0; + // explore the fanins + assert( Aig_ObjIsNode(pObj) ); + if ( !Llb_ManFlowVerifyCut_rec(p, Aig_ObjFanin0(pObj)) ) + return 0; + if ( !Llb_ManFlowVerifyCut_rec(p, Aig_ObjFanin1(pObj)) ) + return 0; + return 1; +} + +/**Function************************************************************* + + Synopsis [Verifies the min-cut is indeed a cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_ManFlowVerifyCut( Aig_Man_t * p, Vec_Ptr_t * vMinCut ) +{ + Aig_Obj_t * pObj; + int i; + // mark the cut with the current traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vMinCut, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // search from the latches for a path to the COs/CIs + Saig_ManForEachLi( p, pObj, i ) + { + if ( !Llb_ManFlowVerifyCut_rec( p, Aig_ObjFanin0(pObj) ) ) + return 0; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Implementation of max-flow/min-cut computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManFlow( Aig_Man_t * p, Vec_Ptr_t * vSources, int * pnFlow ) +{ + Vec_Ptr_t * vMinCut; + Aig_Obj_t * pObj; + int Flow, FlowCur, RetValue, i; + // find the max-flow + Flow = 0; + Aig_ManCleanData( p ); + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vSources, pObj, i ) + { + assert( !pObj->fMarkA && pObj->fMarkB ); + if ( !Aig_ObjFanin0(pObj)->fMarkB ) + { + FlowCur = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pObj) ); + Flow += FlowCur; + if ( FlowCur ) + Aig_ManIncrementTravId(p); + } + if ( Aig_ObjIsNode(pObj) && !Aig_ObjFanin1(pObj)->fMarkB ) + { + FlowCur = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pObj) ); + Flow += FlowCur; + if ( FlowCur ) + Aig_ManIncrementTravId(p); + } + } + if ( pnFlow ) + *pnFlow = Flow; + + // mark the nodes reachable from the latches + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vSources, pObj, i ) + { + assert( !pObj->fMarkA && pObj->fMarkB ); + if ( !Aig_ObjFanin0(pObj)->fMarkB ) + { + RetValue = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pObj) ); + assert( RetValue == 0 ); + } + if ( Aig_ObjIsNode(pObj) && !Aig_ObjFanin1(pObj)->fMarkB ) + { + RetValue = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pObj) ); + assert( RetValue == 0 ); + } + } + + // find the min-cut with the smallest volume + vMinCut = Llb_ManFlowMinCut( p ); + assert( Vec_PtrSize(vMinCut) == Flow ); + // verify the cut + if ( !Llb_ManFlowVerifyCut(p, vMinCut) ) + printf( "Llb_ManFlow() error! The computed min-cut is not a cut!\n" ); +// Llb_ManFlowPrintCut( p, vMinCut ); + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Implementation of max-flow/min-cut computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManFlowCompute( Aig_Man_t * p ) +{ + Vec_Ptr_t * vMinCut; + Aig_Obj_t * pObj; + int Flow, FlowCur, RetValue, i; + // find the max-flow + Flow = 0; + Aig_ManCleanData( p ); + Aig_ManIncrementTravId(p); + Aig_ManForEachObj( p, pObj, i ) + { + if ( !pObj->fMarkB ) + continue; + assert( !pObj->fMarkA ); + if ( !Aig_ObjFanin0(pObj)->fMarkB ) + { +//printf( "%d ", Aig_ObjFanin0(pObj)->Id ); + FlowCur = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pObj) ); + Flow += FlowCur; + if ( FlowCur ) + Aig_ManIncrementTravId(p); + } + if ( Aig_ObjIsNode(pObj) && !Aig_ObjFanin1(pObj)->fMarkB ) + { +//printf( "%d ", Aig_ObjFanin1(pObj)->Id ); + FlowCur = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pObj) ); + Flow += FlowCur; + if ( FlowCur ) + Aig_ManIncrementTravId(p); + } + } +//printf( "\n" ); + + // mark the nodes reachable from the latches + Aig_ManIncrementTravId(p); + Aig_ManForEachObj( p, pObj, i ) + { + if ( !pObj->fMarkB ) + continue; + assert( !pObj->fMarkA ); + if ( !Aig_ObjFanin0(pObj)->fMarkB ) + { + RetValue = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin0(pObj) ); + assert( RetValue == 0 ); + } + if ( Aig_ObjIsNode(pObj) && !Aig_ObjFanin1(pObj)->fMarkB ) + { + RetValue = Llb_ManFlowBwdPath2_rec( p, Aig_ObjFanin1(pObj) ); + assert( RetValue == 0 ); + } + } + // find the min-cut with the smallest volume + vMinCut = Llb_ManFlowMinCut( p ); + assert( Vec_PtrSize(vMinCut) == Flow ); +//printf( "%d ", Vec_PtrSize(vMinCut) ); + Llb_ManFlowUpdateCut( p, vMinCut ); +//printf( "%d ", Vec_PtrSize(vMinCut) ); + // verify the cut + if ( !Llb_ManFlowVerifyCut(p, vMinCut) ) + printf( "Llb_ManFlow() error! The computed min-cut is not a cut!\n" ); +// Llb_ManFlowPrintCut( p, vMinCut ); + return vMinCut; +} + + + + +/**Function************************************************************* + + Synopsis [Cleans markB.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowCleanMarkB_rec( Aig_Obj_t * pObj ) +{ + if ( pObj->fMarkB == 0 ) + return; + pObj->fMarkB = 0; + assert( Aig_ObjIsNode(pObj) ); + Llb_ManFlowCleanMarkB_rec( Aig_ObjFanin0(pObj) ); + Llb_ManFlowCleanMarkB_rec( Aig_ObjFanin1(pObj) ); +} + +/**Function************************************************************* + + Synopsis [Cleans markB.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowSetMarkA_rec( Aig_Obj_t * pObj ) +{ + if ( pObj->fMarkA ) + return; + pObj->fMarkA = 1; + if ( Aig_ObjIsCi(pObj) || Aig_ObjIsConst1(pObj) ) + return; + assert( Aig_ObjIsNode(pObj) ); + Llb_ManFlowSetMarkA_rec( Aig_ObjFanin0(pObj) ); + Llb_ManFlowSetMarkA_rec( Aig_ObjFanin1(pObj) ); +} + +/**Function************************************************************* + + Synopsis [Prepares flow computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowPrepareCut( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Aig_Obj_t * pObj; + int i; + // reset marks + Aig_ManForEachObj( p, pObj, i ) + { + pObj->fMarkA = 0; + pObj->fMarkB = 1; + } + // clean PIs and const + Aig_ManConst1(p)->fMarkB = 0; + Aig_ManForEachCi( p, pObj, i ) + pObj->fMarkB = 0; + // clean upper cut +//printf( "Upper: "); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + { + Llb_ManFlowCleanMarkB_rec( pObj ); +//printf( "%d ", pObj->Id ); + } +//printf( "\n" ); + // set lower cut +//printf( "Lower: "); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + { +//printf( "%d ", pObj->Id ); + assert( pObj->fMarkB == 0 ); + Llb_ManFlowSetMarkA_rec( pObj ); + } +//printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Prepares flow computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowUnmarkCone( Aig_Man_t * p, Vec_Ptr_t * vCone ) +{ + Aig_Obj_t * pObj; + int i; + Vec_PtrForEachEntry( Aig_Obj_t *, vCone, pObj, i ) + { + assert( Aig_ObjIsNode(pObj) ); + assert( pObj->fMarkB == 1 ); + pObj->fMarkB = 0; + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowCollectAndMarkCone_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vCone ) +{ + Aig_Obj_t * pFanout; + int i, iFanout = -1; + if ( Saig_ObjIsLi(p, pObj) ) + return; + if ( pObj->fMarkB ) + return; + if ( pObj->fMarkA == 0 ) + { + assert( Aig_ObjIsNode(pObj) ); + pObj->fMarkB = 1; + if ( Aig_ObjIsNode(pObj) ) + Vec_PtrPush( vCone, pObj ); + } + Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, i ) + Llb_ManFlowCollectAndMarkCone_rec( p, pFanout, vCone ); +} + +/**Function************************************************************* + + Synopsis [Collects the cone.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowCollectAndMarkCone( Aig_Man_t * p, Vec_Ptr_t * vStarts, Vec_Ptr_t * vCone ) +{ + Aig_Obj_t * pObj; + int i; + Vec_PtrClear( vCone ); + Vec_PtrForEachEntry( Aig_Obj_t *, vStarts, pObj, i ) + { + assert( pObj->fMarkA && !pObj->fMarkB ); + Llb_ManFlowCollectAndMarkCone_rec( p, pObj, vCone ); + } +} + + + + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManComputeCutLo( Aig_Man_t * p ) +{ + Vec_Ptr_t * vMinCut; + Aig_Obj_t * pObj; + int i; + vMinCut = Vec_PtrAlloc( 100 ); + Aig_ManForEachCi( p, pObj, i ) + Vec_PtrPush( vMinCut, pObj ); + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManComputeCutLi( Aig_Man_t * p ) +{ + Vec_Ptr_t * vMinCut; + Aig_Obj_t * pObj; + int i; + assert( Saig_ManPoNum(p) == 0 ); + vMinCut = Vec_PtrAlloc( 100 ); + Aig_ManIncrementTravId(p); + Saig_ManForEachLi( p, pObj, i ) + { + pObj = Aig_ObjFanin0(pObj); + if ( Aig_ObjIsConst1(pObj) ) + continue; + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + continue; + Aig_ObjSetTravIdCurrent(p, pObj); + Vec_PtrPush( vMinCut, pObj ); + } + return vMinCut; +} + + + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManFlowGetObjSet( Aig_Man_t * p, Vec_Ptr_t * vLower, int iStart, int nSize, Vec_Ptr_t * vSet ) +{ + Aig_Obj_t * pObj; + int i; + Vec_PtrClear( vSet ); + for ( i = 0; i < nSize; i++ ) + { + pObj = (Aig_Obj_t *)Vec_PtrEntry( vLower, (iStart + i) % Vec_PtrSize(vLower) ); + Vec_PtrPush( vSet, pObj ); + } +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManFlowFindBestCut( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, int Num ) +{ + int nVolMin = Aig_ManNodeNum(p) / Num / 2; + Vec_Ptr_t * vMinCut; + Vec_Ptr_t * vCone, * vSet; + Aig_Obj_t * pObj; + int i, s, Vol, VolLower, VolUpper, VolCmp; + int iBest = -1, iMinCut = ABC_INFINITY, iVolBest = 0; + + Vol = Llb_ManCutVolume( p, vLower, vUpper ); + assert( Vol > nVolMin ); + VolCmp = Abc_MinInt( nVolMin, Vol - nVolMin ); + vCone = Vec_PtrAlloc( 100 ); + vSet = Vec_PtrAlloc( 100 ); + Llb_ManFlowPrepareCut( p, vLower, vUpper ); + for ( s = 1; s < Aig_ManRegNum(p); s += 5 ) + { + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + { + Llb_ManFlowGetObjSet( p, vLower, i, s, vSet ); + Llb_ManFlowCollectAndMarkCone( p, vSet, vCone ); + if ( Vec_PtrSize(vCone) == 0 ) + continue; + vMinCut = Llb_ManFlowCompute( p ); + Llb_ManFlowUnmarkCone( p, vCone ); + + VolLower = Llb_ManCutVolume( p, vLower, vMinCut ); + VolUpper = Llb_ManCutVolume( p, vMinCut, vUpper ); + Vol = Abc_MinInt( VolLower, VolUpper ); + if ( Vol >= VolCmp && (iMinCut == -1 || + iMinCut > Vec_PtrSize(vMinCut) || + (iMinCut == Vec_PtrSize(vMinCut) && iVolBest < Vol)) ) + { + iBest = i; + iMinCut = Vec_PtrSize(vMinCut); + iVolBest = Vol; + } + Vec_PtrFree( vMinCut ); + } + if ( iBest >= 0 ) + break; + } + if ( iBest == -1 ) + { + // cleanup + Vec_PtrFree( vCone ); + Vec_PtrFree( vSet ); + return NULL; + } + // get the best cut + assert( iBest >= 0 ); + Llb_ManFlowGetObjSet( p, vLower, iBest, s, vSet ); + Llb_ManFlowCollectAndMarkCone( p, vSet, vCone ); + vMinCut = Llb_ManFlowCompute( p ); + Llb_ManFlowUnmarkCone( p, vCone ); + // cleanup + Vec_PtrFree( vCone ); + Vec_PtrFree( vSet ); + return vMinCut; +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ManComputeCuts( Aig_Man_t * p, int Num, int fVerbose, int fVeryVerbose ) +{ + int nVolMax = Aig_ManNodeNum(p) / Num; + Vec_Ptr_t * vResult, * vMinCut = NULL, * vLower, * vUpper; + int i, k, nVol; + abctime clk = Abc_Clock(); + vResult = Vec_PtrAlloc( 100 ); + Vec_PtrPush( vResult, Llb_ManComputeCutLo(p) ); + Vec_PtrPush( vResult, Llb_ManComputeCutLi(p) ); + while ( 1 ) + { + // find a place to insert new cut + vLower = (Vec_Ptr_t *)Vec_PtrEntry( vResult, 0 ); + Vec_PtrForEachEntryStart( Vec_Ptr_t *, vResult, vUpper, i, 1 ) + { + nVol = Llb_ManCutVolume( p, vLower, vUpper ); + if ( nVol <= nVolMax ) + { + vLower = vUpper; + continue; + } + + if ( fVeryVerbose ) + Llb_ManCutPrint( p, vLower, vUpper ); + vMinCut = Llb_ManFlowFindBestCut( p, vLower, vUpper, Num ); + if ( vMinCut == NULL ) + { + if ( fVeryVerbose ) + printf( "Could not break the cut.\n" ); + if ( fVeryVerbose ) + printf( "\n" ); + vLower = vUpper; + continue; + } + + if ( fVeryVerbose ) + Llb_ManCutPrint( p, vMinCut, vUpper ); + if ( fVeryVerbose ) + Llb_ManCutPrint( p, vLower, vMinCut ); + if ( fVeryVerbose ) + printf( "\n" ); + + break; + } + if ( i == Vec_PtrSize(vResult) ) + break; + // insert vMinCut before vUpper + Vec_PtrPush( vResult, NULL ); + for ( k = Vec_PtrSize(vResult) - 1; k > i; k-- ) + Vec_PtrWriteEntry( vResult, k, Vec_PtrEntry(vResult, k-1) ); + Vec_PtrWriteEntry( vResult, i, vMinCut ); + } + if ( fVerbose ) + { + printf( "Finished computing %d partitions. ", Vec_PtrSize(vResult) - 1 ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + Llb_ManResultPrint( p, vResult ); + } + return vResult; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_BddSetDefaultParams( Gia_ParLlb_t * p ) +{ + memset( p, 0, sizeof(Gia_ParLlb_t) ); + p->nBddMax = 1000000; + p->nIterMax = 10000000; + p->nClusterMax = 20; + p->nHintDepth = 0; + p->HintFirst = 0; + p->fUseFlow = 0; // use flow + p->nVolumeMax = 100; // max volume + p->nVolumeMin = 30; // min volume + p->fReorder = 1; + p->fIndConstr = 0; + p->fUsePivots = 0; + p->fCluster = 0; + p->fSchedule = 0; + p->fVerbose = 0; + p->fVeryVerbose = 0; + p->fSilent = 0; + p->TimeLimit = 0; +// p->TimeLimit = 0; + p->TimeLimitGlo = 0; + p->TimeTarget = 0; + p->iFrame = -1; +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ManMinCutTest( Aig_Man_t * pAig, int Num ) +{ + extern void Llb_BddConstructTest( Aig_Man_t * p, Vec_Ptr_t * vResult ); + extern void Llb_BddExperiment( Aig_Man_t * pInit, Aig_Man_t * pAig, Gia_ParLlb_t * pPars, Vec_Ptr_t * vResult, Vec_Ptr_t * vMaps ); + + +// int fVerbose = 1; + Gia_ParLlb_t Pars, * pPars = &Pars; + Vec_Ptr_t * vResult;//, * vSupps, * vMaps; + Aig_Man_t * p; + + Llb_BddSetDefaultParams( pPars ); + + p = Aig_ManDupFlopsOnly( pAig ); +//Aig_ManShow( p, 0, NULL ); + Aig_ManPrintStats( pAig ); + Aig_ManPrintStats( p ); + Aig_ManFanoutStart( p ); + + vResult = Llb_ManComputeCuts( p, Num, 1, 0 ); +// vSupps = Llb_ManCutSupps( p, vResult ); +// vMaps = Llb_ManCutMap( p, vResult, vSupps ); + +// Llb_BddExperiment( pAig, p, pPars, vResult, vMaps ); + Llb_CoreExperiment( pAig, p, pPars, vResult, 0 ); + +// Vec_VecFree( (Vec_Vec_t *)vMaps ); +// Vec_VecFree( (Vec_Vec_t *)vSupps ); + Vec_VecFree( (Vec_Vec_t *)vResult ); + + Aig_ManFanoutStop( p ); + Aig_ManCleanMarkAB( p ); + Aig_ManStop( p ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb2Image.c b/src/bdd/llb/llb2Image.c new file mode 100644 index 00000000..e245ba36 --- /dev/null +++ b/src/bdd/llb/llb2Image.c @@ -0,0 +1,482 @@ +/**CFile**************************************************************** + + FileName [llb2Image.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Computes image using partitioned structure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Image.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern Vec_Ptr_t * Llb_ManCutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ); +extern Vec_Ptr_t * Llb_ManCutRange( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes supports of the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_ImgSupports( Aig_Man_t * p, Vec_Ptr_t * vDdMans, Vec_Int_t * vStart, Vec_Int_t * vStop, int fAddPis, int fVerbose ) +{ + Vec_Ptr_t * vSupps; + Vec_Int_t * vOne; + Aig_Obj_t * pObj; + DdManager * dd; + DdNode * bSupp, * bTemp; + int i, Entry, nSize; + nSize = Cudd_ReadSize( (DdManager *)Vec_PtrEntry( vDdMans, 0 ) ); + vSupps = Vec_PtrAlloc( 100 ); + // create initial + vOne = Vec_IntStart( nSize ); + Vec_IntForEachEntry( vStart, Entry, i ) + Vec_IntWriteEntry( vOne, Entry, 1 ); + Vec_PtrPush( vSupps, vOne ); + // create intermediate + Vec_PtrForEachEntry( DdManager *, vDdMans, dd, i ) + { + vOne = Vec_IntStart( nSize ); + bSupp = Cudd_Support( dd, dd->bFunc ); Cudd_Ref( bSupp ); + for ( bTemp = bSupp; bTemp != Cudd_ReadOne(dd); bTemp = cuddT(bTemp) ) + Vec_IntWriteEntry( vOne, bTemp->index, 1 ); + Cudd_RecursiveDeref( dd, bSupp ); + Vec_PtrPush( vSupps, vOne ); + } + // create final + vOne = Vec_IntStart( nSize ); + Vec_IntForEachEntry( vStop, Entry, i ) + Vec_IntWriteEntry( vOne, Entry, 1 ); + if ( fAddPis ) + Saig_ManForEachPi( p, pObj, i ) + Vec_IntWriteEntry( vOne, Aig_ObjId(pObj), 1 ); + Vec_PtrPush( vSupps, vOne ); + + // print supports + assert( nSize == Aig_ManObjNumMax(p) ); + if ( !fVerbose ) + return vSupps; + Aig_ManForEachObj( p, pObj, i ) + { + int k, Counter = 0; + Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, k ) + Counter += Vec_IntEntry(vOne, i); + if ( Counter == 0 ) + continue; + printf( "Obj = %4d : ", i ); + if ( Saig_ObjIsPi(p,pObj) ) + printf( "pi " ); + else if ( Saig_ObjIsLo(p,pObj) ) + printf( "lo " ); + else if ( Saig_ObjIsLi(p,pObj) ) + printf( "li " ); + else if ( Aig_ObjIsNode(pObj) ) + printf( "and " ); + Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, k ) + printf( "%d", Vec_IntEntry(vOne, i) ); + printf( "\n" ); + } + return vSupps; +} + +/**Function************************************************************* + + Synopsis [Computes quantification schedule.] + + Description [Input array contains supports: 0=starting, ... intermediate... + N-1=final. Output arrays contain immediately quantifiable vars (vQuant0) + and vars that should be quantified after conjunction (vQuant1).] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ImgSchedule( Vec_Ptr_t * vSupps, Vec_Ptr_t ** pvQuant0, Vec_Ptr_t ** pvQuant1, int fVerbose ) +{ + Vec_Int_t * vOne; + int nVarsAll, Counter, iSupp = -1, Entry, i, k; + // start quantification arrays + *pvQuant0 = Vec_PtrAlloc( Vec_PtrSize(vSupps) ); + *pvQuant1 = Vec_PtrAlloc( Vec_PtrSize(vSupps) ); + Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, k ) + { + Vec_PtrPush( *pvQuant0, Vec_IntAlloc(16) ); + Vec_PtrPush( *pvQuant1, Vec_IntAlloc(16) ); + } + // count how many times each var appears + nVarsAll = Vec_IntSize( (Vec_Int_t *)Vec_PtrEntry(vSupps, 0) ); + for ( i = 0; i < nVarsAll; i++ ) + { + Counter = 0; + Vec_PtrForEachEntry( Vec_Int_t *, vSupps, vOne, k ) + if ( Vec_IntEntry(vOne, i) ) + { + iSupp = k; + Counter++; + } + if ( Counter == 0 ) + continue; + if ( Counter == 1 ) + Vec_IntPush( (Vec_Int_t *)Vec_PtrEntry(*pvQuant0, iSupp), i ); + else // if ( Counter > 1 ) + Vec_IntPush( (Vec_Int_t *)Vec_PtrEntry(*pvQuant1, iSupp), i ); + } + + if ( fVerbose ) + for ( i = 0; i < Vec_PtrSize(vSupps); i++ ) + { + printf( "%2d : Quant0 = ", i ); + Vec_IntForEachEntry( (Vec_Int_t *)Vec_PtrEntry(*pvQuant0, i), Entry, k ) + printf( "%d ", Entry ); + printf( "\n" ); + } + + if ( fVerbose ) + for ( i = 0; i < Vec_PtrSize(vSupps); i++ ) + { + printf( "%2d : Quant1 = ", i ); + Vec_IntForEachEntry( (Vec_Int_t *)Vec_PtrEntry(*pvQuant1, i), Entry, k ) + printf( "%d ", Entry ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Computes one partition in a separate BDD manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb_ImgPartition( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, abctime TimeTarget ) +{ + Vec_Ptr_t * vNodes, * vRange; + Aig_Obj_t * pObj; + DdManager * dd; + DdNode * bBdd0, * bBdd1, * bProd, * bRes, * bTemp; + int i; + + dd = Cudd_Init( Aig_ManObjNumMax(p), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + dd->TimeStop = TimeTarget; + + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Aig_ObjId(pObj) ); + + vNodes = Llb_ManCutNodes( p, vLower, vUpper ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); +// pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( (DdNode *)pObj->pData ); +// pObj->pData = Extra_bddAndTime( dd, bBdd0, bBdd1, TimeTarget ); + pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); + if ( pObj->pData == NULL ) + { + Cudd_Quit( dd ); + Vec_PtrFree( vNodes ); + return NULL; + } + Cudd_Ref( (DdNode *)pObj->pData ); + } + + vRange = Llb_ManCutRange( p, vLower, vUpper ); + bRes = Cudd_ReadOne(dd); Cudd_Ref( bRes ); + Vec_PtrForEachEntry( Aig_Obj_t *, vRange, pObj, i ) + { + assert( Aig_ObjIsNode(pObj) ); + bProd = Cudd_bddXnor( dd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)), (DdNode *)pObj->pData ); Cudd_Ref( bProd ); +// bRes = Cudd_bddAnd( dd, bTemp = bRes, bProd ); Cudd_Ref( bRes ); +// bRes = Extra_bddAndTime( dd, bTemp = bRes, bProd, TimeTarget ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, bProd ); + if ( bRes == NULL ) + { + Cudd_Quit( dd ); + Vec_PtrFree( vRange ); + Vec_PtrFree( vNodes ); + return NULL; + } + Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + + Vec_PtrFree( vRange ); + Vec_PtrFree( vNodes ); + Cudd_AutodynDisable( dd ); +// Cudd_RecursiveDeref( dd, bRes ); +// Extra_StopManager( dd ); + dd->bFunc = bRes; + dd->TimeStop = 0; + return dd; +} + +/**Function************************************************************* + + Synopsis [Derives positive cube composed of nodes IDs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ImgComputeCube( Aig_Man_t * pAig, Vec_Int_t * vNodeIds, DdManager * dd ) +{ + DdNode * bProd, * bTemp; + Aig_Obj_t * pObj; + int i; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bProd = Cudd_ReadOne(dd); Cudd_Ref( bProd ); + Aig_ManForEachObjVec( vNodeIds, pAig, pObj, i ) + { + bProd = Cudd_bddAnd( dd, bTemp = bProd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)) ); Cudd_Ref( bProd ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bProd ); + dd->TimeStop = TimeStop; + return bProd; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ImgQuantifyFirst( Aig_Man_t * pAig, Vec_Ptr_t * vDdMans, Vec_Ptr_t * vQuant0, int fVerbose ) +{ + DdManager * dd; + DdNode * bProd, * bRes, * bTemp; + int i; + abctime clk = Abc_Clock(); + Vec_PtrForEachEntry( DdManager *, vDdMans, dd, i ) + { + // remember unquantified ones + assert( dd->bFunc2 == NULL ); + dd->bFunc2 = dd->bFunc; Cudd_Ref( dd->bFunc2 ); + + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + + bRes = dd->bFunc; + if ( fVerbose ) + Abc_Print( 1, "Part %2d : Init =%5d. ", i, Cudd_DagSize(bRes) ); + bProd = Llb_ImgComputeCube( pAig, (Vec_Int_t *)Vec_PtrEntry(vQuant0, i+1), dd ); Cudd_Ref( bProd ); + bRes = Cudd_bddExistAbstract( dd, bTemp = bRes, bProd ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bProd ); + dd->bFunc = bRes; + + Cudd_AutodynDisable( dd ); + + if ( fVerbose ) + Abc_Print( 1, "Quant =%5d. ", Cudd_DagSize(bRes) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "Reo = %5d. ", Cudd_DagSize(bRes) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "Reo = %5d. ", Cudd_DagSize(bRes) ); + if ( fVerbose ) + Abc_Print( 1, "Supp = %3d. ", Cudd_SupportSize(dd, bRes) ); + if ( fVerbose ) + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_ImgQuantifyReset( Vec_Ptr_t * vDdMans ) +{ + DdManager * dd; + int i; + Vec_PtrForEachEntry( DdManager *, vDdMans, dd, i ) + { + assert( dd->bFunc2 != NULL ); + Cudd_RecursiveDeref( dd, dd->bFunc ); + dd->bFunc = dd->bFunc2; + dd->bFunc2 = NULL; + } +} + +/**Function************************************************************* + + Synopsis [Computes image of the initial set of states.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_ImgComputeImage( Aig_Man_t * pAig, Vec_Ptr_t * vDdMans, DdManager * dd, DdNode * bInit, + Vec_Ptr_t * vQuant0, Vec_Ptr_t * vQuant1, Vec_Int_t * vDriRefs, + abctime TimeTarget, int fBackward, int fReorder, int fVerbose ) +{ +// int fCheckSupport = 0; + DdManager * ddPart; + DdNode * bImage, * bGroup, * bCube, * bTemp; + int i; + abctime clk, clk0 = Abc_Clock(); + + bImage = bInit; Cudd_Ref( bImage ); + if ( fBackward ) + { + // change polarity + bCube = Llb_DriverPhaseCube( pAig, vDriRefs, dd ); Cudd_Ref( bCube ); + bImage = Extra_bddChangePolarity( dd, bTemp = bImage, bCube ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + } + else + { + // quantify unique vriables + bCube = Llb_ImgComputeCube( pAig, (Vec_Int_t *)Vec_PtrEntry(vQuant0, 0), dd ); Cudd_Ref( bCube ); + bImage = Cudd_bddExistAbstract( dd, bTemp = bImage, bCube ); + if ( bImage == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + return NULL; + } + Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + } + // perform image computation + Vec_PtrForEachEntry( DdManager *, vDdMans, ddPart, i ) + { + clk = Abc_Clock(); +if ( fVerbose ) +printf( " %2d : ", i ); + // transfer the BDD from the group manager to the main manager + bGroup = Cudd_bddTransfer( ddPart, dd, ddPart->bFunc ); + if ( bGroup == NULL ) + return NULL; + Cudd_Ref( bGroup ); +if ( fVerbose ) +printf( "Pt0 =%6d. Pt1 =%6d. ", Cudd_DagSize(ddPart->bFunc), Cudd_DagSize(bGroup) ); + // perform partial product + bCube = Llb_ImgComputeCube( pAig, (Vec_Int_t *)Vec_PtrEntry(vQuant1, i+1), dd ); Cudd_Ref( bCube ); +// bImage = Cudd_bddAndAbstract( dd, bTemp = bImage, bGroup, bCube ); +// bImage = Extra_bddAndAbstractTime( dd, bTemp = bImage, bGroup, bCube, TimeTarget ); + bImage = Cudd_bddAndAbstract( dd, bTemp = bImage, bGroup, bCube ); + if ( bImage == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + Cudd_RecursiveDeref( dd, bGroup ); + return NULL; + } + Cudd_Ref( bImage ); + +if ( fVerbose ) +printf( "Im0 =%6d. Im1 =%6d. ", Cudd_DagSize(bTemp), Cudd_DagSize(bImage) ); +//printf("\n"); Extra_bddPrintSupport(dd, bImage); printf("\n"); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + Cudd_RecursiveDeref( dd, bGroup ); + +// Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); +// Abc_Print( 1, "Reo =%6d. ", Cudd_DagSize(bImage) ); + +if ( fVerbose ) +printf( "Supp =%3d. ", Cudd_SupportSize(dd, bImage) ); +if ( fVerbose ) +Abc_PrintTime( 1, "T", Abc_Clock() - clk ); + } + + if ( !fBackward ) + { + // change polarity + bCube = Llb_DriverPhaseCube( pAig, vDriRefs, dd ); Cudd_Ref( bCube ); + bImage = Extra_bddChangePolarity( dd, bTemp = bImage, bCube ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + } + else + { + // quantify unique vriables + bCube = Llb_ImgComputeCube( pAig, (Vec_Int_t *)Vec_PtrEntry(vQuant0, 0), dd ); Cudd_Ref( bCube ); + bImage = Cudd_bddExistAbstract( dd, bTemp = bImage, bCube ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + } + + if ( fReorder ) + { + if ( fVerbose ) + Abc_Print( 1, " Reordering... Before =%5d. ", Cudd_DagSize(bImage) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "After =%5d. ", Cudd_DagSize(bImage) ); +// Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); +// Abc_Print( 1, "After =%5d. ", Cudd_DagSize(bImage) ); + if ( fVerbose ) + Abc_PrintTime( 1, "Time", Abc_Clock() - clk0 ); +// Abc_Print( 1, "\n" ); + } + + Cudd_Deref( bImage ); + return bImage; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb3Image.c b/src/bdd/llb/llb3Image.c new file mode 100644 index 00000000..72c6120a --- /dev/null +++ b/src/bdd/llb/llb3Image.c @@ -0,0 +1,1095 @@ +/**CFile**************************************************************** + + FileName [llb3Image.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Computes image using partitioned structure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb3Image.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Var_t_ Llb_Var_t; +struct Llb_Var_t_ +{ + int iVar; // variable number + int nScore; // variable score + Vec_Int_t * vParts; // partitions +}; + +typedef struct Llb_Prt_t_ Llb_Prt_t; +struct Llb_Prt_t_ +{ + int iPart; // partition number + int nSize; // the number of BDD nodes + DdNode * bFunc; // the partition + Vec_Int_t * vVars; // support +}; + +typedef struct Llb_Mgr_t_ Llb_Mgr_t; +struct Llb_Mgr_t_ +{ + Aig_Man_t * pAig; // AIG manager + Vec_Ptr_t * vLeaves; // leaves in the AIG manager + Vec_Ptr_t * vRoots; // roots in the AIG manager + DdManager * dd; // working BDD manager + int * pVars2Q; // variables to quantify + // internal + Llb_Prt_t ** pParts; // partitions + Llb_Var_t ** pVars; // variables + int iPartFree; // next free partition + int nVars; // the number of BDD variables + int nSuppMax; // maximum support size + // temporary + int * pSupp; // temporary support storage +}; + +static inline Llb_Var_t * Llb_MgrVar( Llb_Mgr_t * p, int i ) { return p->pVars[i]; } +static inline Llb_Prt_t * Llb_MgrPart( Llb_Mgr_t * p, int i ) { return p->pParts[i]; } + +// iterator over vars +#define Llb_MgrForEachVar( p, pVar, i ) \ + for ( i = 0; (i < p->nVars) && (((pVar) = Llb_MgrVar(p, i)), 1); i++ ) if ( pVar == NULL ) {} else +// iterator over parts +#define Llb_MgrForEachPart( p, pPart, i ) \ + for ( i = 0; (i < p->iPartFree) && (((pPart) = Llb_MgrPart(p, i)), 1); i++ ) if ( pPart == NULL ) {} else + +// iterator over vars of one partition +#define Llb_PartForEachVar( p, pPart, pVar, i ) \ + for ( i = 0; (i < Vec_IntSize(pPart->vVars)) && (((pVar) = Llb_MgrVar(p, Vec_IntEntry(pPart->vVars,i))), 1); i++ ) +// iterator over parts of one variable +#define Llb_VarForEachPart( p, pVar, pPart, i ) \ + for ( i = 0; (i < Vec_IntSize(pVar->vParts)) && (((pPart) = Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,i))), 1); i++ ) + +// statistics +abctime timeBuild, timeAndEx, timeOther; +int nSuppMax; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Removes one variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinRemoveVar( Llb_Mgr_t * p, Llb_Var_t * pVar ) +{ + assert( p->pVars[pVar->iVar] == pVar ); + p->pVars[pVar->iVar] = NULL; + Vec_IntFree( pVar->vParts ); + ABC_FREE( pVar ); +} + +/**Function************************************************************* + + Synopsis [Removes one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinRemovePart( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + assert( p->pParts[pPart->iPart] == pPart ); + p->pParts[pPart->iPart] = NULL; + Vec_IntFree( pPart->vVars ); + Cudd_RecursiveDeref( p->dd, pPart->bFunc ); + ABC_FREE( pPart ); +} + +/**Function************************************************************* + + Synopsis [Create cube with singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_NonlinCreateCube1( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + DdNode * bCube, * bTemp; + Llb_Var_t * pVar; + int i; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); + Llb_PartForEachVar( p, pPart, pVar, i ) + { + assert( Vec_IntSize(pVar->vParts) > 0 ); + if ( Vec_IntSize(pVar->vParts) != 1 ) + continue; + assert( Vec_IntEntry(pVar->vParts, 0) == pPart->iPart ); + bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Cudd_Deref( bCube ); + p->dd->TimeStop = TimeStop; + return bCube; +} + +/**Function************************************************************* + + Synopsis [Create cube of variables appearing only in two partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_NonlinCreateCube2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) +{ + DdNode * bCube, * bTemp; + Llb_Var_t * pVar; + int i; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + assert( Vec_IntSize(pVar->vParts) > 0 ); + if ( Vec_IntSize(pVar->vParts) != 2 ) + continue; + if ( (Vec_IntEntry(pVar->vParts, 0) == pPart1->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart2->iPart) || + (Vec_IntEntry(pVar->vParts, 0) == pPart2->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart1->iPart) ) + { + bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + } + Cudd_Deref( bCube ); + p->dd->TimeStop = TimeStop; + return bCube; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if partition has singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinHasSingletonVars( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + Llb_Var_t * pVar; + int i; + Llb_PartForEachVar( p, pPart, pVar, i ) + if ( Vec_IntSize(pVar->vParts) == 1 ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if partition has singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinPrint( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k; + printf( "\n" ); + Llb_MgrForEachVar( p, pVar, i ) + { + printf( "Var %3d : ", i ); + Llb_VarForEachPart( p, pVar, pPart, k ) + printf( "%d ", pPart->iPart ); + printf( "\n" ); + } + Llb_MgrForEachPart( p, pPart, i ) + { + printf( "Part %3d : ", i ); + Llb_PartForEachVar( p, pPart, pVar, k ) + printf( "%d ", pVar->iVar ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Quantifies singles belonging to one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinQuantify1( Llb_Mgr_t * p, Llb_Prt_t * pPart, int fSubset ) +{ + Llb_Var_t * pVar; + Llb_Prt_t * pTemp; + Vec_Ptr_t * vSingles; + DdNode * bCube, * bTemp; + int i, RetValue, nSizeNew; + if ( fSubset ) + { + int Length; +// int nSuppSize = Cudd_SupportSize( p->dd, pPart->bFunc ); +// pPart->bFunc = Cudd_SubsetHeavyBranch( p->dd, bTemp = pPart->bFunc, nSuppSize, 3*pPart->nSize/4 ); Cudd_Ref( pPart->bFunc ); + pPart->bFunc = Cudd_LargestCube( p->dd, bTemp = pPart->bFunc, &Length ); Cudd_Ref( pPart->bFunc ); + + printf( "Subsetting %3d : ", pPart->iPart ); + printf( "(Supp =%3d Node =%5d) -> ", Cudd_SupportSize(p->dd, bTemp), Cudd_DagSize(bTemp) ); + printf( "(Supp =%3d Node =%5d)\n", Cudd_SupportSize(p->dd, pPart->bFunc), Cudd_DagSize(pPart->bFunc) ); + + RetValue = (Cudd_DagSize(bTemp) == Cudd_DagSize(pPart->bFunc)); + + Cudd_RecursiveDeref( p->dd, bTemp ); + + if ( RetValue ) + return 1; + } + else + { + // create cube to be quantified + bCube = Llb_NonlinCreateCube1( p, pPart ); Cudd_Ref( bCube ); +// assert( !Cudd_IsConstant(bCube) ); + // derive new function + pPart->bFunc = Cudd_bddExistAbstract( p->dd, bTemp = pPart->bFunc, bCube ); Cudd_Ref( pPart->bFunc ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bCube ); + } + // get support + vSingles = Vec_PtrAlloc( 0 ); + nSizeNew = Cudd_DagSize(pPart->bFunc); + Extra_SupportArray( p->dd, pPart->bFunc, p->pSupp ); + Llb_PartForEachVar( p, pPart, pVar, i ) + if ( p->pSupp[pVar->iVar] ) + { + assert( Vec_IntSize(pVar->vParts) > 1 ); + pVar->nScore -= pPart->nSize - nSizeNew; + } + else + { + RetValue = Vec_IntRemove( pVar->vParts, pPart->iPart ); + assert( RetValue ); + pVar->nScore -= pPart->nSize; + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_NonlinRemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + + // update partition + pPart->nSize = nSizeNew; + Vec_IntClear( pPart->vVars ); + for ( i = 0; i < p->nVars; i++ ) + if ( p->pSupp[i] && p->pVars2Q[i] ) + Vec_IntPush( pPart->vVars, i ); + // remove other variables + Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) + Llb_NonlinQuantify1( p, pTemp, 0 ); + Vec_PtrFree( vSingles ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Quantifies singles belonging to one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinQuantify2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) +{ + int fVerbose = 0; + Llb_Var_t * pVar; + Llb_Prt_t * pTemp; + Vec_Ptr_t * vSingles; + DdNode * bCube, * bFunc; + int i, RetValue, nSuppSize; +// int iPart1 = pPart1->iPart; +// int iPart2 = pPart2->iPart; + + // create cube to be quantified + bCube = Llb_NonlinCreateCube2( p, pPart1, pPart2 ); Cudd_Ref( bCube ); +if ( fVerbose ) +{ +printf( "\n" ); +printf( "\n" ); +Llb_NonlinPrint( p ); +printf( "Conjoining partitions %d and %d.\n", pPart1->iPart, pPart2->iPart ); +Extra_bddPrintSupport( p->dd, bCube ); printf( "\n" ); +} + + // derive new function +// bFunc = Cudd_bddAndAbstract( p->dd, pPart1->bFunc, pPart2->bFunc, bCube ); Cudd_Ref( bFunc ); +/* + bFunc = Cudd_bddAndAbstractLimit( p->dd, pPart1->bFunc, pPart2->bFunc, bCube, Limit ); + if ( bFunc == NULL ) + { + int RetValue; + Cudd_RecursiveDeref( p->dd, bCube ); + if ( pPart1->nSize < pPart2->nSize ) + RetValue = Llb_NonlinQuantify1( p, pPart1, 1 ); + else + RetValue = Llb_NonlinQuantify1( p, pPart2, 1 ); + if ( RetValue ) + Limit = Limit + 1000; + Llb_NonlinQuantify2( p, pPart1, pPart2 ); + return 0; + } + Cudd_Ref( bFunc ); +*/ + +// bFunc = Extra_bddAndAbstractTime( p->dd, pPart1->bFunc, pPart2->bFunc, bCube, TimeOut ); + bFunc = Cudd_bddAndAbstract( p->dd, pPart1->bFunc, pPart2->bFunc, bCube ); + if ( bFunc == NULL ) + { + Cudd_RecursiveDeref( p->dd, bCube ); + return 0; + } + Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( p->dd, bCube ); + + // create new partition + pTemp = p->pParts[p->iPartFree] = ABC_CALLOC( Llb_Prt_t, 1 ); + pTemp->iPart = p->iPartFree++; + pTemp->nSize = Cudd_DagSize(bFunc); + pTemp->bFunc = bFunc; + pTemp->vVars = Vec_IntAlloc( 8 ); + // update variables + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + RetValue = Vec_IntRemove( pVar->vParts, pPart1->iPart ); + assert( RetValue ); + pVar->nScore -= pPart1->nSize; + } + // update variables + Llb_PartForEachVar( p, pPart2, pVar, i ) + { + RetValue = Vec_IntRemove( pVar->vParts, pPart2->iPart ); + assert( RetValue ); + pVar->nScore -= pPart2->nSize; + } + // add variables to the new partition + nSuppSize = 0; + Extra_SupportArray( p->dd, bFunc, p->pSupp ); + for ( i = 0; i < p->nVars; i++ ) + { + nSuppSize += p->pSupp[i]; + if ( p->pSupp[i] && p->pVars2Q[i] ) + { + pVar = Llb_MgrVar( p, i ); + pVar->nScore += pTemp->nSize; + Vec_IntPush( pVar->vParts, pTemp->iPart ); + Vec_IntPush( pTemp->vVars, i ); + } + } + p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); + // remove variables and collect partitions with singleton variables + vSingles = Vec_PtrAlloc( 0 ); + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_NonlinRemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + { + if ( fVerbose ) + printf( "Adding partition %d because of var %d.\n", + Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + } + Llb_PartForEachVar( p, pPart2, pVar, i ) + { + if ( pVar == NULL ) + continue; + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_NonlinRemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + { + if ( fVerbose ) + printf( "Adding partition %d because of var %d.\n", + Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + } + // remove partitions + Llb_NonlinRemovePart( p, pPart1 ); + Llb_NonlinRemovePart( p, pPart2 ); + // remove other variables +if ( fVerbose ) +Llb_NonlinPrint( p ); + Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) + { +if ( fVerbose ) +printf( "Updating partitiong %d with singlton vars.\n", pTemp->iPart ); + Llb_NonlinQuantify1( p, pTemp, 0 ); + } +if ( fVerbose ) +Llb_NonlinPrint( p ); + Vec_PtrFree( vSingles ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinCutNodes_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return; + Aig_ObjSetTravIdCurrent(p, pObj); + if ( Saig_ObjIsLi(p, pObj) ) + { + Llb_NonlinCutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); + return; + } + if ( Aig_ObjIsConst1(pObj) ) + return; + assert( Aig_ObjIsNode(pObj) ); + Llb_NonlinCutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); + Llb_NonlinCutNodes_rec(p, Aig_ObjFanin1(pObj), vNodes); + Vec_PtrPush( vNodes, pObj ); +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_NonlinCutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vNodes; + Aig_Obj_t * pObj; + int i; + // mark the lower cut with the traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // count the upper cut + vNodes = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + Llb_NonlinCutNodes_rec( p, pObj, vNodes ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Returns array of BDDs for the roots in terms of the leaves.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_NonlinBuildBdds( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, DdManager * dd ) +{ + Vec_Ptr_t * vNodes, * vResult; + Aig_Obj_t * pObj; + DdNode * bBdd0, * bBdd1, * bProd; + int i, k; + + Aig_ManConst1(p)->pData = Cudd_ReadOne( dd ); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Aig_ObjId(pObj) ); + + vNodes = Llb_NonlinCutNodes( p, vLower, vUpper ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); +// pObj->pData = Extra_bddAndTime( dd, bBdd0, bBdd1, TimeOut ); + pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); + if ( pObj->pData == NULL ) + { + Vec_PtrForEachEntryStop( Aig_Obj_t *, vNodes, pObj, k, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Vec_PtrFree( vNodes ); + return NULL; + } + Cudd_Ref( (DdNode *)pObj->pData ); + } + + vResult = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + { + if ( Aig_ObjIsNode(pObj) ) + { + bProd = Cudd_bddXnor( dd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)), (DdNode *)pObj->pData ); Cudd_Ref( bProd ); + } + else + { + assert( Saig_ObjIsLi(p, pObj) ); + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bProd = Cudd_bddXnor( dd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)), bBdd0 ); Cudd_Ref( bProd ); + } + Vec_PtrPush( vResult, bProd ); + } + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + + Vec_PtrFree( vNodes ); + return vResult; +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinAddPair( Llb_Mgr_t * p, DdNode * bFunc, int iPart, int iVar ) +{ + if ( p->pVars[iVar] == NULL ) + { + p->pVars[iVar] = ABC_CALLOC( Llb_Var_t, 1 ); + p->pVars[iVar]->iVar = iVar; + p->pVars[iVar]->nScore = 0; + p->pVars[iVar]->vParts = Vec_IntAlloc( 8 ); + } + Vec_IntPush( p->pVars[iVar]->vParts, iPart ); + Vec_IntPush( p->pParts[iPart]->vVars, iVar ); +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinAddPartition( Llb_Mgr_t * p, int i, DdNode * bFunc ) +{ + int k, nSuppSize; + assert( !Cudd_IsConstant(bFunc) ); + // create partition + p->pParts[i] = ABC_CALLOC( Llb_Prt_t, 1 ); + p->pParts[i]->iPart = i; + p->pParts[i]->bFunc = bFunc; + p->pParts[i]->vVars = Vec_IntAlloc( 8 ); + // add support dependencies + nSuppSize = 0; + Extra_SupportArray( p->dd, bFunc, p->pSupp ); + for ( k = 0; k < p->nVars; k++ ) + { + nSuppSize += p->pSupp[k]; + if ( p->pSupp[k] && p->pVars2Q[k] ) + Llb_NonlinAddPair( p, bFunc, i, k ); + } + p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinStart( Llb_Mgr_t * p ) +{ + Vec_Ptr_t * vRootBdds; + DdNode * bFunc; + int i; + // create and collect BDDs + vRootBdds = Llb_NonlinBuildBdds( p->pAig, p->vLeaves, p->vRoots, p->dd ); // come referenced + if ( vRootBdds == NULL ) + return 0; + // add pairs (refs are consumed inside) + Vec_PtrForEachEntry( DdNode *, vRootBdds, bFunc, i ) + Llb_NonlinAddPartition( p, i, bFunc ); + Vec_PtrFree( vRootBdds ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Checks that each var appears in at least one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] +**********************************************************************/ +void Llb_NonlinCheckVars( Llb_Mgr_t * p ) +{ + Llb_Var_t * pVar; + int i; + Llb_MgrForEachVar( p, pVar, i ) + assert( Vec_IntSize(pVar->vParts) > 1 ); +} + +/**Function************************************************************* + + Synopsis [Find next partition to quantify] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinNextPartitions( Llb_Mgr_t * p, Llb_Prt_t ** ppPart1, Llb_Prt_t ** ppPart2 ) +{ + Llb_Var_t * pVar, * pVarBest = NULL; + Llb_Prt_t * pPart, * pPart1Best = NULL, * pPart2Best = NULL; + int i; + Llb_NonlinCheckVars( p ); + // find variable with minimum score + Llb_MgrForEachVar( p, pVar, i ) + if ( pVarBest == NULL || pVarBest->nScore > pVar->nScore ) + pVarBest = pVar; + if ( pVarBest == NULL ) + return 0; + // find two partitions with minimum size + Llb_VarForEachPart( p, pVarBest, pPart, i ) + { + if ( pPart1Best == NULL ) + pPart1Best = pPart; + else if ( pPart2Best == NULL ) + pPart2Best = pPart; + else if ( pPart1Best->nSize > pPart->nSize || pPart2Best->nSize > pPart->nSize ) + { + if ( pPart1Best->nSize > pPart2Best->nSize ) + pPart1Best = pPart; + else + pPart2Best = pPart; + } + } + *ppPart1 = pPart1Best; + *ppPart2 = pPart2Best; + return 1; +} + +/**Function************************************************************* + + Synopsis [Reorders BDDs in the working manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinReorder( DdManager * dd, int fTwice, int fVerbose ) +{ + abctime clk = Abc_Clock(); + if ( fVerbose ) + Abc_Print( 1, "Reordering... Before =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + if ( fTwice ) + { + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + } + if ( fVerbose ) + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); +} + +/**Function************************************************************* + + Synopsis [Recomputes scores after variable reordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinRecomputeScores( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k; + Llb_MgrForEachPart( p, pPart, i ) + pPart->nSize = Cudd_DagSize(pPart->bFunc); + Llb_MgrForEachVar( p, pVar, i ) + { + pVar->nScore = 0; + Llb_VarForEachPart( p, pVar, pPart, k ) + pVar->nScore += pPart->nSize; + } +} + +/**Function************************************************************* + + Synopsis [Recomputes scores after variable reordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinVerifyScores( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k, nScore; + Llb_MgrForEachPart( p, pPart, i ) + assert( pPart->nSize == Cudd_DagSize(pPart->bFunc) ); + Llb_MgrForEachVar( p, pVar, i ) + { + nScore = 0; + Llb_VarForEachPart( p, pVar, pPart, k ) + nScore += pPart->nSize; + assert( nScore == pVar->nScore ); + } +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mgr_t * Llb_NonlinAlloc( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, DdManager * dd ) +{ + Llb_Mgr_t * p; + p = ABC_CALLOC( Llb_Mgr_t, 1 ); + p->pAig = pAig; + p->vLeaves = vLeaves; + p->vRoots = vRoots; + p->dd = dd; + p->pVars2Q = pVars2Q; + p->nVars = Cudd_ReadSize(dd); + p->iPartFree = Vec_PtrSize(vRoots); + p->pVars = ABC_CALLOC( Llb_Var_t *, p->nVars ); + p->pParts = ABC_CALLOC( Llb_Prt_t *, 2 * p->iPartFree + 2 ); + p->pSupp = ABC_ALLOC( int, Cudd_ReadSize(dd) ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinFree( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i; + Llb_MgrForEachVar( p, pVar, i ) + Llb_NonlinRemoveVar( p, pVar ); + Llb_MgrForEachPart( p, pPart, i ) + Llb_NonlinRemovePart( p, pPart ); + ABC_FREE( p->pVars ); + ABC_FREE( p->pParts ); + ABC_FREE( p->pSupp ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [Performs image computation.] + + Description [Computes image of BDDs (vFuncs).] + + SideEffects [BDDs in vFuncs are derefed inside. The result is refed.] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_NonlinImage( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, + DdManager * dd, DdNode * bCurrent, int fReorder, int fVerbose, int * pOrder ) +{ + Llb_Prt_t * pPart, * pPart1, * pPart2; + Llb_Mgr_t * p; + DdNode * bFunc, * bTemp; + int i, nReorders, timeInside; + abctime clk = Abc_Clock(), clk2; + // start the manager + clk2 = Abc_Clock(); + p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd ); + if ( !Llb_NonlinStart( p ) ) + { + Llb_NonlinFree( p ); + return NULL; + } + // add partition + Llb_NonlinAddPartition( p, p->iPartFree++, bCurrent ); + // remove singles + Llb_MgrForEachPart( p, pPart, i ) + if ( Llb_NonlinHasSingletonVars(p, pPart) ) + Llb_NonlinQuantify1( p, pPart, 0 ); + timeBuild += Abc_Clock() - clk2; + timeInside = Abc_Clock() - clk2; + // compute scores + Llb_NonlinRecomputeScores( p ); + // save permutation + if ( pOrder ) + memcpy( pOrder, dd->invperm, sizeof(int) * dd->size ); + // iteratively quantify variables + while ( Llb_NonlinNextPartitions(p, &pPart1, &pPart2) ) + { + clk2 = Abc_Clock(); + nReorders = Cudd_ReadReorderings(dd); + if ( !Llb_NonlinQuantify2( p, pPart1, pPart2 ) ) + { + Llb_NonlinFree( p ); + return NULL; + } + timeAndEx += Abc_Clock() - clk2; + timeInside += Abc_Clock() - clk2; + if ( nReorders < Cudd_ReadReorderings(dd) ) + Llb_NonlinRecomputeScores( p ); +// else +// Llb_NonlinVerifyScores( p ); + } + // load partitions + bFunc = Cudd_ReadOne(p->dd); Cudd_Ref( bFunc ); + Llb_MgrForEachPart( p, pPart, i ) + { + bFunc = Cudd_bddAnd( p->dd, bTemp = bFunc, pPart->bFunc ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + nSuppMax = p->nSuppMax; + Llb_NonlinFree( p ); + // reorder variables + if ( fReorder ) + Llb_NonlinReorder( dd, 0, fVerbose ); + timeOther += Abc_Clock() - clk - timeInside; + // return + Cudd_Deref( bFunc ); + return bFunc; +} + + + +static Llb_Mgr_t * p = NULL; + +/**Function************************************************************* + + Synopsis [Starts image computation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb_NonlinImageStart( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, int * pOrder, int fFirst, abctime TimeTarget ) +{ + DdManager * dd; + abctime clk = Abc_Clock(); + assert( p == NULL ); + // start a new manager (disable reordering) + dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + dd->TimeStop = TimeTarget; + Cudd_ShuffleHeap( dd, pOrder ); +// if ( fFirst ) + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + // start the manager + p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd ); + if ( !Llb_NonlinStart( p ) ) + { + Llb_NonlinFree( p ); + p = NULL; + return NULL; + } + timeBuild += Abc_Clock() - clk; +// if ( !fFirst ) +// Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + return dd; +} + +/**Function************************************************************* + + Synopsis [Performs image computation.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_NonlinImageCompute( DdNode * bCurrent, int fReorder, int fDrop, int fVerbose, int * pOrder ) +{ + Llb_Prt_t * pPart, * pPart1, * pPart2; + DdNode * bFunc, * bTemp; + int i, nReorders, timeInside = 0; + abctime clk = Abc_Clock(), clk2; + + // add partition + Llb_NonlinAddPartition( p, p->iPartFree++, bCurrent ); + // remove singles + Llb_MgrForEachPart( p, pPart, i ) + if ( Llb_NonlinHasSingletonVars(p, pPart) ) + Llb_NonlinQuantify1( p, pPart, 0 ); + // reorder + if ( fReorder ) + Llb_NonlinReorder( p->dd, 0, 0 ); + // save permutation + memcpy( pOrder, p->dd->invperm, sizeof(int) * p->dd->size ); + + // compute scores + Llb_NonlinRecomputeScores( p ); + // iteratively quantify variables + while ( Llb_NonlinNextPartitions(p, &pPart1, &pPart2) ) + { + clk2 = Abc_Clock(); + nReorders = Cudd_ReadReorderings(p->dd); + if ( !Llb_NonlinQuantify2( p, pPart1, pPart2 ) ) + { + Llb_NonlinFree( p ); + return NULL; + } + timeAndEx += Abc_Clock() - clk2; + timeInside += Abc_Clock() - clk2; + if ( nReorders < Cudd_ReadReorderings(p->dd) ) + Llb_NonlinRecomputeScores( p ); +// else +// Llb_NonlinVerifyScores( p ); + } + // load partitions + bFunc = Cudd_ReadOne(p->dd); Cudd_Ref( bFunc ); + Llb_MgrForEachPart( p, pPart, i ) + { + bFunc = Cudd_bddAnd( p->dd, bTemp = bFunc, pPart->bFunc ); + if ( bFunc == NULL ) + { + Cudd_RecursiveDeref( p->dd, bTemp ); + Llb_NonlinFree( p ); + return NULL; + } + Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + nSuppMax = p->nSuppMax; + // reorder variables +// if ( fReorder ) +// Llb_NonlinReorder( p->dd, 0, fVerbose ); + // save permutation +// memcpy( pOrder, p->dd->invperm, sizeof(int) * Cudd_ReadSize(p->dd) ); + + timeOther += Abc_Clock() - clk - timeInside; + // return + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function************************************************************* + + Synopsis [Quits image computation manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinImageQuit() +{ + DdManager * dd; + if ( p == NULL ) + return; + dd = p->dd; + Llb_NonlinFree( p ); + if ( dd->bFunc ) + Cudd_RecursiveDeref( dd, dd->bFunc ); + Extra_StopManager( dd ); +// Cudd_Quit ( dd ); + p = NULL; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb3Nonlin.c b/src/bdd/llb/llb3Nonlin.c new file mode 100644 index 00000000..94a48bbf --- /dev/null +++ b/src/bdd/llb/llb3Nonlin.c @@ -0,0 +1,872 @@ +/**CFile**************************************************************** + + FileName [llb2Nonlin.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Nonlin.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Mnn_t_ Llb_Mnn_t; +struct Llb_Mnn_t_ +{ + Aig_Man_t * pInit; // AIG manager + Aig_Man_t * pAig; // AIG manager + Gia_ParLlb_t * pPars; // parameters + + DdManager * dd; // BDD manager + DdManager * ddG; // BDD manager + DdManager * ddR; // BDD manager + Vec_Ptr_t * vRings; // onion rings in ddR + + Vec_Ptr_t * vLeaves; + Vec_Ptr_t * vRoots; + int * pVars2Q; + int * pOrderL; + int * pOrderL2; + int * pOrderG; + + Vec_Int_t * vCs2Glo; // cur state variables into global variables + Vec_Int_t * vNs2Glo; // next state variables into global variables + Vec_Int_t * vGlo2Cs; // global variables into cur state variables + Vec_Int_t * vGlo2Ns; // global variables into next state variables + + int ddLocReos; + int ddLocGrbs; + + abctime timeImage; + abctime timeTran1; + abctime timeTran2; + abctime timeGloba; + abctime timeOther; + abctime timeTotal; + abctime timeReo; + abctime timeReoG; + +}; + +extern abctime timeBuild, timeAndEx, timeOther; +extern int nSuppMax; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Finds variable whose 0-cofactor is the smallest.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinFindBestVar( DdManager * dd, DdNode * bFunc, Aig_Man_t * pAig ) +{ + int fVerbose = 0; + Aig_Obj_t * pObj; + DdNode * bCof, * bVar; + int i, iVar, iVarBest = -1, iValue, iValueBest = ABC_INFINITY, Size0Best = -1; + int Size, Size0, Size1; + abctime clk = Abc_Clock(); + Size = Cudd_DagSize(bFunc); +// printf( "Original = %6d. SuppSize = %3d. Vars = %3d.\n", +// Size = Cudd_DagSize(bFunc), Cudd_SupportSize(dd, bFunc), Aig_ManRegNum(pAig) ); + Saig_ManForEachLo( pAig, pObj, i ) + { + iVar = Aig_ObjId(pObj); + +if ( fVerbose ) +printf( "Var =%3d : ", iVar ); + bVar = Cudd_bddIthVar(dd, iVar); + + bCof = Cudd_bddAnd( dd, bFunc, Cudd_Not(bVar) ); Cudd_Ref( bCof ); + Size0 = Cudd_DagSize(bCof); +if ( fVerbose ) +printf( "Supp0 =%3d ", Cudd_SupportSize(dd, bCof) ); +if ( fVerbose ) +printf( "Size0 =%6d ", Size0 ); + Cudd_RecursiveDeref( dd, bCof ); + + bCof = Cudd_bddAnd( dd, bFunc, bVar ); Cudd_Ref( bCof ); + Size1 = Cudd_DagSize(bCof); +if ( fVerbose ) +printf( "Supp1 =%3d ", Cudd_SupportSize(dd, bCof) ); +if ( fVerbose ) +printf( "Size1 =%6d ", Size1 ); + Cudd_RecursiveDeref( dd, bCof ); + + iValue = Abc_MaxInt(Size0, Size1) - Abc_MinInt(Size0, Size1) + Size0 + Size1 - Size; +if ( fVerbose ) +printf( "D =%6d ", Size0 + Size1 - Size ); +if ( fVerbose ) +printf( "B =%6d ", Abc_MaxInt(Size0, Size1) - Abc_MinInt(Size0, Size1) ); +if ( fVerbose ) +printf( "S =%6d\n", iValue ); + if ( Size0 > 1 && Size1 > 1 && iValueBest > iValue ) + { + iValueBest = iValue; + iVarBest = i; + Size0Best = Size0; + } + } + printf( "BestVar = %4d/%4d. Value =%6d. Orig =%6d. Size0 =%6d. ", + iVarBest, Aig_ObjId(Saig_ManLo(pAig,iVarBest)), iValueBest, Size, Size0Best ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + return iVarBest; +} + + +/**Function************************************************************* + + Synopsis [Finds variable whose 0-cofactor is the smallest.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinTrySubsetting( DdManager * dd, DdNode * bFunc ) +{ + DdNode * bNew; + printf( "Original = %6d. SuppSize = %3d. ", + Cudd_DagSize(bFunc), Cudd_SupportSize(dd, bFunc) ); + bNew = Cudd_SubsetHeavyBranch( dd, bFunc, Cudd_SupportSize(dd, bFunc), 1000 ); Cudd_Ref( bNew ); + printf( "Result = %6d. SuppSize = %3d.\n", + Cudd_DagSize(bNew), Cudd_SupportSize(dd, bNew) ); + Cudd_RecursiveDeref( dd, bNew ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinPrepareVarMap( Llb_Mnn_t * p ) +{ + Aig_Obj_t * pObjLi, * pObjLo, * pObj; + int i, iVarLi, iVarLo; + p->vCs2Glo = Vec_IntStartFull( Aig_ManObjNumMax(p->pAig) ); + p->vNs2Glo = Vec_IntStartFull( Aig_ManObjNumMax(p->pAig) ); + p->vGlo2Cs = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + p->vGlo2Ns = Vec_IntStartFull( Aig_ManRegNum(p->pAig) ); + Saig_ManForEachLiLo( p->pAig, pObjLi, pObjLo, i ) + { + iVarLi = Aig_ObjId(pObjLi); + iVarLo = Aig_ObjId(pObjLo); + assert( iVarLi >= 0 && iVarLi < Aig_ManObjNumMax(p->pAig) ); + assert( iVarLo >= 0 && iVarLo < Aig_ManObjNumMax(p->pAig) ); + Vec_IntWriteEntry( p->vCs2Glo, iVarLo, i ); + Vec_IntWriteEntry( p->vNs2Glo, iVarLi, i ); + Vec_IntWriteEntry( p->vGlo2Cs, i, iVarLo ); + Vec_IntWriteEntry( p->vGlo2Ns, i, iVarLi ); + } + // add mapping of the PIs + Saig_ManForEachPi( p->pAig, pObj, i ) + { + Vec_IntWriteEntry( p->vCs2Glo, Aig_ObjId(pObj), Aig_ManRegNum(p->pAig)+i ); + Vec_IntWriteEntry( p->vNs2Glo, Aig_ObjId(pObj), Aig_ManRegNum(p->pAig)+i ); + } +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_NonlinComputeInitState( Aig_Man_t * pAig, DdManager * dd ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bVar, * bTemp; + int i, iVar; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Saig_ManForEachLo( pAig, pObj, i ) + { + iVar = (Cudd_ReadSize(dd) == Aig_ManRegNum(pAig)) ? i : Aig_ObjId(pObj); + bVar = Cudd_bddIthVar( dd, iVar ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, Cudd_Not(bVar) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return bRes; +} + + +/**Function************************************************************* + + Synopsis [Derives counter-example by backward reachability.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Llb_NonlinDeriveCex( Llb_Mnn_t * p ) +{ + Abc_Cex_t * pCex; + Aig_Obj_t * pObj; + Vec_Int_t * vVarsNs; + DdNode * bState = NULL, * bImage, * bOneCube, * bTemp, * bRing; + int i, v, RetValue, nPiOffset; + char * pValues = ABC_ALLOC( char, Cudd_ReadSize(p->ddR) ); + assert( Vec_PtrSize(p->vRings) > 0 ); + + p->dd->TimeStop = 0; + p->ddR->TimeStop = 0; + + // update quantifiable vars + memset( p->pVars2Q, 0, sizeof(int) * Cudd_ReadSize(p->dd) ); + vVarsNs = Vec_IntAlloc( Aig_ManRegNum(p->pAig) ); + Saig_ManForEachLi( p->pAig, pObj, i ) + { + p->pVars2Q[Aig_ObjId(pObj)] = 1; + Vec_IntPush( vVarsNs, Aig_ObjId(pObj) ); + } +/* + Saig_ManForEachLo( p->pAig, pObj, i ) + printf( "%d ", pObj->Id ); + printf( "\n" ); + Saig_ManForEachLi( p->pAig, pObj, i ) + printf( "%d(%d) ", pObj->Id, Aig_ObjFaninId0(pObj) ); + printf( "\n" ); +*/ + // allocate room for the counter-example + pCex = Abc_CexAlloc( Saig_ManRegNum(p->pAig), Saig_ManPiNum(p->pAig), Vec_PtrSize(p->vRings) ); + pCex->iFrame = Vec_PtrSize(p->vRings) - 1; + pCex->iPo = -1; + + // get the last cube + bOneCube = Cudd_bddIntersect( p->ddR, (DdNode *)Vec_PtrEntryLast(p->vRings), p->ddR->bFunc ); Cudd_Ref( bOneCube ); + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); + + // write PIs of counter-example + nPiOffset = Saig_ManRegNum(p->pAig) + Saig_ManPiNum(p->pAig) * (Vec_PtrSize(p->vRings) - 1); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // write state in terms of NS variables + if ( Vec_PtrSize(p->vRings) > 1 ) + { + bState = Llb_CoreComputeCube( p->dd, vVarsNs, 1, pValues ); Cudd_Ref( bState ); + } + // perform backward analysis + Vec_PtrForEachEntryReverse( DdNode *, p->vRings, bRing, v ) + { + if ( v == Vec_PtrSize(p->vRings) - 1 ) + continue; +//Extra_bddPrintSupport( p->dd, bState ); printf( "\n" ); +//Extra_bddPrintSupport( p->dd, bRing ); printf( "\n" ); + // compute the next states + bImage = Llb_NonlinImage( p->pAig, p->vLeaves, p->vRoots, p->pVars2Q, p->dd, bState, + p->pPars->fReorder, p->pPars->fVeryVerbose, NULL ); // consumed reference + assert( bImage != NULL ); + Cudd_Ref( bImage ); +//Extra_bddPrintSupport( p->dd, bImage ); printf( "\n" ); + + // move reached states into ring manager + bImage = Extra_TransferPermute( p->dd, p->ddR, bTemp = bImage, Vec_IntArray(p->vCs2Glo) ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( p->dd, bTemp ); + + // intersect with the previous set + bOneCube = Cudd_bddIntersect( p->ddR, bImage, bRing ); Cudd_Ref( bOneCube ); + Cudd_RecursiveDeref( p->ddR, bImage ); + + // find any assignment of the BDD + RetValue = Cudd_bddPickOneCube( p->ddR, bOneCube, pValues ); + Cudd_RecursiveDeref( p->ddR, bOneCube ); + assert( RetValue ); + + // write PIs of counter-example + nPiOffset -= Saig_ManPiNum(p->pAig); + Saig_ManForEachPi( p->pAig, pObj, i ) + if ( pValues[Saig_ManRegNum(p->pAig)+i] == 1 ) + Abc_InfoSetBit( pCex->pData, nPiOffset + i ); + + // check that we get the init state + if ( v == 0 ) + { + Saig_ManForEachLo( p->pAig, pObj, i ) + assert( pValues[i] == 0 ); + break; + } + + // write state in terms of NS variables + bState = Llb_CoreComputeCube( p->dd, vVarsNs, 1, pValues ); Cudd_Ref( bState ); + } + assert( nPiOffset == Saig_ManRegNum(p->pAig) ); + // update the output number +//Abc_CexPrint( pCex ); + RetValue = Saig_ManFindFailedPoCex( p->pInit, pCex ); + assert( RetValue >= 0 && RetValue < Saig_ManPoNum(p->pInit) ); // invalid CEX!!! + pCex->iPo = RetValue; + // cleanup + ABC_FREE( pValues ); + Vec_IntFree( vVarsNs ); + return pCex; +} + + +/**Function************************************************************* + + Synopsis [Perform reachability with hints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinReoHook( DdManager * dd, char * Type, void * Method ) +{ + Aig_Man_t * pAig = (Aig_Man_t *)dd->bFunc; + Aig_Obj_t * pObj; + int i; + printf( "Order: " ); + for ( i = 0; i < Cudd_ReadSize(dd); i++ ) + { + pObj = Aig_ManObj( pAig, i ); + if ( pObj == NULL ) + continue; + if ( Saig_ObjIsPi(pAig, pObj) ) + printf( "pi" ); + else if ( Saig_ObjIsLo(pAig, pObj) ) + printf( "lo" ); + else if ( Saig_ObjIsPo(pAig, pObj) ) + printf( "po" ); + else if ( Saig_ObjIsLi(pAig, pObj) ) + printf( "li" ); + else continue; + printf( "%d=%d ", i, dd->perm[i] ); + } + printf( "\n" ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Perform reachability with hints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinCompPerms( DdManager * dd, int * pVar2Lev ) +{ + DdSubtable * pSubt; + int i, Sum = 0, Entry; + for ( i = 0; i < dd->size; i++ ) + { + pSubt = &(dd->subtables[dd->perm[i]]); + if ( pSubt->keys == pSubt->dead + 1 ) + continue; + Entry = Abc_MaxInt(dd->perm[i], pVar2Lev[i]) - Abc_MinInt(dd->perm[i], pVar2Lev[i]); + Sum += Entry; +//printf( "%d-%d(%d) ", dd->perm[i], pV2L[i], Entry ); + } + return Sum; +} + +/**Function************************************************************* + + Synopsis [Perform reachability with hints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinReachability( Llb_Mnn_t * p ) +{ + DdNode * bTemp, * bNext; + int nIters, nBddSize0, nBddSize = -1, NumCmp;//, Limit = p->pPars->nBddMax; + abctime clk2, clk3, clk = Abc_Clock(); + assert( Aig_ManRegNum(p->pAig) > 0 ); + + // compute time to stop + p->pPars->TimeTarget = p->pPars->TimeLimit ? p->pPars->TimeLimit * CLOCKS_PER_SEC + Abc_Clock(): 0; + + // set the stop time parameter + p->dd->TimeStop = p->pPars->TimeTarget; + p->ddG->TimeStop = p->pPars->TimeTarget; + p->ddR->TimeStop = p->pPars->TimeTarget; + + // set reordering hooks + assert( p->dd->bFunc == NULL ); +// p->dd->bFunc = (DdNode *)p->pAig; +// Cudd_AddHook( p->dd, Llb_NonlinReoHook, CUDD_POST_REORDERING_HOOK ); + + // create bad state in the ring manager + p->ddR->bFunc = Llb_BddComputeBad( p->pInit, p->ddR, p->pPars->TimeTarget ); + if ( p->ddR->bFunc == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->ddR->bFunc ); + // compute the starting set of states + Cudd_Quit( p->dd ); + p->dd = Llb_NonlinImageStart( p->pAig, p->vLeaves, p->vRoots, p->pVars2Q, p->pOrderL, 1, p->pPars->TimeTarget ); + if ( p->dd == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + p->dd->bFunc = Llb_NonlinComputeInitState( p->pAig, p->dd ); Cudd_Ref( p->dd->bFunc ); // current + p->ddG->bFunc = Llb_NonlinComputeInitState( p->pAig, p->ddG ); Cudd_Ref( p->ddG->bFunc ); // reached + p->ddG->bFunc2 = Llb_NonlinComputeInitState( p->pAig, p->ddG ); Cudd_Ref( p->ddG->bFunc2 ); // frontier + for ( nIters = 0; nIters < p->pPars->nIterMax; nIters++ ) + { + // check the runtime limit + clk2 = Abc_Clock(); + if ( p->pPars->TimeLimit && Abc_Clock() > p->pPars->TimeTarget ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Llb_NonlinImageQuit(); + return -1; + } + + // save the onion ring + bTemp = Extra_TransferPermute( p->dd, p->ddR, p->dd->bFunc, Vec_IntArray(p->vCs2Glo) ); + if ( bTemp == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during ring transfer.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( bTemp ); + Vec_PtrPush( p->vRings, bTemp ); + + // check it for bad states + if ( !p->pPars->fSkipOutCheck && !Cudd_bddLeq( p->ddR, bTemp, Cudd_Not(p->ddR->bFunc) ) ) + { + assert( p->pInit->pSeqModel == NULL ); + if ( !p->pPars->fBackward ) + p->pInit->pSeqModel = Llb_NonlinDeriveCex( p ); + if ( !p->pPars->fSilent ) + { + if ( !p->pPars->fBackward ) + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", p->pInit->pSeqModel->iPo, nIters ); + else + Abc_Print( 1, "Output ??? was asserted in frame %d (counter-example is not produced). ", nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = nIters - 1; + Llb_NonlinImageQuit(); + return 0; + } + + // compute the next states + clk3 = Abc_Clock(); + nBddSize0 = Cudd_DagSize( p->dd->bFunc ); + bNext = Llb_NonlinImageCompute( p->dd->bFunc, p->pPars->fReorder, 0, 1, p->pOrderL ); // consumes ref +// bNext = Llb_NonlinImage( p->pAig, p->vLeaves, p->vRoots, p->pVars2Q, p->dd, bCurrent, +// p->pPars->fReorder, p->pPars->fVeryVerbose, NULL, ABC_INFINITY, p->pPars->TimeTarget ); + if ( bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in quantification.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( bNext ); + nBddSize = Cudd_DagSize( bNext ); + p->timeImage += Abc_Clock() - clk3; + + + // transfer to the state manager + clk3 = Abc_Clock(); + Cudd_RecursiveDeref( p->ddG, p->ddG->bFunc2 ); + p->ddG->bFunc2 = Extra_TransferPermute( p->dd, p->ddG, bNext, Vec_IntArray(p->vNs2Glo) ); +// p->ddG->bFunc2 = Extra_bddAndPermute( p->ddG, Cudd_Not(p->ddG->bFunc), p->dd, bNext, Vec_IntArray(p->vNs2Glo) ); + if ( p->ddG->bFunc2 == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bNext ); + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( p->ddG->bFunc2 ); + Cudd_RecursiveDeref( p->dd, bNext ); + p->timeTran1 += Abc_Clock() - clk3; + + // save permutation + NumCmp = Llb_NonlinCompPerms( p->dd, p->pOrderL2 ); + // save order before image computation + memcpy( p->pOrderL2, p->dd->perm, sizeof(int) * p->dd->size ); + // update the image computation manager + p->timeReo += Cudd_ReadReorderingTime(p->dd); + p->ddLocReos += Cudd_ReadReorderings(p->dd); + p->ddLocGrbs += Cudd_ReadGarbageCollections(p->dd); + Llb_NonlinImageQuit(); + p->dd = Llb_NonlinImageStart( p->pAig, p->vLeaves, p->vRoots, p->pVars2Q, p->pOrderL, 0, p->pPars->TimeTarget ); + if ( p->dd == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + return -1; + } + //Extra_TestAndPerm( p->ddG, Cudd_Not(p->ddG->bFunc), p->ddG->bFunc2 ); + + // derive new states + clk3 = Abc_Clock(); + p->ddG->bFunc2 = Cudd_bddAnd( p->ddG, bTemp = p->ddG->bFunc2, Cudd_Not(p->ddG->bFunc) ); + if ( p->ddG->bFunc2 == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->ddG, bTemp ); + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( p->ddG->bFunc2 ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + p->timeGloba += Abc_Clock() - clk3; + + if ( Cudd_IsConstant(p->ddG->bFunc2) ) + break; + // add to the reached set + clk3 = Abc_Clock(); + p->ddG->bFunc = Cudd_bddOr( p->ddG, bTemp = p->ddG->bFunc, p->ddG->bFunc2 ); + if ( p->ddG->bFunc == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->ddG, bTemp ); + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( p->ddG->bFunc ); + Cudd_RecursiveDeref( p->ddG, bTemp ); + p->timeGloba += Abc_Clock() - clk3; + + // reset permutation +// RetValue = Cudd_CheckZeroRef( dd ); +// assert( RetValue == 0 ); +// Cudd_ShuffleHeap( dd, pOrderG ); + + // move new states to the working manager + clk3 = Abc_Clock(); + p->dd->bFunc = Extra_TransferPermute( p->ddG, p->dd, p->ddG->bFunc2, Vec_IntArray(p->vGlo2Cs) ); + if ( p->dd->bFunc == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 2.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Llb_NonlinImageQuit(); + return -1; + } + Cudd_Ref( p->dd->bFunc ); + p->timeTran2 += Abc_Clock() - clk3; + + // report the results + if ( p->pPars->fVerbose ) + { + printf( "I =%3d : ", nIters ); + printf( "Fr =%7d ", nBddSize0 ); + printf( "Im =%7d ", nBddSize ); + printf( "(%4d %4d) ", p->ddLocReos, p->ddLocGrbs ); + printf( "Rea =%6d ", Cudd_DagSize(p->ddG->bFunc) ); + printf( "(%4d %4d) ", Cudd_ReadReorderings(p->ddG), Cudd_ReadGarbageCollections(p->ddG) ); + printf( "S =%4d ", nSuppMax ); + printf( "cL =%5d ", NumCmp ); + printf( "cG =%5d ", Llb_NonlinCompPerms( p->ddG, p->pOrderG ) ); + Abc_PrintTime( 1, "T", Abc_Clock() - clk2 ); + memcpy( p->pOrderG, p->ddG->perm, sizeof(int) * p->ddG->size ); + } +/* + if ( pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(ddG, bReached, Saig_ManRegNum(pAig) ); +// Extra_bddPrint( ddG, bReached );printf( "\n" ); + printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(pAig)) ); + fflush( stdout ); + } +*/ + if ( nIters == p->pPars->nIterMax - 1 ) + { + if ( !p->pPars->fSilent ) + printf( "Reached limit on the number of timeframes (%d).\n", p->pPars->nIterMax ); + p->pPars->iFrame = nIters; + Llb_NonlinImageQuit(); + return -1; + } + } + Llb_NonlinImageQuit(); + + // report the stats + if ( p->pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->ddG, p->ddG->bFunc, Saig_ManRegNum(p->pAig) ); + if ( nIters >= p->pPars->nIterMax || nBddSize > p->pPars->nBddMax ) + printf( "Reachability analysis is stopped after %d frames.\n", nIters ); + else + printf( "Reachability analysis completed after %d frames.\n", nIters ); + printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } + if ( nIters >= p->pPars->nIterMax || nBddSize > p->pPars->nBddMax ) + { + if ( !p->pPars->fSilent ) + printf( "Verified only for states reachable in %d frames. ", nIters ); + p->pPars->iFrame = p->pPars->nIterMax; + return -1; // undecided + } + // report + if ( !p->pPars->fSilent ) + printf( "The miter is proved unreachable after %d iterations. ", nIters ); + p->pPars->iFrame = nIters - 1; + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + return 1; // unreachable +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mnn_t * Llb_MnnStart( Aig_Man_t * pInit, Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Mnn_t * p; + Aig_Obj_t * pObj; + int i; + p = ABC_CALLOC( Llb_Mnn_t, 1 ); + p->pInit = pInit; + p->pAig = pAig; + p->pPars = pPars; + p->dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + p->ddG = Cudd_Init( Aig_ManRegNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + p->ddR = Cudd_Init( Aig_ManCiNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddG, CUDD_REORDER_SYMM_SIFT ); + Cudd_AutodynEnable( p->ddR, CUDD_REORDER_SYMM_SIFT ); + p->vRings = Vec_PtrAlloc( 100 ); + // create leaves + p->vLeaves = Vec_PtrAlloc( Aig_ManCiNum(pAig) ); + Aig_ManForEachCi( pAig, pObj, i ) + Vec_PtrPush( p->vLeaves, pObj ); + // create roots + p->vRoots = Vec_PtrAlloc( Aig_ManCoNum(pAig) ); + Saig_ManForEachLi( pAig, pObj, i ) + Vec_PtrPush( p->vRoots, pObj ); + // variables to quantify + p->pOrderL = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) ); + p->pOrderL2= ABC_CALLOC( int, Aig_ManObjNumMax(pAig) ); + p->pOrderG = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) ); + p->pVars2Q = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) ); + Aig_ManForEachCi( pAig, pObj, i ) + p->pVars2Q[Aig_ObjId(pObj)] = 1; + for ( i = 0; i < Aig_ManObjNumMax(pAig); i++ ) + p->pOrderL[i] = p->pOrderL2[i] = p->pOrderG[i] = i; + Llb_NonlinPrepareVarMap( p ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MnnStop( Llb_Mnn_t * p ) +{ + DdNode * bTemp; + int i; + if ( p->pPars->fVerbose ) + { + p->timeOther = p->timeTotal - p->timeImage - p->timeTran1 - p->timeTran2 - p->timeGloba; + p->timeReoG = Cudd_ReadReorderingTime(p->ddG); + ABC_PRTP( "Image ", p->timeImage, p->timeTotal ); + ABC_PRTP( " build ", timeBuild, p->timeTotal ); + ABC_PRTP( " and-ex ", timeAndEx, p->timeTotal ); + ABC_PRTP( " other ", timeOther, p->timeTotal ); + ABC_PRTP( "Transfer1", p->timeTran1, p->timeTotal ); + ABC_PRTP( "Transfer2", p->timeTran2, p->timeTotal ); + ABC_PRTP( "Global ", p->timeGloba, p->timeTotal ); + ABC_PRTP( "Other ", p->timeOther, p->timeTotal ); + ABC_PRTP( "TOTAL ", p->timeTotal, p->timeTotal ); + ABC_PRTP( " reo ", p->timeReo, p->timeTotal ); + ABC_PRTP( " reoG ", p->timeReoG, p->timeTotal ); + } + if ( p->ddR->bFunc ) + Cudd_RecursiveDeref( p->ddR, p->ddR->bFunc ); + Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i ) + Cudd_RecursiveDeref( p->ddR, bTemp ); + Vec_PtrFree( p->vRings ); + if ( p->ddG->bFunc ) + Cudd_RecursiveDeref( p->ddG, p->ddG->bFunc ); + if ( p->ddG->bFunc2 ) + Cudd_RecursiveDeref( p->ddG, p->ddG->bFunc2 ); +// printf( "manager1\n" ); +// Extra_StopManager( p->dd ); +// printf( "manager2\n" ); + Extra_StopManager( p->ddG ); +// printf( "manager3\n" ); + Extra_StopManager( p->ddR ); + Vec_IntFreeP( &p->vCs2Glo ); + Vec_IntFreeP( &p->vNs2Glo ); + Vec_IntFreeP( &p->vGlo2Cs ); + Vec_IntFreeP( &p->vGlo2Ns ); + Vec_PtrFree( p->vLeaves ); + Vec_PtrFree( p->vRoots ); + ABC_FREE( p->pVars2Q ); + ABC_FREE( p->pOrderL ); + ABC_FREE( p->pOrderL2 ); + ABC_FREE( p->pOrderG ); + ABC_FREE( p ); +} + + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_NonlinExperiment( Aig_Man_t * pAig, int Num ) +{ + Llb_Mnn_t * pMnn; + Gia_ParLlb_t Pars, * pPars = &Pars; + Aig_Man_t * p; + abctime clk = Abc_Clock(); + + Llb_ManSetDefaultParams( pPars ); + pPars->fVerbose = 1; + + p = Aig_ManDupFlopsOnly( pAig ); +//Aig_ManShow( p, 0, NULL ); + Aig_ManPrintStats( pAig ); + Aig_ManPrintStats( p ); + + pMnn = Llb_MnnStart( pAig, p, pPars ); + Llb_NonlinReachability( pMnn ); + pMnn->timeTotal = Abc_Clock() - clk; + Llb_MnnStop( pMnn ); + + Aig_ManStop( p ); +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_NonlinCoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Mnn_t * pMnn; + Aig_Man_t * p; + int RetValue = -1; + + p = Aig_ManDupFlopsOnly( pAig ); +//Aig_ManShow( p, 0, NULL ); + if ( pPars->fVerbose ) + Aig_ManPrintStats( pAig ); + if ( pPars->fVerbose ) + Aig_ManPrintStats( p ); + + if ( !pPars->fSkipReach ) + { + abctime clk = Abc_Clock(); + pMnn = Llb_MnnStart( pAig, p, pPars ); + RetValue = Llb_NonlinReachability( pMnn ); + pMnn->timeTotal = Abc_Clock() - clk; + Llb_MnnStop( pMnn ); + } + + Aig_ManStop( p ); + return RetValue; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Cex.c b/src/bdd/llb/llb4Cex.c new file mode 100644 index 00000000..18aeaf04 --- /dev/null +++ b/src/bdd/llb/llb4Cex.c @@ -0,0 +1,320 @@ +/**CFile**************************************************************** + + FileName [llb2Cex.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Cex.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" +#include "sat/cnf/cnf.h" +#include "sat/bsat/satSolver.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Translates a sequence of states into a counter-example.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Llb4_Nonlin4TransformCex( Aig_Man_t * pAig, Vec_Ptr_t * vStates, int iCexPo, int fVerbose ) +{ + Abc_Cex_t * pCex; + Cnf_Dat_t * pCnf; + Vec_Int_t * vAssumps; + sat_solver * pSat; + Aig_Obj_t * pObj; + unsigned * pNext, * pThis; + int i, k, iBit, status, nRegs;//, clk = Abc_Clock(); +/* + Vec_PtrForEachEntry( unsigned *, vStates, pNext, i ) + { + printf( "%4d : ", i ); + Extra_PrintBinary( stdout, pNext, Aig_ManRegNum(pAig) ); + printf( "\n" ); + } +*/ + // derive SAT solver + nRegs = Aig_ManRegNum(pAig); pAig->nRegs = 0; + pCnf = Cnf_Derive( pAig, Aig_ManCoNum(pAig) ); + pAig->nRegs = nRegs; +// Cnf_DataTranformPolarity( pCnf, 0 ); + // convert into SAT solver + pSat = (sat_solver *)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); + if ( pSat == NULL ) + { + printf( "Llb4_Nonlin4TransformCex(): Counter-example generation has failed.\n" ); + Cnf_DataFree( pCnf ); + return NULL; + } + // simplify the problem + status = sat_solver_simplify(pSat); + if ( status == 0 ) + { + printf( "Llb4_Nonlin4TransformCex(): SAT solver is invalid.\n" ); + sat_solver_delete( pSat ); + Cnf_DataFree( pCnf ); + return NULL; + } + // start the counter-example + pCex = Abc_CexAlloc( Saig_ManRegNum(pAig), Saig_ManPiNum(pAig), Vec_PtrSize(vStates) ); + pCex->iFrame = Vec_PtrSize(vStates)-1; + pCex->iPo = -1; + + // solve each time frame + iBit = Saig_ManRegNum(pAig); + pThis = (unsigned *)Vec_PtrEntry( vStates, 0 ); + vAssumps = Vec_IntAlloc( 2 * Aig_ManRegNum(pAig) ); + Vec_PtrForEachEntryStart( unsigned *, vStates, pNext, i, 1 ) + { + // create assumptions + Vec_IntClear( vAssumps ); + Saig_ManForEachLo( pAig, pObj, k ) + Vec_IntPush( vAssumps, toLitCond( pCnf->pVarNums[Aig_ObjId(pObj)], !Abc_InfoHasBit(pThis,k) ) ); + Saig_ManForEachLi( pAig, pObj, k ) + Vec_IntPush( vAssumps, toLitCond( pCnf->pVarNums[Aig_ObjId(pObj)], !Abc_InfoHasBit(pNext,k) ) ); + // solve SAT problem + status = sat_solver_solve( pSat, Vec_IntArray(vAssumps), Vec_IntArray(vAssumps) + Vec_IntSize(vAssumps), + (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 ); + // if the problem is SAT, get the counterexample + if ( status != l_True ) + { + printf( "Llb4_Nonlin4TransformCex(): There is no transition between state %d and %d.\n", i-1, i ); + Vec_IntFree( vAssumps ); + sat_solver_delete( pSat ); + Cnf_DataFree( pCnf ); + ABC_FREE( pCex ); + return NULL; + } + // get the assignment of PIs + Saig_ManForEachPi( pAig, pObj, k ) + if ( sat_solver_var_value(pSat, pCnf->pVarNums[Aig_ObjId(pObj)]) ) + Abc_InfoSetBit( pCex->pData, iBit + k ); + // update the counter + iBit += Saig_ManPiNum(pAig); + pThis = pNext; + } + + // add the last frame when the property fails + Vec_IntClear( vAssumps ); + if ( iCexPo >= 0 ) + { + Saig_ManForEachPo( pAig, pObj, k ) + if ( k == iCexPo ) + Vec_IntPush( vAssumps, toLitCond( pCnf->pVarNums[Aig_ObjId(pObj)], 0 ) ); + } + else + { + Saig_ManForEachPo( pAig, pObj, k ) + Vec_IntPush( vAssumps, toLitCond( pCnf->pVarNums[Aig_ObjId(pObj)], 0 ) ); + } + + // add clause + status = sat_solver_addclause( pSat, Vec_IntArray(vAssumps), Vec_IntArray(vAssumps) + Vec_IntSize(vAssumps) ); + if ( status == 0 ) + { + printf( "Llb4_Nonlin4TransformCex(): The SAT solver is unsat after adding last clause.\n" ); + Vec_IntFree( vAssumps ); + sat_solver_delete( pSat ); + Cnf_DataFree( pCnf ); + ABC_FREE( pCex ); + return NULL; + } + // create assumptions + Vec_IntClear( vAssumps ); + Saig_ManForEachLo( pAig, pObj, k ) + Vec_IntPush( vAssumps, toLitCond( pCnf->pVarNums[Aig_ObjId(pObj)], !Abc_InfoHasBit(pThis,k) ) ); + // solve the last frame + status = sat_solver_solve( pSat, Vec_IntArray(vAssumps), Vec_IntArray(vAssumps) + Vec_IntSize(vAssumps), + (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 ); + if ( status != l_True ) + { + printf( "Llb4_Nonlin4TransformCex(): There is no last transition that makes the property fail.\n" ); + Vec_IntFree( vAssumps ); + sat_solver_delete( pSat ); + Cnf_DataFree( pCnf ); + ABC_FREE( pCex ); + return NULL; + } + // get the assignment of PIs + Saig_ManForEachPi( pAig, pObj, k ) + if ( sat_solver_var_value(pSat, pCnf->pVarNums[Aig_ObjId(pObj)]) ) + Abc_InfoSetBit( pCex->pData, iBit + k ); + iBit += Saig_ManPiNum(pAig); + assert( iBit == pCex->nBits ); + + // free the sat_solver + Vec_IntFree( vAssumps ); + sat_solver_delete( pSat ); + Cnf_DataFree( pCnf ); + + // verify counter-example + status = Saig_ManFindFailedPoCex( pAig, pCex ); + if ( status >= 0 && status < Saig_ManPoNum(pAig) ) + pCex->iPo = status; + else + { + printf( "Llb4_Nonlin4TransformCex(): Counter-example verification has FAILED.\n" ); + ABC_FREE( pCex ); + return NULL; + } + // report the results +// if ( fVerbose ) +// Abc_PrintTime( 1, "SAT-based cex generation time", Abc_Clock() - clk ); + return pCex; +} + + +/**Function************************************************************* + + Synopsis [Resimulates the counter-example.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb4_Nonlin4VerifyCex( Aig_Man_t * pAig, Abc_Cex_t * p ) +{ + Vec_Ptr_t * vStates; + Aig_Obj_t * pObj, * pObjRi, * pObjRo; + int i, k, iBit = 0; + // create storage for states + vStates = Vec_PtrAllocSimInfo( p->iFrame+1, Abc_BitWordNum(Aig_ManRegNum(pAig)) ); + Vec_PtrCleanSimInfo( vStates, 0, Abc_BitWordNum(Aig_ManRegNum(pAig)) ); + // verify counter-example + Aig_ManCleanMarkB(pAig); + Aig_ManConst1(pAig)->fMarkB = 1; + Saig_ManForEachLo( pAig, pObj, i ) + pObj->fMarkB = 0; //Abc_InfoHasBit(p->pData, iBit++); + // do not require equal flop count in the AIG and in the CEX + iBit = p->nRegs; + for ( i = 0; i <= p->iFrame; i++ ) + { + // save current state + Saig_ManForEachLo( pAig, pObj, k ) + if ( pObj->fMarkB ) + Abc_InfoSetBit( (unsigned *)Vec_PtrEntry(vStates, i), k ); + // compute new state + Saig_ManForEachPi( pAig, pObj, k ) + pObj->fMarkB = Abc_InfoHasBit(p->pData, iBit++); + Aig_ManForEachNode( pAig, pObj, k ) + pObj->fMarkB = (Aig_ObjFanin0(pObj)->fMarkB ^ Aig_ObjFaninC0(pObj)) & + (Aig_ObjFanin1(pObj)->fMarkB ^ Aig_ObjFaninC1(pObj)); + Aig_ManForEachCo( pAig, pObj, k ) + pObj->fMarkB = Aig_ObjFanin0(pObj)->fMarkB ^ Aig_ObjFaninC0(pObj); + if ( i == p->iFrame ) + break; + Saig_ManForEachLiLo( pAig, pObjRi, pObjRo, k ) + pObjRo->fMarkB = pObjRi->fMarkB; + } +/* + { + unsigned * pNext; + Vec_PtrForEachEntry( unsigned *, vStates, pNext, i ) + { + printf( "%4d : ", i ); + Extra_PrintBinary( stdout, pNext, Aig_ManRegNum(pAig) ); + printf( "\n" ); + } + } +*/ + assert( iBit == p->nBits ); +// if ( Aig_ManCo(pAig, p->iPo)->fMarkB == 0 ) +// Vec_PtrFreeP( &vStates ); + for ( i = Saig_ManPoNum(pAig) - 1; i >= 0; i-- ) + { + if ( Aig_ManCo(pAig, i)->fMarkB ) + { + p->iPo = i; + break; + } + } + if ( i == -1 ) + Vec_PtrFreeP( &vStates ); + Aig_ManCleanMarkB(pAig); + return vStates; +} + +/**Function************************************************************* + + Synopsis [Translates a sequence of states into a counter-example.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Cex_t * Llb4_Nonlin4NormalizeCex( Aig_Man_t * pAigOrg, Aig_Man_t * pAigRpm, Abc_Cex_t * pCexRpm ) +{ + Abc_Cex_t * pCexOrg; + Vec_Ptr_t * vStates; + // check parameters of the AIG + if ( Saig_ManRegNum(pAigOrg) != Saig_ManRegNum(pAigRpm) ) + { + printf( "Llb4_Nonlin4NormalizeCex(): The number of flops in the original and reparametrized AIGs do not agree.\n" ); + return NULL; + } +/* + if ( Saig_ManRegNum(pAigRpm) != pCexRpm->nRegs ) + { + printf( "Llb4_Nonlin4NormalizeCex(): The number of flops in the reparametrized AIG and in the CEX do not agree.\n" ); + return NULL; + } +*/ + if ( Saig_ManPiNum(pAigRpm) != pCexRpm->nPis ) + { + printf( "Llb4_Nonlin4NormalizeCex(): The number of PIs in the reparametrized AIG and in the CEX do not agree.\n" ); + return NULL; + } + // get the sequence of states + vStates = Llb4_Nonlin4VerifyCex( pAigRpm, pCexRpm ); + if ( vStates == NULL ) + { + Abc_Print( 1, "Llb4_Nonlin4NormalizeCex(): The given CEX does not fail outputs of pAigRpm.\n" ); + return NULL; + } + // derive updated counter-example + pCexOrg = Llb4_Nonlin4TransformCex( pAigOrg, vStates, pCexRpm->iPo, 0 ); + Vec_PtrFree( vStates ); + return pCexOrg; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Cluster.c b/src/bdd/llb/llb4Cluster.c new file mode 100644 index 00000000..7e325597 --- /dev/null +++ b/src/bdd/llb/llb4Cluster.c @@ -0,0 +1,452 @@ +/**CFile**************************************************************** + + FileName [llb2Cluster.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Cluster.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4FindOrder_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Int_t * vOrder, int * pCounter ) +{ + Aig_Obj_t * pFanin0, * pFanin1; + if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) + return; + Aig_ObjSetTravIdCurrent( pAig, pObj ); + assert( Llb_ObjBddVar(vOrder, pObj) < 0 ); + if ( Aig_ObjIsCi(pObj) ) + { + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); + return; + } + // try fanins with higher level first + pFanin0 = Aig_ObjFanin0(pObj); + pFanin1 = Aig_ObjFanin1(pObj); +// if ( pFanin0->Level > pFanin1->Level || (pFanin0->Level == pFanin1->Level && pFanin0->Id < pFanin1->Id) ) + if ( pFanin0->Level > pFanin1->Level ) + { + Llb_Nonlin4FindOrder_rec( pAig, pFanin0, vOrder, pCounter ); + Llb_Nonlin4FindOrder_rec( pAig, pFanin1, vOrder, pCounter ); + } + else + { + Llb_Nonlin4FindOrder_rec( pAig, pFanin1, vOrder, pCounter ); + Llb_Nonlin4FindOrder_rec( pAig, pFanin0, vOrder, pCounter ); + } + if ( pObj->fMarkA ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); +} + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4FindOrder( Aig_Man_t * pAig, int * pCounter ) +{ + Vec_Int_t * vNodes = NULL; + Vec_Int_t * vOrder; + Aig_Obj_t * pObj; + int i, Counter = 0; + // mark nodes to exclude: AND with low level and CO drivers + Aig_ManCleanMarkA( pAig ); + Aig_ManForEachNode( pAig, pObj, i ) + if ( Aig_ObjLevel(pObj) > 3 ) + pObj->fMarkA = 1; + Aig_ManForEachCo( pAig, pObj, i ) + Aig_ObjFanin0(pObj)->fMarkA = 0; + + // collect nodes in the order + vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); + Aig_ManIncrementTravId( pAig ); + Aig_ObjSetTravIdCurrent( pAig, Aig_ManConst1(pAig) ); +// Aig_ManForEachCo( pAig, pObj, i ) + Saig_ManForEachLi( pAig, pObj, i ) + { + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + Llb_Nonlin4FindOrder_rec( pAig, Aig_ObjFanin0(pObj), vOrder, &Counter ); + } + Aig_ManForEachCi( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + Aig_ManCleanMarkA( pAig ); + Vec_IntFreeP( &vNodes ); +// assert( Counter == Aig_ManObjNum(pAig) - 1 ); + +/* + Saig_ManForEachPi( pAig, pObj, i ) + printf( "pi%d ", Llb_ObjBddVar(vOrder, pObj) ); + printf( "\n" ); + Saig_ManForEachLo( pAig, pObj, i ) + printf( "lo%d ", Llb_ObjBddVar(vOrder, pObj) ); + printf( "\n" ); + Saig_ManForEachPo( pAig, pObj, i ) + printf( "po%d ", Llb_ObjBddVar(vOrder, pObj) ); + printf( "\n" ); + Saig_ManForEachLi( pAig, pObj, i ) + printf( "li%d ", Llb_ObjBddVar(vOrder, pObj) ); + printf( "\n" ); + Aig_ManForEachNode( pAig, pObj, i ) + printf( "n%d ", Llb_ObjBddVar(vOrder, pObj) ); + printf( "\n" ); +*/ + if ( pCounter ) + *pCounter = Counter; + return vOrder; +} + +/**Function************************************************************* + + Synopsis [Derives BDDs for the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4FindPartitions_rec( DdManager * dd, Aig_Obj_t * pObj, Vec_Int_t * vOrder, Vec_Ptr_t * vRoots ) +{ + DdNode * bBdd, * bBdd0, * bBdd1, * bPart, * vVar; + if ( Aig_ObjIsConst1(pObj) ) + return Cudd_ReadOne(dd); + if ( Aig_ObjIsCi(pObj) ) + return Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + if ( pObj->pData ) + return (DdNode *)pObj->pData; + if ( Aig_ObjIsCo(pObj) ) + { + bBdd0 = Cudd_NotCond( Llb_Nonlin4FindPartitions_rec(dd, Aig_ObjFanin0(pObj), vOrder, vRoots), Aig_ObjFaninC0(pObj) ); + bPart = Cudd_bddXnor( dd, Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ), bBdd0 ); Cudd_Ref( bPart ); + Vec_PtrPush( vRoots, bPart ); + return NULL; + } + bBdd0 = Cudd_NotCond( Llb_Nonlin4FindPartitions_rec(dd, Aig_ObjFanin0(pObj), vOrder, vRoots), Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( Llb_Nonlin4FindPartitions_rec(dd, Aig_ObjFanin1(pObj), vOrder, vRoots), Aig_ObjFaninC1(pObj) ); + bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( bBdd ); + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + { + vVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + bPart = Cudd_bddXnor( dd, vVar, bBdd ); Cudd_Ref( bPart ); + Vec_PtrPush( vRoots, bPart ); + Cudd_RecursiveDeref( dd, bBdd ); + bBdd = vVar; Cudd_Ref( vVar ); + } + pObj->pData = bBdd; + return bBdd; +} + +/**Function************************************************************* + + Synopsis [Derives BDDs for the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4FindPartitions( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fOutputs ) +{ + Vec_Ptr_t * vRoots; + Aig_Obj_t * pObj; + int i; + Aig_ManCleanData( pAig ); + vRoots = Vec_PtrAlloc( 100 ); + if ( fOutputs ) + { + Saig_ManForEachPo( pAig, pObj, i ) + Llb_Nonlin4FindPartitions_rec( dd, pObj, vOrder, vRoots ); + } + else + { + Saig_ManForEachLi( pAig, pObj, i ) + Llb_Nonlin4FindPartitions_rec( dd, pObj, vOrder, vRoots ); + } + Aig_ManForEachNode( pAig, pObj, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + return vRoots; +} + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4FindVars2Q( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) +{ + Vec_Int_t * vVars2Q; + Aig_Obj_t * pObj; + int i; + vVars2Q = Vec_IntAlloc( 0 ); + Vec_IntFill( vVars2Q, Cudd_ReadSize(dd), 1 ); + Saig_ManForEachLo( pAig, pObj, i ) + Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, pObj), 0 ); +// Aig_ManForEachCo( pAig, pObj, i ) + Saig_ManForEachLi( pAig, pObj, i ) + Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, pObj), 0 ); + return vVars2Q; +} + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4CountTerms( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, DdNode * bFunc, int fCo, int fFlop ) +{ + DdNode * bSupp; + Aig_Obj_t * pObj; + int i, Counter = 0; + bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); + if ( !fCo && !fFlop ) + { + Saig_ManForEachPi( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + Counter += Cudd_bddLeq( dd, bSupp, Cudd_bddIthVar(dd, Llb_ObjBddVar(vOrder, pObj)) ); + } + else if ( fCo && !fFlop ) + { + Saig_ManForEachPo( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + Counter += Cudd_bddLeq( dd, bSupp, Cudd_bddIthVar(dd, Llb_ObjBddVar(vOrder, pObj)) ); + } + else if ( !fCo && fFlop ) + { + Saig_ManForEachLo( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + Counter += Cudd_bddLeq( dd, bSupp, Cudd_bddIthVar(dd, Llb_ObjBddVar(vOrder, pObj)) ); + } + else if ( fCo && fFlop ) + { + Saig_ManForEachLi( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + Counter += Cudd_bddLeq( dd, bSupp, Cudd_bddIthVar(dd, Llb_ObjBddVar(vOrder, pObj)) ); + } + Cudd_RecursiveDeref( dd, bSupp ); + return Counter; +} + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4PrintGroups( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, Vec_Ptr_t * vGroups ) +{ + DdNode * bTemp; + int i, nSuppAll, nSuppPi, nSuppPo, nSuppLi, nSuppLo, nSuppAnd; + Vec_PtrForEachEntry( DdNode *, vGroups, bTemp, i ) + { +//Extra_bddPrintSupport(dd, bTemp); printf("\n" ); + nSuppAll = Cudd_SupportSize(dd,bTemp); + nSuppPi = Llb_Nonlin4CountTerms(dd, pAig, vOrder, bTemp, 0, 0); + nSuppPo = Llb_Nonlin4CountTerms(dd, pAig, vOrder, bTemp, 1, 0); + nSuppLi = Llb_Nonlin4CountTerms(dd, pAig, vOrder, bTemp, 0, 1); + nSuppLo = Llb_Nonlin4CountTerms(dd, pAig, vOrder, bTemp, 1, 1); + nSuppAnd = nSuppAll - (nSuppPi+nSuppPo+nSuppLi+nSuppLo); + + if ( Cudd_DagSize(bTemp) <= 10 ) + continue; + + printf( "%4d : bdd =%6d supp =%3d ", i, Cudd_DagSize(bTemp), nSuppAll ); + printf( "pi =%3d ", nSuppPi ); + printf( "po =%3d ", nSuppPo ); + printf( "lo =%3d ", nSuppLo ); + printf( "li =%3d ", nSuppLi ); + printf( "and =%3d", nSuppAnd ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4PrintSuppProfile( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, Vec_Ptr_t * vGroups ) +{ + Aig_Obj_t * pObj; + int i, * pSupp; + int nSuppAll = 0, nSuppPi = 0, nSuppPo = 0, nSuppLi = 0, nSuppLo = 0, nSuppAnd = 0; + + pSupp = ABC_CALLOC( int, Cudd_ReadSize(dd) ); + Extra_VectorSupportArray( dd, (DdNode **)Vec_PtrArray(vGroups), Vec_PtrSize(vGroups), pSupp ); + + Aig_ManForEachObj( pAig, pObj, i ) + { + if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) + continue; + // remove variables that do not participate + if ( pSupp[Llb_ObjBddVar(vOrder, pObj)] == 0 ) + { + if ( Aig_ObjIsNode(pObj) ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), -1 ); + continue; + } + nSuppAll++; + if ( Saig_ObjIsPi(pAig, pObj) ) + nSuppPi++; + else if ( Saig_ObjIsLo(pAig, pObj) ) + nSuppLo++; + else if ( Saig_ObjIsPo(pAig, pObj) ) + nSuppPo++; + else if ( Saig_ObjIsLi(pAig, pObj) ) + nSuppLi++; + else + nSuppAnd++; + } + ABC_FREE( pSupp ); + + printf( "Groups =%3d ", Vec_PtrSize(vGroups) ); + printf( "Variables: all =%4d ", nSuppAll ); + printf( "pi =%4d ", nSuppPi ); + printf( "po =%4d ", nSuppPo ); + printf( "lo =%4d ", nSuppLo ); + printf( "li =%4d ", nSuppLi ); + printf( "and =%4d", nSuppAnd ); + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4Cluster( Aig_Man_t * pAig, DdManager ** pdd, Vec_Int_t ** pvOrder, Vec_Ptr_t ** pvGroups, int nBddMax, int fVerbose ) +{ + DdManager * dd; + Vec_Int_t * vOrder, * vVars2Q; + Vec_Ptr_t * vParts, * vGroups; + DdNode * bTemp; + int i, nVarNum; + + // create the BDD manager + vOrder = Llb_Nonlin4FindOrder( pAig, &nVarNum ); + dd = Cudd_Init( nVarNum, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); +// Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + + vVars2Q = Llb_Nonlin4FindVars2Q( dd, pAig, vOrder ); + vParts = Llb_Nonlin4FindPartitions( dd, pAig, vOrder, 0 ); + + vGroups = Llb_Nonlin4Group( dd, vParts, vVars2Q, nBddMax ); + Vec_IntFree( vVars2Q ); + + Vec_PtrForEachEntry( DdNode *, vParts, bTemp, i ) + Cudd_RecursiveDeref( dd, bTemp ); + Vec_PtrFree( vParts ); + + +// if ( fVerbose ) + Llb_Nonlin4PrintSuppProfile( dd, pAig, vOrder, vGroups ); + if ( fVerbose ) + printf( "Before reordering\n" ); + if ( fVerbose ) + Llb_Nonlin4PrintGroups( dd, pAig, vOrder, vGroups ); + +// Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 1 ); +// printf( "After reordering\n" ); +// Llb_Nonlin4PrintGroups( dd, pAig, vOrder, vGroups ); + + if ( pvOrder ) + *pvOrder = vOrder; + else + Vec_IntFree( vOrder ); + + if ( pvGroups ) + *pvGroups = vGroups; + else + { + Vec_PtrForEachEntry( DdNode *, vGroups, bTemp, i ) + Cudd_RecursiveDeref( dd, bTemp ); + Vec_PtrFree( vGroups ); + } + + if ( pdd ) + *pdd = dd; + else + Extra_StopManager( dd ); +// Cudd_Quit( dd ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Image.c b/src/bdd/llb/llb4Image.c new file mode 100644 index 00000000..2ba4fcfd --- /dev/null +++ b/src/bdd/llb/llb4Image.c @@ -0,0 +1,863 @@ +/**CFile**************************************************************** + + FileName [llb3Image.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Computes image using partitioned structure.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb3Image.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Var_t_ Llb_Var_t; +struct Llb_Var_t_ +{ + int iVar; // variable number + int nScore; // variable score + Vec_Int_t * vParts; // partitions +}; + +typedef struct Llb_Prt_t_ Llb_Prt_t; +struct Llb_Prt_t_ +{ + int iPart; // partition number + int nSize; // the number of BDD nodes + DdNode * bFunc; // the partition + Vec_Int_t * vVars; // support +}; + +typedef struct Llb_Mgr_t_ Llb_Mgr_t; +struct Llb_Mgr_t_ +{ + DdManager * dd; // working BDD manager + Vec_Int_t * vVars2Q; // variables to quantify + int nSizeMax; // maximum size of the cluster + // internal + Llb_Prt_t ** pParts; // partitions + Llb_Var_t ** pVars; // variables + int iPartFree; // next free partition + int nVars; // the number of BDD variables + int nSuppMax; // maximum support size + // temporary + int * pSupp; // temporary support storage +}; + +static inline Llb_Var_t * Llb_MgrVar( Llb_Mgr_t * p, int i ) { return p->pVars[i]; } +static inline Llb_Prt_t * Llb_MgrPart( Llb_Mgr_t * p, int i ) { return p->pParts[i]; } + +// iterator over vars +#define Llb_MgrForEachVar( p, pVar, i ) \ + for ( i = 0; (i < p->nVars) && (((pVar) = Llb_MgrVar(p, i)), 1); i++ ) if ( pVar == NULL ) {} else +// iterator over parts +#define Llb_MgrForEachPart( p, pPart, i ) \ + for ( i = 0; (i < p->iPartFree) && (((pPart) = Llb_MgrPart(p, i)), 1); i++ ) if ( pPart == NULL ) {} else + +// iterator over vars of one partition +#define Llb_PartForEachVar( p, pPart, pVar, i ) \ + for ( i = 0; (i < Vec_IntSize(pPart->vVars)) && (((pVar) = Llb_MgrVar(p, Vec_IntEntry(pPart->vVars,i))), 1); i++ ) +// iterator over parts of one variable +#define Llb_VarForEachPart( p, pVar, pPart, i ) \ + for ( i = 0; (i < Vec_IntSize(pVar->vParts)) && (((pPart) = Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,i))), 1); i++ ) + +// statistics +//abctime timeBuild, timeAndEx, timeOther; +//int nSuppMax; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Removes one variable.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4RemoveVar( Llb_Mgr_t * p, Llb_Var_t * pVar ) +{ + assert( p->pVars[pVar->iVar] == pVar ); + p->pVars[pVar->iVar] = NULL; + Vec_IntFree( pVar->vParts ); + ABC_FREE( pVar ); +} + +/**Function************************************************************* + + Synopsis [Removes one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4RemovePart( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ +//printf( "Removing %d\n", pPart->iPart ); + assert( p->pParts[pPart->iPart] == pPart ); + p->pParts[pPart->iPart] = NULL; + Vec_IntFree( pPart->vVars ); + Cudd_RecursiveDeref( p->dd, pPart->bFunc ); + ABC_FREE( pPart ); +} + +/**Function************************************************************* + + Synopsis [Create cube with singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4CreateCube1( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + DdNode * bCube, * bTemp; + Llb_Var_t * pVar; + int i; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); + Llb_PartForEachVar( p, pPart, pVar, i ) + { + assert( Vec_IntSize(pVar->vParts) > 0 ); + if ( Vec_IntSize(pVar->vParts) != 1 ) + continue; + assert( Vec_IntEntry(pVar->vParts, 0) == pPart->iPart ); + bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + Cudd_Deref( bCube ); + p->dd->TimeStop = TimeStop; + return bCube; +} + +/**Function************************************************************* + + Synopsis [Create cube of variables appearing only in two partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4CreateCube2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) +{ + DdNode * bCube, * bTemp; + Llb_Var_t * pVar; + int i; + abctime TimeStop; + TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; + bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + assert( Vec_IntSize(pVar->vParts) > 0 ); + if ( Vec_IntSize(pVar->vParts) != 2 ) + continue; + if ( (Vec_IntEntry(pVar->vParts, 0) == pPart1->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart2->iPart) || + (Vec_IntEntry(pVar->vParts, 0) == pPart2->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart1->iPart) ) + { + bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } + } + Cudd_Deref( bCube ); + p->dd->TimeStop = TimeStop; + return bCube; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if partition has singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4HasSingletonVars( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + Llb_Var_t * pVar; + int i; + Llb_PartForEachVar( p, pPart, pVar, i ) + if ( Vec_IntSize(pVar->vParts) == 1 ) + return 1; + return 0; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if partition has singleton variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4Print( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k; + printf( "\n" ); + Llb_MgrForEachVar( p, pVar, i ) + { + printf( "Var %3d : ", i ); + Llb_VarForEachPart( p, pVar, pPart, k ) + printf( "%d ", pPart->iPart ); + printf( "\n" ); + } + Llb_MgrForEachPart( p, pPart, i ) + { + printf( "Part %3d : ", i ); + Llb_PartForEachVar( p, pPart, pVar, k ) + printf( "%d ", pVar->iVar ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Quantifies singles belonging to one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4Quantify1( Llb_Mgr_t * p, Llb_Prt_t * pPart ) +{ + Llb_Var_t * pVar; + Llb_Prt_t * pTemp; + Vec_Ptr_t * vSingles; + DdNode * bCube, * bTemp; + int i, RetValue, nSizeNew; + // create cube to be quantified + bCube = Llb_Nonlin4CreateCube1( p, pPart ); Cudd_Ref( bCube ); +// assert( !Cudd_IsConstant(bCube) ); + // derive new function + pPart->bFunc = Cudd_bddExistAbstract( p->dd, bTemp = pPart->bFunc, bCube ); Cudd_Ref( pPart->bFunc ); + Cudd_RecursiveDeref( p->dd, bTemp ); + Cudd_RecursiveDeref( p->dd, bCube ); + // get support + vSingles = Vec_PtrAlloc( 0 ); + nSizeNew = Cudd_DagSize(pPart->bFunc); + Extra_SupportArray( p->dd, pPart->bFunc, p->pSupp ); + Llb_PartForEachVar( p, pPart, pVar, i ) + if ( p->pSupp[pVar->iVar] ) + { + assert( Vec_IntSize(pVar->vParts) > 1 ); + pVar->nScore -= pPart->nSize - nSizeNew; + } + else + { + RetValue = Vec_IntRemove( pVar->vParts, pPart->iPart ); + assert( RetValue ); + pVar->nScore -= pPart->nSize; + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_Nonlin4RemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + + // update partition + pPart->nSize = nSizeNew; + Vec_IntClear( pPart->vVars ); + for ( i = 0; i < p->nVars; i++ ) + if ( p->pSupp[i] && Vec_IntEntry(p->vVars2Q, i) ) + Vec_IntPush( pPart->vVars, i ); + // remove other variables + Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) + Llb_Nonlin4Quantify1( p, pTemp ); + Vec_PtrFree( vSingles ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Quantifies singles belonging to one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4Quantify2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) +{ + int fVerbose = 0; + Llb_Var_t * pVar; + Llb_Prt_t * pTemp; + Vec_Ptr_t * vSingles; + DdNode * bCube, * bFunc; + int i, RetValue, nSuppSize; +// int iPart1 = pPart1->iPart; +// int iPart2 = pPart2->iPart; + int liveBeg, liveEnd; + + // create cube to be quantified + bCube = Llb_Nonlin4CreateCube2( p, pPart1, pPart2 ); Cudd_Ref( bCube ); + +//printf( "Quantifying " ); Extra_bddPrintSupport( p->dd, bCube ); printf( "\n" ); + +if ( fVerbose ) +{ +printf( "\n" ); +printf( "\n" ); +Llb_Nonlin4Print( p ); +printf( "Conjoining partitions %d and %d.\n", pPart1->iPart, pPart2->iPart ); +Extra_bddPrintSupport( p->dd, bCube ); printf( "\n" ); +} +liveBeg = p->dd->keys - p->dd->dead; + bFunc = Cudd_bddAndAbstract( p->dd, pPart1->bFunc, pPart2->bFunc, bCube ); +liveEnd = p->dd->keys - p->dd->dead; +//printf( "%d ", liveEnd-liveBeg ); + + if ( bFunc == NULL ) + { + Cudd_RecursiveDeref( p->dd, bCube ); + return 0; + } + Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( p->dd, bCube ); + +//printf( "Creating part %d ", p->iPartFree ); Extra_bddPrintSupport( p->dd, bFunc ); printf( "\n" ); + +//printf( "Creating %d\n", p->iPartFree ); + + // create new partition + pTemp = p->pParts[p->iPartFree] = ABC_CALLOC( Llb_Prt_t, 1 ); + pTemp->iPart = p->iPartFree++; + pTemp->nSize = Cudd_DagSize(bFunc); + pTemp->bFunc = bFunc; + pTemp->vVars = Vec_IntAlloc( 8 ); + // update variables + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + RetValue = Vec_IntRemove( pVar->vParts, pPart1->iPart ); + assert( RetValue ); + pVar->nScore -= pPart1->nSize; + } + // update variables + Llb_PartForEachVar( p, pPart2, pVar, i ) + { + RetValue = Vec_IntRemove( pVar->vParts, pPart2->iPart ); + assert( RetValue ); + pVar->nScore -= pPart2->nSize; + } + // add variables to the new partition + nSuppSize = 0; + Extra_SupportArray( p->dd, bFunc, p->pSupp ); + for ( i = 0; i < p->nVars; i++ ) + { + nSuppSize += p->pSupp[i]; + if ( p->pSupp[i] && Vec_IntEntry(p->vVars2Q, i) ) + { + pVar = Llb_MgrVar( p, i ); + pVar->nScore += pTemp->nSize; + Vec_IntPush( pVar->vParts, pTemp->iPart ); + Vec_IntPush( pTemp->vVars, i ); + } + } + p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); + // remove variables and collect partitions with singleton variables + vSingles = Vec_PtrAlloc( 0 ); + Llb_PartForEachVar( p, pPart1, pVar, i ) + { + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_Nonlin4RemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + { + if ( fVerbose ) + printf( "Adding partition %d because of var %d.\n", + Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + } + Llb_PartForEachVar( p, pPart2, pVar, i ) + { + if ( pVar == NULL ) + continue; + if ( Vec_IntSize(pVar->vParts) == 0 ) + Llb_Nonlin4RemoveVar( p, pVar ); + else if ( Vec_IntSize(pVar->vParts) == 1 ) + { + if ( fVerbose ) + printf( "Adding partition %d because of var %d.\n", + Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); + Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); + } + } + // remove partitions + Llb_Nonlin4RemovePart( p, pPart1 ); + Llb_Nonlin4RemovePart( p, pPart2 ); + // remove other variables +if ( fVerbose ) +Llb_Nonlin4Print( p ); + Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) + { +if ( fVerbose ) +printf( "Updating partitiong %d with singlton vars.\n", pTemp->iPart ); + Llb_Nonlin4Quantify1( p, pTemp ); + } +if ( fVerbose ) +Llb_Nonlin4Print( p ); + Vec_PtrFree( vSingles ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4CutNodes_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes ) +{ + if ( Aig_ObjIsTravIdCurrent(p, pObj) ) + return; + Aig_ObjSetTravIdCurrent(p, pObj); + if ( Saig_ObjIsLi(p, pObj) ) + { + Llb_Nonlin4CutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); + return; + } + if ( Aig_ObjIsConst1(pObj) ) + return; + assert( Aig_ObjIsNode(pObj) ); + Llb_Nonlin4CutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); + Llb_Nonlin4CutNodes_rec(p, Aig_ObjFanin1(pObj), vNodes); + Vec_PtrPush( vNodes, pObj ); +} + +/**Function************************************************************* + + Synopsis [Computes volume of the cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4CutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) +{ + Vec_Ptr_t * vNodes; + Aig_Obj_t * pObj; + int i; + // mark the lower cut with the traversal ID + Aig_ManIncrementTravId(p); + Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) + Aig_ObjSetTravIdCurrent( p, pObj ); + // count the upper cut + vNodes = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) + Llb_Nonlin4CutNodes_rec( p, pObj, vNodes ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4AddPair( Llb_Mgr_t * p, int iPart, int iVar ) +{ + if ( p->pVars[iVar] == NULL ) + { + p->pVars[iVar] = ABC_CALLOC( Llb_Var_t, 1 ); + p->pVars[iVar]->iVar = iVar; + p->pVars[iVar]->nScore = 0; + p->pVars[iVar]->vParts = Vec_IntAlloc( 8 ); + } + Vec_IntPush( p->pVars[iVar]->vParts, iPart ); + Vec_IntPush( p->pParts[iPart]->vVars, iVar ); +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4AddPartition( Llb_Mgr_t * p, int i, DdNode * bFunc ) +{ + int k, nSuppSize; + assert( !Cudd_IsConstant(bFunc) ); +//printf( "Creating init %d\n", i ); + // create partition + p->pParts[i] = ABC_CALLOC( Llb_Prt_t, 1 ); + p->pParts[i]->iPart = i; + p->pParts[i]->bFunc = bFunc; Cudd_Ref( bFunc ); + p->pParts[i]->vVars = Vec_IntAlloc( 8 ); + // add support dependencies + nSuppSize = 0; + Extra_SupportArray( p->dd, bFunc, p->pSupp ); + for ( k = 0; k < p->nVars; k++ ) + { + nSuppSize += p->pSupp[k]; + if ( p->pSupp[k] && Vec_IntEntry(p->vVars2Q, k) ) + Llb_Nonlin4AddPair( p, i, k ); + } + p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); +} + +/**Function************************************************************* + + Synopsis [Checks that each var appears in at least one partition.] + + Description [] + + SideEffects [] + + SeeAlso [] +**********************************************************************/ +void Llb_Nonlin4CheckVars( Llb_Mgr_t * p ) +{ + Llb_Var_t * pVar; + int i; + Llb_MgrForEachVar( p, pVar, i ) + assert( Vec_IntSize(pVar->vParts) > 1 ); +} + +/**Function************************************************************* + + Synopsis [Find next partition to quantify] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4NextPartitions( Llb_Mgr_t * p, Llb_Prt_t ** ppPart1, Llb_Prt_t ** ppPart2 ) +{ + Llb_Var_t * pVar, * pVarBest = NULL; + Llb_Prt_t * pPart, * pPart1Best = NULL, * pPart2Best = NULL; + int i; + Llb_Nonlin4CheckVars( p ); + // find variable with minimum score + Llb_MgrForEachVar( p, pVar, i ) + { + if ( p->nSizeMax && pVar->nScore > p->nSizeMax ) + continue; +// if ( pVarBest == NULL || Vec_IntSize(pVarBest->vParts) * pVarBest->nScore > Vec_IntSize(pVar->vParts) * pVar->nScore ) + if ( pVarBest == NULL || pVarBest->nScore > pVar->nScore ) + pVarBest = pVar; +// printf( "%d ", pVar->nScore ); + } +//printf( "\n" ); + if ( pVarBest == NULL ) + return 0; + // find two partitions with minimum size + Llb_VarForEachPart( p, pVarBest, pPart, i ) + { + if ( pPart1Best == NULL ) + pPart1Best = pPart; + else if ( pPart2Best == NULL ) + pPart2Best = pPart; + else if ( pPart1Best->nSize > pPart->nSize || pPart2Best->nSize > pPart->nSize ) + { + if ( pPart1Best->nSize > pPart2Best->nSize ) + pPart1Best = pPart; + else + pPart2Best = pPart; + } + } +//printf( "Selecting %d and parts %d and %d\n", pVarBest->iVar, pPart1Best->nSize, pPart2Best->nSize ); +//Extra_bddPrintSupport( p->dd, pPart1Best->bFunc ); printf( "\n" ); +//Extra_bddPrintSupport( p->dd, pPart2Best->bFunc ); printf( "\n" ); + + *ppPart1 = pPart1Best; + *ppPart2 = pPart2Best; + return 1; +} + +/**Function************************************************************* + + Synopsis [Recomputes scores after variable reordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4RecomputeScores( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k; + Llb_MgrForEachPart( p, pPart, i ) + pPart->nSize = Cudd_DagSize(pPart->bFunc); + Llb_MgrForEachVar( p, pVar, i ) + { + pVar->nScore = 0; + Llb_VarForEachPart( p, pVar, pPart, k ) + pVar->nScore += pPart->nSize; + } +} + +/**Function************************************************************* + + Synopsis [Recomputes scores after variable reordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4VerifyScores( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i, k, nScore; + Llb_MgrForEachPart( p, pPart, i ) + assert( pPart->nSize == Cudd_DagSize(pPart->bFunc) ); + Llb_MgrForEachVar( p, pVar, i ) + { + nScore = 0; + Llb_VarForEachPart( p, pVar, pPart, k ) + nScore += pPart->nSize; + assert( nScore == pVar->nScore ); + } +} + +/**Function************************************************************* + + Synopsis [Starts non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mgr_t * Llb_Nonlin4Alloc( DdManager * dd, Vec_Ptr_t * vParts, DdNode * bCurrent, Vec_Int_t * vVars2Q, int nSizeMax ) +{ + Llb_Mgr_t * p; + DdNode * bFunc; + int i; + p = ABC_CALLOC( Llb_Mgr_t, 1 ); + p->dd = dd; + p->nSizeMax = nSizeMax; + p->vVars2Q = vVars2Q; + p->nVars = Cudd_ReadSize(dd); + p->iPartFree = Vec_PtrSize(vParts); + p->pVars = ABC_CALLOC( Llb_Var_t *, p->nVars ); + p->pParts = ABC_CALLOC( Llb_Prt_t *, 2 * p->iPartFree + 2 ); + p->pSupp = ABC_ALLOC( int, Cudd_ReadSize(dd) ); + // add pairs (refs are consumed inside) + Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) + Llb_Nonlin4AddPartition( p, i, bFunc ); + // add partition + if ( bCurrent ) + Llb_Nonlin4AddPartition( p, p->iPartFree++, bCurrent ); + return p; +} + +/**Function************************************************************* + + Synopsis [Stops non-linear quantification scheduling.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4Free( Llb_Mgr_t * p ) +{ + Llb_Prt_t * pPart; + Llb_Var_t * pVar; + int i; + Llb_MgrForEachVar( p, pVar, i ) + Llb_Nonlin4RemoveVar( p, pVar ); + Llb_MgrForEachPart( p, pPart, i ) + Llb_Nonlin4RemovePart( p, pPart ); + ABC_FREE( p->pVars ); + ABC_FREE( p->pParts ); + ABC_FREE( p->pSupp ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4Image( DdManager * dd, Vec_Ptr_t * vParts, DdNode * bCurrent, Vec_Int_t * vVars2Q ) +{ + Llb_Prt_t * pPart, * pPart1, * pPart2; + Llb_Mgr_t * p; + DdNode * bFunc, * bTemp; + int i, nReorders; + // start the manager + p = Llb_Nonlin4Alloc( dd, vParts, bCurrent, vVars2Q, 0 ); + // remove singles + Llb_MgrForEachPart( p, pPart, i ) + if ( Llb_Nonlin4HasSingletonVars(p, pPart) ) + Llb_Nonlin4Quantify1( p, pPart ); + // compute scores + Llb_Nonlin4RecomputeScores( p ); + // iteratively quantify variables + while ( Llb_Nonlin4NextPartitions(p, &pPart1, &pPart2) ) + { + nReorders = Cudd_ReadReorderings(dd); + if ( !Llb_Nonlin4Quantify2( p, pPart1, pPart2 ) ) + { + Llb_Nonlin4Free( p ); + return NULL; + } + if ( nReorders < Cudd_ReadReorderings(dd) ) + Llb_Nonlin4RecomputeScores( p ); +// else +// Llb_Nonlin4VerifyScores( p ); + } + // load partitions + bFunc = Cudd_ReadOne(p->dd); Cudd_Ref( bFunc ); + Llb_MgrForEachPart( p, pPart, i ) + { + bFunc = Cudd_bddAnd( p->dd, bTemp = bFunc, pPart->bFunc ); Cudd_Ref( bFunc ); + Cudd_RecursiveDeref( p->dd, bTemp ); + } +// nSuppMax = p->nSuppMax; + Llb_Nonlin4Free( p ); +//printf( "\n" ); + // return + Cudd_Deref( bFunc ); + return bFunc; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4Group( DdManager * dd, Vec_Ptr_t * vParts, Vec_Int_t * vVars2Q, int nSizeMax ) +{ + Vec_Ptr_t * vGroups; + Llb_Prt_t * pPart, * pPart1, * pPart2; + Llb_Mgr_t * p; + int i, nReorders;//, clk = Abc_Clock(); + // start the manager + p = Llb_Nonlin4Alloc( dd, vParts, NULL, vVars2Q, nSizeMax ); + // remove singles + Llb_MgrForEachPart( p, pPart, i ) + if ( Llb_Nonlin4HasSingletonVars(p, pPart) ) + Llb_Nonlin4Quantify1( p, pPart ); + // compute scores + Llb_Nonlin4RecomputeScores( p ); + // iteratively quantify variables + while ( Llb_Nonlin4NextPartitions(p, &pPart1, &pPart2) ) + { + nReorders = Cudd_ReadReorderings(dd); + if ( !Llb_Nonlin4Quantify2( p, pPart1, pPart2 ) ) + { + Llb_Nonlin4Free( p ); + return NULL; + } + if ( nReorders < Cudd_ReadReorderings(dd) ) + Llb_Nonlin4RecomputeScores( p ); +// else +// Llb_Nonlin4VerifyScores( p ); + } + // load partitions + vGroups = Vec_PtrAlloc( 1000 ); + Llb_MgrForEachPart( p, pPart, i ) + { +//printf( "Iteration %d ", pPart->iPart ); + if ( Cudd_IsConstant(pPart->bFunc) ) + { +//printf( "Constant\n" ); + assert( !Cudd_IsComplement(pPart->bFunc) ); + continue; + } +//printf( "\n" ); + Vec_PtrPush( vGroups, pPart->bFunc ); + Cudd_Ref( pPart->bFunc ); +//printf( "Part %d ", pPart->iPart ); +//Extra_bddPrintSupport( p->dd, pPart->bFunc ); printf( "\n" ); + } + Llb_Nonlin4Free( p ); +//Abc_PrintTime( 1, "Reparametrization time", Abc_Clock() - clk ); + return vGroups; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Map.c b/src/bdd/llb/llb4Map.c new file mode 100644 index 00000000..4487ce25 --- /dev/null +++ b/src/bdd/llb/llb4Map.c @@ -0,0 +1,123 @@ +/**CFile**************************************************************** + + FileName [llb2Map.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Map.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" +#include "base/abc/abc.h" +#include "map/if/if.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Returns internal nodes used in the mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_AigMap( Aig_Man_t * pAig, int nLutSize, int nLutMin ) +{ + extern Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pMan ); + extern If_Man_t * Abc_NtkToIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ); + extern void Gia_ManSetIfParsDefault( void * pPars ); + If_Par_t Pars, * pPars = &Pars; + If_Man_t * pIfMan; + If_Obj_t * pAnd; + Abc_Ntk_t * pNtk; + Abc_Obj_t * pNode; + Vec_Int_t * vNodes; + Aig_Obj_t * pObj; + int i; + + // create ABC network + pNtk = Abc_NtkFromAigPhase( pAig ); + assert( Abc_NtkIsStrash(pNtk) ); + + // derive mapping parameters + Gia_ManSetIfParsDefault( pPars ); + pPars->nLutSize = nLutSize; + + // get timing information + pPars->pTimesArr = Abc_NtkGetCiArrivalFloats(pNtk); + pPars->pTimesReq = Abc_NtkGetCoRequiredFloats(pNtk); + + // perform LUT mapping + pIfMan = Abc_NtkToIf( pNtk, pPars ); + if ( pIfMan == NULL ) + { + Abc_NtkDelete( pNtk ); + return NULL; + } + if ( !If_ManPerformMapping( pIfMan ) ) + { + Abc_NtkDelete( pNtk ); + If_ManStop( pIfMan ); + return NULL; + } + + // mark nodes in the AIG used in the mapping + Aig_ManCleanMarkA( pAig ); + Aig_ManForEachNode( pAig, pObj, i ) + { + pNode = (Abc_Obj_t *)pObj->pData; + if ( pNode == NULL ) + continue; + pAnd = (If_Obj_t *)pNode->pCopy; + if ( pAnd == NULL ) + continue; + if ( pAnd->nRefs > 0 && (int)If_ObjCutBest(pAnd)->nLeaves >= nLutMin ) + pObj->fMarkA = 1; + } + Abc_NtkDelete( pNtk ); + If_ManStop( pIfMan ); + + // unmark flop drivers + Saig_ManForEachLi( pAig, pObj, i ) + Aig_ObjFanin0(pObj)->fMarkA = 0; + + // collect mapping + vNodes = Vec_IntAlloc( 100 ); + Aig_ManForEachNode( pAig, pObj, i ) + if ( pObj->fMarkA ) + Vec_IntPush( vNodes, Aig_ObjId(pObj) ); + Aig_ManCleanMarkA( pAig ); + return vNodes; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Nonlin.c b/src/bdd/llb/llb4Nonlin.c new file mode 100644 index 00000000..a9421358 --- /dev/null +++ b/src/bdd/llb/llb4Nonlin.c @@ -0,0 +1,1185 @@ +/**CFile**************************************************************** + + FileName [llb2Nonlin.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Nonlin.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" +#include "base/abc/abc.h" +#include "aig/gia/giaAig.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Mnx_t_ Llb_Mnx_t; +struct Llb_Mnx_t_ +{ + // user info + Aig_Man_t * pAig; // AIG manager + Gia_ParLlb_t * pPars; // parameters + + // intermediate BDDs + DdManager * dd; // BDD manager + DdNode * bBad; // bad states in terms of CIs + DdNode * bReached; // reached states + DdNode * bCurrent; // from states + DdNode * bNext; // to states + Vec_Ptr_t * vRings; // onion rings in ddR + Vec_Ptr_t * vRoots; // BDDs for partitions + + // structural info + Vec_Int_t * vOrder; // for each object ID, its BDD variable number or -1 + Vec_Int_t * vVars2Q; // 1 if variable is quantifiable; 0 othervise + + abctime timeImage; + abctime timeRemap; + abctime timeReo; + abctime timeOther; + abctime timeTotal; +}; + +//extern int timeBuild, timeAndEx, timeOther; +//extern int nSuppMax; + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes bad in working manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4ComputeBad( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) +{ + Vec_Ptr_t * vNodes; + DdNode * bBdd, * bBdd0, * bBdd1, * bTemp, * bResult, * bCube; + Aig_Obj_t * pObj; + int i; + Aig_ManCleanData( pAig ); + // assign elementary variables + Aig_ManConst1(pAig)->pData = Cudd_ReadOne(dd); + Aig_ManForEachCi( pAig, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + // compute internal nodes + vNodes = Aig_ManDfsNodes( pAig, (Aig_Obj_t **)Vec_PtrArray(pAig->vCos), Saig_ManPoNum(pAig) ); + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + { + if ( !Aig_ObjIsNode(pObj) ) + continue; + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); + if ( bBdd == NULL ) + { + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + if ( Aig_ObjIsNode(pObj) && pObj->pData != NULL ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Vec_PtrFree( vNodes ); + return NULL; + } + Cudd_Ref( bBdd ); + pObj->pData = bBdd; + } + // quantify PIs of each PO + bResult = Cudd_ReadLogicZero( dd ); Cudd_Ref( bResult ); + Saig_ManForEachPo( pAig, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bResult = Cudd_bddOr( dd, bTemp = bResult, bBdd0 ); + if ( bResult == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + break; + } + Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + } + // deref + Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) + if ( Aig_ObjIsNode(pObj) && pObj->pData != NULL ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Vec_PtrFree( vNodes ); + if ( bResult ) + { + bCube = Cudd_ReadOne(dd); Cudd_Ref( bCube ); + Saig_ManForEachPi( pAig, pObj, i ) + { + bCube = Cudd_bddAnd( dd, bTemp = bCube, (DdNode *)pObj->pData ); + if ( bCube == NULL ) + { + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bResult ); + bResult = NULL; + break; + } + Cudd_Ref( bCube ); + Cudd_RecursiveDeref( dd, bTemp ); + } + if ( bResult != NULL ) + { + bResult = Cudd_bddExistAbstract( dd, bTemp = bResult, bCube ); Cudd_Ref( bResult ); + Cudd_RecursiveDeref( dd, bTemp ); + Cudd_RecursiveDeref( dd, bCube ); + Cudd_Deref( bResult ); + } + } +//if ( bResult ) +//printf( "Bad state = %d.\n", Cudd_DagSize(bResult) ); + return bResult; +} + +/**Function************************************************************* + + Synopsis [Derives BDDs for the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4DerivePartitions( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) +{ + Vec_Ptr_t * vRoots; + Aig_Obj_t * pObj; + DdNode * bBdd, * bBdd0, * bBdd1, * bPart; + int i; + Aig_ManCleanData( pAig ); + // assign elementary variables + Aig_ManConst1(pAig)->pData = Cudd_ReadOne(dd); + Aig_ManForEachCi( pAig, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + Aig_ManForEachNode( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + { + pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + Cudd_Ref( (DdNode *)pObj->pData ); + } + Saig_ManForEachLi( pAig, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + // compute intermediate BDDs + vRoots = Vec_PtrAlloc( 100 ); + Aig_ManForEachNode( pAig, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); + if ( bBdd == NULL ) + goto finish; + Cudd_Ref( bBdd ); + if ( pObj->pData == NULL ) + { + pObj->pData = bBdd; + continue; + } + // create new partition + bPart = Cudd_bddXnor( dd, (DdNode *)pObj->pData, bBdd ); + if ( bPart == NULL ) + goto finish; + Cudd_Ref( bPart ); + Cudd_RecursiveDeref( dd, bBdd ); + Vec_PtrPush( vRoots, bPart ); +//printf( "%d ", Cudd_DagSize(bPart) ); + } + // compute register output BDDs + Saig_ManForEachLi( pAig, pObj, i ) + { + bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bPart = Cudd_bddXnor( dd, (DdNode *)pObj->pData, bBdd0 ); + if ( bPart == NULL ) + goto finish; + Cudd_Ref( bPart ); + Vec_PtrPush( vRoots, bPart ); +//printf( "%d ", Cudd_DagSize(bPart) ); + } +//printf( "\n" ); + Aig_ManForEachNode( pAig, pObj, i ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + return vRoots; + // early termination +finish: + Aig_ManForEachNode( pAig, pObj, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Vec_PtrForEachEntry( DdNode *, vRoots, bPart, i ) + Cudd_RecursiveDeref( dd, bPart ); + Vec_PtrFree( vRoots ); + return NULL; +} + +/**Function************************************************************* + + Synopsis [Find simple variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4CreateOrderSimple( Aig_Man_t * pAig ) +{ + Vec_Int_t * vOrder; + Aig_Obj_t * pObj; + int i, Counter = 0; + vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); + Aig_ManForEachCi( pAig, pObj, i ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + Saig_ManForEachLi( pAig, pObj, i ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + return vOrder; +} + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4CreateOrder_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Int_t * vOrder, int * pCounter ) +{ + Aig_Obj_t * pFanin0, * pFanin1; + if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) + return; + Aig_ObjSetTravIdCurrent( pAig, pObj ); + assert( Llb_ObjBddVar(vOrder, pObj) < 0 ); + if ( Aig_ObjIsCi(pObj) ) + { +// if ( Saig_ObjIsLo(pAig, pObj) ) +// Vec_IntWriteEntry( vOrder, Aig_ObjId(Saig_ObjLoToLi(pAig, pObj)), (*pCounter)++ ); + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); + return; + } + // try fanins with higher level first + pFanin0 = Aig_ObjFanin0(pObj); + pFanin1 = Aig_ObjFanin1(pObj); +// if ( pFanin0->Level > pFanin1->Level || (pFanin0->Level == pFanin1->Level && pFanin0->Id < pFanin1->Id) ) + if ( pFanin0->Level > pFanin1->Level ) + { + Llb_Nonlin4CreateOrder_rec( pAig, pFanin0, vOrder, pCounter ); + Llb_Nonlin4CreateOrder_rec( pAig, pFanin1, vOrder, pCounter ); + } + else + { + Llb_Nonlin4CreateOrder_rec( pAig, pFanin1, vOrder, pCounter ); + Llb_Nonlin4CreateOrder_rec( pAig, pFanin0, vOrder, pCounter ); + } + if ( pObj->fMarkA ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); +} + +/**Function************************************************************* + + Synopsis [Collect nodes with the given fanout count.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4CollectHighRefNodes( Aig_Man_t * pAig, int nFans ) +{ + Vec_Int_t * vNodes; + Aig_Obj_t * pObj; + int i; + Aig_ManCleanMarkA( pAig ); + Aig_ManForEachNode( pAig, pObj, i ) + if ( Aig_ObjRefs(pObj) >= nFans ) + pObj->fMarkA = 1; + // unmark flop drivers + Saig_ManForEachLi( pAig, pObj, i ) + Aig_ObjFanin0(pObj)->fMarkA = 0; + // collect mapping + vNodes = Vec_IntAlloc( 100 ); + Aig_ManForEachNode( pAig, pObj, i ) + if ( pObj->fMarkA ) + Vec_IntPush( vNodes, Aig_ObjId(pObj) ); + Aig_ManCleanMarkA( pAig ); + return vNodes; +} + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4CreateOrder( Aig_Man_t * pAig ) +{ + Vec_Int_t * vNodes = NULL; + Vec_Int_t * vOrder; + Aig_Obj_t * pObj; + int i, Counter = 0; +/* + // mark internal nodes to be used + Aig_ManCleanMarkA( pAig ); + vNodes = Llb_Nonlin4CollectHighRefNodes( pAig, 4 ); + Aig_ManForEachObjVec( vNodes, pAig, pObj, i ) + pObj->fMarkA = 1; +printf( "Techmapping added %d pivots.\n", Vec_IntSize(vNodes) ); +*/ + // collect nodes in the order + vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); + Aig_ManIncrementTravId( pAig ); + Aig_ObjSetTravIdCurrent( pAig, Aig_ManConst1(pAig) ); + Saig_ManForEachLi( pAig, pObj, i ) + { + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + Llb_Nonlin4CreateOrder_rec( pAig, Aig_ObjFanin0(pObj), vOrder, &Counter ); + } + Aig_ManForEachCi( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) + { +// if ( Saig_ObjIsLo(pAig, pObj) ) +// Vec_IntWriteEntry( vOrder, Aig_ObjId(Saig_ObjLoToLi(pAig, pObj)), Counter++ ); + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + } + assert( Counter <= Aig_ManCiNum(pAig) + Aig_ManRegNum(pAig) + (vNodes?Vec_IntSize(vNodes):0) ); + Aig_ManCleanMarkA( pAig ); + Vec_IntFreeP( &vNodes ); + return vOrder; +} + + +/**Function************************************************************* + + Synopsis [Creates quantifiable varaibles for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4CreateVars2Q( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fBackward ) +{ + Vec_Int_t * vVars2Q; + Aig_Obj_t * pObjLi, * pObjLo; + int i; + vVars2Q = Vec_IntAlloc( 0 ); + Vec_IntFill( vVars2Q, Cudd_ReadSize(dd), 1 ); + Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) + Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, fBackward ? pObjLo : pObjLi), 0 ); + return vVars2Q; +} + +/**Function************************************************************* + + Synopsis [Compute initial state in terms of current state variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4SetupVarMap( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) +{ + DdNode ** pVarsX, ** pVarsY; + Aig_Obj_t * pObjLo, * pObjLi; + int i; + pVarsX = ABC_ALLOC( DdNode *, Cudd_ReadSize(dd) ); + pVarsY = ABC_ALLOC( DdNode *, Cudd_ReadSize(dd) ); + Saig_ManForEachLiLo( pAig, pObjLo, pObjLi, i ) + { + assert( Llb_ObjBddVar(vOrder, pObjLo) >= 0 ); + assert( Llb_ObjBddVar(vOrder, pObjLi) >= 0 ); + pVarsX[i] = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLo) ); + pVarsY[i] = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLi) ); + } + Cudd_SetVarMap( dd, pVarsX, pVarsY, Aig_ManRegNum(pAig) ); + ABC_FREE( pVarsX ); + ABC_FREE( pVarsY ); +} + +/**Function************************************************************* + + Synopsis [Compute initial state in terms of current state variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4ComputeInitState( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fBackward ) +{ + Aig_Obj_t * pObjLi, * pObjLo; + DdNode * bRes, * bVar, * bTemp; + int i; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) + { + bVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, fBackward? pObjLi : pObjLo) ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, Cudd_Not(bVar) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [Compute initial state in terms of current state variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4ComputeCube( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, char * pValues, int Flag ) +{ + Aig_Obj_t * pObjLo, * pObjLi, * pObjTemp; + DdNode * bRes, * bVar, * bTemp; + int i; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) + { + if ( Flag ) + pObjTemp = pObjLo, pObjLo = pObjLi, pObjLi = pObjTemp; + // get the correspoding flop input variable + bVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLi) ); + if ( pValues[Llb_ObjBddVar(vOrder, pObjLo)] != 1 ) + bVar = Cudd_Not(bVar); + // create cube + bRes = Cudd_bddAnd( dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return bRes; +} + +/**Function************************************************************* + + Synopsis [Compute initial state in terms of current state variables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4RecordState( Aig_Man_t * pAig, Vec_Int_t * vOrder, unsigned * pState, char * pValues, int fBackward ) +{ + Aig_Obj_t * pObjLo, * pObjLi; + int i; + Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) + if ( pValues[Llb_ObjBddVar(vOrder, fBackward? pObjLi : pObjLo)] == 1 ) + Abc_InfoSetBit( pState, i ); +} + +/**Function************************************************************* + + Synopsis [Multiply every partition by the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4Multiply( DdManager * dd, DdNode * bCube, Vec_Ptr_t * vParts ) +{ + Vec_Ptr_t * vNew; + DdNode * bTemp, * bFunc; + int i; + vNew = Vec_PtrAlloc( Vec_PtrSize(vParts) ); + Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) + { + bTemp = Cudd_bddAnd( dd, bFunc, bCube ); Cudd_Ref( bTemp ); + Vec_PtrPush( vNew, bTemp ); + } + return vNew; +} + +/**Function************************************************************* + + Synopsis [Multiply every partition by the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4Deref( DdManager * dd, Vec_Ptr_t * vParts ) +{ + DdNode * bFunc; + int i; + Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) + Cudd_RecursiveDeref( dd, bFunc ); + Vec_PtrFree( vParts ); +} + +/**Function************************************************************* + + Synopsis [Derives counter-example by backward reachability.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4DeriveCex( Llb_Mnx_t * p, int fBackward, int fVerbose ) +{ + Vec_Int_t * vVars2Q; + Vec_Ptr_t * vStates, * vRootsNew; + Aig_Obj_t * pObj; + DdNode * bState = NULL, * bImage, * bOneCube, * bRing; + int i, v, RetValue;//, clk = Abc_Clock(); + char * pValues; + assert( Vec_PtrSize(p->vRings) > 0 ); + // disable the timeout + p->dd->TimeStop = 0; + + // start the state set + vStates = Vec_PtrAllocSimInfo( Vec_PtrSize(p->vRings), Abc_BitWordNum(Aig_ManRegNum(p->pAig)) ); + Vec_PtrCleanSimInfo( vStates, 0, Abc_BitWordNum(Aig_ManRegNum(p->pAig)) ); + if ( fBackward ) + Vec_PtrReverseOrder( vStates ); + + // get the last cube + pValues = ABC_ALLOC( char, Cudd_ReadSize(p->dd) ); + bOneCube = Cudd_bddIntersect( p->dd, (DdNode *)Vec_PtrEntryLast(p->vRings), p->bBad ); Cudd_Ref( bOneCube ); + RetValue = Cudd_bddPickOneCube( p->dd, bOneCube, pValues ); + Cudd_RecursiveDeref( p->dd, bOneCube ); + assert( RetValue ); + + // record the cube + Llb_Nonlin4RecordState( p->pAig, p->vOrder, (unsigned *)Vec_PtrEntryLast(vStates), pValues, fBackward ); + + // write state in terms of NS variables + if ( Vec_PtrSize(p->vRings) > 1 ) + { + bState = Llb_Nonlin4ComputeCube( p->dd, p->pAig, p->vOrder, pValues, fBackward ); Cudd_Ref( bState ); + } + // perform backward analysis + vVars2Q = Llb_Nonlin4CreateVars2Q( p->dd, p->pAig, p->vOrder, !fBackward ); + Vec_PtrForEachEntryReverse( DdNode *, p->vRings, bRing, v ) + { + if ( v == Vec_PtrSize(p->vRings) - 1 ) + continue; + + // preprocess partitions + vRootsNew = Llb_Nonlin4Multiply( p->dd, bState, p->vRoots ); + Cudd_RecursiveDeref( p->dd, bState ); + + // compute the next states + bImage = Llb_Nonlin4Image( p->dd, vRootsNew, NULL, vVars2Q ); Cudd_Ref( bImage ); + Llb_Nonlin4Deref( p->dd, vRootsNew ); + + // intersect with the previous set + bOneCube = Cudd_bddIntersect( p->dd, bImage, bRing ); Cudd_Ref( bOneCube ); + Cudd_RecursiveDeref( p->dd, bImage ); + + // find any assignment of the BDD + RetValue = Cudd_bddPickOneCube( p->dd, bOneCube, pValues ); + Cudd_RecursiveDeref( p->dd, bOneCube ); + assert( RetValue ); + + // record the cube + Llb_Nonlin4RecordState( p->pAig, p->vOrder, (unsigned *)Vec_PtrEntry(vStates, v), pValues, fBackward ); + + // check that we get the init state + if ( v == 0 ) + { + Saig_ManForEachLo( p->pAig, pObj, i ) + assert( fBackward || pValues[Llb_ObjBddVar(p->vOrder, pObj)] == 0 ); + break; + } + + // write state in terms of NS variables + bState = Llb_Nonlin4ComputeCube( p->dd, p->pAig, p->vOrder, pValues, fBackward ); Cudd_Ref( bState ); + } + Vec_IntFree( vVars2Q ); + ABC_FREE( pValues ); + if ( fBackward ) + Vec_PtrReverseOrder( vStates ); +// if ( fVerbose ) +// Abc_PrintTime( 1, "BDD-based cex generation time", Abc_Clock() - clk ); + return vStates; +} + + +/**Function************************************************************* + + Synopsis [Perform reachability with hints.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4Reachability( Llb_Mnx_t * p ) +{ + DdNode * bAux; + int nIters, nBddSizeFr = 0, nBddSizeTo = 0, nBddSizeTo2 = 0; + abctime clkTemp, clkIter, clk = Abc_Clock(); + assert( Aig_ManRegNum(p->pAig) > 0 ); + + if ( p->pPars->fBackward ) + { + // create bad state in the ring manager + if ( !p->pPars->fSkipOutCheck ) + { + p->bBad = Llb_Nonlin4ComputeInitState( p->dd, p->pAig, p->vOrder, p->pPars->fBackward ); Cudd_Ref( p->bBad ); + } + // create init state + if ( p->pPars->fCluster ) + p->bCurrent = p->dd->bFunc, p->dd->bFunc = NULL; + else + { + p->bCurrent = Llb_Nonlin4ComputeBad( p->dd, p->pAig, p->vOrder ); + if ( p->bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->bCurrent ); + } + // remap into the next states + p->bCurrent = Cudd_bddVarMap( p->dd, bAux = p->bCurrent ); + if ( p->bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during remapping bad states.\n", p->pPars->TimeLimit ); + Cudd_RecursiveDeref( p->dd, bAux ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->bCurrent ); + Cudd_RecursiveDeref( p->dd, bAux ); + } + else + { + // create bad state in the ring manager + if ( !p->pPars->fSkipOutCheck ) + { + if ( p->pPars->fCluster ) + p->bBad = p->dd->bFunc, p->dd->bFunc = NULL; + else + { + p->bBad = Llb_Nonlin4ComputeBad( p->dd, p->pAig, p->vOrder ); + if ( p->bBad == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = -1; + return -1; + } + Cudd_Ref( p->bBad ); + } + } + else if ( p->dd->bFunc ) + Cudd_RecursiveDeref( p->dd, p->dd->bFunc ), p->dd->bFunc = NULL; + // compute the starting set of states + p->bCurrent = Llb_Nonlin4ComputeInitState( p->dd, p->pAig, p->vOrder, p->pPars->fBackward ); Cudd_Ref( p->bCurrent ); + } + // perform iterations + p->bReached = p->bCurrent; Cudd_Ref( p->bReached ); + for ( nIters = 0; nIters < p->pPars->nIterMax; nIters++ ) + { + clkIter = Abc_Clock(); + // check the runtime limit + if ( p->pPars->TimeLimit && Abc_Clock() > p->pPars->TimeTarget ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + return -1; + } + + // save the onion ring + Vec_PtrPush( p->vRings, p->bCurrent ); Cudd_Ref( p->bCurrent ); + + // check it for bad states + if ( !p->pPars->fSkipOutCheck && !Cudd_bddLeq( p->dd, p->bCurrent, Cudd_Not(p->bBad) ) ) + { + Vec_Ptr_t * vStates; + assert( p->pAig->pSeqModel == NULL ); + vStates = Llb_Nonlin4DeriveCex( p, p->pPars->fBackward, p->pPars->fVerbose ); + p->pAig->pSeqModel = Llb4_Nonlin4TransformCex( p->pAig, vStates, -1, p->pPars->fVerbose ); + Vec_PtrFreeP( &vStates ); + if ( !p->pPars->fSilent ) + { + Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", p->pAig->pSeqModel->iPo, p->pAig->pName, nIters ); + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + } + p->pPars->iFrame = nIters - 1; + return 0; + } + + // compute the next states + clkTemp = Abc_Clock(); + p->bNext = Llb_Nonlin4Image( p->dd, p->vRoots, p->bCurrent, p->vVars2Q ); + if ( p->bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in quantification.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + return -1; + } + Cudd_Ref( p->bNext ); + p->timeImage += Abc_Clock() - clkTemp; + + // remap into current states + clkTemp = Abc_Clock(); + p->bNext = Cudd_bddVarMap( p->dd, bAux = p->bNext ); + if ( p->bNext == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during remapping next states.\n", p->pPars->TimeLimit ); + Cudd_RecursiveDeref( p->dd, bAux ); + p->pPars->iFrame = nIters - 1; + return -1; + } + Cudd_Ref( p->bNext ); + Cudd_RecursiveDeref( p->dd, bAux ); + p->timeRemap += Abc_Clock() - clkTemp; + + // collect statistics + if ( p->pPars->fVerbose ) + { + nBddSizeFr = Cudd_DagSize( p->bCurrent ); + nBddSizeTo = Cudd_DagSize( bAux ); + nBddSizeTo2 = Cudd_DagSize( p->bNext ); + } + Cudd_RecursiveDeref( p->dd, p->bCurrent ); p->bCurrent = NULL; + + // derive new states + p->bCurrent = Cudd_bddAnd( p->dd, p->bNext, Cudd_Not(p->bReached) ); + if ( p->bCurrent == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + return -1; + } + Cudd_Ref( p->bCurrent ); + Cudd_RecursiveDeref( p->dd, p->bNext ); p->bNext = NULL; + if ( Cudd_IsConstant(p->bCurrent) ) + break; +/* + // reduce BDD size using constrain // Cudd_bddRestrict + p->bCurrent = Cudd_bddRestrict( p->dd, bAux = p->bCurrent, Cudd_Not(p->bReached) ); + Cudd_Ref( p->bCurrent ); +printf( "Before = %d. After = %d.\n", Cudd_DagSize(bAux), Cudd_DagSize(p->bCurrent) ); + Cudd_RecursiveDeref( p->dd, bAux ); +*/ + + // add to the reached set + p->bReached = Cudd_bddOr( p->dd, bAux = p->bReached, p->bCurrent ); + if ( p->bReached == NULL ) + { + if ( !p->pPars->fSilent ) + printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); + p->pPars->iFrame = nIters - 1; + Cudd_RecursiveDeref( p->dd, bAux ); + return -1; + } + Cudd_Ref( p->bReached ); + Cudd_RecursiveDeref( p->dd, bAux ); + + + // report the results + if ( p->pPars->fVerbose ) + { + printf( "I =%5d : ", nIters ); + printf( "Fr =%7d ", nBddSizeFr ); + printf( "ImNs =%7d ", nBddSizeTo ); + printf( "ImCs =%7d ", nBddSizeTo2 ); + printf( "Rea =%7d ", Cudd_DagSize(p->bReached) ); + printf( "(%4d %4d) ", Cudd_ReadReorderings(p->dd), Cudd_ReadGarbageCollections(p->dd) ); + Abc_PrintTime( 1, "T", Abc_Clock() - clkIter ); + } +/* + if ( pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->dd, bReached, Saig_ManRegNum(p->pAig) ); +// Extra_bddPrint( p->dd, bReached );printf( "\n" ); + printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } +*/ + if ( nIters == p->pPars->nIterMax - 1 ) + { + if ( !p->pPars->fSilent ) + printf( "Reached limit on the number of timeframes (%d).\n", p->pPars->nIterMax ); + p->pPars->iFrame = nIters; + return -1; + } + } + + // report the stats + if ( p->pPars->fVerbose ) + { + double nMints = Cudd_CountMinterm(p->dd, p->bReached, Saig_ManRegNum(p->pAig) ); + if ( p->bCurrent && Cudd_IsConstant(p->bCurrent) ) + printf( "Reachability analysis completed after %d frames.\n", nIters ); + else + printf( "Reachability analysis is stopped after %d frames.\n", nIters ); + printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); + fflush( stdout ); + } + if ( p->bCurrent == NULL || !Cudd_IsConstant(p->bCurrent) ) + { + if ( !p->pPars->fSilent ) + printf( "Verified only for states reachable in %d frames. ", nIters ); + p->pPars->iFrame = p->pPars->nIterMax; + return -1; // undecided + } + // report + if ( !p->pPars->fSilent ) + printf( "The miter is proved unreachable after %d iterations. ", nIters ); + if ( !p->pPars->fSilent ) + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); + p->pPars->iFrame = nIters - 1; + return 1; // unreachable +} + +/**Function************************************************************* + + Synopsis [Reorders BDDs in the working manager.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4Reorder( DdManager * dd, int fTwice, int fVerbose ) +{ + abctime clk = Abc_Clock(); + if ( fVerbose ) + Abc_Print( 1, "Reordering... Before =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + if ( fTwice ) + { + Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); + if ( fVerbose ) + Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); + } + if ( fVerbose ) + Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Llb_Mnx_t * Llb_MnxStart( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Mnx_t * p; + + p = ABC_CALLOC( Llb_Mnx_t, 1 ); + p->pAig = pAig; + p->pPars = pPars; + + // compute time to stop + p->pPars->TimeTarget = p->pPars->TimeLimit ? p->pPars->TimeLimit * CLOCKS_PER_SEC + Abc_Clock(): 0; + + if ( pPars->fCluster ) + { +// Llb_Nonlin4Cluster( p->pAig, &p->dd, &p->vOrder, &p->vRoots, pPars->nBddMax, pPars->fVerbose ); +// Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); + Llb4_Nonlin4Sweep( p->pAig, pPars->nBddMax, pPars->nClusterMax, &p->dd, &p->vOrder, &p->vRoots, pPars->fVerbose ); + // set the stop time parameter + p->dd->TimeStop = p->pPars->TimeTarget; + } + else + { +// p->vOrder = Llb_Nonlin4CreateOrderSimple( pAig ); + p->vOrder = Llb_Nonlin4CreateOrder( pAig ); + p->dd = Cudd_Init( Vec_IntCountPositive(p->vOrder) + 1, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); + Cudd_SetMaxGrowth( p->dd, 1.05 ); + // set the stop time parameter + p->dd->TimeStop = p->pPars->TimeTarget; + p->vRoots = Llb_Nonlin4DerivePartitions( p->dd, pAig, p->vOrder ); + } + + Llb_Nonlin4SetupVarMap( p->dd, pAig, p->vOrder ); + p->vVars2Q = Llb_Nonlin4CreateVars2Q( p->dd, pAig, p->vOrder, p->pPars->fBackward ); + p->vRings = Vec_PtrAlloc( 100 ); + + if ( pPars->fReorder ) + Llb_Nonlin4Reorder( p->dd, 0, 1 ); + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MnxStop( Llb_Mnx_t * p ) +{ + DdNode * bTemp; + int i; + if ( p->pPars->fVerbose ) + { + p->timeReo = Cudd_ReadReorderingTime(p->dd); + p->timeOther = p->timeTotal - p->timeImage - p->timeRemap; + ABC_PRTP( "Image ", p->timeImage, p->timeTotal ); + ABC_PRTP( "Remap ", p->timeRemap, p->timeTotal ); + ABC_PRTP( "Other ", p->timeOther, p->timeTotal ); + ABC_PRTP( "TOTAL ", p->timeTotal, p->timeTotal ); + ABC_PRTP( " reo ", p->timeReo, p->timeTotal ); + } + // remove BDDs + if ( p->bBad ) + Cudd_RecursiveDeref( p->dd, p->bBad ); + if ( p->bReached ) + Cudd_RecursiveDeref( p->dd, p->bReached ); + if ( p->bCurrent ) + Cudd_RecursiveDeref( p->dd, p->bCurrent ); + if ( p->bNext ) + Cudd_RecursiveDeref( p->dd, p->bNext ); + if ( p->vRings ) + Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i ) + Cudd_RecursiveDeref( p->dd, bTemp ); + if ( p->vRoots ) + Vec_PtrForEachEntry( DdNode *, p->vRoots, bTemp, i ) + Cudd_RecursiveDeref( p->dd, bTemp ); + // remove arrays + Vec_PtrFreeP( &p->vRings ); + Vec_PtrFreeP( &p->vRoots ); +//Cudd_PrintInfo( p->dd, stdout ); + Extra_StopManager( p->dd ); + Vec_IntFreeP( &p->vOrder ); + Vec_IntFreeP( &p->vVars2Q ); + ABC_FREE( p ); +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_MnxCheckNextStateVars( Llb_Mnx_t * p ) +{ + Aig_Obj_t * pObj; + int i, Counter0 = 0, Counter1 = 0; + Saig_ManForEachLi( p->pAig, pObj, i ) + if ( Saig_ObjIsLo(p->pAig, Aig_ObjFanin0(pObj)) ) + { + if ( Aig_ObjFaninC0(pObj) ) + Counter0++; + else + Counter1++; + } + printf( "Total = %d. Direct LO = %d. Compl LO = %d.\n", Aig_ManRegNum(p->pAig), Counter1, Counter0 ); +} + +/**Function************************************************************* + + Synopsis [Finds balanced cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb_Nonlin4CoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) +{ + Llb_Mnx_t * pMnn; + int RetValue = -1; + if ( pPars->fVerbose ) + Aig_ManPrintStats( pAig ); + if ( pPars->fCluster && Aig_ManObjNum(pAig) >= (1 << 15) ) + { + printf( "The number of objects is more than 2^15. Clustering cannot be used.\n" ); + return RetValue; + } + { + abctime clk = Abc_Clock(); + pMnn = Llb_MnxStart( pAig, pPars ); +//Llb_MnxCheckNextStateVars( pMnn ); + if ( !pPars->fSkipReach ) + RetValue = Llb_Nonlin4Reachability( pMnn ); + pMnn->timeTotal = Abc_Clock() - clk; + Llb_MnxStop( pMnn ); + } + return RetValue; +} + + +/**Function************************************************************* + + Synopsis [Takes an AIG and returns an AIG representing reachable states.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Aig_Man_t * Llb_ReachableStates( Aig_Man_t * pAig ) +{ + extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); + Vec_Int_t * vPermute; + Vec_Ptr_t * vNames; + Gia_ParLlb_t Pars, * pPars = &Pars; + DdManager * dd; + DdNode * bReached; + Llb_Mnx_t * pMnn; + Abc_Ntk_t * pNtk, * pNtkMuxes; + Aig_Obj_t * pObj; + int i, RetValue; + abctime clk = Abc_Clock(); + + // create parameters + Llb_ManSetDefaultParams( pPars ); + pPars->fSkipOutCheck = 1; + pPars->fCluster = 0; + pPars->fReorder = 0; + pPars->fSilent = 1; + pPars->nBddMax = 100; + pPars->nClusterMax = 500; + + // run reachability + pMnn = Llb_MnxStart( pAig, pPars ); + RetValue = Llb_Nonlin4Reachability( pMnn ); + assert( RetValue == 1 ); + + // print BDD +// Extra_bddPrint( pMnn->dd, pMnn->bReached ); +// Extra_bddPrintSupport( pMnn->dd, pMnn->bReached ); +// printf( "\n" ); + + // collect flop output variables + vPermute = Vec_IntStartFull( Cudd_ReadSize(pMnn->dd) ); + Saig_ManForEachLo( pAig, pObj, i ) + Vec_IntWriteEntry( vPermute, Llb_ObjBddVar(pMnn->vOrder, pObj), i ); + + // transfer the reached state BDD into the new manager + dd = Cudd_Init( Saig_ManRegNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + bReached = Extra_TransferPermute( pMnn->dd, dd, pMnn->bReached, Vec_IntArray(vPermute) ); Cudd_Ref( bReached ); + Vec_IntFree( vPermute ); + assert( Cudd_ReadSize(dd) == Saig_ManRegNum(pAig) ); + + // quit reachability engine + pMnn->timeTotal = Abc_Clock() - clk; + Llb_MnxStop( pMnn ); + + // derive the network + vNames = Abc_NodeGetFakeNames( Saig_ManRegNum(pAig) ); + pNtk = Abc_NtkDeriveFromBdd( dd, bReached, "reached", vNames ); + Abc_NodeFreeNames( vNames ); + Cudd_RecursiveDeref( dd, bReached ); + Cudd_Quit( dd ); + + // convert + pNtkMuxes = Abc_NtkBddToMuxes( pNtk ); + Abc_NtkDelete( pNtk ); + pNtk = Abc_NtkStrash( pNtkMuxes, 0, 1, 0 ); + Abc_NtkDelete( pNtkMuxes ); + pAig = Abc_NtkToDar( pNtk, 0, 0 ); + Abc_NtkDelete( pNtk ); + return pAig; +} +Gia_Man_t * Llb_ReachableStatesGia( Gia_Man_t * p ) +{ + Gia_Man_t * pNew; + Aig_Man_t * pAig, * pReached; + pAig = Gia_ManToAigSimple( p ); + pReached = Llb_ReachableStates( pAig ); + Aig_ManStop( pAig ); + pNew = Gia_ManFromAigSimple( pReached ); + Aig_ManStop( pReached ); + return pNew; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llb4Sweep.c b/src/bdd/llb/llb4Sweep.c new file mode 100644 index 00000000..6b318572 --- /dev/null +++ b/src/bdd/llb/llb4Sweep.c @@ -0,0 +1,589 @@ +/**CFile**************************************************************** + + FileName [llb2Sweep.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD based reachability.] + + Synopsis [Non-linear quantification scheduling.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: llb2Sweep.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "llbInt.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4SweepOrder_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Int_t * vOrder, int * pCounter, int fSaveAll ) +{ + Aig_Obj_t * pFanin0, * pFanin1; + if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) + return; + Aig_ObjSetTravIdCurrent( pAig, pObj ); + assert( Llb_ObjBddVar(vOrder, pObj) < 0 ); + if ( Aig_ObjIsCi(pObj) ) + { + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); + return; + } + // try fanins with higher level first + pFanin0 = Aig_ObjFanin0(pObj); + pFanin1 = Aig_ObjFanin1(pObj); +// if ( pFanin0->Level > pFanin1->Level || (pFanin0->Level == pFanin1->Level && pFanin0->Id < pFanin1->Id) ) + if ( pFanin0->Level > pFanin1->Level ) + { + Llb_Nonlin4SweepOrder_rec( pAig, pFanin0, vOrder, pCounter, fSaveAll ); + Llb_Nonlin4SweepOrder_rec( pAig, pFanin1, vOrder, pCounter, fSaveAll ); + } + else + { + Llb_Nonlin4SweepOrder_rec( pAig, pFanin1, vOrder, pCounter, fSaveAll ); + Llb_Nonlin4SweepOrder_rec( pAig, pFanin0, vOrder, pCounter, fSaveAll ); + } + if ( fSaveAll || pObj->fMarkA ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); +} + +/**Function************************************************************* + + Synopsis [Find good static variable ordering.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4SweepOrder( Aig_Man_t * pAig, int * pCounter, int fSaveAll ) +{ + Vec_Int_t * vOrder; + Aig_Obj_t * pObj; + int i, Counter = 0; + // collect nodes in the order + vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); + Aig_ManIncrementTravId( pAig ); + Aig_ObjSetTravIdCurrent( pAig, Aig_ManConst1(pAig) ); + Aig_ManForEachCo( pAig, pObj, i ) + { + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); + Llb_Nonlin4SweepOrder_rec( pAig, Aig_ObjFanin0(pObj), vOrder, &Counter, fSaveAll ); + } + Aig_ManForEachCi( pAig, pObj, i ) + if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); +// assert( Counter == Aig_ManObjNum(pAig) - 1 ); // no dangling nodes + if ( pCounter ) + *pCounter = Counter - Aig_ManCiNum(pAig) - Aig_ManCoNum(pAig); + return vOrder; +} + + +/**Function************************************************************* + + Synopsis [Performs BDD sweep on the netlist.] + + Description [Returns AIG with internal cut points labeled with fMarkA.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Llb4_Nonlin4SweepCutpoints( Aig_Man_t * pAig, Vec_Int_t * vOrder, int nBddLimit, int fVerbose ) +{ + DdManager * dd; + DdNode * bFunc0, * bFunc1, * bFunc; + Aig_Obj_t * pObj; + int i, Counter = 0, Counter1 = 0; + dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + // assign elementary variables + Aig_ManCleanData( pAig ); + Aig_ManForEachCi( pAig, pObj, i ) + pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + // sweep internal nodes + Aig_ManForEachNode( pAig, pObj, i ) + { +/* + if ( pObj->nRefs >= 4 ) + { + bFunc = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); Cudd_Ref( bFunc ); + pObj->pData = bFunc; + Counter1++; + continue; + } +*/ + bFunc0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bFunc1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc ); + if ( Cudd_DagSize(bFunc) > nBddLimit ) + { +// if ( fVerbose ) +// printf( "Node %5d : Beg =%5d. ", i, Cudd_DagSize(bFunc) ); + + // add cutpoint at a larger one + Cudd_RecursiveDeref( dd, bFunc ); + if ( Cudd_DagSize(bFunc0) >= Cudd_DagSize(bFunc1) ) + { + Cudd_RecursiveDeref( dd, (DdNode *)Aig_ObjFanin0(pObj)->pData ); + bFunc = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, Aig_ObjFanin0(pObj)) ); + Aig_ObjFanin0(pObj)->pData = bFunc; Cudd_Ref( bFunc ); + Aig_ObjFanin0(pObj)->fMarkA = 1; + +// if ( fVerbose ) +// printf( "Ref =%3d ", Aig_ObjFanin0(pObj)->nRefs ); + } + else + { + Cudd_RecursiveDeref( dd, (DdNode *)Aig_ObjFanin1(pObj)->pData ); + bFunc = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, Aig_ObjFanin1(pObj)) ); + Aig_ObjFanin1(pObj)->pData = bFunc; Cudd_Ref( bFunc ); + Aig_ObjFanin1(pObj)->fMarkA = 1; + +// if ( fVerbose ) +// printf( "Ref =%3d ", Aig_ObjFanin1(pObj)->nRefs ); + } + // perform new operation + bFunc0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); + bFunc1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); + bFunc = Cudd_bddAnd( dd, bFunc0, bFunc1 ); Cudd_Ref( bFunc ); +// assert( Cudd_DagSize(bFunc) <= nBddLimit ); + +// if ( fVerbose ) +// printf( "End =%5d.\n", Cudd_DagSize(bFunc) ); + Counter++; + } + pObj->pData = bFunc; +//printf( "%d ", Cudd_DagSize(bFunc) ); + } +//printf( "\n" ); + // clean up + Aig_ManForEachNode( pAig, pObj, i ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + Extra_StopManager( dd ); +// Aig_ManCleanMarkA( pAig ); + if ( fVerbose ) + printf( "Added %d cut points. Used %d high fanout points.\n", Counter, Counter1 ); + return Counter + Counter1; +} + +/**Function************************************************************* + + Synopsis [Derives BDDs for the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb_Nonlin4SweepPartitions_rec( DdManager * dd, Aig_Obj_t * pObj, Vec_Int_t * vOrder, Vec_Ptr_t * vRoots ) +{ + DdNode * bBdd, * bBdd0, * bBdd1, * bPart, * vVar; + if ( Aig_ObjIsConst1(pObj) ) + return Cudd_ReadOne(dd); + if ( Aig_ObjIsCi(pObj) ) + return Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + if ( pObj->pData ) + return (DdNode *)pObj->pData; + if ( Aig_ObjIsCo(pObj) ) + { + bBdd0 = Cudd_NotCond( Llb_Nonlin4SweepPartitions_rec(dd, Aig_ObjFanin0(pObj), vOrder, vRoots), Aig_ObjFaninC0(pObj) ); + bPart = Cudd_bddXnor( dd, Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ), bBdd0 ); Cudd_Ref( bPart ); + Vec_PtrPush( vRoots, bPart ); + return NULL; + } + bBdd0 = Cudd_NotCond( Llb_Nonlin4SweepPartitions_rec(dd, Aig_ObjFanin0(pObj), vOrder, vRoots), Aig_ObjFaninC0(pObj) ); + bBdd1 = Cudd_NotCond( Llb_Nonlin4SweepPartitions_rec(dd, Aig_ObjFanin1(pObj), vOrder, vRoots), Aig_ObjFaninC1(pObj) ); + bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); Cudd_Ref( bBdd ); + if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) + { + vVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + bPart = Cudd_bddXnor( dd, vVar, bBdd ); Cudd_Ref( bPart ); + Vec_PtrPush( vRoots, bPart ); + Cudd_RecursiveDeref( dd, bBdd ); + bBdd = vVar; Cudd_Ref( vVar ); + } + pObj->pData = bBdd; + return bBdd; +} + +/**Function************************************************************* + + Synopsis [Derives BDDs for the partitions.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Ptr_t * Llb_Nonlin4SweepPartitions( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fTransition ) +{ + Vec_Ptr_t * vRoots; + Aig_Obj_t * pObj; + int i; + Aig_ManCleanData( pAig ); + vRoots = Vec_PtrAlloc( 100 ); + if ( fTransition ) + { + Saig_ManForEachLi( pAig, pObj, i ) + Llb_Nonlin4SweepPartitions_rec( dd, pObj, vOrder, vRoots ); + } + else + { + Saig_ManForEachPo( pAig, pObj, i ) + Llb_Nonlin4SweepPartitions_rec( dd, pObj, vOrder, vRoots ); + } + Aig_ManForEachNode( pAig, pObj, i ) + if ( pObj->pData ) + Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); + return vRoots; +} + +/**Function************************************************************* + + Synopsis [Get bad state monitor.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdNode * Llb4_Nonlin4SweepBadMonitor( Aig_Man_t * pAig, Vec_Int_t * vOrder, DdManager * dd ) +{ + Aig_Obj_t * pObj; + DdNode * bRes, * bVar, * bTemp; + int i; + abctime TimeStop; + TimeStop = dd->TimeStop; dd->TimeStop = 0; + bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); + Saig_ManForEachPo( pAig, pObj, i ) + { + bVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); + bRes = Cudd_bddAnd( dd, bTemp = bRes, Cudd_Not(bVar) ); Cudd_Ref( bRes ); + Cudd_RecursiveDeref( dd, bTemp ); + } + Cudd_Deref( bRes ); + dd->TimeStop = TimeStop; + return Cudd_Not(bRes); +} + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Llb_Nonlin4SweepVars2Q( Aig_Man_t * pAig, Vec_Int_t * vOrder, int fAddLis ) +{ + Vec_Int_t * vVars2Q; + Aig_Obj_t * pObj; + int i; + vVars2Q = Vec_IntAlloc( 0 ); + Vec_IntFill( vVars2Q, Aig_ManObjNumMax(pAig), 1 ); + // add flop outputs + Saig_ManForEachLo( pAig, pObj, i ) + Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, pObj), 0 ); + // add flop inputs + if ( fAddLis ) + Saig_ManForEachLi( pAig, pObj, i ) + Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, pObj), 0 ); + return vVars2Q; +} + +/**Function************************************************************* + + Synopsis [Multiply every partition by the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4SweepDeref( DdManager * dd, Vec_Ptr_t * vParts ) +{ + DdNode * bFunc; + int i; + Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) + Cudd_RecursiveDeref( dd, bFunc ); + Vec_PtrFree( vParts ); +} + +/**Function************************************************************* + + Synopsis [Multiply every partition by the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4SweepPrint( Vec_Ptr_t * vFuncs ) +{ + DdNode * bFunc; + int i; + printf( "(%d) ", Vec_PtrSize(vFuncs) ); + Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i ) + printf( "%d ", Cudd_DagSize(bFunc) ); + printf( "\n" ); +} + +/**Function************************************************************* + + Synopsis [Computes bad states.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb4_Nonlin4SweepBadStates( Aig_Man_t * pAig, Vec_Int_t * vOrder, int nVars ) +{ + DdManager * dd; + Vec_Ptr_t * vParts; + Vec_Int_t * vVars2Q; + DdNode * bMonitor, * bImage; + // get quantifiable variables + vVars2Q = Llb_Nonlin4SweepVars2Q( pAig, vOrder, 0 ); + // start BDD manager and create partitions + dd = Cudd_Init( nVars, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + vParts = Llb_Nonlin4SweepPartitions( dd, pAig, vOrder, 0 ); +//printf( "Outputs: " ); +//Llb_Nonlin4SweepPrint( vParts ); + // compute image of the partitions + bMonitor = Llb4_Nonlin4SweepBadMonitor( pAig, vOrder, dd ); Cudd_Ref( bMonitor ); + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + bImage = Llb_Nonlin4Image( dd, vParts, bMonitor, vVars2Q ); Cudd_Ref( bImage ); + Cudd_RecursiveDeref( dd, bMonitor ); + Llb_Nonlin4SweepDeref( dd, vParts ); + Vec_IntFree( vVars2Q ); + // save image and return + dd->bFunc = bImage; + return dd; +} + +/**Function************************************************************* + + Synopsis [Computes clusters.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +DdManager * Llb4_Nonlin4SweepGroups( Aig_Man_t * pAig, Vec_Int_t * vOrder, int nVars, Vec_Ptr_t ** pvGroups, int nBddLimitClp, int fVerbose ) +{ + DdManager * dd; + Vec_Ptr_t * vParts; + Vec_Int_t * vVars2Q; + // get quantifiable variables + vVars2Q = Llb_Nonlin4SweepVars2Q( pAig, vOrder, 1 ); + // start BDD manager and create partitions + dd = Cudd_Init( nVars, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); + vParts = Llb_Nonlin4SweepPartitions( dd, pAig, vOrder, 1 ); +//printf( "Transitions: " ); +//Llb_Nonlin4SweepPrint( vParts ); + // compute image of the partitions + + Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); + *pvGroups = Llb_Nonlin4Group( dd, vParts, vVars2Q, nBddLimitClp ); + Llb_Nonlin4SweepDeref( dd, vParts ); +// *pvGroups = vParts; + +if ( fVerbose ) +{ +printf( "Groups: " ); +Llb_Nonlin4SweepPrint( *pvGroups ); +} + + Vec_IntFree( vVars2Q ); + return dd; +} + + +/**Function************************************************************* + + Synopsis [Creates quantifiable variables for both types of traversal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb_Nonlin4SweepPrintSuppProfile( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, Vec_Ptr_t * vGroups, int fVerbose ) +{ + Aig_Obj_t * pObj; + int i, * pSupp; + int nSuppAll = 0, nSuppPi = 0, nSuppPo = 0, nSuppLi = 0, nSuppLo = 0, nSuppAnd = 0; + + pSupp = ABC_CALLOC( int, Cudd_ReadSize(dd) ); + Extra_VectorSupportArray( dd, (DdNode **)Vec_PtrArray(vGroups), Vec_PtrSize(vGroups), pSupp ); + + Aig_ManForEachObj( pAig, pObj, i ) + { + if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) + continue; + // remove variables that do not participate + if ( pSupp[Llb_ObjBddVar(vOrder, pObj)] == 0 ) + { + if ( Aig_ObjIsNode(pObj) ) + Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), -1 ); + continue; + } + nSuppAll++; + if ( Saig_ObjIsPi(pAig, pObj) ) + nSuppPi++; + else if ( Saig_ObjIsLo(pAig, pObj) ) + nSuppLo++; + else if ( Saig_ObjIsPo(pAig, pObj) ) + nSuppPo++; + else if ( Saig_ObjIsLi(pAig, pObj) ) + nSuppLi++; + else + nSuppAnd++; + } + ABC_FREE( pSupp ); + + if ( fVerbose ) + { + printf( "Groups =%3d ", Vec_PtrSize(vGroups) ); + printf( "Variables: all =%4d ", nSuppAll ); + printf( "pi =%4d ", nSuppPi ); + printf( "po =%4d ", nSuppPo ); + printf( "lo =%4d ", nSuppLo ); + printf( "li =%4d ", nSuppLi ); + printf( "and =%4d", nSuppAnd ); + printf( "\n" ); + } +} + +/**Function************************************************************* + + Synopsis [Performs BDD sweep on the netlist.] + + Description [Returns BDD manager, ordering, clusters, and bad states + inside dd->bFunc.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb4_Nonlin4Sweep( Aig_Man_t * pAig, int nSweepMax, int nClusterMax, DdManager ** pdd, Vec_Int_t ** pvOrder, Vec_Ptr_t ** pvGroups, int fVerbose ) +{ + DdManager * ddBad, * ddWork; + Vec_Ptr_t * vGroups; + Vec_Int_t * vOrder; + int Counter, nCutPoints; + + // get the original ordering + Aig_ManCleanMarkA( pAig ); + vOrder = Llb_Nonlin4SweepOrder( pAig, &Counter, 1 ); + assert( Counter == Aig_ManNodeNum(pAig) ); + // mark the nodes + nCutPoints = Llb4_Nonlin4SweepCutpoints( pAig, vOrder, nSweepMax, fVerbose ); + Vec_IntFree( vOrder ); + // get better ordering + vOrder = Llb_Nonlin4SweepOrder( pAig, &Counter, 0 ); + assert( Counter == nCutPoints ); + Aig_ManCleanMarkA( pAig ); + // compute the BAD states + ddBad = Llb4_Nonlin4SweepBadStates( pAig, vOrder, nCutPoints + Aig_ManCiNum(pAig) + Aig_ManCoNum(pAig) ); + // compute the clusters + ddWork = Llb4_Nonlin4SweepGroups( pAig, vOrder, nCutPoints + Aig_ManCiNum(pAig) + Aig_ManCoNum(pAig), &vGroups, nClusterMax, fVerbose ); + // transfer the result from the Bad manager +//printf( "Bad before = %d.\n", Cudd_DagSize(ddBad->bFunc) ); + ddWork->bFunc = Cudd_bddTransfer( ddBad, ddWork, ddBad->bFunc ); Cudd_Ref( ddWork->bFunc ); + Cudd_RecursiveDeref( ddBad, ddBad->bFunc ); ddBad->bFunc = NULL; + Extra_StopManager( ddBad ); + // update ordering to exclude quantified variables +//printf( "Bad after = %d.\n", Cudd_DagSize(ddWork->bFunc) ); + + Llb_Nonlin4SweepPrintSuppProfile( ddWork, pAig, vOrder, vGroups, fVerbose ); + + // return the result + *pdd = ddWork; + *pvOrder = vOrder; + *pvGroups = vGroups; +} + +/**Function************************************************************* + + Synopsis [Performs BDD sweep on the netlist.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Llb4_Nonlin4SweepExperiment( Aig_Man_t * pAig ) +{ + DdManager * dd; + Vec_Int_t * vOrder; + Vec_Ptr_t * vGroups; + Llb4_Nonlin4Sweep( pAig, 100, 500, &dd, &vOrder, &vGroups, 1 ); + + Llb_Nonlin4SweepDeref( dd, vGroups ); + + Cudd_RecursiveDeref( dd, dd->bFunc ); + Extra_StopManager( dd ); + Vec_IntFree( vOrder ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/bdd/llb/llbInt.h b/src/bdd/llb/llbInt.h new file mode 100644 index 00000000..238da04e --- /dev/null +++ b/src/bdd/llb/llbInt.h @@ -0,0 +1,212 @@ +/**CFile**************************************************************** + + FileName [llbInt.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [BDD-based reachability.] + + Synopsis [External declarations.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 8, 2010.] + + Revision [$Id: llbInt.h,v 1.00 2010/05/08 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef ABC__aig__llb__llbInt_h +#define ABC__aig__llb__llbInt_h + + +//////////////////////////////////////////////////////////////////////// +/// INCLUDES /// +//////////////////////////////////////////////////////////////////////// + +#include +#include "aig/aig/aig.h" +#include "aig/saig/saig.h" +#include "proof/ssw/ssw.h" +#include "llb.h" + +#include "bdd/extrab/extraBdd.h" + +//////////////////////////////////////////////////////////////////////// +/// PARAMETERS /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_HEADER_START + +//////////////////////////////////////////////////////////////////////// +/// BASIC TYPES /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Llb_Man_t_ Llb_Man_t; +typedef struct Llb_Mtr_t_ Llb_Mtr_t; +typedef struct Llb_Grp_t_ Llb_Grp_t; + +struct Llb_Man_t_ +{ + Gia_ParLlb_t * pPars; // parameters + Aig_Man_t * pAigGlo; // initial AIG manager (owned by the caller) + Aig_Man_t * pAig; // derived AIG manager (created in this package) + DdManager * dd; // BDD manager + DdManager * ddG; // BDD manager + DdManager * ddR; // BDD manager + Vec_Int_t * vObj2Var; // mapping AIG ObjId into BDD var index + Vec_Int_t * vVar2Obj; // mapping BDD var index into AIG ObjId + Vec_Ptr_t * vGroups; // group Id into group pointer + Llb_Mtr_t * pMatrix; // dependency matrix + // image computation + Vec_Ptr_t * vRings; // onion rings + Vec_Int_t * vVarBegs; // the first group where the var appears + Vec_Int_t * vVarEnds; // the last group where the var appears + // variable mapping + Vec_Int_t * vNs2Glo; // next state variables into global variables + Vec_Int_t * vCs2Glo; // next state variables into global variables + Vec_Int_t * vGlo2Cs; // global variables into current state variables + Vec_Int_t * vGlo2Ns; // global variables into current state variables + // flow computation +// Vec_Int_t * vMem; +// Vec_Ptr_t * vTops; +// Vec_Ptr_t * vBots; +// Vec_Ptr_t * vCuts; +}; + +struct Llb_Mtr_t_ +{ + int nPis; // number of primary inputs + int nFfs; // number of flip-flops + int nRows; // number of rows + int nCols; // number of columns + int * pColSums; // sum of values in a column + Llb_Grp_t ** pColGrps; // group structure for each col + int * pRowSums; // sum of values in a row + char ** pMatrix; // dependency matrix + Llb_Man_t * pMan; // manager + // partial product + char * pProdVars; // variables in the partial product + int * pProdNums; // var counts in the remaining partitions +}; + +struct Llb_Grp_t_ +{ + int Id; // group ID + Vec_Ptr_t * vIns; // input AIG objs + Vec_Ptr_t * vOuts; // output AIG objs + Vec_Ptr_t * vNodes; // internal AIG objs + Llb_Man_t * pMan; // manager + Llb_Grp_t * pPrev; // previous group + Llb_Grp_t * pNext; // next group +}; + +//////////////////////////////////////////////////////////////////////// +/// MACRO DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +static inline int Llb_ObjBddVar( Vec_Int_t * vOrder, Aig_Obj_t * pObj ) { return Vec_IntEntry(vOrder, Aig_ObjId(pObj)); } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +/*=== llbConstr.c ======================================================*/ +extern Vec_Int_t * Llb_ManDeriveConstraints( Aig_Man_t * p ); +extern void Llb_ManPrintEntries( Aig_Man_t * p, Vec_Int_t * vCands ); +/*=== llbCore.c ======================================================*/ +extern int Llb_ManModelCheckAig( Aig_Man_t * pAigGlo, Gia_ParLlb_t * pPars, Vec_Int_t * vHints, DdManager ** pddGlo ); +/*=== llbCluster.c ======================================================*/ +extern void Llb_ManCluster( Llb_Mtr_t * p ); +/*=== llbDump.c ======================================================*/ +extern void Llb_ManDumpReached( DdManager * ddG, DdNode * bReached, char * pModel, char * pFileName ); +/*=== llbFlow.c ======================================================*/ +extern Vec_Ptr_t * Llb_ManFlow( Aig_Man_t * p, Vec_Ptr_t * vSources, int * pnFlow ); +/*=== llbHint.c ======================================================*/ +extern int Llb_ManReachabilityWithHints( Llb_Man_t * p ); +extern int Llb_ManModelCheckAigWithHints( Aig_Man_t * pAigGlo, Gia_ParLlb_t * pPars ); +/*=== llbMan.c =======================================================*/ +extern void Llb_ManPrepareVarMap( Llb_Man_t * p ); +extern Llb_Man_t * Llb_ManStart( Aig_Man_t * pAigGlo, Aig_Man_t * pAig, Gia_ParLlb_t * pPars ); +extern void Llb_ManStop( Llb_Man_t * p ); +/*=== llbMatrix.c ====================================================*/ +extern void Llb_MtrVerifyMatrix( Llb_Mtr_t * p ); +extern Llb_Mtr_t * Llb_MtrCreate( Llb_Man_t * p ); +extern void Llb_MtrFree( Llb_Mtr_t * p ); +extern void Llb_MtrPrint( Llb_Mtr_t * p, int fOrder ); +extern void Llb_MtrPrintMatrixStats( Llb_Mtr_t * p ); +/*=== llbPart.c ======================================================*/ +extern Llb_Grp_t * Llb_ManGroupAlloc( Llb_Man_t * pMan ); +extern void Llb_ManGroupStop( Llb_Grp_t * p ); +extern void Llb_ManPrepareGroups( Llb_Man_t * pMan ); +extern Llb_Grp_t * Llb_ManGroupsCombine( Llb_Grp_t * p1, Llb_Grp_t * p2 ); +extern Llb_Grp_t * Llb_ManGroupCreateFromCuts( Llb_Man_t * pMan, Vec_Int_t * vCut1, Vec_Int_t * vCut2 ); +extern void Llb_ManPrepareVarLimits( Llb_Man_t * p ); +/*=== llbPivot.c =====================================================*/ +extern int Llb_ManTracePaths( Aig_Man_t * p, Aig_Obj_t * pPivot ); +extern Vec_Int_t * Llb_ManMarkPivotNodes( Aig_Man_t * p, int fUseInternal ); +/*=== llbReach.c =====================================================*/ +extern int Llb_ManReachability( Llb_Man_t * p, Vec_Int_t * vHints, DdManager ** pddGlo ); +/*=== llbSched.c =====================================================*/ +extern void Llb_MtrSchedule( Llb_Mtr_t * p ); + +/*=== llb2Bad.c ======================================================*/ +extern DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd, abctime TimeOut ); +extern DdNode * Llb_BddQuantifyPis( Aig_Man_t * pInit, DdManager * dd, DdNode * bFunc ); +/*=== llb2Core.c ======================================================*/ +extern DdNode * Llb_CoreComputeCube( DdManager * dd, Vec_Int_t * vVars, int fUseVarIndex, char * pValues ); +extern int Llb_CoreExperiment( Aig_Man_t * pInit, Aig_Man_t * pAig, Gia_ParLlb_t * pPars, Vec_Ptr_t * vResult, abctime TimeTarget ); +/*=== llb2Driver.c ======================================================*/ +extern Vec_Int_t * Llb_DriverCountRefs( Aig_Man_t * p ); +extern Vec_Int_t * Llb_DriverCollectNs( Aig_Man_t * pAig, Vec_Int_t * vDriRefs ); +extern Vec_Int_t * Llb_DriverCollectCs( Aig_Man_t * pAig ); +extern DdNode * Llb_DriverPhaseCube( Aig_Man_t * pAig, Vec_Int_t * vDriRefs, DdManager * dd ); +extern DdManager * Llb_DriverLastPartition( Aig_Man_t * p, Vec_Int_t * vVarsNs, abctime TimeTarget ); +/*=== llb2Image.c ======================================================*/ +extern Vec_Ptr_t * Llb_ImgSupports( Aig_Man_t * p, Vec_Ptr_t * vDdMans, Vec_Int_t * vStart, Vec_Int_t * vStop, int fAddPis, int fVerbose ); +extern void Llb_ImgSchedule( Vec_Ptr_t * vSupps, Vec_Ptr_t ** pvQuant0, Vec_Ptr_t ** pvQuant1, int fVerbose ); +extern DdManager * Llb_ImgPartition( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, abctime TimeTarget ); +extern void Llb_ImgQuantifyFirst( Aig_Man_t * pAig, Vec_Ptr_t * vDdMans, Vec_Ptr_t * vQuant0, int fVerbose ); +extern void Llb_ImgQuantifyReset( Vec_Ptr_t * vDdMans ); +extern DdNode * Llb_ImgComputeImage( Aig_Man_t * pAig, Vec_Ptr_t * vDdMans, DdManager * dd, DdNode * bInit, + Vec_Ptr_t * vQuant0, Vec_Ptr_t * vQuant1, Vec_Int_t * vDriRefs, + abctime TimeTarget, int fBackward, int fReorder, int fVerbose ); + +extern DdManager * Llb_NonlinImageStart( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, int * pOrder, int fFirst, abctime TimeTarget ); +extern DdNode * Llb_NonlinImageCompute( DdNode * bCurrent, int fReorder, int fDrop, int fVerbose, int * pOrder ); +extern void Llb_NonlinImageQuit(); + +/*=== llb3Image.c =======================================================*/ +extern DdNode * Llb_NonlinImage( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, + DdManager * dd, DdNode * bCurrent, int fReorder, int fVerbose, int * pOrder ); +/*=== llb3Nonlin.c ======================================================*/ +extern DdNode * Llb_NonlinComputeInitState( Aig_Man_t * pAig, DdManager * dd ); + + +/*=== llb4Cex.c =======================================================*/ +extern Abc_Cex_t * Llb4_Nonlin4TransformCex( Aig_Man_t * pAig, Vec_Ptr_t * vStates, int iCexPo, int fVerbose ); +/*=== llb4Cluster.c =======================================================*/ +//extern void Llb_Nonlin4Cluster( Aig_Man_t * pAig, DdManager ** pdd, Vec_Int_t ** pvOrder, Vec_Ptr_t ** pvGroups, int nBddMax, int fVerbose ); +/*=== llb4Image.c =======================================================*/ +extern DdNode * Llb_Nonlin4Image( DdManager * dd, Vec_Ptr_t * vParts, DdNode * bCurrent, Vec_Int_t * vVars2Q ); +extern Vec_Ptr_t * Llb_Nonlin4Group( DdManager * dd, Vec_Ptr_t * vParts, Vec_Int_t * vVars2Q, int nSizeMax ); +/*=== llb4Map.c =========================================================*/ +//extern Vec_Int_t * Llb_AigMap( Aig_Man_t * pAig, int nLutSize, int nLutMin ); +/*=== llb4Nonlin.c ======================================================*/ +//extern int Llb_Nonlin4CoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ); +/*=== llb4Sweep.c ======================================================*/ +extern void Llb4_Nonlin4Sweep( Aig_Man_t * pAig, int nSweepMax, int nClusterMax, DdManager ** pdd, Vec_Int_t ** pvOrder, Vec_Ptr_t ** pvGroups, int fVerbose ); + + +ABC_NAMESPACE_HEADER_END + + + +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + diff --git a/src/bdd/llb/module.make b/src/bdd/llb/module.make new file mode 100644 index 00000000..6d253d50 --- /dev/null +++ b/src/bdd/llb/module.make @@ -0,0 +1,22 @@ +SRC += src/bdd/llb/llb1Cluster.c \ + src/bdd/llb/llb1Constr.c \ + src/bdd/llb/llb1Core.c \ + src/bdd/llb/llb1Group.c \ + src/bdd/llb/llb1Hint.c \ + src/bdd/llb/llb1Man.c \ + src/bdd/llb/llb1Matrix.c \ + src/bdd/llb/llb1Pivot.c \ + src/bdd/llb/llb1Reach.c \ + src/bdd/llb/llb1Sched.c \ + src/bdd/llb/llb2Bad.c \ + src/bdd/llb/llb2Core.c \ + src/bdd/llb/llb2Driver.c \ + src/bdd/llb/llb2Dump.c \ + src/bdd/llb/llb2Flow.c \ + src/bdd/llb/llb2Image.c \ + src/bdd/llb/llb3Image.c \ + src/bdd/llb/llb3Nonlin.c \ + src/bdd/llb/llb4Cex.c \ + src/bdd/llb/llb4Image.c \ + src/bdd/llb/llb4Nonlin.c \ + src/bdd/llb/llb4Sweep.c diff --git a/src/bdd/parse/module.make b/src/bdd/parse/module.make deleted file mode 100644 index 4f590f01..00000000 --- a/src/bdd/parse/module.make +++ /dev/null @@ -1,3 +0,0 @@ -SRC += src/bdd/parse/parseCore.c \ - src/bdd/parse/parseEqn.c \ - src/bdd/parse/parseStack.c diff --git a/src/bdd/parse/parse.h b/src/bdd/parse/parse.h deleted file mode 100644 index 584ec30a..00000000 --- a/src/bdd/parse/parse.h +++ /dev/null @@ -1,62 +0,0 @@ -/**CFile**************************************************************** - - FileName [parse.h] - - PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] - - Synopsis [Parsing symbolic Boolean formulas into BDDs.] - - Author [MVSIS Group] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - September 8, 2003.] - - Revision [$Id: parse.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#ifndef ABC__bdd__parse__parse_h -#define ABC__bdd__parse__parse_h - - -ABC_NAMESPACE_HEADER_START - - -//////////////////////////////////////////////////////////////////////// -/// INCLUDES /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// PARAMETERS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// STRUCTURE DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// GLOBAL VARIABLES /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// MACRO DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/*=== parseCore.c =============================================================*/ -extern DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormula, int nVars, int nRanks, - char * ppVarNames[], DdManager * dd, DdNode * pbVars[] ); - - - -ABC_NAMESPACE_HEADER_END - -#endif - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// diff --git a/src/bdd/parse/parseCore.c b/src/bdd/parse/parseCore.c deleted file mode 100644 index f451d3aa..00000000 --- a/src/bdd/parse/parseCore.c +++ /dev/null @@ -1,536 +0,0 @@ -/**CFile**************************************************************** - - FileNameIn [parseCore.c] - - PackageName [MVSIS 1.3: Multi-valued logic synthesis system.] - - Synopsis [Boolean formula parser.] - - Author [MVSIS Group] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - February 1, 2003.] - - Revision [$Id: parseCore.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] - -***********************************************************************/ - -/* - Some aspects of Boolean Formula Parser: - - 1) The names in the boolean formulas can be any strings of symbols - that start with char or underscore and contain chars, digits - and underscores: For example: 1) a&b <+> c'&d => a + b; - 2) a1 b2 c3' dummy' + (a2+b2')c3 dummy - 2) Constant values 0 and 1 can be used just like normal variables - 3) Any boolean operator (listed below) and parentheses can be used - any number of times provided there are equal number of opening - and closing parentheses. - 4) By default, absence of an operator between vars and before and - after parentheses is taken for AND. - 5) Both complementation prefix and complementation suffix can be - used at the same time (but who needs this?) - 6) Spaces (tabs, end-of-lines) may be inserted anywhere, - except between characters of the operations: <=>, =>, <=, <+> - 7) The stack size is defined by macro STACKSIZE and is used by the - stack constructor. -*/ - -//////////////////////////////////////////////////////////////////////// -/// DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -#include "parseInt.h" - -ABC_NAMESPACE_IMPL_START - - -// the list of operation symbols to be used in expressions -#define PARSE_SYM_OPEN '(' // opening parenthesis -#define PARSE_SYM_CLOSE ')' // closing parenthesis -#define PARSE_SYM_LOWER '[' // shifts one rank down -#define PARSE_SYM_RAISE ']' // shifts one rank up -#define PARSE_SYM_CONST0 '0' // constant 0 -#define PARSE_SYM_CONST1 '1' // constant 1 -#define PARSE_SYM_NEGBEF1 '!' // negation before the variable -#define PARSE_SYM_NEGBEF2 '~' // negation before the variable -#define PARSE_SYM_NEGAFT '\'' // negation after the variable -#define PARSE_SYM_AND1 '&' // logic AND -#define PARSE_SYM_AND2 '*' // logic AND -#define PARSE_SYM_XOR1 '<' // logic EXOR (the 1st symbol) -#define PARSE_SYM_XOR2 '+' // logic EXOR (the 2nd symbol) -#define PARSE_SYM_XOR3 '>' // logic EXOR (the 3rd symbol) -#define PARSE_SYM_XOR '^' // logic XOR -#define PARSE_SYM_OR1 '+' // logic OR -#define PARSE_SYM_OR2 '|' // logic OR -#define PARSE_SYM_EQU1 '<' // equvalence (the 1st symbol) -#define PARSE_SYM_EQU2 '=' // equvalence (the 2nd symbol) -#define PARSE_SYM_EQU3 '>' // equvalence (the 3rd symbol) -#define PARSE_SYM_FLR1 '=' // implication (the 1st symbol) -#define PARSE_SYM_FLR2 '>' // implication (the 2nd symbol) -#define PARSE_SYM_FLL1 '<' // backward imp (the 1st symbol) -#define PARSE_SYM_FLL2 '=' // backward imp (the 2nd symbol) -// PARSE_SYM_FLR1 and PARSE_SYM_FLR2 should be the same as PARSE_SYM_EQU2 and PARSE_SYM_EQU3! - -// the list of opcodes (also specifying operation precedence) -#define PARSE_OPER_NEG 10 // negation -#define PARSE_OPER_AND 9 // logic AND -#define PARSE_OPER_XOR 8 // logic EXOR (a'b | ab') -#define PARSE_OPER_OR 7 // logic OR -#define PARSE_OPER_EQU 6 // equvalence (a'b'| ab ) -#define PARSE_OPER_FLR 5 // implication ( a' | b ) -#define PARSE_OPER_FLL 4 // backward imp ( 'b | a ) -#define PARSE_OPER_MARK 1 // OpStack token standing for an opening parenthesis - -// these are values of the internal Flag -#define PARSE_FLAG_START 1 // after the opening parenthesis -#define PARSE_FLAG_VAR 2 // after operation is received -#define PARSE_FLAG_OPER 3 // after operation symbol is received -#define PARSE_FLAG_ERROR 4 // when error is detected - -#define STACKSIZE 1000 - -static DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper ); - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/**Function************************************************************* - - Synopsis [Derives the BDD corresponding to the formula in language L.] - - Description [Takes the stream to output messages, the formula, the number - variables and the rank in the formula. The array of variable names is also - given. The BDD manager and the elementary 0-rank variable are the last two - arguments. The manager should have at least as many variables as - nVars * (nRanks + 1). The 0-rank variables should have numbers larger - than the variables of other ranks.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -DdNode * Parse_FormulaParser( FILE * pOutput, char * pFormulaInit, int nVars, int nRanks, - char * ppVarNames[], DdManager * dd, DdNode * pbVars[] ) -{ - char * pFormula; - Parse_StackFn_t * pStackFn; - Parse_StackOp_t * pStackOp; - DdNode * bFunc, * bTemp; - char * pTemp; - int nParans, fFound, Flag; - int Oper, Oper1, Oper2; - int i, fLower; - int v = -1; // Suppress "might be used uninitialized" - - // make sure that the number of vars and ranks is correct - if ( nVars * (nRanks + 1) > dd->size ) - { - printf( "Parse_FormulaParser(): The BDD manager does not have enough variables.\n" ); - return NULL; - } - - // make sure that the number of opening and closing parentheses is the same - nParans = 0; - for ( pTemp = pFormulaInit; *pTemp; pTemp++ ) - if ( *pTemp == '(' ) - nParans++; - else if ( *pTemp == ')' ) - nParans--; - if ( nParans != 0 ) - { - fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing parentheses ().\n" ); - return NULL; - } - - nParans = 0; - for ( pTemp = pFormulaInit; *pTemp; pTemp++ ) - if ( *pTemp == '[' ) - nParans++; - else if ( *pTemp == ']' ) - nParans--; - if ( nParans != 0 ) - { - fprintf( pOutput, "Parse_FormulaParser(): Different number of opening and closing brackets [].\n" ); - return NULL; - } - - // copy the formula - pFormula = ABC_ALLOC( char, strlen(pFormulaInit) + 3 ); - sprintf( pFormula, "(%s)", pFormulaInit ); - - // start the stacks - pStackFn = Parse_StackFnStart( STACKSIZE ); - pStackOp = Parse_StackOpStart( STACKSIZE ); - - Flag = PARSE_FLAG_START; - fLower = 0; - for ( pTemp = pFormula; *pTemp; pTemp++ ) - { - switch ( *pTemp ) - { - // skip all spaces, tabs, and end-of-lines - case ' ': - case '\t': - case '\r': - case '\n': - continue; - - // treat Constant 0 as a variable - case PARSE_SYM_CONST0: - Parse_StackFnPush( pStackFn, b0 ); Cudd_Ref( b0 ); - if ( Flag == PARSE_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 0.\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - Flag = PARSE_FLAG_VAR; - break; - - // the same for Constant 1 - case PARSE_SYM_CONST1: - Parse_StackFnPush( pStackFn, b1 ); Cudd_Ref( b1 ); - if ( Flag == PARSE_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParser(): No operation symbol before constant 1.\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - Flag = PARSE_FLAG_VAR; - break; - - case PARSE_SYM_NEGBEF1: - case PARSE_SYM_NEGBEF2: - if ( Flag == PARSE_FLAG_VAR ) - {// if NEGBEF follows a variable, AND is assumed - Parse_StackOpPush( pStackOp, PARSE_OPER_AND ); - Flag = PARSE_FLAG_OPER; - } - Parse_StackOpPush( pStackOp, PARSE_OPER_NEG ); - break; - - case PARSE_SYM_NEGAFT: - if ( Flag != PARSE_FLAG_VAR ) - {// if there is no variable before NEGAFT, it is an error - fprintf( pOutput, "Parse_FormulaParser(): No variable is specified before the negation suffix.\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - else // if ( Flag == PARSE_FLAG_VAR ) - Parse_StackFnPush( pStackFn, Cudd_Not( Parse_StackFnPop(pStackFn) ) ); - break; - - case PARSE_SYM_AND1: - case PARSE_SYM_AND2: - case PARSE_SYM_OR1: - case PARSE_SYM_OR2: - case PARSE_SYM_XOR: - if ( Flag != PARSE_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParser(): There is no variable before AND, EXOR, or OR.\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - if ( *pTemp == PARSE_SYM_AND1 || *pTemp == PARSE_SYM_AND2 ) - Parse_StackOpPush( pStackOp, PARSE_OPER_AND ); - else if ( *pTemp == PARSE_SYM_OR1 || *pTemp == PARSE_SYM_OR2 ) - Parse_StackOpPush( pStackOp, PARSE_OPER_OR ); - else //if ( Str[Pos] == PARSE_SYM_XOR ) - Parse_StackOpPush( pStackOp, PARSE_OPER_XOR ); - Flag = PARSE_FLAG_OPER; - break; - - case PARSE_SYM_EQU1: - if ( Flag != PARSE_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Equivalence or Implication\n" ); - Flag = PARSE_FLAG_ERROR; break; - } - if ( pTemp[1] == PARSE_SYM_EQU2 ) - { // check what is the next symbol in the string - pTemp++; - if ( pTemp[1] == PARSE_SYM_EQU3 ) - { - pTemp++; - Parse_StackOpPush( pStackOp, PARSE_OPER_EQU ); - } - else - { - Parse_StackOpPush( pStackOp, PARSE_OPER_FLL ); - } - } - else if ( pTemp[1] == PARSE_SYM_XOR2 ) - { - pTemp++; - if ( pTemp[1] == PARSE_SYM_XOR3 ) - { - pTemp++; - Parse_StackOpPush( pStackOp, PARSE_OPER_XOR ); - } - else - { - fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c%c\"\n", PARSE_SYM_EQU1, PARSE_SYM_XOR2 ); - Flag = PARSE_FLAG_ERROR; - break; - } - } - else - { - fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU1 ); - Flag = PARSE_FLAG_ERROR; - break; - } - Flag = PARSE_FLAG_OPER; - break; - - case PARSE_SYM_EQU2: - if ( Flag != PARSE_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParser(): There is no variable before Reverse Implication\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - if ( pTemp[1] == PARSE_SYM_EQU3 ) - { - pTemp++; - Parse_StackOpPush( pStackOp, PARSE_OPER_FLR ); - } - else - { - fprintf( pOutput, "Parse_FormulaParser(): Wrong symbol after \"%c\"\n", PARSE_SYM_EQU2 ); - Flag = PARSE_FLAG_ERROR; - break; - } - Flag = PARSE_FLAG_OPER; - break; - - case PARSE_SYM_LOWER: - case PARSE_SYM_OPEN: - if ( Flag == PARSE_FLAG_VAR ) - Parse_StackOpPush( pStackOp, PARSE_OPER_AND ); - Parse_StackOpPush( pStackOp, PARSE_OPER_MARK ); - // after an opening bracket, it feels like starting over again - Flag = PARSE_FLAG_START; - break; - - case PARSE_SYM_RAISE: - fLower = 1; - case PARSE_SYM_CLOSE: - if ( !Parse_StackOpIsEmpty( pStackOp ) ) - { - while ( 1 ) - { - if ( Parse_StackOpIsEmpty( pStackOp ) ) - { - fprintf( pOutput, "Parse_FormulaParser(): There is no opening parenthesis\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - Oper = Parse_StackOpPop( pStackOp ); - if ( Oper == PARSE_OPER_MARK ) - break; - - // perform the given operation - if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper ) == NULL ) - { - fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" ); - ABC_FREE( pFormula ); - return NULL; - } - } - - if ( fLower ) - { - bFunc = (DdNode *)Parse_StackFnPop( pStackFn ); - bFunc = Extra_bddMove( dd, bTemp = bFunc, -nVars ); Cudd_Ref( bFunc ); - Cudd_RecursiveDeref( dd, bTemp ); - Parse_StackFnPush( pStackFn, bFunc ); - } - } - else - { - fprintf( pOutput, "Parse_FormulaParser(): There is no opening parenthesis\n" ); - Flag = PARSE_FLAG_ERROR; - break; - } - if ( Flag != PARSE_FLAG_ERROR ) - Flag = PARSE_FLAG_VAR; - fLower = 0; - break; - - - default: - // scan the next name -/* - fFound = 0; - for ( i = 0; pTemp[i] && pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n'; i++ ) - { - for ( v = 0; v < nVars; v++ ) - if ( strncmp( pTemp, ppVarNames[v], i+1 ) == 0 && strlen(ppVarNames[v]) == (unsigned)(i+1) ) - { - pTemp += i; - fFound = 1; - break; - } - if ( fFound ) - break; - } -*/ - // bug fix by SV (9/11/08) - fFound = 0; - for ( i = 0; pTemp[i] && pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n' && - pTemp[i] != PARSE_SYM_AND1 && pTemp[i] != PARSE_SYM_AND2 && pTemp[i] != PARSE_SYM_XOR1 && - pTemp[i] != PARSE_SYM_XOR2 && pTemp[i] != PARSE_SYM_XOR3 && pTemp[i] != PARSE_SYM_XOR && - pTemp[i] != PARSE_SYM_OR1 && pTemp[i] != PARSE_SYM_OR2 && pTemp[i] != PARSE_SYM_CLOSE && - pTemp[i] != PARSE_SYM_NEGAFT; - i++ ) - {} - for ( v = 0; v < nVars; v++ ) - { - if ( strncmp( pTemp, ppVarNames[v], i ) == 0 && strlen(ppVarNames[v]) == (unsigned)(i) ) - { - pTemp += i-1; - fFound = 1; - break; - } - } - - if ( !fFound ) - { - fprintf( pOutput, "Parse_FormulaParser(): The parser cannot find var \"%s\" in the input var list.\n", pTemp ); - Flag = PARSE_FLAG_ERROR; - break; - } - // assume operation AND, if vars follow one another - if ( Flag == PARSE_FLAG_VAR ) - Parse_StackOpPush( pStackOp, PARSE_OPER_AND ); - Parse_StackFnPush( pStackFn, pbVars[v] ); Cudd_Ref( pbVars[v] ); - Flag = PARSE_FLAG_VAR; - break; - } - - if ( Flag == PARSE_FLAG_ERROR ) - break; // error exit - else if ( Flag == PARSE_FLAG_START ) - continue; // go on parsing - else if ( Flag == PARSE_FLAG_VAR ) - while ( 1 ) - { // check if there are negations in the OpStack - if ( Parse_StackOpIsEmpty(pStackOp) ) - break; - Oper = Parse_StackOpPop( pStackOp ); - if ( Oper != PARSE_OPER_NEG ) - { - Parse_StackOpPush( pStackOp, Oper ); - break; - } - else - { - Parse_StackFnPush( pStackFn, Cudd_Not(Parse_StackFnPop(pStackFn)) ); - } - } - else // if ( Flag == PARSE_FLAG_OPER ) - while ( 1 ) - { // execute all the operations in the OpStack - // with precedence higher or equal than the last one - Oper1 = Parse_StackOpPop( pStackOp ); // the last operation - if ( Parse_StackOpIsEmpty(pStackOp) ) - { // if it is the only operation, push it back - Parse_StackOpPush( pStackOp, Oper1 ); - break; - } - Oper2 = Parse_StackOpPop( pStackOp ); // the operation before the last one - if ( Oper2 >= Oper1 ) - { // if Oper2 precedence is higher or equal, execute it -// Parse_StackPush( pStackFn, Operation( FunStack.Pop(), FunStack.Pop(), Oper2 ) ); - if ( Parse_ParserPerformTopOp( dd, pStackFn, Oper2 ) == NULL ) - { - fprintf( pOutput, "Parse_FormulaParser(): Unknown operation\n" ); - ABC_FREE( pFormula ); - return NULL; - } - Parse_StackOpPush( pStackOp, Oper1 ); // push the last operation back - } - else - { // if Oper2 precedence is lower, push them back and done - Parse_StackOpPush( pStackOp, Oper2 ); - Parse_StackOpPush( pStackOp, Oper1 ); - break; - } - } - } - - if ( Flag != PARSE_FLAG_ERROR ) - { - if ( !Parse_StackFnIsEmpty(pStackFn) ) - { - bFunc = (DdNode *)Parse_StackFnPop(pStackFn); - if ( Parse_StackFnIsEmpty(pStackFn) ) - if ( Parse_StackOpIsEmpty(pStackOp) ) - { - Parse_StackFnFree(pStackFn); - Parse_StackOpFree(pStackOp); - Cudd_Deref( bFunc ); - ABC_FREE( pFormula ); - return bFunc; - } - else - fprintf( pOutput, "Parse_FormulaParser(): Something is left in the operation stack\n" ); - else - fprintf( pOutput, "Parse_FormulaParser(): Something is left in the function stack\n" ); - } - else - fprintf( pOutput, "Parse_FormulaParser(): The input string is empty\n" ); - } - ABC_FREE( pFormula ); - return NULL; -} - -/**Function************************************************************* - - Synopsis [Performs the operation on the top entries in the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -DdNode * Parse_ParserPerformTopOp( DdManager * dd, Parse_StackFn_t * pStackFn, int Oper ) -{ - DdNode * bArg1, * bArg2, * bFunc; - // perform the given operation - bArg2 = (DdNode *)Parse_StackFnPop( pStackFn ); - bArg1 = (DdNode *)Parse_StackFnPop( pStackFn ); - if ( Oper == PARSE_OPER_AND ) - bFunc = Cudd_bddAnd( dd, bArg1, bArg2 ); - else if ( Oper == PARSE_OPER_XOR ) - bFunc = Cudd_bddXor( dd, bArg1, bArg2 ); - else if ( Oper == PARSE_OPER_OR ) - bFunc = Cudd_bddOr( dd, bArg1, bArg2 ); - else if ( Oper == PARSE_OPER_EQU ) - bFunc = Cudd_bddXnor( dd, bArg1, bArg2 ); - else if ( Oper == PARSE_OPER_FLR ) - bFunc = Cudd_bddOr( dd, Cudd_Not(bArg1), bArg2 ); - else if ( Oper == PARSE_OPER_FLL ) - bFunc = Cudd_bddOr( dd, Cudd_Not(bArg2), bArg1 ); - else - return NULL; - Cudd_Ref( bFunc ); - Cudd_RecursiveDeref( dd, bArg1 ); - Cudd_RecursiveDeref( dd, bArg2 ); - Parse_StackFnPush( pStackFn, bFunc ); - return bFunc; -} - - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// -ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/parse/parseEqn.c b/src/bdd/parse/parseEqn.c deleted file mode 100644 index ac32e528..00000000 --- a/src/bdd/parse/parseEqn.c +++ /dev/null @@ -1,358 +0,0 @@ -/**CFile**************************************************************** - - FileNameIn [parseEqn.c] - - PackageName [ABC: Logic synthesis and verification system.] - - Synopsis [Boolean formula parser.] - - Author [Alan Mishchenko] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - December 18, 2006.] - - Revision [$Id: parseEqn.c,v 1.0 2006/12/18 00:00:00 alanmi Exp $] - -***********************************************************************/ - - -//////////////////////////////////////////////////////////////////////// -/// DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -#include "parseInt.h" -#include "misc/vec/vec.h" -#include "aig/hop/hop.h" - -ABC_NAMESPACE_IMPL_START - - -// the list of operation symbols to be used in expressions -#define PARSE_EQN_SYM_OPEN '(' // opening parenthesis -#define PARSE_EQN_SYM_CLOSE ')' // closing parenthesis -#define PARSE_EQN_SYM_CONST0 '0' // constant 0 -#define PARSE_EQN_SYM_CONST1 '1' // constant 1 -#define PARSE_EQN_SYM_NEG '!' // negation before the variable -#define PARSE_EQN_SYM_AND '*' // logic AND -#define PARSE_EQN_SYM_OR '+' // logic OR - -// the list of opcodes (also specifying operation precedence) -#define PARSE_EQN_OPER_NEG 10 // negation -#define PARSE_EQN_OPER_AND 9 // logic AND -#define PARSE_EQN_OPER_OR 7 // logic OR -#define PARSE_EQN_OPER_MARK 1 // OpStack token standing for an opening parenthesis - -// these are values of the internal Flag -#define PARSE_EQN_FLAG_START 1 // after the opening parenthesis -#define PARSE_EQN_FLAG_VAR 2 // after operation is received -#define PARSE_EQN_FLAG_OPER 3 // after operation symbol is received -#define PARSE_EQN_FLAG_ERROR 4 // when error is detected - -#define PARSE_EQN_STACKSIZE 1000 - -static Hop_Obj_t * Parse_ParserPerformTopOp( Hop_Man_t * pMan, Parse_StackFn_t * pStackFn, int Oper ); - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/**Function************************************************************* - - Synopsis [Derives the AIG corresponding to the equation.] - - Description [Takes the stream to output messages, the formula, the vector - of variable names and the AIG manager.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Hop_Obj_t * Parse_FormulaParserEqn( FILE * pOutput, char * pFormInit, Vec_Ptr_t * vVarNames, Hop_Man_t * pMan ) -{ - char * pFormula; - Parse_StackFn_t * pStackFn; - Parse_StackOp_t * pStackOp; - Hop_Obj_t * gFunc; - char * pTemp, * pName; - int nParans, fFound, Flag; - int Oper, Oper1, Oper2; - int i, v; - - // make sure that the number of opening and closing parentheses is the same - nParans = 0; - for ( pTemp = pFormInit; *pTemp; pTemp++ ) - if ( *pTemp == '(' ) - nParans++; - else if ( *pTemp == ')' ) - nParans--; - if ( nParans != 0 ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): Different number of opening and closing parentheses ().\n" ); - return NULL; - } - - // copy the formula - pFormula = ABC_ALLOC( char, strlen(pFormInit) + 3 ); - sprintf( pFormula, "(%s)", pFormInit ); - - // start the stacks - pStackFn = Parse_StackFnStart( PARSE_EQN_STACKSIZE ); - pStackOp = Parse_StackOpStart( PARSE_EQN_STACKSIZE ); - - Flag = PARSE_EQN_FLAG_START; - for ( pTemp = pFormula; *pTemp; pTemp++ ) - { - switch ( *pTemp ) - { - // skip all spaces, tabs, and end-of-lines - case ' ': - case '\t': - case '\r': - case '\n': - continue; - case PARSE_EQN_SYM_CONST0: - Parse_StackFnPush( pStackFn, Hop_ManConst0(pMan) ); // Cudd_Ref( b0 ); - if ( Flag == PARSE_EQN_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): No operation symbol before constant 0.\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - Flag = PARSE_EQN_FLAG_VAR; - break; - case PARSE_EQN_SYM_CONST1: - Parse_StackFnPush( pStackFn, Hop_ManConst1(pMan) ); // Cudd_Ref( b1 ); - if ( Flag == PARSE_EQN_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): No operation symbol before constant 1.\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - Flag = PARSE_EQN_FLAG_VAR; - break; - case PARSE_EQN_SYM_NEG: - if ( Flag == PARSE_EQN_FLAG_VAR ) - {// if NEGBEF follows a variable, AND is assumed - Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_AND ); - Flag = PARSE_EQN_FLAG_OPER; - } - Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_NEG ); - break; - case PARSE_EQN_SYM_AND: - case PARSE_EQN_SYM_OR: - if ( Flag != PARSE_EQN_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): There is no variable before AND, EXOR, or OR.\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - if ( *pTemp == PARSE_EQN_SYM_AND ) - Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_AND ); - else //if ( *pTemp == PARSE_EQN_SYM_OR ) - Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_OR ); - Flag = PARSE_EQN_FLAG_OPER; - break; - case PARSE_EQN_SYM_OPEN: - if ( Flag == PARSE_EQN_FLAG_VAR ) - { -// Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_AND ); - fprintf( pOutput, "Parse_FormulaParserEqn(): An opening parenthesis follows a var without operation sign.\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - Parse_StackOpPush( pStackOp, PARSE_EQN_OPER_MARK ); - // after an opening bracket, it feels like starting over again - Flag = PARSE_EQN_FLAG_START; - break; - case PARSE_EQN_SYM_CLOSE: - if ( !Parse_StackOpIsEmpty( pStackOp ) ) - { - while ( 1 ) - { - if ( Parse_StackOpIsEmpty( pStackOp ) ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): There is no opening parenthesis\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - Oper = Parse_StackOpPop( pStackOp ); - if ( Oper == PARSE_EQN_OPER_MARK ) - break; - - // perform the given operation - if ( Parse_ParserPerformTopOp( pMan, pStackFn, Oper ) == NULL ) - { - Parse_StackFnFree( pStackFn ); - Parse_StackOpFree( pStackOp ); - fprintf( pOutput, "Parse_FormulaParserEqn(): Unknown operation\n" ); - ABC_FREE( pFormula ); - return NULL; - } - } - } - else - { - fprintf( pOutput, "Parse_FormulaParserEqn(): There is no opening parenthesis\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - if ( Flag != PARSE_EQN_FLAG_ERROR ) - Flag = PARSE_EQN_FLAG_VAR; - break; - - - default: - // scan the next name - for ( i = 0; pTemp[i] && - pTemp[i] != ' ' && pTemp[i] != '\t' && pTemp[i] != '\r' && pTemp[i] != '\n' && - pTemp[i] != PARSE_EQN_SYM_AND && pTemp[i] != PARSE_EQN_SYM_OR && pTemp[i] != PARSE_EQN_SYM_CLOSE; i++ ) - { - if ( pTemp[i] == PARSE_EQN_SYM_NEG || pTemp[i] == PARSE_EQN_SYM_OPEN ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): The negation sign or an opening parenthesis inside the variable name.\n" ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - } - // variable name is found - fFound = 0; - Vec_PtrForEachEntry( char *, vVarNames, pName, v ) - if ( strncmp(pTemp, pName, i) == 0 && strlen(pName) == (unsigned)i ) - { - pTemp += i-1; - fFound = 1; - break; - } - if ( !fFound ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): The parser cannot find var \"%s\" in the input var list.\n", pTemp ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - if ( Flag == PARSE_EQN_FLAG_VAR ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): The variable name \"%s\" follows another var without operation sign.\n", pTemp ); - Flag = PARSE_EQN_FLAG_ERROR; - break; - } - Parse_StackFnPush( pStackFn, Hop_IthVar( pMan, v ) ); // Cudd_Ref( pbVars[v] ); - Flag = PARSE_EQN_FLAG_VAR; - break; - } - - if ( Flag == PARSE_EQN_FLAG_ERROR ) - break; // error exit - else if ( Flag == PARSE_EQN_FLAG_START ) - continue; // go on parsing - else if ( Flag == PARSE_EQN_FLAG_VAR ) - while ( 1 ) - { // check if there are negations in the OpStack - if ( Parse_StackOpIsEmpty(pStackOp) ) - break; - Oper = Parse_StackOpPop( pStackOp ); - if ( Oper != PARSE_EQN_OPER_NEG ) - { - Parse_StackOpPush( pStackOp, Oper ); - break; - } - else - { - Parse_StackFnPush( pStackFn, Hop_Not((Hop_Obj_t *)Parse_StackFnPop(pStackFn)) ); - } - } - else // if ( Flag == PARSE_EQN_FLAG_OPER ) - while ( 1 ) - { // execute all the operations in the OpStack - // with precedence higher or equal than the last one - Oper1 = Parse_StackOpPop( pStackOp ); // the last operation - if ( Parse_StackOpIsEmpty(pStackOp) ) - { // if it is the only operation, push it back - Parse_StackOpPush( pStackOp, Oper1 ); - break; - } - Oper2 = Parse_StackOpPop( pStackOp ); // the operation before the last one - if ( Oper2 >= Oper1 ) - { // if Oper2 precedence is higher or equal, execute it - if ( Parse_ParserPerformTopOp( pMan, pStackFn, Oper2 ) == NULL ) - { - fprintf( pOutput, "Parse_FormulaParserEqn(): Unknown operation\n" ); - ABC_FREE( pFormula ); - Parse_StackFnFree( pStackFn ); - Parse_StackOpFree( pStackOp ); - return NULL; - } - Parse_StackOpPush( pStackOp, Oper1 ); // push the last operation back - } - else - { // if Oper2 precedence is lower, push them back and done - Parse_StackOpPush( pStackOp, Oper2 ); - Parse_StackOpPush( pStackOp, Oper1 ); - break; - } - } - } - - if ( Flag != PARSE_EQN_FLAG_ERROR ) - { - if ( !Parse_StackFnIsEmpty(pStackFn) ) - { - gFunc = (Hop_Obj_t *)Parse_StackFnPop(pStackFn); - if ( Parse_StackFnIsEmpty(pStackFn) ) - if ( Parse_StackOpIsEmpty(pStackOp) ) - { - Parse_StackFnFree(pStackFn); - Parse_StackOpFree(pStackOp); -// Cudd_Deref( gFunc ); - ABC_FREE( pFormula ); - return gFunc; - } - else - fprintf( pOutput, "Parse_FormulaParserEqn(): Something is left in the operation stack\n" ); - else - fprintf( pOutput, "Parse_FormulaParserEqn(): Something is left in the function stack\n" ); - } - else - fprintf( pOutput, "Parse_FormulaParserEqn(): The input string is empty\n" ); - } - ABC_FREE( pFormula ); - return NULL; -} - -/**Function************************************************************* - - Synopsis [Performs the operation on the top entries in the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Hop_Obj_t * Parse_ParserPerformTopOp( Hop_Man_t * pMan, Parse_StackFn_t * pStackFn, int Oper ) -{ - Hop_Obj_t * gArg1, * gArg2, * gFunc; - // perform the given operation - gArg2 = (Hop_Obj_t *)Parse_StackFnPop( pStackFn ); - gArg1 = (Hop_Obj_t *)Parse_StackFnPop( pStackFn ); - if ( Oper == PARSE_EQN_OPER_AND ) - gFunc = Hop_And( pMan, gArg1, gArg2 ); - else if ( Oper == PARSE_EQN_OPER_OR ) - gFunc = Hop_Or( pMan, gArg1, gArg2 ); - else - return NULL; -// Cudd_Ref( gFunc ); -// Cudd_RecursiveDeref( dd, gArg1 ); -// Cudd_RecursiveDeref( dd, gArg2 ); - Parse_StackFnPush( pStackFn, gFunc ); - return gFunc; -} - - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// -ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/parse/parseInt.h b/src/bdd/parse/parseInt.h deleted file mode 100644 index 80ed945a..00000000 --- a/src/bdd/parse/parseInt.h +++ /dev/null @@ -1,79 +0,0 @@ -/**CFile**************************************************************** - - FileName [parseInt.h] - - PackageName [MVSIS 2.0: Multi-valued logic synthesis system.] - - Synopsis [Parsing symbolic Boolean formulas into BDDs.] - - Author [MVSIS Group] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - September 8, 2003.] - - Revision [$Id: parseInt.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#ifndef ABC__bdd__parse__parseInt_h -#define ABC__bdd__parse__parseInt_h - - -//////////////////////////////////////////////////////////////////////// -/// INCLUDES /// -//////////////////////////////////////////////////////////////////////// - - -#include -#include "misc/extra/extraBdd.h" -#include "parse.h" - -ABC_NAMESPACE_HEADER_START - - -//////////////////////////////////////////////////////////////////////// -/// PARAMETERS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// STRUCTURE DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -typedef struct ParseStackFnStruct Parse_StackFn_t; // the function stack -typedef struct ParseStackOpStruct Parse_StackOp_t; // the operation stack - -//////////////////////////////////////////////////////////////////////// -/// GLOBAL VARIABLES /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// MACRO DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/*=== parseStack.c =============================================================*/ -extern Parse_StackFn_t * Parse_StackFnStart ( int nDepth ); -extern int Parse_StackFnIsEmpty( Parse_StackFn_t * p ); -extern void Parse_StackFnPush ( Parse_StackFn_t * p, void * bFunc ); -extern void * Parse_StackFnPop ( Parse_StackFn_t * p ); -extern void Parse_StackFnFree ( Parse_StackFn_t * p ); - -extern Parse_StackOp_t * Parse_StackOpStart ( int nDepth ); -extern int Parse_StackOpIsEmpty( Parse_StackOp_t * p ); -extern void Parse_StackOpPush ( Parse_StackOp_t * p, int Oper ); -extern int Parse_StackOpPop ( Parse_StackOp_t * p ); -extern void Parse_StackOpFree ( Parse_StackOp_t * p ); - - - -ABC_NAMESPACE_HEADER_END - -#endif - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// diff --git a/src/bdd/parse/parseStack.c b/src/bdd/parse/parseStack.c deleted file mode 100644 index 2e6d266d..00000000 --- a/src/bdd/parse/parseStack.c +++ /dev/null @@ -1,248 +0,0 @@ -/**CFile**************************************************************** - - FileName [parseStack.c] - - PackageName [MVSIS 1.3: Multi-valued logic synthesis system.] - - Synopsis [Stacks used by the formula parser.] - - Author [MVSIS Group] - - Affiliation [UC Berkeley] - - Date [Ver. 1.0. Started - August 18, 2003.] - - Revision [$Id: parseStack.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $] - -***********************************************************************/ - -#include "parseInt.h" - -ABC_NAMESPACE_IMPL_START - - -//////////////////////////////////////////////////////////////////////// -/// DECLARATIONS /// -//////////////////////////////////////////////////////////////////////// - -struct ParseStackFnStruct -{ - void ** pData; // the array of elements - int Top; // the index - int Size; // the stack size -}; - -struct ParseStackOpStruct -{ - int * pData; // the array of elements - int Top; // the index - int Size; // the stack size -}; - -//////////////////////////////////////////////////////////////////////// -/// FUNCTION DEFINITIONS /// -//////////////////////////////////////////////////////////////////////// - -/**Function************************************************************* - - Synopsis [Starts the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Parse_StackFn_t * Parse_StackFnStart( int nDepth ) -{ - Parse_StackFn_t * p; - p = ABC_ALLOC( Parse_StackFn_t, 1 ); - memset( p, 0, sizeof(Parse_StackFn_t) ); - p->pData = ABC_ALLOC( void *, nDepth ); - p->Size = nDepth; - return p; -} - -/**Function************************************************************* - - Synopsis [Checks whether the stack is empty.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int Parse_StackFnIsEmpty( Parse_StackFn_t * p ) -{ - return (int)(p->Top == 0); -} - -/**Function************************************************************* - - Synopsis [Pushes an entry into the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Parse_StackFnPush( Parse_StackFn_t * p, void * bFunc ) -{ - if ( p->Top >= p->Size ) - { - printf( "Parse_StackFnPush(): Stack size is too small!\n" ); - return; - } - p->pData[ p->Top++ ] = bFunc; -} - -/**Function************************************************************* - - Synopsis [Pops an entry out of the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void * Parse_StackFnPop( Parse_StackFn_t * p ) -{ - if ( p->Top == 0 ) - { - printf( "Parse_StackFnPush(): Trying to extract data from the empty stack!\n" ); - return NULL; - } - return p->pData[ --p->Top ]; -} - -/**Function************************************************************* - - Synopsis [Deletes the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Parse_StackFnFree( Parse_StackFn_t * p ) -{ - ABC_FREE( p->pData ); - ABC_FREE( p ); -} - - - - -/**Function************************************************************* - - Synopsis [Starts the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Parse_StackOp_t * Parse_StackOpStart( int nDepth ) -{ - Parse_StackOp_t * p; - p = ABC_ALLOC( Parse_StackOp_t, 1 ); - memset( p, 0, sizeof(Parse_StackOp_t) ); - p->pData = ABC_ALLOC( int, nDepth ); - p->Size = nDepth; - return p; -} - -/**Function************************************************************* - - Synopsis [Checks whether the stack is empty.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int Parse_StackOpIsEmpty( Parse_StackOp_t * p ) -{ - return (int)(p->Top == 0); -} - -/**Function************************************************************* - - Synopsis [Pushes an entry into the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Parse_StackOpPush( Parse_StackOp_t * p, int Oper ) -{ - if ( p->Top >= p->Size ) - { - printf( "Parse_StackOpPush(): Stack size is too small!\n" ); - return; - } - p->pData[ p->Top++ ] = Oper; -} - -/**Function************************************************************* - - Synopsis [Pops an entry out of the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int Parse_StackOpPop( Parse_StackOp_t * p ) -{ - if ( p->Top == 0 ) - { - printf( "Parse_StackOpPush(): Trying to extract data from the empty stack!\n" ); - return -1; - } - return p->pData[ --p->Top ]; -} - -/**Function************************************************************* - - Synopsis [Deletes the stack.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Parse_StackOpFree( Parse_StackOp_t * p ) -{ - ABC_FREE( p->pData ); - ABC_FREE( p ); -} - - -//////////////////////////////////////////////////////////////////////// -/// END OF FILE /// -//////////////////////////////////////////////////////////////////////// - - -ABC_NAMESPACE_IMPL_END - -- cgit v1.2.3