summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Mishchenko <alanmi@berkeley.edu>2011-02-04 20:22:10 -0800
committerAlan Mishchenko <alanmi@berkeley.edu>2011-02-04 20:22:10 -0800
commit3e92b873622ce7ca7baf74520abc28cc7c68dded (patch)
tree44db42075cc0ff05d7b92d00c926aace7ec00816 /src
parent82e9de90005ee38fdc9fa4c52d335d4e87c93196 (diff)
downloadabc-3e92b873622ce7ca7baf74520abc28cc7c68dded.tar.gz
abc-3e92b873622ce7ca7baf74520abc28cc7c68dded.tar.bz2
abc-3e92b873622ce7ca7baf74520abc28cc7c68dded.zip
Added timeout to &reachn.
Diffstat (limited to 'src')
-rw-r--r--src/aig/llb/llb2Bad.c12
-rw-r--r--src/aig/llb/llb2Core.c22
-rw-r--r--src/aig/llb/llb3Image.c26
-rw-r--r--src/aig/llb/llb3Nonlin.c65
-rw-r--r--src/aig/llb/llb3Nonlin_multi.c1490
-rw-r--r--src/aig/llb/llbInt.h4
6 files changed, 114 insertions, 1505 deletions
diff --git a/src/aig/llb/llb2Bad.c b/src/aig/llb/llb2Bad.c
index 8322698b..4099805b 100644
--- a/src/aig/llb/llb2Bad.c
+++ b/src/aig/llb/llb2Bad.c
@@ -42,12 +42,12 @@ ABC_NAMESPACE_IMPL_START
SeeAlso []
***********************************************************************/
-DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd )
+DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd, int TimeOut )
{
Vec_Ptr_t * vNodes;
DdNode * bBdd0, * bBdd1, * bTemp, * bResult;
Aig_Obj_t * pObj;
- int i;
+ int i, k;
assert( Cudd_ReadSize(dd) == Aig_ManPiNum(pInit) );
// initialize elementary variables
Aig_ManConst1(pInit)->pData = Cudd_ReadOne( dd );
@@ -64,6 +64,14 @@ DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd )
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 );
+
+ if ( i % 10 == 0 && TimeOut && clock() >= TimeOut )
+ {
+ Vec_PtrForEachEntryStop( Aig_Obj_t *, vNodes, pObj, k, i+1 )
+ Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData );
+ Vec_PtrFree( vNodes );
+ return NULL;
+ }
}
// quantify PIs of each PO
bResult = Cudd_ReadLogicZero( dd ); Cudd_Ref( bResult );
diff --git a/src/aig/llb/llb2Core.c b/src/aig/llb/llb2Core.c
index e440438f..45add7e9 100644
--- a/src/aig/llb/llb2Core.c
+++ b/src/aig/llb/llb2Core.c
@@ -217,10 +217,17 @@ int Llb_CoreReachability_int( Llb_Img_t * p, Vec_Ptr_t * vQuant0, Vec_Ptr_t * vQ
// compute initial states
if ( p->pPars->fBackward )
{
+ // create init state in the global manager
+ bTemp = Llb_BddComputeBad( p->pInit, p->ddR, p->pPars->TimeLimit );
+ if ( bTemp == NULL )
+ {
+ if ( !p->pPars->fSilent )
+ printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit );
+ 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 );
- // create init state in the global manager
- bTemp = Llb_BddComputeBad( p->pInit, p->ddR ); Cudd_Ref( bTemp );
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 );
@@ -231,7 +238,16 @@ int Llb_CoreReachability_int( Llb_Img_t * p, Vec_Ptr_t * vQuant0, Vec_Ptr_t * vQ
else
{
// create bad state in the ring manager
- p->ddR->bFunc = Llb_BddComputeBad( p->pInit, p->ddR ); Cudd_Ref( p->ddR->bFunc );
+ p->ddR->bFunc = Llb_BddComputeBad( p->pInit, p->ddR, p->pPars->TimeLimit );
+ if ( p->ddR->bFunc == NULL )
+ {
+ if ( !p->pPars->fSilent )
+ printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit );
+ return -1;
+ }
+ if ( p->ddR->bFunc == NULL )
+ 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 );
diff --git a/src/aig/llb/llb3Image.c b/src/aig/llb/llb3Image.c
index 1866a87c..87e09c46 100644
--- a/src/aig/llb/llb3Image.c
+++ b/src/aig/llb/llb3Image.c
@@ -524,7 +524,7 @@ Vec_Ptr_t * Llb_NonlinCutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * v
SeeAlso []
***********************************************************************/
-Vec_Ptr_t * Llb_NonlinBuildBdds( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, DdManager * dd )
+Vec_Ptr_t * Llb_NonlinBuildBdds( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, DdManager * dd, int TimeOut )
{
Vec_Ptr_t * vNodes, * vResult;
Aig_Obj_t * pObj;
@@ -541,6 +541,15 @@ Vec_Ptr_t * Llb_NonlinBuildBdds( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t *
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 );
+
+ if ( i % 10 == 0 && TimeOut && clock() >= TimeOut )
+ {
+ Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
+ if ( pObj->pData )
+ Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData );
+ Vec_PtrFree( vNodes );
+ return NULL;
+ }
}
vResult = Vec_PtrAlloc( 100 );
@@ -600,14 +609,16 @@ void Llb_NonlinAddPair( Llb_Mgr_t * p, DdNode * bFunc, int iPart, int iVar )
SeeAlso []
***********************************************************************/
-void Llb_NonlinStart( Llb_Mgr_t * p )
+int Llb_NonlinStart( Llb_Mgr_t * p, int TimeOut )
{
Vec_Ptr_t * vRootBdds;
Llb_Prt_t * pPart;
DdNode * bFunc;
int i, k, nSuppSize;
// create and collect BDDs
- vRootBdds = Llb_NonlinBuildBdds( p->pAig, p->vLeaves, p->vRoots, p->dd ); // come referenced
+ vRootBdds = Llb_NonlinBuildBdds( p->pAig, p->vLeaves, p->vRoots, p->dd, TimeOut ); // come referenced
+ if ( vRootBdds == NULL )
+ return 0;
Vec_PtrPush( vRootBdds, p->bCurrent );
// add pairs (refs are consumed inside)
Vec_PtrForEachEntry( DdNode *, vRootBdds, bFunc, i )
@@ -634,6 +645,7 @@ void Llb_NonlinStart( Llb_Mgr_t * p )
Llb_MgrForEachPart( p, pPart, i )
if ( Llb_NonlinHasSingletonVars(p, pPart) )
Llb_NonlinQuantify1( p, pPart, 0 );
+ return 1;
}
/**Function*************************************************************
@@ -844,7 +856,7 @@ void Llb_NonlinFree( Llb_Mgr_t * p )
***********************************************************************/
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, int Limit )
+ DdManager * dd, DdNode * bCurrent, int fReorder, int fVerbose, int * pOrder, int Limit, int TimeOut )
{
Llb_Prt_t * pPart, * pPart1, * pPart2;
Llb_Mgr_t * p;
@@ -854,7 +866,11 @@ DdNode * Llb_NonlinImage( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRo
// start the manager
clk2 = clock();
p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd, bCurrent );
- Llb_NonlinStart( p );
+ if ( !Llb_NonlinStart( p, TimeOut ) )
+ {
+ Llb_NonlinFree( p );
+ return NULL;
+ }
timeBuild += clock() - clk2;
timeInside = clock() - clk2;
// compute scores
diff --git a/src/aig/llb/llb3Nonlin.c b/src/aig/llb/llb3Nonlin.c
index c22f5a0c..59304768 100644
--- a/src/aig/llb/llb3Nonlin.c
+++ b/src/aig/llb/llb3Nonlin.c
@@ -294,7 +294,7 @@ Abc_Cex_t * Llb_NonlinDeriveCex( Llb_Mnn_t * p )
//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, p->pOrder, ABC_INFINITY ); // consumed reference
+ p->pPars->fReorder, p->pPars->fVeryVerbose, p->pOrder, ABC_INFINITY, ABC_INFINITY ); // consumed reference
assert( bImage != NULL );
Cudd_Ref( bImage );
//Extra_bddPrintSupport( p->dd, bImage ); printf( "\n" );
@@ -340,6 +340,44 @@ Abc_Cex_t * Llb_NonlinDeriveCex( Llb_Mnn_t * p )
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.]
@@ -364,8 +402,20 @@ int Llb_NonlinReachability( Llb_Mnn_t * p )
else
p->pPars->TimeTarget = 0;
+ // 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 ); Cudd_Ref( p->ddR->bFunc );
+ 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 );
+ return -1;
+ }
+ Cudd_Ref( p->ddR->bFunc );
// compute the starting set of states
bCurrent = Llb_NonlinComputeInitState( p->pAig, p->dd ); Cudd_Ref( bCurrent );
p->ddG->bFunc = Llb_NonlinComputeInitState( p->pAig, p->ddG ); Cudd_Ref( p->ddG->bFunc ); // reached
@@ -429,8 +479,16 @@ int Llb_NonlinReachability( Llb_Mnn_t * p )
nBddSize0 = Cudd_DagSize( bCurrent );
bNext = Llb_NonlinImage( p->pAig, p->vLeaves, p->vRoots, p->pVars2Q, p->dd, bCurrent,
// p->pPars->fReorder, p->pPars->fVeryVerbose, p->pOrder, nIters ? p->pPars->nBddMax : ABC_INFINITY );
- p->pPars->fReorder, p->pPars->fVeryVerbose, p->pOrder, ABC_INFINITY );
+ p->pPars->fReorder, p->pPars->fVeryVerbose, p->pOrder, ABC_INFINITY, p->pPars->TimeTarget );
// Abc_PrintTime( 1, "Image time", clock() - clk3 );
+ if ( bNext == NULL )
+ {
+ 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;
+ return -1;
+ }
if ( bNext == NULL ) // Llb_NonlimImage() consumes reference of bCurrent!!!
{
DdNode * bVar, * bVarG;
@@ -632,6 +690,7 @@ void Llb_MnnStop( Llb_Mnn_t * p )
ABC_PRTP( " reo ", p->timeReo, p->timeTotal );
ABC_PRTP( " reoG ", p->timeReoG, p->timeTotal );
}
+ p->dd->bFunc = NULL;
if ( p->ddR->bFunc )
Cudd_RecursiveDeref( p->ddR, p->ddR->bFunc );
Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i )
diff --git a/src/aig/llb/llb3Nonlin_multi.c b/src/aig/llb/llb3Nonlin_multi.c
deleted file mode 100644
index 22ff2491..00000000
--- a/src/aig/llb/llb3Nonlin_multi.c
+++ /dev/null
@@ -1,1490 +0,0 @@
-/**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_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
- Vec_Ptr_t * vFuncs; // current state functions in terms of vLeaves
- 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++ )
-
-static int timeBuild, timeAndEx, timeOther;
-static int nSuppMax;
-
-
-////////////////////////////////////////////////////////////////////////
-/// FUNCTION DEFINITIONS ///
-////////////////////////////////////////////////////////////////////////
-
-/**Function*************************************************************
-
- Synopsis [Finds variable whose 0-cofactor is the smallest.]
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-int Llb_NonlinFindBestVar( DdManager * dd, DdNode * bFunc, Vec_Int_t * vVars )
-{
- DdNode * bCof, * bVar;
- int i, iVar, iVarBest = -1;
- int Size, Size0, Size1;
- if ( vVars == NULL )
- vVars = Vec_IntStartNatural( Cudd_ReadSize(dd) );
- printf( "\nOriginal = %6d. SuppSize = %3d. Vars = %3d.\n",
- Size = Cudd_DagSize(bFunc), Cudd_SupportSize(dd, bFunc), Vec_IntSize(vVars) );
- Vec_IntForEachEntry( vVars, iVar, i )
- {
- printf( "Var =%3d : ", iVar );
- bVar = Cudd_bddIthVar(dd, iVar);
-
- bCof = Cudd_Cofactor( dd, bFunc, Cudd_Not(bVar) ); Cudd_Ref( bCof );
- printf( "Supp0 =%3d ", Cudd_SupportSize(dd, bCof) );
- printf( "Size0 =%6d ", Size0 = Cudd_DagSize(bCof) );
- Cudd_RecursiveDeref( dd, bCof );
-
- bCof = Cudd_Cofactor( dd, bFunc, bVar ); Cudd_Ref( bCof );
- printf( "Supp1 =%3d ", Cudd_SupportSize(dd, bCof) );
- printf( "Size1 =%6d ", Size1 = Cudd_DagSize(bCof) );
- Cudd_RecursiveDeref( dd, bCof );
-
- printf( "D =%6d ", Size0 + Size1 - Size );
- printf( "B =%6d\n", ABC_MAX(Size0, Size1) - ABC_MIN(Size0, Size1) );
- }
- 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 [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;
- 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 );
- 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;
- 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 );
- 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 Limit )
-{
- 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;
-/*
- if ( iPart1 == 91 && iPart2 == 134 )
- {
- fVerbose = 1;
- }
-*/
- // 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, Limit );
- return 1;
- }
- 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_MAX( 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 0;
-}
-
-/**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;
-
- 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 = Cudd_bddAnd( dd, bBdd0, bBdd1 ); 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_NonlinStart( Llb_Mgr_t * p )
-{
- Vec_Ptr_t * vRootBdds;
- Llb_Prt_t * pPart;
- DdNode * bFunc;
- int i, k, nSuppSize;
- // create and collect BDDs
- vRootBdds = Llb_NonlinBuildBdds( p->pAig, p->vLeaves, p->vRoots, p->dd ); // come referenced
- Vec_PtrForEachEntry( DdNode *, p->vFuncs, bFunc, i )
- Vec_PtrPush( vRootBdds, bFunc );
- // add pairs (refs are consumed inside)
- Vec_PtrForEachEntry( DdNode *, vRootBdds, bFunc, i )
- {
- 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_MAX( p->nSuppMax, nSuppSize );
- }
- Vec_PtrFree( vRootBdds );
- // remove singles
- Llb_MgrForEachPart( p, pPart, i )
- if ( Llb_NonlinHasSingletonVars(p, pPart) )
- Llb_NonlinQuantify1( p, pPart, 0 );
-}
-
-/**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, Vec_Ptr_t * vFuncs )
-{
- Llb_Mgr_t * p;
- p = ABC_CALLOC( Llb_Mgr_t, 1 );
- p->pAig = pAig;
- p->vLeaves = vLeaves;
- p->vRoots = vRoots;
- p->dd = dd;
- p->vFuncs = vFuncs;
- p->pVars2Q = pVars2Q;
- p->nVars = Cudd_ReadSize(dd);
- p->iPartFree = Vec_PtrSize(vRoots) + Vec_PtrSize(vFuncs);
- p->pVars = ABC_CALLOC( Llb_Var_t *, p->nVars );
- p->pParts = ABC_CALLOC( Llb_Prt_t *, 2 * p->iPartFree );
- 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 [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 fVerbose )
-{
- int clk = 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) );
- 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", 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 [Performs image computation.]
-
- Description [Computes image of BDDs (vFuncs).]
-
- SideEffects [BDDs in vFuncs are derefed inside. The result is refed.]
-
- SeeAlso []
-
-***********************************************************************/
-int Llb_NonlinImage( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q,
- DdManager * dd, Vec_Ptr_t * vFuncs, int fReorder, int fVerbose, int * pOrder, int * pfSubset, int Limit )
-{
- Llb_Prt_t * pPart, * pPart1, * pPart2;
- Llb_Mgr_t * p;
- int i, nReorders, timeInside, fSubset = 0;
- int clk = clock(), clk2;
- // start the manager
- clk2 = clock();
- p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd, vFuncs );
- Llb_NonlinStart( p );
- timeBuild += clock() - clk2;
- timeInside = clock() - clk2;
- // reorder variables
-// if ( fReorder )
-// Llb_NonlinReorder( dd, fVerbose );
- // compute scores
- Llb_NonlinRecomputeScores( p );
- // save permutation
- memcpy( pOrder, dd->invperm, sizeof(int) * dd->size );
- // iteratively quantify variables
- while ( Llb_NonlinNextPartitions(p, &pPart1, &pPart2) )
- {
- nReorders = Cudd_ReadReorderings(dd);
- clk2 = clock();
- fSubset |= Llb_NonlinQuantify2( p, pPart1, pPart2, Limit );
- timeAndEx += clock() - clk2;
- timeInside += clock() - clk2;
- if ( nReorders < Cudd_ReadReorderings(dd) )
- Llb_NonlinRecomputeScores( p );
-// else
-// Llb_NonlinVerifyScores( p );
- }
- // load partitions
- Vec_PtrClear( vFuncs );
- Llb_MgrForEachPart( p, pPart, i )
- {
- Vec_PtrPush( vFuncs, pPart->bFunc );
- Cudd_Ref( pPart->bFunc );
- }
- nSuppMax = p->nSuppMax;
- Llb_NonlinFree( p );
- // reorder variables
- if ( fReorder )
- Llb_NonlinReorder( dd, fVerbose );
- timeOther += clock() - clk - timeInside;
- if ( pfSubset )
- *pfSubset |= fSubset;
- return 1;
-}
-
-
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinPrepareVarMap( Aig_Man_t * pAig, Vec_Int_t ** pvNs2Glo, Vec_Int_t ** pvGlo2Cs )
-{
- Aig_Obj_t * pObjLi, * pObjLo;
- int i, iVarLi, iVarLo;
- *pvNs2Glo = Vec_IntStartFull( Aig_ManObjNumMax(pAig) );
- *pvGlo2Cs = Vec_IntStartFull( Aig_ManRegNum(pAig) );
- Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i )
- {
- iVarLi = Aig_ObjId(pObjLi);
- iVarLo = Aig_ObjId(pObjLo);
- assert( iVarLi >= 0 && iVarLi < Aig_ManObjNumMax(pAig) );
- assert( iVarLo >= 0 && iVarLo < Aig_ManObjNumMax(pAig) );
- Vec_IntWriteEntry( *pvNs2Glo, iVarLi, i );
- Vec_IntWriteEntry( *pvGlo2Cs, i, iVarLo );
- }
-}
-
-
-/**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;
- 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 );
- return bRes;
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-Vec_Ptr_t * Llb_NonlinComputeInitStateVec( Aig_Man_t * pAig, DdManager * dd )
-{
- Vec_Ptr_t * vFuncs;
- Aig_Obj_t * pObj;
- DdNode * bVar;
- int i;
- vFuncs = Vec_PtrAlloc( Aig_ManRegNum(pAig) );
- Saig_ManForEachLo( pAig, pObj, i )
- {
- bVar = Cudd_bddIthVar( dd, Aig_ObjId(pObj) ); Cudd_Ref( bVar );
- Vec_PtrPush( vFuncs, Cudd_Not(bVar) );
- }
- return vFuncs;
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinDerefVec( DdManager * dd, Vec_Ptr_t * vFuncs )
-{
- DdNode * bFunc;
- int i;
- Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i )
- Cudd_RecursiveDeref( dd, bFunc );
- Vec_PtrFree( vFuncs );
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinTransferVec( DdManager * dd, DdManager * ddG, Vec_Ptr_t * vFuncs, Vec_Int_t * vNs2Glo )
-{
- DdNode * bFunc, * bTemp;
- int i;
- Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i )
- {
- bFunc = Extra_TransferPermute( dd, ddG, bTemp = bFunc, Vec_IntArray(vNs2Glo) ); Cudd_Ref( bFunc );
- Cudd_RecursiveDeref( dd, bTemp );
- Vec_PtrWriteEntry( vFuncs, i, bFunc );
- }
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinSharpVec( DdManager * ddG, DdNode * bReached, Vec_Ptr_t * vFuncs )
-{
- DdNode * bFunc, * bTemp;
- int i;
- Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i )
- {
- bFunc = Cudd_bddAnd( ddG, bTemp = bFunc, Cudd_Not(bReached) ); Cudd_Ref( bFunc );
- Cudd_RecursiveDeref( ddG, bTemp );
- Vec_PtrWriteEntry( vFuncs, i, bFunc );
- }
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-DdNode * Llb_NonlinAddToReachVec( DdManager * ddG, DdNode * bReached, Vec_Ptr_t * vFuncs )
-{
- DdNode * bFunc, * bProd, * bTemp;
- int i;
- bProd = Cudd_ReadOne( ddG ); Cudd_Ref( bProd );
- Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i )
- {
- bProd = Cudd_bddAnd( ddG, bTemp = bProd, bFunc ); Cudd_Ref( bProd );
- Cudd_RecursiveDeref( ddG, bTemp );
- }
- if ( Cudd_IsConstant(bProd) )
- {
- Cudd_RecursiveDeref( ddG, bProd );
- return NULL;
- }
- bTemp = Cudd_bddOr( ddG, bReached, bProd ); Cudd_Ref( bTemp );
- Cudd_RecursiveDeref( ddG, bProd );
- Cudd_Deref( bTemp );
- return bTemp;
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-Vec_Ptr_t * Llb_NonlinCreateReachVec( DdManager * dd, DdManager * ddG, DdNode * bReachG, Vec_Int_t * vGlo2Cs )
-{
- Vec_Ptr_t * vFuncs;
- DdNode * bFunc;
- vFuncs = Vec_PtrAlloc( 1 );
- bFunc = Extra_TransferPermute( ddG, dd, bReachG, Vec_IntArray(vGlo2Cs) ); Cudd_Ref( bFunc );
- Vec_PtrPush( vFuncs, bFunc );
-// Llb_NonlinReorder( dd, 1 );
- return vFuncs;
-}
-
-/**Function*************************************************************
-
- Synopsis []
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinPrintVec( DdManager * dd, Vec_Ptr_t * vFuncs )
-{
- DdNode * bFunc;
- int i;
- Vec_PtrForEachEntry( DdNode *, vFuncs, bFunc, i )
- {
- printf( "%2d : ", i );
- printf( "Support =%5d ", Cudd_SupportSize(dd, bFunc) );
- printf( "DagSize =%7d\n", Cudd_DagSize(bFunc) );
- }
-}
-
-/**Function*************************************************************
-
- Synopsis [Perform reachability with hints.]
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-int Llb_NonlinReachability( Aig_Man_t * pAig, Gia_ParLlb_t * pPars )
-{
- Aig_Obj_t * pObj;
- Vec_Ptr_t * vLeaves, * vRoots, * vParts;
- Vec_Int_t * vNs2Glo, * vGlo2Cs;
- DdManager * dd, * ddG;
- DdNode * bReached, * bTemp;
- int i, nIters, nBddSize0, nBddSize, Limit, fSubset, * pVars2Q, * pOrder;
- int clk2, clk3, clk = clock();
-// int RetValue;
- int timeImage = 0;
- int timeTran1 = 0;
- int timeTran2 = 0;
- int timeGloba = 0;
- int timeOther = 0;
- int timeTotal = 0;
- int timeReo = 0;
- int timeReoG = 0;
- assert( Aig_ManRegNum(pAig) > 0 );
- timeBuild = timeAndEx = timeOther = 0;
-
- // compute time to stop
- if ( pPars->TimeLimit )
- pPars->TimeTarget = clock() + pPars->TimeLimit * CLOCKS_PER_SEC;
- else
- pPars->TimeTarget = 0;
-
- // create leaves
- vLeaves = Vec_PtrAlloc( Aig_ManPiNum(pAig) );
- Aig_ManForEachPi( pAig, pObj, i )
- Vec_PtrPush( vLeaves, pObj );
-
- // create roots
- vRoots = Vec_PtrAlloc( Aig_ManPoNum(pAig) );
- Saig_ManForEachLi( pAig, pObj, i )
- Vec_PtrPush( vRoots, pObj );
-
- // variables to quantify
- pOrder = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) );
- pVars2Q = ABC_CALLOC( int, Aig_ManObjNumMax(pAig) );
- Aig_ManForEachPi( pAig, pObj, i )
- pVars2Q[Aig_ObjId(pObj)] = 1;
-
- // start the managers
- Llb_NonlinPrepareVarMap( pAig, &vNs2Glo, &vGlo2Cs );
- dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
- ddG = Cudd_Init( Aig_ManRegNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
- Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT );
- Cudd_AutodynEnable( ddG, CUDD_REORDER_SYMM_SIFT );
-
- // compute the starting set of states
- vParts = Llb_NonlinComputeInitStateVec( pAig, dd );
- bReached = Llb_NonlinComputeInitState( pAig, ddG ); Cudd_Ref( bReached );
- fSubset = 1;
- for ( Limit = pPars->nBddMax; fSubset; Limit *= 2 )
- {
- if ( pPars->fVerbose )
- printf( "*********** LIMIT %d ************\n", Limit );
- fSubset = 0;
- for ( nIters = 0; nIters < pPars->nIterMax; nIters++ )
- {
- clk2 = clock();
- // check the runtime limit
- if ( pPars->TimeLimit && clock() >= pPars->TimeTarget )
- {
- if ( !pPars->fSilent )
- printf( "Reached timeout during image computation (%d seconds).\n", pPars->TimeLimit );
- pPars->iFrame = nIters - 1;
- Llb_NonlinDerefVec( dd, vParts ); vParts = NULL;
- Cudd_RecursiveDeref( ddG, bReached ); bReached = NULL;
- return -1;
- }
-
-// Llb_NonlinReorder( dd, 1 );
-
- // compute the next states
- clk3 = clock();
- nBddSize0 = Cudd_SharingSize( (DdNode **)Vec_PtrArray(vParts), Vec_PtrSize(vParts) );
- if ( !Llb_NonlinImage( pAig, vLeaves, vRoots, pVars2Q, dd, vParts, pPars->fReorder, pPars->fVeryVerbose, pOrder, &fSubset, Limit ) )
- {
- if ( !pPars->fSilent )
- printf( "Reached timeout during image computation (%d seconds).\n", pPars->TimeLimit );
- pPars->iFrame = nIters - 1;
- Llb_NonlinDerefVec( dd, vParts ); vParts = NULL;
- Cudd_RecursiveDeref( ddG, bReached ); bReached = NULL;
- return -1;
- }
- timeImage += clock() - clk3;
- nBddSize = Cudd_SharingSize( (DdNode **)Vec_PtrArray(vParts), Vec_PtrSize(vParts) );
-// Llb_NonlinPrintVec( dd, vParts );
-
- // check containment in reached and derive new frontier
- clk3 = clock();
- Llb_NonlinTransferVec( dd, ddG, vParts, vNs2Glo );
- timeTran1 += clock() - clk3;
-
- clk3 = clock();
- Llb_NonlinSharpVec( ddG, bReached, vParts );
- bReached = Llb_NonlinAddToReachVec( ddG, bTemp = bReached, vParts );
- if ( bReached == NULL )
- {
- bReached = bTemp;
- Llb_NonlinDerefVec( ddG, vParts ); vParts = NULL;
- if ( fSubset )
- vParts = Llb_NonlinCreateReachVec( dd, ddG, bReached, vGlo2Cs );
- break;
- }
- Cudd_Ref( bReached );
- Cudd_RecursiveDeref( ddG, bTemp );
- timeGloba += clock() - clk3;
-
- // reset permutation
- // RetValue = Cudd_CheckZeroRef( dd );
- // assert( RetValue == 0 );
- // Cudd_ShuffleHeap( dd, pOrder );
-
- clk3 = clock();
- Llb_NonlinTransferVec( ddG, dd, vParts, vGlo2Cs );
-// Llb_NonlinDerefVec( ddG, vParts ); vParts = NULL;
-// vParts = Llb_NonlinCreateReachVec( dd, ddG, bReached, vGlo2Cs );
- timeTran2 += clock() - clk3;
-
- // report the results
- if ( pPars->fVerbose )
- {
- printf( "I =%3d : ", nIters );
- printf( "Fr =%6d ", nBddSize0 );
- printf( "Im =%6d ", nBddSize );
- printf( "(%4d %3d) ", Cudd_ReadReorderings(dd), Cudd_ReadGarbageCollections(dd) );
- printf( "Rea =%6d ", Cudd_DagSize(bReached) );
- printf( "(%4d %3d) ", Cudd_ReadReorderings(ddG), Cudd_ReadGarbageCollections(ddG) );
- printf( "S =%4d ", nSuppMax );
- printf( "P =%2d ", Vec_PtrSize(vParts) );
- Abc_PrintTime( 1, "T", clock() - clk2 );
- }
- /*
- 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 == pPars->nIterMax - 1 )
- {
- if ( !pPars->fSilent )
- printf( "Reached limit on the number of timeframes (%d).\n", pPars->nIterMax );
- pPars->iFrame = nIters;
- Llb_NonlinDerefVec( dd, vParts ); vParts = NULL;
- Cudd_RecursiveDeref( ddG, bReached ); bReached = NULL;
- return -1;
- }
-
-// Llb_NonlinReorder( ddG, 1 );
-// Llb_NonlinFindBestVar( ddG, bReached, NULL );
- }
- }
-
- if ( bReached == NULL )
- return 0; // reachable
- // report the stats
- if ( pPars->fVerbose )
- {
- double nMints = Cudd_CountMinterm(ddG, bReached, Saig_ManRegNum(pAig) );
- if ( nIters >= pPars->nIterMax || nBddSize > 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(pAig)) );
- fflush( stdout );
- }
- if ( nIters >= pPars->nIterMax || nBddSize > pPars->nBddMax )
- {
- if ( !pPars->fSilent )
- printf( "Verified only for states reachable in %d frames. ", nIters );
- Cudd_RecursiveDeref( ddG, bReached );
- return -1; // undecided
- }
- // cleanup
- Cudd_RecursiveDeref( ddG, bReached );
- timeReo = Cudd_ReadReorderingTime(dd);
- timeReoG = Cudd_ReadReorderingTime(ddG);
- Extra_StopManager( dd );
- Extra_StopManager( ddG );
- // cleanup
- Vec_IntFree( vNs2Glo );
- Vec_IntFree( vGlo2Cs );
- Vec_PtrFree( vLeaves );
- Vec_PtrFree( vRoots );
- ABC_FREE( pVars2Q );
- ABC_FREE( pOrder );
- // report
- if ( !pPars->fSilent )
- printf( "The miter is proved unreachable after %d iterations. ", nIters );
- pPars->iFrame = nIters - 1;
- Abc_PrintTime( 1, "Time", clock() - clk );
-
- if ( pPars->fVerbose )
- {
- timeTotal = clock() - clk;
- timeOther = timeTotal - timeImage - timeTran1 - timeTran2 - timeGloba;
- ABC_PRTP( "Image ", timeImage, timeTotal );
- ABC_PRTP( " build ", timeBuild, timeTotal );
- ABC_PRTP( " and-ex ", timeAndEx, timeTotal );
- ABC_PRTP( " other ", timeOther, timeTotal );
- ABC_PRTP( "Transfer1", timeTran1, timeTotal );
- ABC_PRTP( "Transfer2", timeTran2, timeTotal );
- ABC_PRTP( "Global ", timeGloba, timeTotal );
- ABC_PRTP( "Other ", timeOther, timeTotal );
- ABC_PRTP( "TOTAL ", timeTotal, timeTotal );
- ABC_PRTP( " reo ", timeReo, timeTotal );
- ABC_PRTP( " reoG ", timeReoG, timeTotal );
- }
- return 1; // unreachable
-}
-
-/**Function*************************************************************
-
- Synopsis [Finds balanced cut.]
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-void Llb_NonlinExperiment( Aig_Man_t * pAig, int Num )
-{
- Gia_ParLlb_t Pars, * pPars = &Pars;
- Aig_Man_t * p;
-
- Llb_ManSetDefaultParams( pPars );
- pPars->fVerbose = 1;
-
- p = Aig_ManDupFlopsOnly( pAig );
-//Aig_ManShow( p, 0, NULL );
- Aig_ManPrintStats( pAig );
- Aig_ManPrintStats( p );
-
- Llb_NonlinReachability( p, pPars );
-
- Aig_ManStop( p );
-}
-
-/**Function*************************************************************
-
- Synopsis [Finds balanced cut.]
-
- Description []
-
- SideEffects []
-
- SeeAlso []
-
-***********************************************************************/
-int Llb_NonlinCoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars )
-{
- 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 )
- RetValue = Llb_NonlinReachability( p, pPars );
-
- Aig_ManStop( p );
- return RetValue;
-}
-
-////////////////////////////////////////////////////////////////////////
-/// END OF FILE ///
-////////////////////////////////////////////////////////////////////////
-
-
-ABC_NAMESPACE_IMPL_END
-
diff --git a/src/aig/llb/llbInt.h b/src/aig/llb/llbInt.h
index 80f391fe..36d3796c 100644
--- a/src/aig/llb/llbInt.h
+++ b/src/aig/llb/llbInt.h
@@ -146,7 +146,7 @@ extern int Llb_ManReachability( Llb_Man_t * p, Vec_Int_t * vHints, D
extern void Llb_MtrSchedule( Llb_Mtr_t * p );
/*=== llb2Bad.c ======================================================*/
-extern DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd );
+extern DdNode * Llb_BddComputeBad( Aig_Man_t * pInit, DdManager * dd, int 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 );
@@ -168,7 +168,7 @@ extern DdNode * Llb_ImgComputeImage( Aig_Man_t * pAig, Vec_Ptr_t * vDdMan
/*=== 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, int Limit );
+ DdManager * dd, DdNode * bCurrent, int fReorder, int fVerbose, int * pOrder, int Limit, int TimeLimit );
ABC_NAMESPACE_HEADER_END