blob: 47a9e7a0e19d2abe2fe8d09cb60c8f0b5b2ce3dc [file] [log] [blame]
/**CFile****************************************************************
FileName [fraClass.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [New FRAIG package.]
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 30, 2007.]
Revision [$Id: fraClass.c,v 1.00 2007/06/30 00:00:00 alanmi Exp $]
***********************************************************************/
#include "fra.h"
ABC_NAMESPACE_IMPL_START
/*
The candidate equivalence classes are stored as a vector of pointers
to the array of pointers to the nodes in each class.
The first node of the class is its representative node.
The representative has the smallest topological order among the class nodes.
The nodes inside each class are ordered according to their topological order.
The classes are ordered according to the topological order of their representatives.
The array of pointers to the class nodes is terminated with a NULL pointer.
To enable dynamic addition of new classes (during class refinement),
each array has at least as many NULLs in the end, as there are nodes in the class.
*/
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static inline Aig_Obj_t * Fra_ObjNext( Aig_Obj_t ** ppNexts, Aig_Obj_t * pObj ) { return ppNexts[pObj->Id]; }
static inline void Fra_ObjSetNext( Aig_Obj_t ** ppNexts, Aig_Obj_t * pObj, Aig_Obj_t * pNext ) { ppNexts[pObj->Id] = pNext; }
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Starts representation of equivalence classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Fra_Cla_t * Fra_ClassesStart( Aig_Man_t * pAig )
{
Fra_Cla_t * p;
p = ABC_ALLOC( Fra_Cla_t, 1 );
memset( p, 0, sizeof(Fra_Cla_t) );
p->pAig = pAig;
p->pMemRepr = ABC_ALLOC( Aig_Obj_t *, Aig_ManObjNumMax(pAig) );
memset( p->pMemRepr, 0, sizeof(Aig_Obj_t *) * Aig_ManObjNumMax(pAig) );
p->vClasses = Vec_PtrAlloc( 100 );
p->vClasses1 = Vec_PtrAlloc( 100 );
p->vClassesTemp = Vec_PtrAlloc( 100 );
p->vClassOld = Vec_PtrAlloc( 100 );
p->vClassNew = Vec_PtrAlloc( 100 );
p->pFuncNodeHash = Fra_SmlNodeHash;
p->pFuncNodeIsConst = Fra_SmlNodeIsConst;
p->pFuncNodesAreEqual = Fra_SmlNodesAreEqual;
return p;
}
/**Function*************************************************************
Synopsis [Stop representation of equivalence classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesStop( Fra_Cla_t * p )
{
ABC_FREE( p->pMemClasses );
ABC_FREE( p->pMemRepr );
if ( p->vClassesTemp ) Vec_PtrFree( p->vClassesTemp );
if ( p->vClassNew ) Vec_PtrFree( p->vClassNew );
if ( p->vClassOld ) Vec_PtrFree( p->vClassOld );
if ( p->vClasses1 ) Vec_PtrFree( p->vClasses1 );
if ( p->vClasses ) Vec_PtrFree( p->vClasses );
if ( p->vImps ) Vec_IntFree( p->vImps );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis [Starts representation of equivalence classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesCopyReprs( Fra_Cla_t * p, Vec_Ptr_t * vFailed )
{
Aig_Obj_t * pObj;
int i;
Aig_ManReprStart( p->pAig, Aig_ManObjNumMax(p->pAig) );
memmove( p->pAig->pReprs, p->pMemRepr, sizeof(Aig_Obj_t *) * Aig_ManObjNumMax(p->pAig) );
if ( Vec_PtrSize(p->vClasses1) == 0 && Vec_PtrSize(p->vClasses) == 0 )
{
Aig_ManForEachObj( p->pAig, pObj, i )
{
if ( p->pAig->pReprs[i] != NULL )
printf( "Classes are not cleared!\n" );
assert( p->pAig->pReprs[i] == NULL );
}
}
if ( vFailed )
Vec_PtrForEachEntry( Aig_Obj_t *, vFailed, pObj, i )
p->pAig->pReprs[pObj->Id] = NULL;
}
/**Function*************************************************************
Synopsis [Prints simulation classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ClassCount( Aig_Obj_t ** pClass )
{
Aig_Obj_t * pTemp;
int i;
for ( i = 0; (pTemp = pClass[i]); i++ );
return i;
}
/**Function*************************************************************
Synopsis [Count the number of literals.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ClassesCountLits( Fra_Cla_t * p )
{
Aig_Obj_t ** pClass;
int i, nNodes, nLits = 0;
nLits = Vec_PtrSize( p->vClasses1 );
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, pClass, i )
{
nNodes = Fra_ClassCount( pClass );
assert( nNodes > 1 );
nLits += nNodes - 1;
}
return nLits;
}
/**Function*************************************************************
Synopsis [Count the number of pairs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ClassesCountPairs( Fra_Cla_t * p )
{
Aig_Obj_t ** pClass;
int i, nNodes, nPairs = 0;
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, pClass, i )
{
nNodes = Fra_ClassCount( pClass );
assert( nNodes > 1 );
nPairs += nNodes * (nNodes - 1) / 2;
}
return nPairs;
}
/**Function*************************************************************
Synopsis [Prints simulation classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_PrintClass( Fra_Cla_t * p, Aig_Obj_t ** pClass )
{
Aig_Obj_t * pTemp;
int i;
for ( i = 1; (pTemp = pClass[i]); i++ )
assert( Fra_ClassObjRepr(pTemp) == pClass[0] );
printf( "{ " );
for ( i = 0; (pTemp = pClass[i]); i++ )
printf( "%d(%d,%d) ", pTemp->Id, pTemp->Level, Aig_SupportSize(p->pAig,pTemp) );
printf( "}\n" );
}
/**Function*************************************************************
Synopsis [Prints simulation classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesPrint( Fra_Cla_t * p, int fVeryVerbose )
{
Aig_Obj_t ** pClass;
Aig_Obj_t * pObj;
int i;
printf( "Const = %5d. Class = %5d. Lit = %5d. ",
Vec_PtrSize(p->vClasses1), Vec_PtrSize(p->vClasses), Fra_ClassesCountLits(p) );
if ( p->vImps && Vec_IntSize(p->vImps) > 0 )
printf( "Imp = %5d. ", Vec_IntSize(p->vImps) );
printf( "\n" );
if ( fVeryVerbose )
{
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClasses1, pObj, i )
assert( Fra_ClassObjRepr(pObj) == Aig_ManConst1(p->pAig) );
printf( "Constants { " );
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClasses1, pObj, i )
printf( "%d(%d,%d) ", pObj->Id, pObj->Level, Aig_SupportSize(p->pAig,pObj) );
printf( "}\n" );
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, pClass, i )
{
printf( "%3d (%3d) : ", i, Fra_ClassCount(pClass) );
Fra_PrintClass( p, pClass );
}
printf( "\n" );
}
}
/**Function*************************************************************
Synopsis [Creates initial simulation classes.]
Description [Assumes that simulation info is assigned.]
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesPrepare( Fra_Cla_t * p, int fLatchCorr, int nMaxLevs )
{
Aig_Obj_t ** ppTable, ** ppNexts;
Aig_Obj_t * pObj, * pTemp;
int i, k, nTableSize, nEntries, nNodes, iEntry;
// allocate the hash table hashing simulation info into nodes
nTableSize = Abc_PrimeCudd( Aig_ManObjNumMax(p->pAig) );
ppTable = ABC_FALLOC( Aig_Obj_t *, nTableSize );
ppNexts = ABC_FALLOC( Aig_Obj_t *, nTableSize );
memset( ppTable, 0, sizeof(Aig_Obj_t *) * nTableSize );
// add all the nodes to the hash table
Vec_PtrClear( p->vClasses1 );
Aig_ManForEachObj( p->pAig, pObj, i )
{
if ( fLatchCorr )
{
if ( !Aig_ObjIsCi(pObj) )
continue;
}
else
{
if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) )
continue;
// skip the node with more that the given number of levels
if ( nMaxLevs && (int)pObj->Level > nMaxLevs )
continue;
}
// hash the node by its simulation info
iEntry = p->pFuncNodeHash( pObj, nTableSize );
// check if the node belongs to the class of constant 1
if ( p->pFuncNodeIsConst( pObj ) )
{
Vec_PtrPush( p->vClasses1, pObj );
Fra_ClassObjSetRepr( pObj, Aig_ManConst1(p->pAig) );
continue;
}
// add the node to the class
if ( ppTable[iEntry] == NULL )
{
ppTable[iEntry] = pObj;
Fra_ObjSetNext( ppNexts, pObj, pObj );
}
else
{
Fra_ObjSetNext( ppNexts, pObj, Fra_ObjNext(ppNexts,ppTable[iEntry]) );
Fra_ObjSetNext( ppNexts, ppTable[iEntry], pObj );
}
}
// count the total number of nodes in the non-trivial classes
// mark the representative nodes of each equivalence class
nEntries = 0;
for ( i = 0; i < nTableSize; i++ )
if ( ppTable[i] && ppTable[i] != Fra_ObjNext(ppNexts, ppTable[i]) )
{
for ( pTemp = Fra_ObjNext(ppNexts, ppTable[i]), k = 1;
pTemp != ppTable[i];
pTemp = Fra_ObjNext(ppNexts, pTemp), k++ );
assert( k > 1 );
nEntries += k;
// mark the node
assert( ppTable[i]->fMarkA == 0 );
ppTable[i]->fMarkA = 1;
}
// allocate room for classes
p->pMemClasses = ABC_ALLOC( Aig_Obj_t *, 2*(nEntries + Vec_PtrSize(p->vClasses1)) );
p->pMemClassesFree = p->pMemClasses + 2*nEntries;
// copy the entries into storage in the topological order
Vec_PtrClear( p->vClasses );
nEntries = 0;
Aig_ManForEachObj( p->pAig, pObj, i )
{
if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) )
continue;
// skip the nodes that are not representatives of non-trivial classes
if ( pObj->fMarkA == 0 )
continue;
pObj->fMarkA = 0;
// add the class of nodes
Vec_PtrPush( p->vClasses, p->pMemClasses + 2*nEntries );
// count the number of entries in this class
for ( pTemp = Fra_ObjNext(ppNexts, pObj), k = 1;
pTemp != pObj;
pTemp = Fra_ObjNext(ppNexts, pTemp), k++ );
nNodes = k;
assert( nNodes > 1 );
// add the nodes to the class in the topological order
p->pMemClasses[2*nEntries] = pObj;
for ( pTemp = Fra_ObjNext(ppNexts, pObj), k = 1;
pTemp != pObj;
pTemp = Fra_ObjNext(ppNexts, pTemp), k++ )
{
p->pMemClasses[2*nEntries+nNodes-k] = pTemp;
Fra_ClassObjSetRepr( pTemp, pObj );
}
// add as many empty entries
p->pMemClasses[2*nEntries + nNodes] = NULL;
// increment the number of entries
nEntries += k;
}
ABC_FREE( ppTable );
ABC_FREE( ppNexts );
// now it is time to refine the classes
Fra_ClassesRefine( p );
// Fra_ClassesPrint( p, 0 );
}
/**Function*************************************************************
Synopsis [Refines one class using simulation info.]
Description [Returns the new class if refinement happened.]
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Obj_t ** Fra_RefineClassOne( Fra_Cla_t * p, Aig_Obj_t ** ppClass )
{
Aig_Obj_t * pObj, ** ppThis;
int i;
assert( ppClass[0] != NULL && ppClass[1] != NULL );
// check if the class is going to be refined
for ( ppThis = ppClass + 1; (pObj = *ppThis); ppThis++ )
if ( !p->pFuncNodesAreEqual(ppClass[0], pObj) )
break;
if ( pObj == NULL )
return NULL;
// split the class
Vec_PtrClear( p->vClassOld );
Vec_PtrClear( p->vClassNew );
Vec_PtrPush( p->vClassOld, ppClass[0] );
for ( ppThis = ppClass + 1; (pObj = *ppThis); ppThis++ )
if ( p->pFuncNodesAreEqual(ppClass[0], pObj) )
Vec_PtrPush( p->vClassOld, pObj );
else
Vec_PtrPush( p->vClassNew, pObj );
/*
printf( "Refining class (" );
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassOld, pObj, i )
printf( "%d,", pObj->Id );
printf( ") + (" );
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i )
printf( "%d,", pObj->Id );
printf( ")\n" );
*/
// put the nodes back into the class memory
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassOld, pObj, i )
{
ppClass[i] = pObj;
ppClass[Vec_PtrSize(p->vClassOld)+i] = NULL;
Fra_ClassObjSetRepr( pObj, i? ppClass[0] : NULL );
}
ppClass += 2*Vec_PtrSize(p->vClassOld);
// put the new nodes into the class memory
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i )
{
ppClass[i] = pObj;
ppClass[Vec_PtrSize(p->vClassNew)+i] = NULL;
Fra_ClassObjSetRepr( pObj, i? ppClass[0] : NULL );
}
return ppClass;
}
/**Function*************************************************************
Synopsis [Iteratively refines the classes after simulation.]
Description [Returns the number of refinements performed.]
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_RefineClassLastIter( Fra_Cla_t * p, Vec_Ptr_t * vClasses )
{
Aig_Obj_t ** pClass, ** pClass2;
int nRefis;
pClass = (Aig_Obj_t **)Vec_PtrEntryLast( vClasses );
for ( nRefis = 0; (pClass2 = Fra_RefineClassOne( p, pClass )); nRefis++ )
{
// if the original class is trivial, remove it
if ( pClass[1] == NULL )
Vec_PtrPop( vClasses );
// if the new class is trivial, stop
if ( pClass2[1] == NULL )
{
nRefis++;
break;
}
// othewise, add the class and continue
assert( pClass2[0] != NULL );
Vec_PtrPush( vClasses, pClass2 );
pClass = pClass2;
}
return nRefis;
}
/**Function*************************************************************
Synopsis [Refines the classes after simulation.]
Description [Assumes that simulation info is assigned. Returns the
number of classes refined.]
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ClassesRefine( Fra_Cla_t * p )
{
Vec_Ptr_t * vTemp;
Aig_Obj_t ** pClass;
int i, nRefis;
// refine the classes
nRefis = 0;
Vec_PtrClear( p->vClassesTemp );
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, pClass, i )
{
// add the class to the new array
assert( pClass[0] != NULL );
Vec_PtrPush( p->vClassesTemp, pClass );
// refine the class iteratively
nRefis += Fra_RefineClassLastIter( p, p->vClassesTemp );
}
// exchange the class representation
vTemp = p->vClassesTemp;
p->vClassesTemp = p->vClasses;
p->vClasses = vTemp;
return nRefis;
}
/**Function*************************************************************
Synopsis [Refines constant 1 equivalence class.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ClassesRefine1( Fra_Cla_t * p, int fRefineNewClass, int * pSkipped )
{
Aig_Obj_t * pObj, ** ppClass;
int i, k, nRefis = 1;
// check if there is anything to refine
if ( Vec_PtrSize(p->vClasses1) == 0 )
return 0;
// make sure constant 1 class contains only non-constant nodes
assert( Vec_PtrEntry(p->vClasses1,0) != Aig_ManConst1(p->pAig) );
// collect all the nodes to be refined
k = 0;
Vec_PtrClear( p->vClassNew );
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClasses1, pObj, i )
{
if ( p->pFuncNodeIsConst( pObj ) )
Vec_PtrWriteEntry( p->vClasses1, k++, pObj );
else
Vec_PtrPush( p->vClassNew, pObj );
}
Vec_PtrShrink( p->vClasses1, k );
if ( Vec_PtrSize(p->vClassNew) == 0 )
return 0;
/*
printf( "Refined const-1 class: {" );
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i )
printf( " %d", pObj->Id );
printf( " }\n" );
*/
if ( Vec_PtrSize(p->vClassNew) == 1 )
{
Fra_ClassObjSetRepr( (Aig_Obj_t *)Vec_PtrEntry(p->vClassNew,0), NULL );
return 1;
}
// create a new class composed of these nodes
ppClass = p->pMemClassesFree;
p->pMemClassesFree += 2 * Vec_PtrSize(p->vClassNew);
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClassNew, pObj, i )
{
ppClass[i] = pObj;
ppClass[Vec_PtrSize(p->vClassNew)+i] = NULL;
Fra_ClassObjSetRepr( pObj, i? ppClass[0] : NULL );
}
assert( ppClass[0] != NULL );
Vec_PtrPush( p->vClasses, ppClass );
// iteratively refine this class
if ( fRefineNewClass )
nRefis += Fra_RefineClassLastIter( p, p->vClasses );
else if ( pSkipped )
(*pSkipped)++;
return nRefis;
}
/**Function*************************************************************
Synopsis [Starts representation of equivalence classes with one class.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesTest( Fra_Cla_t * p, int Id1, int Id2 )
{
Aig_Obj_t ** pClass;
p->pMemClasses = ABC_ALLOC( Aig_Obj_t *, 4 );
pClass = p->pMemClasses;
assert( Id1 < Id2 );
pClass[0] = Aig_ManObj( p->pAig, Id1 );
pClass[1] = Aig_ManObj( p->pAig, Id2 );
pClass[2] = NULL;
pClass[3] = NULL;
Fra_ClassObjSetRepr( pClass[1], pClass[0] );
Vec_PtrPush( p->vClasses, pClass );
}
/**Function*************************************************************
Synopsis [Creates latch correspondence classes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesLatchCorr( Fra_Man_t * p )
{
Aig_Obj_t * pObj;
int i, nEntries = 0;
Vec_PtrClear( p->pCla->vClasses1 );
Aig_ManForEachLoSeq( p->pManAig, pObj, i )
{
Vec_PtrPush( p->pCla->vClasses1, pObj );
Fra_ClassObjSetRepr( pObj, Aig_ManConst1(p->pManAig) );
}
// allocate room for classes
p->pCla->pMemClasses = ABC_ALLOC( Aig_Obj_t *, 2*(nEntries + Vec_PtrSize(p->pCla->vClasses1)) );
p->pCla->pMemClassesFree = p->pCla->pMemClasses + 2*nEntries;
}
/**Function*************************************************************
Synopsis [Postprocesses the classes by removing half of the less useful.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesPostprocess( Fra_Cla_t * p )
{
int Ratio = 2;
Fra_Sml_t * pComb;
Aig_Obj_t * pObj, * pRepr, ** ppClass;
int * pWeights, WeightMax = 0, i, k, c;
// perform combinational simulation
pComb = Fra_SmlSimulateComb( p->pAig, 32, 0 );
// compute the weight of each node in the classes
pWeights = ABC_ALLOC( int, Aig_ManObjNumMax(p->pAig) );
memset( pWeights, 0, sizeof(int) * Aig_ManObjNumMax(p->pAig) );
Aig_ManForEachObj( p->pAig, pObj, i )
{
pRepr = Fra_ClassObjRepr( pObj );
if ( pRepr == NULL )
continue;
pWeights[i] = Fra_SmlNodeNotEquWeight( pComb, pRepr->Id, pObj->Id );
WeightMax = Abc_MaxInt( WeightMax, pWeights[i] );
}
Fra_SmlStop( pComb );
printf( "Before: Const = %6d. Class = %6d. ", Vec_PtrSize(p->vClasses1), Vec_PtrSize(p->vClasses) );
// remove nodes from classes whose weight is less than WeightMax/Ratio
k = 0;
Vec_PtrForEachEntry( Aig_Obj_t *, p->vClasses1, pObj, i )
{
if ( pWeights[pObj->Id] >= WeightMax/Ratio )
Vec_PtrWriteEntry( p->vClasses1, k++, pObj );
else
Fra_ClassObjSetRepr( pObj, NULL );
}
Vec_PtrShrink( p->vClasses1, k );
// in each class, compact the nodes
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, ppClass, i )
{
k = 1;
for ( c = 1; ppClass[c]; c++ )
{
if ( pWeights[ppClass[c]->Id] >= WeightMax/Ratio )
ppClass[k++] = ppClass[c];
else
Fra_ClassObjSetRepr( ppClass[c], NULL );
}
ppClass[k] = NULL;
}
// remove classes with only repr
k = 0;
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, ppClass, i )
if ( ppClass[1] != NULL )
Vec_PtrWriteEntry( p->vClasses, k++, ppClass );
Vec_PtrShrink( p->vClasses, k );
printf( "After: Const = %6d. Class = %6d. \n", Vec_PtrSize(p->vClasses1), Vec_PtrSize(p->vClasses) );
ABC_FREE( pWeights );
}
/**Function*************************************************************
Synopsis [Postprocesses the classes by selecting representative lowest in top order.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ClassesSelectRepr( Fra_Cla_t * p )
{
Aig_Obj_t ** pClass, * pNodeMin;
int i, c, cMinSupp, nSuppSizeMin, nSuppSizeCur;
// reassign representatives in each class
Vec_PtrForEachEntry( Aig_Obj_t **, p->vClasses, pClass, i )
{
// collect support sizes and find the min-support node
cMinSupp = -1;
pNodeMin = NULL;
nSuppSizeMin = ABC_INFINITY;
for ( c = 0; pClass[c]; c++ )
{
nSuppSizeCur = Aig_SupportSize( p->pAig, pClass[c] );
// nSuppSizeCur = 1;
if ( nSuppSizeMin > nSuppSizeCur ||
(nSuppSizeMin == nSuppSizeCur && pNodeMin->Level > pClass[c]->Level) )
{
nSuppSizeMin = nSuppSizeCur;
pNodeMin = pClass[c];
cMinSupp = c;
}
}
// skip the case when the repr did not change
if ( cMinSupp == 0 )
continue;
// make the new node the representative of the class
pClass[cMinSupp] = pClass[0];
pClass[0] = pNodeMin;
// set the representative
for ( c = 0; pClass[c]; c++ )
Fra_ClassObjSetRepr( pClass[c], c? pClass[0] : NULL );
}
}
static inline Aig_Obj_t * Fra_ObjEqu( Aig_Obj_t ** ppEquivs, Aig_Obj_t * pObj ) { return ppEquivs[pObj->Id]; }
static inline void Fra_ObjSetEqu( Aig_Obj_t ** ppEquivs, Aig_Obj_t * pObj, Aig_Obj_t * pNode ) { ppEquivs[pObj->Id] = pNode; }
static inline Aig_Obj_t * Fra_ObjChild0Equ( Aig_Obj_t ** ppEquivs, Aig_Obj_t * pObj ) { return Aig_NotCond(Fra_ObjEqu(ppEquivs,Aig_ObjFanin0(pObj)), Aig_ObjFaninC0(pObj)); }
static inline Aig_Obj_t * Fra_ObjChild1Equ( Aig_Obj_t ** ppEquivs, Aig_Obj_t * pObj ) { return Aig_NotCond(Fra_ObjEqu(ppEquivs,Aig_ObjFanin1(pObj)), Aig_ObjFaninC1(pObj)); }
/**Function*************************************************************
Synopsis [Add the node and its constraints to the new AIG.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Fra_ClassesDeriveNode( Aig_Man_t * pManFraig, Aig_Obj_t * pObj, Aig_Obj_t ** ppEquivs )
{
Aig_Obj_t * pObjNew, * pObjRepr, * pObjReprNew, * pMiter;//, * pObjNew2;
// skip nodes without representative
if ( (pObjRepr = Fra_ClassObjRepr(pObj)) == NULL )
return;
assert( pObjRepr->Id < pObj->Id );
// get the new node
pObjNew = Fra_ObjEqu( ppEquivs, pObj );
// get the new node of the representative
pObjReprNew = Fra_ObjEqu( ppEquivs, pObjRepr );
// if this is the same node, no need to add constraints
if ( Aig_Regular(pObjNew) == Aig_Regular(pObjReprNew) )
return;
// these are different nodes - perform speculative reduction
// pObjNew2 = Aig_NotCond( pObjReprNew, pObj->fPhase ^ pObjRepr->fPhase );
// set the new node
// Fra_ObjSetEqu( ppEquivs, pObj, pObjNew2 );
// add the constraint
pMiter = Aig_Exor( pManFraig, Aig_Regular(pObjNew), Aig_Regular(pObjReprNew) );
pMiter = Aig_NotCond( pMiter, Aig_Regular(pMiter)->fPhase ^ Aig_IsComplement(pMiter) );
pMiter = Aig_Not( pMiter );
Aig_ObjCreateCo( pManFraig, pMiter );
}
/**Function*************************************************************
Synopsis [Derives AIG for the partitioned problem.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Aig_Man_t * Fra_ClassesDeriveAig( Fra_Cla_t * p, int nFramesK )
{
Aig_Man_t * pManFraig;
Aig_Obj_t * pObj, * pObjNew;
Aig_Obj_t ** pLatches, ** ppEquivs;
int i, k, f, nFramesAll = nFramesK + 1;
assert( Aig_ManRegNum(p->pAig) > 0 );
assert( Aig_ManRegNum(p->pAig) < Aig_ManCiNum(p->pAig) );
assert( nFramesK > 0 );
// start the fraig package
pManFraig = Aig_ManStart( Aig_ManObjNumMax(p->pAig) * nFramesAll );
pManFraig->pName = Abc_UtilStrsav( p->pAig->pName );
pManFraig->pSpec = Abc_UtilStrsav( p->pAig->pSpec );
// allocate place for the node mapping
ppEquivs = ABC_ALLOC( Aig_Obj_t *, Aig_ManObjNumMax(p->pAig) );
Fra_ObjSetEqu( ppEquivs, Aig_ManConst1(p->pAig), Aig_ManConst1(pManFraig) );
// create latches for the first frame
Aig_ManForEachLoSeq( p->pAig, pObj, i )
Fra_ObjSetEqu( ppEquivs, pObj, Aig_ObjCreateCi(pManFraig) );
// add timeframes
pLatches = ABC_ALLOC( Aig_Obj_t *, Aig_ManRegNum(p->pAig) );
for ( f = 0; f < nFramesAll; f++ )
{
// create PIs for this frame
Aig_ManForEachPiSeq( p->pAig, pObj, i )
Fra_ObjSetEqu( ppEquivs, pObj, Aig_ObjCreateCi(pManFraig) );
// set the constraints on the latch outputs
Aig_ManForEachLoSeq( p->pAig, pObj, i )
Fra_ClassesDeriveNode( pManFraig, pObj, ppEquivs );
// add internal nodes of this frame
Aig_ManForEachNode( p->pAig, pObj, i )
{
pObjNew = Aig_And( pManFraig, Fra_ObjChild0Equ(ppEquivs, pObj), Fra_ObjChild1Equ(ppEquivs, pObj) );
Fra_ObjSetEqu( ppEquivs, pObj, pObjNew );
Fra_ClassesDeriveNode( pManFraig, pObj, ppEquivs );
}
if ( f == nFramesAll - 1 )
break;
if ( f == nFramesAll - 2 )
pManFraig->nAsserts = Aig_ManCoNum(pManFraig);
// save the latch input values
k = 0;
Aig_ManForEachLiSeq( p->pAig, pObj, i )
pLatches[k++] = Fra_ObjChild0Equ( ppEquivs, pObj );
// insert them to the latch output values
k = 0;
Aig_ManForEachLoSeq( p->pAig, pObj, i )
Fra_ObjSetEqu( ppEquivs, pObj, pLatches[k++] );
}
ABC_FREE( pLatches );
ABC_FREE( ppEquivs );
// mark the asserts
assert( Aig_ManCoNum(pManFraig) % nFramesAll == 0 );
printf( "Assert miters = %6d. Output miters = %6d.\n",
pManFraig->nAsserts, Aig_ManCoNum(pManFraig) - pManFraig->nAsserts );
// remove dangling nodes
Aig_ManCleanup( pManFraig );
return pManFraig;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END