summaryrefslogtreecommitdiffstats
path: root/src/bdd
diff options
context:
space:
mode:
authorAlan Mishchenko <alanmi@berkeley.edu>2015-08-24 21:09:50 -0700
committerAlan Mishchenko <alanmi@berkeley.edu>2015-08-24 21:09:50 -0700
commit24f2a120f2203acc8038ccce4e8dd141564a7a04 (patch)
treed8c0d0efa6c2dc1ef656624f807ba3f4f6db8b9d /src/bdd
parenteb699bbaf80e4a6a0e85f87d7575ca1ffebef37f (diff)
downloadabc-24f2a120f2203acc8038ccce4e8dd141564a7a04.tar.gz
abc-24f2a120f2203acc8038ccce4e8dd141564a7a04.tar.bz2
abc-24f2a120f2203acc8038ccce4e8dd141564a7a04.zip
Changes to be able to compile ABC without CUDD.
Diffstat (limited to 'src/bdd')
-rw-r--r--src/bdd/bbr/bbr.h93
-rw-r--r--src/bdd/bbr/bbrCex.c172
-rw-r--r--src/bdd/bbr/bbrImage.c1327
-rw-r--r--src/bdd/bbr/bbrNtbdd.c218
-rw-r--r--src/bdd/bbr/bbrReach.c615
-rw-r--r--src/bdd/bbr/bbr_.c52
-rw-r--r--src/bdd/bbr/module.make4
-rw-r--r--src/bdd/extrab/extraBdd.h317
-rw-r--r--src/bdd/extrab/extraBddAuto.c1563
-rw-r--r--src/bdd/extrab/extraBddCas.c1235
-rw-r--r--src/bdd/extrab/extraBddImage.c1162
-rw-r--r--src/bdd/extrab/extraBddKmap.c876
-rw-r--r--src/bdd/extrab/extraBddMisc.c2342
-rw-r--r--src/bdd/extrab/extraBddSymm.c1474
-rw-r--r--src/bdd/extrab/extraBddTime.c660
-rw-r--r--src/bdd/extrab/extraBddUnate.c646
-rw-r--r--src/bdd/extrab/module.make8
-rw-r--r--src/bdd/llb/llb.c52
-rw-r--r--src/bdd/llb/llb.h96
-rw-r--r--src/bdd/llb/llb1Cluster.c356
-rw-r--r--src/bdd/llb/llb1Constr.c313
-rw-r--r--src/bdd/llb/llb1Core.c222
-rw-r--r--src/bdd/llb/llb1Group.c474
-rw-r--r--src/bdd/llb/llb1Hint.c226
-rw-r--r--src/bdd/llb/llb1Man.c218
-rw-r--r--src/bdd/llb/llb1Matrix.c430
-rw-r--r--src/bdd/llb/llb1Pivot.c254
-rw-r--r--src/bdd/llb/llb1Reach.c904
-rw-r--r--src/bdd/llb/llb1Sched.c257
-rw-r--r--src/bdd/llb/llb2Bad.c138
-rw-r--r--src/bdd/llb/llb2Core.c777
-rw-r--r--src/bdd/llb/llb2Driver.c222
-rw-r--r--src/bdd/llb/llb2Dump.c104
-rw-r--r--src/bdd/llb/llb2Flow.c1376
-rw-r--r--src/bdd/llb/llb2Image.c482
-rw-r--r--src/bdd/llb/llb3Image.c1095
-rw-r--r--src/bdd/llb/llb3Nonlin.c872
-rw-r--r--src/bdd/llb/llb4Cex.c320
-rw-r--r--src/bdd/llb/llb4Cluster.c452
-rw-r--r--src/bdd/llb/llb4Image.c863
-rw-r--r--src/bdd/llb/llb4Map.c123
-rw-r--r--src/bdd/llb/llb4Nonlin.c1185
-rw-r--r--src/bdd/llb/llb4Sweep.c589
-rw-r--r--src/bdd/llb/llbInt.h212
-rw-r--r--src/bdd/llb/module.make22
-rw-r--r--src/bdd/parse/module.make3
-rw-r--r--src/bdd/parse/parse.h62
-rw-r--r--src/bdd/parse/parseCore.c536
-rw-r--r--src/bdd/parse/parseEqn.c358
-rw-r--r--src/bdd/parse/parseInt.h79
-rw-r--r--src/bdd/parse/parseStack.c248
51 files changed, 25398 insertions, 1286 deletions
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 <stdio.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#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<<s_MultiStart) );
+ if ( nMints > 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<<s_MultiStart) );
+ }
+ else
+ {
+ DdNode * bFunc0, * bFunc1;
+ DdNode * bVarsCof0, * bVarsCof1;
+ DdNode * bVarsCofR = Cudd_Regular(bVarsCof);
+ unsigned Res;
+
+ // get the levels
+ int LevelF = dd->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 <windows.h>
+#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<<nVarsVer);
+ nCellsHor = (1<<nVarsHor);
+ nSkipSpaces = nVarsVer + 1;
+
+ ////////////////////////////////////////////////////////////////////
+ // print variable names
+ fprintf( Output, "\n" );
+ for ( w = 0; w < nVarsVer; w++ )
+ if ( pVarNames == NULL )
+ fprintf( Output, "%c", 'a'+nVarsHor+w );
+ else
+ fprintf( Output, " %s", pVarNames[nVarsHor+w] );
+
+ if ( fHorizontalVarNamesPrintedAbove )
+ {
+ fprintf( Output, " \\ " );
+ for ( w = 0; w < nVarsHor; w++ )
+ if ( pVarNames == NULL )
+ fprintf( Output, "%c", 'a'+w );
+ else
+ fprintf( Output, "%s ", pVarNames[w] );
+ }
+ fprintf( Output, "\n" );
+
+ if ( fHorizontalVarNamesPrintedAbove )
+ {
+ ////////////////////////////////////////////////////////////////////
+ // print horizontal digits
+ for ( d = 0; d < nVarsHor; d++ )
+ {
+ for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nCellsHor; n++ )
+ if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
+ fprintf( Output, "1 " );
+ else
+ fprintf( Output, "0 " );
+ fprintf( Output, "\n" );
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // print the upper line
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ fprintf( Output, "%c", DOUBLE_TOP_LEFT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", D_JOINS_D_HOR_BOT );
+ else
+ fprintf( Output, "%c", S_JOINS_D_HOR_BOT );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_TOP_RIGHT );
+ fprintf( Output, "\n" );
+
+ ////////////////////////////////////////////////////////////////////
+ // print the map
+ for ( v = 0; v < nCellsVer; v++ )
+ {
+ DdNode * CubeVerBDD;
+
+ // print horizontal digits
+// for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nVarsVer; n++ )
+ if ( GrayCode(v) & (1<<(nVarsVer-1-n)) )
+ fprintf( Output, "1" );
+ else
+ fprintf( Output, "0" );
+ fprintf( Output, " " );
+
+ // find vertical cube
+ CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nVarsVer, s_XVars+nVarsHor, 1 ); Cudd_Ref( CubeVerBDD );
+
+ // print text line
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ for ( h = 0; h < nCellsHor; h++ )
+ {
+ DdNode * CubeHorBDD, * Prod, * ValueOnSet, * ValueOffSet;
+
+ fprintf( Output, " " );
+// fprintf( Output, "x" );
+ ///////////////////////////////////////////////////////////////
+ // determine what should be printed
+ CubeHorBDD = Extra_bddBitsToCube( dd, GrayCode(h), nVarsHor, s_XVars, 1 ); Cudd_Ref( CubeHorBDD );
+ Prod = Cudd_bddAnd( dd, CubeHorBDD, CubeVerBDD ); Cudd_Ref( Prod );
+ Cudd_RecursiveDeref( dd, CubeHorBDD );
+
+ ValueOnSet = Cudd_Cofactor( dd, OnSet, Prod ); Cudd_Ref( ValueOnSet );
+ ValueOffSet = Cudd_Cofactor( dd, OffSet, Prod ); Cudd_Ref( ValueOffSet );
+ Cudd_RecursiveDeref( dd, Prod );
+
+#ifdef WIN32
+ {
+ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ char Symb = 0, Color = 0;
+ if ( ValueOnSet == b1 && ValueOffSet == b0 )
+ Symb = SYMBOL_ONE, Color = 14; // yellow
+ else if ( ValueOnSet == b0 && ValueOffSet == b1 )
+ Symb = SYMBOL_ZERO, Color = 11; // blue
+ else if ( ValueOnSet == b0 && ValueOffSet == b0 )
+ Symb = SYMBOL_DC, Color = 10; // green
+ else if ( ValueOnSet == b1 && ValueOffSet == b1 )
+ Symb = SYMBOL_OVERLAP, Color = 12; // red
+ else
+ assert(0);
+ SetConsoleTextAttribute( hConsole, Color );
+ fprintf( Output, "%c", Symb );
+ SetConsoleTextAttribute( hConsole, 7 );
+ }
+#else
+ {
+ if ( ValueOnSet == b1 && ValueOffSet == b0 )
+ fprintf( Output, "%c", SYMBOL_ONE );
+ else if ( ValueOnSet == b0 && ValueOffSet == b1 )
+ fprintf( Output, "%c", SYMBOL_ZERO );
+ else if ( ValueOnSet == b0 && ValueOffSet == b0 )
+ fprintf( Output, "%c", SYMBOL_DC );
+ else if ( ValueOnSet == b1 && ValueOffSet == b1 )
+ fprintf( Output, "%c", SYMBOL_OVERLAP );
+ else
+ assert(0);
+ }
+#endif
+
+ Cudd_RecursiveDeref( dd, ValueOnSet );
+ Cudd_RecursiveDeref( dd, ValueOffSet );
+ ///////////////////////////////////////////////////////////////
+ fprintf( Output, " " );
+
+ if ( h != nCellsHor-1 )
+ {
+ if ( h&1 )
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ else
+ fprintf( Output, "%c", SINGLE_VERTICAL );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ fprintf( Output, "\n" );
+
+ Cudd_RecursiveDeref( dd, CubeVerBDD );
+
+ if ( v != nCellsVer-1 )
+ // print separator line
+ {
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ if ( v&1 )
+ {
+ fprintf( Output, "%c", D_JOINS_D_VER_RIGHT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", DOUBLES_CROSS );
+ else
+ fprintf( Output, "%c", S_VER_CROSS_D_HOR );
+ }
+ }
+ fprintf( Output, "%c", D_JOINS_D_VER_LEFT );
+ }
+ else
+ {
+ fprintf( Output, "%c", S_JOINS_D_VER_RIGHT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", S_HOR_CROSS_D_VER );
+ else
+ fprintf( Output, "%c", SINGLES_CROSS );
+ }
+ }
+ fprintf( Output, "%c", S_JOINS_D_VER_LEFT );
+ }
+ fprintf( Output, "\n" );
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // print the lower line
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ fprintf( Output, "%c", DOUBLE_BOT_LEFT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", D_JOINS_D_HOR_TOP );
+ else
+ fprintf( Output, "%c", S_JOINS_D_HOR_TOP );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_BOT_RIGHT );
+ fprintf( Output, "\n" );
+
+ if ( !fHorizontalVarNamesPrintedAbove )
+ {
+ ////////////////////////////////////////////////////////////////////
+ // print horizontal digits
+ for ( d = 0; d < nVarsHor; d++ )
+ {
+ for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nCellsHor; n++ )
+ if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
+ fprintf( Output, "1 " );
+ else
+ fprintf( Output, "0 " );
+
+ /////////////////////////////////
+ fprintf( Output, "%c", (char)('a'+d) );
+ /////////////////////////////////
+ fprintf( Output, "\n" );
+ }
+ }
+}
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints the K-map of the relation.]
+
+ Description [Assumes that the relation depends the first nXVars of XVars and
+ the first nYVars of YVars. Draws X and Y vars and vertical and horizontal vars.]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Extra_PrintKMapRelation(
+ FILE * Output, /* the output stream */
+ DdManager * dd,
+ DdNode * OnSet,
+ DdNode * OffSet,
+ int nXVars,
+ int nYVars,
+ DdNode ** XVars,
+ DdNode ** YVars ) /* the flag which determines how support is computed */
+{
+ int d, p, n, s, v, h, w;
+ int nVars;
+ 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 ( OnSet == b1 )
+ {
+ fprintf( Output, "PrintKMap(): Constant 1\n" );
+ return;
+ }
+ if ( OffSet == b1 )
+ {
+ fprintf( Output, "PrintKMap(): Constant 0\n" );
+ return;
+ }
+
+ nVars = nXVars + nYVars;
+ 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 Karnaugh map parameters
+ nVarsVer = nXVars;
+ nVarsHor = nYVars;
+ nCellsVer = (1<<nVarsVer);
+ nCellsHor = (1<<nVarsHor);
+ nSkipSpaces = nVarsVer + 1;
+
+ ////////////////////////////////////////////////////////////////////
+ // print variable names
+ fprintf( Output, "\n" );
+ for ( w = 0; w < nVarsVer; w++ )
+ fprintf( Output, "%c", 'a'+nVarsHor+w );
+ if ( fHorizontalVarNamesPrintedAbove )
+ {
+ fprintf( Output, " \\ " );
+ for ( w = 0; w < nVarsHor; w++ )
+ fprintf( Output, "%c", 'a'+w );
+ }
+ fprintf( Output, "\n" );
+
+ if ( fHorizontalVarNamesPrintedAbove )
+ {
+ ////////////////////////////////////////////////////////////////////
+ // print horizontal digits
+ for ( d = 0; d < nVarsHor; d++ )
+ {
+ for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nCellsHor; n++ )
+ if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
+ fprintf( Output, "1 " );
+ else
+ fprintf( Output, "0 " );
+ fprintf( Output, "\n" );
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // print the upper line
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ fprintf( Output, "%c", DOUBLE_TOP_LEFT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", D_JOINS_D_HOR_BOT );
+ else
+ fprintf( Output, "%c", S_JOINS_D_HOR_BOT );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_TOP_RIGHT );
+ fprintf( Output, "\n" );
+
+ ////////////////////////////////////////////////////////////////////
+ // print the map
+ for ( v = 0; v < nCellsVer; v++ )
+ {
+ DdNode * CubeVerBDD;
+
+ // print horizontal digits
+// for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nVarsVer; n++ )
+ if ( GrayCode(v) & (1<<(nVarsVer-1-n)) )
+ fprintf( Output, "1" );
+ else
+ fprintf( Output, "0" );
+ fprintf( Output, " " );
+
+ // find vertical cube
+// CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nVarsVer, s_XVars+nVarsHor ); Cudd_Ref( CubeVerBDD );
+ CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nXVars, XVars, 1 ); Cudd_Ref( CubeVerBDD );
+
+ // print text line
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ for ( h = 0; h < nCellsHor; h++ )
+ {
+ DdNode * CubeHorBDD, * Prod, * ValueOnSet, * ValueOffSet;
+
+ fprintf( Output, " " );
+// fprintf( Output, "x" );
+ ///////////////////////////////////////////////////////////////
+ // determine what should be printed
+// CubeHorBDD = Extra_bddBitsToCube( dd, GrayCode(h), nVarsHor, s_XVars ); Cudd_Ref( CubeHorBDD );
+ CubeHorBDD = Extra_bddBitsToCube( dd, GrayCode(h), nYVars, YVars, 1 ); Cudd_Ref( CubeHorBDD );
+ Prod = Cudd_bddAnd( dd, CubeHorBDD, CubeVerBDD ); Cudd_Ref( Prod );
+ Cudd_RecursiveDeref( dd, CubeHorBDD );
+
+ ValueOnSet = Cudd_Cofactor( dd, OnSet, Prod ); Cudd_Ref( ValueOnSet );
+ ValueOffSet = Cudd_Cofactor( dd, OffSet, Prod ); Cudd_Ref( ValueOffSet );
+ Cudd_RecursiveDeref( dd, Prod );
+
+ if ( ValueOnSet == b1 && ValueOffSet == b0 )
+ fprintf( Output, "%c", SYMBOL_ONE );
+ else if ( ValueOnSet == b0 && ValueOffSet == b1 )
+ fprintf( Output, "%c", SYMBOL_ZERO );
+ else if ( ValueOnSet == b0 && ValueOffSet == b0 )
+ fprintf( Output, "%c", SYMBOL_DC );
+ else if ( ValueOnSet == b1 && ValueOffSet == b1 )
+ fprintf( Output, "%c", SYMBOL_OVERLAP );
+ else
+ assert(0);
+
+ Cudd_RecursiveDeref( dd, ValueOnSet );
+ Cudd_RecursiveDeref( dd, ValueOffSet );
+ ///////////////////////////////////////////////////////////////
+ fprintf( Output, " " );
+
+ if ( h != nCellsHor-1 )
+ {
+ if ( h&1 )
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ else
+ fprintf( Output, "%c", SINGLE_VERTICAL );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_VERTICAL );
+ fprintf( Output, "\n" );
+
+ Cudd_RecursiveDeref( dd, CubeVerBDD );
+
+ if ( v != nCellsVer-1 )
+ // print separator line
+ {
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ if ( v&1 )
+ {
+ fprintf( Output, "%c", D_JOINS_D_VER_RIGHT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", DOUBLES_CROSS );
+ else
+ fprintf( Output, "%c", S_VER_CROSS_D_HOR );
+ }
+ }
+ fprintf( Output, "%c", D_JOINS_D_VER_LEFT );
+ }
+ else
+ {
+ fprintf( Output, "%c", S_JOINS_D_VER_RIGHT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ fprintf( Output, "%c", SINGLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", S_HOR_CROSS_D_VER );
+ else
+ fprintf( Output, "%c", SINGLES_CROSS );
+ }
+ }
+ fprintf( Output, "%c", S_JOINS_D_VER_LEFT );
+ }
+ fprintf( Output, "\n" );
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // print the lower line
+ for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
+ fprintf( Output, "%c", DOUBLE_BOT_LEFT );
+ for ( s = 0; s < nCellsHor; s++ )
+ {
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ fprintf( Output, "%c", DOUBLE_HORIZONTAL );
+ if ( s != nCellsHor-1 )
+ {
+ if ( s&1 )
+ fprintf( Output, "%c", D_JOINS_D_HOR_TOP );
+ else
+ fprintf( Output, "%c", S_JOINS_D_HOR_TOP );
+ }
+ }
+ fprintf( Output, "%c", DOUBLE_BOT_RIGHT );
+ fprintf( Output, "\n" );
+
+ if ( !fHorizontalVarNamesPrintedAbove )
+ {
+ ////////////////////////////////////////////////////////////////////
+ // print horizontal digits
+ for ( d = 0; d < nVarsHor; d++ )
+ {
+ for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
+ for ( n = 0; n < nCellsHor; n++ )
+ if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
+ fprintf( Output, "1 " );
+ else
+ fprintf( Output, "0 " );
+
+ /////////////////////////////////
+ fprintf( Output, "%c", (char)('a'+d) );
+ /////////////////////////////////
+ fprintf( Output, "\n" );
+ }
+ }
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+int GrayCode ( int BinCode )
+{
+ return BinCode ^ ( BinCode >> 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.<p>
+ 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 <n>;
+ * reate the first argument, which stands for <k>
+ * as when we are talking about the tuple of <k> out of <n> */
+ 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 <stdio.h>
+#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 <stdio.h>
-#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
-