blob: a94213580ab8c19baabf404fee57ac6cd8f1d101 [file] [log] [blame]
/**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