blob: 3ce0458b5762535785b343c39ebc33375c43b336 [file] [log] [blame]
/**CFile****************************************************************
FileName [retFlow.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Implementation of maximum flow (min-area retiming).]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - Oct 31, 2006.]
Revision [$Id: retFlow.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $]
***********************************************************************/
#include "retInt.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static inline int Abc_ObjSetPath( Abc_Obj_t * pObj, Abc_Obj_t * pNext ) { pObj->pCopy = pNext; return 1; }
static inline Abc_Obj_t * Abc_ObjGetPath( Abc_Obj_t * pObj ) { return pObj->pCopy; }
static inline Abc_Obj_t * Abc_ObjGetFanoutPath( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanout;
int i;
assert( Abc_ObjGetPath(pObj) );
Abc_ObjForEachFanout( pObj, pFanout, i )
if ( Abc_ObjGetPath(pFanout) == pObj )
return pFanout;
return NULL;
}
static inline Abc_Obj_t * Abc_ObjGetFaninPath( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanin;
int i;
assert( Abc_ObjGetPath(pObj) );
Abc_ObjForEachFanin( pObj, pFanin, i )
if ( Abc_ObjGetPath(pFanin) == pObj )
return pFanin;
return NULL;
}
static inline Abc_Obj_t * Abc_ObjGetPredecessorBwd( Abc_Obj_t * pObj )
{
Abc_Obj_t * pNext;
int i;
Abc_ObjForEachFanout( pObj, pNext, i )
if ( Abc_ObjGetPath(pNext) == pObj )
return pNext;
Abc_ObjForEachFanin( pObj, pNext, i )
if ( Abc_ObjGetPath(pNext) == pObj )
return pNext;
return NULL;
}
static inline Abc_Obj_t * Abc_ObjGetPredecessorFwd( Abc_Obj_t * pObj )
{
Abc_Obj_t * pNext;
int i;
Abc_ObjForEachFanin( pObj, pNext, i )
if ( Abc_ObjGetPath(pNext) == pObj )
return pNext;
Abc_ObjForEachFanout( pObj, pNext, i )
if ( Abc_ObjGetPath(pNext) == pObj )
return pNext;
return NULL;
}
static int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj );
static int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj );
static int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj );
static int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj );
//static int Abc_NtkMaxFlowBwdPath3_rec( Abc_Obj_t * pObj );
static int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin );
static Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward );
static void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward );
static int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward );
static void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut );
static void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Test-bench for the max-flow computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowTest( Abc_Ntk_t * pNtk )
{
Vec_Ptr_t * vMinCut;
Abc_Obj_t * pObj;
int i;
// forward flow
Abc_NtkForEachPo( pNtk, pObj, i )
pObj->fMarkA = 1;
Abc_NtkForEachLatch( pNtk, pObj, i )
pObj->fMarkA = Abc_ObjFanin0(pObj)->fMarkA = 1;
// Abc_ObjFanin0(pObj)->fMarkA = 1;
vMinCut = Abc_NtkMaxFlow( pNtk, 1, 1 );
Vec_PtrFree( vMinCut );
Abc_NtkCleanMarkA( pNtk );
// backward flow
Abc_NtkForEachPi( pNtk, pObj, i )
pObj->fMarkA = 1;
Abc_NtkForEachLatch( pNtk, pObj, i )
pObj->fMarkA = Abc_ObjFanout0(pObj)->fMarkA = 1;
// Abc_ObjFanout0(pObj)->fMarkA = 1;
vMinCut = Abc_NtkMaxFlow( pNtk, 0, 1 );
Vec_PtrFree( vMinCut );
Abc_NtkCleanMarkA( pNtk );
}
/**Function*************************************************************
Synopsis [Implementation of max-flow/min-cut computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkMaxFlow( Abc_Ntk_t * pNtk, int fForward, int fVerbose )
{
Vec_Ptr_t * vMinCut;
Abc_Obj_t * pLatch;
int Flow, FlowCur, RetValue, i;
abctime clk = Abc_Clock();
int fUseDirectedFlow = 1;
// find the max-flow
Abc_NtkCleanCopy( pNtk );
Flow = 0;
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( fForward )
{
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
FlowCur = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) );
// FlowCur = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 );
Flow += FlowCur;
}
else
{
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
FlowCur = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) );
Flow += FlowCur;
}
if ( FlowCur )
Abc_NtkIncrementTravId(pNtk);
}
if ( !fUseDirectedFlow )
{
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( fForward )
{
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
FlowCur = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) );
Flow += FlowCur;
}
else
{
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
FlowCur = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) );
Flow += FlowCur;
}
if ( FlowCur )
Abc_NtkIncrementTravId(pNtk);
}
}
// Abc_NtkMaxFlowPrintFlow( pNtk, fForward );
// mark the nodes reachable from the latches
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch( pNtk, pLatch, i )
{
if ( fForward )
{
// assert( !Abc_ObjFanout0(pLatch)->fMarkA );
if ( fUseDirectedFlow )
RetValue = Abc_NtkMaxFlowFwdPath2_rec( Abc_ObjFanout0(pLatch) );
// RetValue = Abc_NtkMaxFlowFwdPath3_rec( Abc_ObjFanout0(pLatch), pLatch, 1 );
else
RetValue = Abc_NtkMaxFlowFwdPath_rec( Abc_ObjFanout0(pLatch) );
}
else
{
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
if ( fUseDirectedFlow )
RetValue = Abc_NtkMaxFlowBwdPath2_rec( Abc_ObjFanin0(pLatch) );
else
RetValue = Abc_NtkMaxFlowBwdPath_rec( Abc_ObjFanin0(pLatch) );
}
assert( RetValue == 0 );
}
// find the min-cut with the smallest volume
vMinCut = Abc_NtkMaxFlowMinCut( pNtk, fForward );
// verify the cut
if ( !Abc_NtkMaxFlowVerifyCut(pNtk, vMinCut, fForward) )
printf( "Abc_NtkMaxFlow() error! The computed min-cut is not a cut!\n" );
// make the cut retimable
Abc_NtkMaxFlowMinCutUpdate( pNtk, vMinCut, fForward );
// report the results
if ( fVerbose )
{
printf( "L = %6d. %s max-flow = %6d. Min-cut = %6d. ",
Abc_NtkLatchNum(pNtk), fForward? "Forward " : "Backward", Flow, Vec_PtrSize(vMinCut) );
ABC_PRT( "Time", Abc_Clock() - clk );
}
// Abc_NtkMaxFlowPrintCut( pNtk, vMinCut );
return vMinCut;
}
/**Function*************************************************************
Synopsis [Tries to find an augmenting path originating in this node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowBwdPath_rec( Abc_Obj_t * pObj )
{
Abc_Obj_t * pNext, * pPred;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 0;
Abc_NodeSetTravIdCurrent(pObj);
// get the predecessor
pPred = Abc_ObjGetPredecessorBwd( pObj );
// process node without flow
if ( !Abc_ObjGetPath(pObj) )
{
// start the path if we reached a terminal node
if ( pObj->fMarkA )
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
// explore the fanins
Abc_ObjForEachFanin( pObj, pNext, i )
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) )
return Abc_ObjSetPath( pObj, pNext );
Abc_ObjForEachFanout( pObj, pNext, i )
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec(pNext) )
return Abc_ObjSetPath( pObj, pNext );
return 0;
}
// pObj has flow - find the fanout with flow
if ( pPred == NULL )
return 0;
// go through the successors of the predecessor
Abc_ObjForEachFanin( pPred, pNext, i )
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) )
return Abc_ObjSetPath( pPred, pNext );
Abc_ObjForEachFanout( pPred, pNext, i )
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowBwdPath_rec( pNext ) )
return Abc_ObjSetPath( pPred, pNext );
// try the fanout
if ( Abc_NtkMaxFlowBwdPath_rec( pPred ) )
return Abc_ObjSetPath( pPred, NULL );
return 0;
}
/**Function*************************************************************
Synopsis [Tries to find an augmenting path originating in this node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowFwdPath_rec( Abc_Obj_t * pObj )
{
Abc_Obj_t * pNext, * pPred;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 0;
Abc_NodeSetTravIdCurrent(pObj);
// get the predecessor
pPred = Abc_ObjGetPredecessorFwd( pObj );
// process node without flow
if ( !Abc_ObjGetPath(pObj) )
{
// start the path if we reached a terminal node
if ( pObj->fMarkA )
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
// explore the fanins
Abc_ObjForEachFanout( pObj, pNext, i )
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) )
return Abc_ObjSetPath( pObj, pNext );
Abc_ObjForEachFanin( pObj, pNext, i )
if ( pNext != pPred && !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec(pNext) )
return Abc_ObjSetPath( pObj, pNext );
return 0;
}
// pObj has flow - find the fanout with flow
if ( pPred == NULL )
return 0;
// go through the successors of the predecessor
Abc_ObjForEachFanout( pPred, pNext, i )
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) )
return Abc_ObjSetPath( pPred, pNext );
Abc_ObjForEachFanin( pPred, pNext, i )
if ( !Abc_ObjIsLatch(pNext) && Abc_NtkMaxFlowFwdPath_rec( pNext ) )
return Abc_ObjSetPath( pPred, pNext );
// try the fanout
if ( Abc_NtkMaxFlowFwdPath_rec( pPred ) )
return Abc_ObjSetPath( pPred, NULL );
return 0;
}
/**Function*************************************************************
Synopsis [Tries to find an augmenting path originating in this edge.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowFwdPath3_rec( Abc_Obj_t * pObj, Abc_Obj_t * pPrev, int fFanin )
{
Abc_Obj_t * pFanin, * pFanout;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 0;
Abc_NodeSetTravIdCurrent(pObj);
// skip the fanin which already has flow
if ( fFanin && Abc_ObjGetPath(pPrev) )
return 0;
// if the node has no flow, try to push through the fanouts
if ( !Abc_ObjGetPath(pObj) )
{
// start the path if we reached a terminal node
if ( pObj->fMarkA )
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
// try to push flow through the fanouts
Abc_ObjForEachFanout( pObj, pFanout, i )
if ( Abc_NtkMaxFlowFwdPath3_rec(pFanout, pObj, 1) )
return fFanin? Abc_ObjSetPath(pPrev, pObj) : 1;
}
// try to push through the fanins
Abc_ObjForEachFanin( pObj, pFanin, i )
if ( !Abc_ObjIsLatch(pFanin) && Abc_NtkMaxFlowFwdPath3_rec(pFanin, pObj, 0) )
return Abc_ObjSetPath( pFanin, NULL );
return 0;
}
/**Function*************************************************************
Synopsis [Tries to find an augmenting path originating in this node.]
Description [This procedure works for directed graphs only!]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowBwdPath2_rec( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanout, * pFanin;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 0;
Abc_NodeSetTravIdCurrent(pObj);
// process node without flow
if ( !Abc_ObjGetPath(pObj) )
{
// start the path if we reached a terminal node
if ( pObj->fMarkA )
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
// explore the fanins
Abc_ObjForEachFanin( pObj, pFanin, i )
if ( Abc_NtkMaxFlowBwdPath2_rec(pFanin) )
return Abc_ObjSetPath( pObj, pFanin );
return 0;
}
// pObj has flow - find the fanout with flow
pFanout = Abc_ObjGetFanoutPath( pObj );
if ( pFanout == NULL )
return 0;
// go through the fanins of the fanout with flow
Abc_ObjForEachFanin( pFanout, pFanin, i )
if ( Abc_NtkMaxFlowBwdPath2_rec( pFanin ) )
return Abc_ObjSetPath( pFanout, pFanin );
// try the fanout
if ( Abc_NtkMaxFlowBwdPath2_rec( pFanout ) )
return Abc_ObjSetPath( pFanout, NULL );
return 0;
}
/**Function*************************************************************
Synopsis [Tries to find an augmenting path originating in this node.]
Description [This procedure works for directed graphs only!]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowFwdPath2_rec( Abc_Obj_t * pObj )
{
Abc_Obj_t * pFanout, * pFanin;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 0;
Abc_NodeSetTravIdCurrent(pObj);
// process node without flow
if ( !Abc_ObjGetPath(pObj) )
{
// start the path if we reached a terminal node
if ( pObj->fMarkA )
return Abc_ObjSetPath( pObj, (Abc_Obj_t *)1 );
// explore the fanins
Abc_ObjForEachFanout( pObj, pFanout, i )
if ( Abc_NtkMaxFlowFwdPath2_rec(pFanout) )
return Abc_ObjSetPath( pObj, pFanout );
return 0;
}
// pObj has flow - find the fanout with flow
pFanin = Abc_ObjGetFaninPath( pObj );
if ( pFanin == NULL )
return 0;
// go through the fanins of the fanout with flow
Abc_ObjForEachFanout( pFanin, pFanout, i )
if ( Abc_NtkMaxFlowFwdPath2_rec( pFanout ) )
return Abc_ObjSetPath( pFanin, pFanout );
// try the fanout
if ( Abc_NtkMaxFlowFwdPath2_rec( pFanin ) )
return Abc_ObjSetPath( pFanin, NULL );
return 0;
}
/**Function*************************************************************
Synopsis [Find minimum-volume minumum cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Abc_NtkMaxFlowMinCut( Abc_Ntk_t * pNtk, int fForward )
{
Vec_Ptr_t * vMinCut;
Abc_Obj_t * pObj;
int i;
// collect the cut nodes
vMinCut = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
Abc_NtkForEachObj( pNtk, pObj, i )
{
// node without flow is not a cut node
if ( !Abc_ObjGetPath(pObj) )
continue;
// unvisited node is below the cut
if ( !Abc_NodeIsTravIdCurrent(pObj) )
continue;
// add terminal with flow or node whose path is not visited
if ( pObj->fMarkA || !Abc_NodeIsTravIdCurrent( Abc_ObjGetPath(pObj) ) )
Vec_PtrPush( vMinCut, pObj );
}
return vMinCut;
}
/**Function*************************************************************
Synopsis [Marks the TFI cone with MarkA.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowMarkCut_rec( Abc_Obj_t * pObj )
{
Abc_Obj_t * pNext;
int i;
if ( pObj->fMarkA )
return;
pObj->fMarkA = 1;
Abc_ObjForEachFanin( pObj, pNext, i )
Abc_NtkMaxFlowMarkCut_rec( pNext );
}
/**Function*************************************************************
Synopsis [Visits the TFI up to marked nodes and collects marked nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowCollectCut_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vNodes )
{
Abc_Obj_t * pNext;
int i;
if ( Abc_NodeIsTravIdCurrent(pObj) )
return;
Abc_NodeSetTravIdCurrent(pObj);
if ( pObj->fMarkA )
{
Vec_PtrPush( vNodes, pObj );
return;
}
Abc_ObjForEachFanin( pObj, pNext, i )
Abc_NtkMaxFlowCollectCut_rec( pNext, vNodes );
}
/**Function*************************************************************
Synopsis [Updates the minimum cut to be retimable.]
Description [This procedure also labels the nodes reachable from
the latches to the cut with fMarkA.]
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowMinCutUpdate( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward )
{
Abc_Obj_t * pObj, * pNext;
int i, k;
// clean marks
Abc_NtkForEachObj( pNtk, pObj, i )
pObj->fMarkA = 0;
// set latch outputs
Abc_NtkForEachLatch( pNtk, pObj, i )
Abc_ObjFanout0(pObj)->fMarkA = 1;
// traverse from cut nodes
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
Abc_NtkMaxFlowMarkCut_rec( pObj );
if ( fForward )
{
// change mincut to be nodes with unmarked fanouts
Vec_PtrClear( vMinCut );
Abc_NtkForEachObj( pNtk, pObj, i )
{
if ( !pObj->fMarkA )
continue;
Abc_ObjForEachFanout( pObj, pNext, k )
{
if ( pNext->fMarkA )
continue;
Vec_PtrPush( vMinCut, pObj );
break;
}
}
}
else
{
// change mincut to be marked fanins of the unmarked nodes
Vec_PtrClear( vMinCut );
Abc_NtkIncrementTravId(pNtk);
Abc_NtkForEachLatch( pNtk, pObj, i )
Abc_NtkMaxFlowCollectCut_rec( Abc_ObjFanin0(pObj), vMinCut );
// transfer the attribute
Abc_NtkForEachObj( pNtk, pObj, i )
pObj->fMarkA = Abc_NodeIsTravIdCurrent(pObj);
// unmark the cut nodes
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
pObj->fMarkA = 0;
}
}
/**Function*************************************************************
Synopsis [Verifies the min-cut is indeed a cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowVerifyCut_rec( Abc_Obj_t * pObj, int fForward )
{
Abc_Obj_t * pNext;
int i;
// skip visited nodes
if ( Abc_NodeIsTravIdCurrent(pObj) )
return 1;
Abc_NodeSetTravIdCurrent(pObj);
// visit the node
if ( fForward )
{
if ( Abc_ObjIsCo(pObj) )
return 0;
// explore the fanouts
Abc_ObjForEachFanout( pObj, pNext, i )
if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) )
return 0;
}
else
{
if ( Abc_ObjIsCi(pObj) )
return 0;
// explore the fanins
Abc_ObjForEachFanin( pObj, pNext, i )
if ( !Abc_NtkMaxFlowVerifyCut_rec(pNext, fForward) )
return 0;
}
return 1;
}
/**Function*************************************************************
Synopsis [Verifies the min-cut is indeed a cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMaxFlowVerifyCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut, int fForward )
{
Abc_Obj_t * pObj;
int i;
// mark the cut with the current traversal ID
Abc_NtkIncrementTravId(pNtk);
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
Abc_NodeSetTravIdCurrent( pObj );
// search from the latches for a path to the COs/CIs
Abc_NtkForEachLatch( pNtk, pObj, i )
{
if ( fForward )
{
if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanout0(pObj), fForward ) )
return 0;
}
else
{
if ( !Abc_NtkMaxFlowVerifyCut_rec( Abc_ObjFanin0(pObj), fForward ) )
return 0;
}
}
/*
{
// count the volume of the cut
int Counter = 0;
Abc_NtkForEachObj( pNtk, pObj, i )
Counter += Abc_NodeIsTravIdCurrent( pObj );
printf( "Volume = %d.\n", Counter );
}
*/
return 1;
}
/**Function*************************************************************
Synopsis [Prints the flows.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowPrintFlow( Abc_Ntk_t * pNtk, int fForward )
{
Abc_Obj_t * pLatch, * pNext;
Abc_Obj_t * pPrev = NULL; // Suppress "might be used uninitialized"
int i;
if ( fForward )
{
Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vBoxes, pLatch, i )
{
assert( !Abc_ObjFanout0(pLatch)->fMarkA );
if ( Abc_ObjGetPath(Abc_ObjFanout0(pLatch)) == NULL ) // no flow through this latch
continue;
printf( "Path = " );
for ( pNext = Abc_ObjFanout0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) )
{
printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id );
pPrev = pNext;
}
if ( !Abc_ObjIsPo(pPrev) )
printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanout0(pPrev)), Abc_ObjFanout0(pPrev)->Id );
printf( "\n" );
}
}
else
{
Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vBoxes, pLatch, i )
{
assert( !Abc_ObjFanin0(pLatch)->fMarkA );
if ( Abc_ObjGetPath(Abc_ObjFanin0(pLatch)) == NULL ) // no flow through this latch
continue;
printf( "Path = " );
for ( pNext = Abc_ObjFanin0(pLatch); pNext != (void *)1; pNext = Abc_ObjGetPath(pNext) )
{
printf( "%s(%d) ", Abc_ObjName(pNext), pNext->Id );
pPrev = pNext;
}
if ( !Abc_ObjIsPi(pPrev) )
printf( "%s(%d) ", Abc_ObjName(Abc_ObjFanin0(pPrev)), Abc_ObjFanin0(pPrev)->Id );
printf( "\n" );
}
}
}
/**Function*************************************************************
Synopsis [Prints the min-cut.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkMaxFlowPrintCut( Abc_Ntk_t * pNtk, Vec_Ptr_t * vMinCut )
{
Abc_Obj_t * pObj;
int i;
printf( "Min-cut: " );
Vec_PtrForEachEntry( Abc_Obj_t *, vMinCut, pObj, i )
printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id );
printf( "\n" );
printf( "Marked nodes: " );
Abc_NtkForEachObj( pNtk, pObj, i )
if ( pObj->fMarkA )
printf( "%s(%d) ", Abc_ObjName(pObj), pObj->Id );
printf( "\n" );
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END