/**CFile****************************************************************

  FileName    [abcNtk.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Network and node package.]

  Synopsis    [Network creation/duplication/deletion procedures.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - June 20, 2005.]

  Revision    [$Id: abcNtk.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]

***********************************************************************/

#include "abc.h"
#include "abcInt.h"
#include "base/main/main.h"
#include "map/mio/mio.h"
#include "aig/gia/gia.h"

#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#endif

ABC_NAMESPACE_IMPL_START


////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    [Creates a new Ntk.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkAlloc( Abc_NtkType_t Type, Abc_NtkFunc_t Func, int fUseMemMan )
{
    Abc_Ntk_t * pNtk;
    pNtk = ABC_ALLOC( Abc_Ntk_t, 1 );
    memset( pNtk, 0, sizeof(Abc_Ntk_t) );
    pNtk->ntkType     = Type;
    pNtk->ntkFunc     = Func;
    // start the object storage
    pNtk->vObjs       = Vec_PtrAlloc( 100 );
    pNtk->vPios       = Vec_PtrAlloc( 100 );
    pNtk->vPis        = Vec_PtrAlloc( 100 );
    pNtk->vPos        = Vec_PtrAlloc( 100 );
    pNtk->vCis        = Vec_PtrAlloc( 100 );
    pNtk->vCos        = Vec_PtrAlloc( 100 );
    pNtk->vBoxes      = Vec_PtrAlloc( 100 );
    pNtk->vLtlProperties = Vec_PtrAlloc( 100 );
    // start the memory managers
    pNtk->pMmObj      = fUseMemMan? Mem_FixedStart( sizeof(Abc_Obj_t) ) : NULL;
    pNtk->pMmStep     = fUseMemMan? Mem_StepStart( ABC_NUM_STEPS ) : NULL;
    // get ready to assign the first Obj ID
    pNtk->nTravIds    = 1;
    // start the functionality manager
    if ( !Abc_NtkIsStrash(pNtk) )
        Vec_PtrPush( pNtk->vObjs, NULL );
    if ( Abc_NtkIsStrash(pNtk) )
        pNtk->pManFunc = Abc_AigAlloc( pNtk );
    else if ( Abc_NtkHasSop(pNtk) || Abc_NtkHasBlifMv(pNtk) )
        pNtk->pManFunc = Mem_FlexStart();
#ifdef ABC_USE_CUDD
    else if ( Abc_NtkHasBdd(pNtk) )
        pNtk->pManFunc = Cudd_Init( 20, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
#endif
    else if ( Abc_NtkHasAig(pNtk) )
        pNtk->pManFunc = Hop_ManStart();
    else if ( Abc_NtkHasMapping(pNtk) )
        pNtk->pManFunc = Abc_FrameReadLibGen();
    else if ( !Abc_NtkHasBlackbox(pNtk) )
        assert( 0 );
    // name manager
    pNtk->pManName = Nm_ManCreate( 200 );
    // attribute manager
    pNtk->vAttrs = Vec_PtrStart( VEC_ATTR_TOTAL_NUM );
    // estimated AndGateDelay
    pNtk->AndGateDelay = 0.0;
    return pNtk;
}

/**Function*************************************************************

  Synopsis    [Starts a new network using existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkStartFrom( Abc_Ntk_t * pNtk, Abc_NtkType_t Type, Abc_NtkFunc_t Func )
{
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj;
    int fCopyNames, i;
    if ( pNtk == NULL )
        return NULL;
    // decide whether to copy the names
    fCopyNames = ( Type != ABC_NTK_NETLIST );
    // start the network
    pNtkNew = Abc_NtkAlloc( Type, Func, 1 );
    pNtkNew->nConstrs   = pNtk->nConstrs;
    pNtkNew->nBarBufs   = pNtk->nBarBufs;
    // duplicate the name and the spec
    pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
    pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec);
    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // map the constant nodes
    if ( Abc_NtkIsStrash(pNtk) && Abc_NtkIsStrash(pNtkNew) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, fCopyNames );
    Abc_NtkForEachPo( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, fCopyNames );
    Abc_NtkForEachBox( pNtk, pObj, i )
        Abc_NtkDupBox( pNtkNew, pObj, fCopyNames );
    // transfer logic level
    Abc_NtkForEachCi( pNtk, pObj, i )
        pObj->pCopy->Level = pObj->Level;
    // transfer the names
//    Abc_NtkTrasferNames( pNtk, pNtkNew );
    Abc_ManTimeDup( pNtk, pNtkNew );
    if ( pNtk->vOnehots )
        pNtkNew->vOnehots = (Vec_Ptr_t *)Vec_VecDupInt( (Vec_Vec_t *)pNtk->vOnehots );
    if ( pNtk->pSeqModel )
        pNtkNew->pSeqModel = Abc_CexDup( pNtk->pSeqModel, Abc_NtkLatchNum(pNtk) );
    if ( pNtk->vObjPerm )
        pNtkNew->vObjPerm = Vec_IntDup( pNtk->vObjPerm );
    pNtkNew->AndGateDelay = pNtk->AndGateDelay;
    if ( pNtkNew->pManTime && Abc_FrameReadLibGen() && pNtkNew->AndGateDelay == 0.0 )
        pNtkNew->AndGateDelay = Mio_LibraryReadDelayAigNode((Mio_Library_t *)Abc_FrameReadLibGen());
    // initialize logic level of the CIs
    if ( pNtk->AndGateDelay != 0.0 && pNtk->pManTime != NULL && pNtk->ntkType != ABC_NTK_STRASH && Type == ABC_NTK_STRASH )
    {
        Abc_NtkForEachCi( pNtk, pObj, i )
            pObj->pCopy->Level = (int)(Abc_MaxFloat(0, Abc_NodeReadArrivalWorst(pObj)) / pNtk->AndGateDelay);
    }
    // check that the CI/CO/latches are copied correctly
    assert( Abc_NtkCiNum(pNtk)    == Abc_NtkCiNum(pNtkNew) );
    assert( Abc_NtkCoNum(pNtk)    == Abc_NtkCoNum(pNtkNew) );
    assert( Abc_NtkLatchNum(pNtk) == Abc_NtkLatchNum(pNtkNew) );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Starts a new network using existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkStartFromWithLatches( Abc_Ntk_t * pNtk, Abc_NtkType_t Type, Abc_NtkFunc_t Func, int nLatches )
{
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pNode0, * pNode1;
    int fCopyNames, i;
    if ( pNtk == NULL )
        return NULL;
    assert( Abc_NtkLatchNum(pNtk) == 0 );
    // decide whether to copy the names
    fCopyNames = ( Type != ABC_NTK_NETLIST );
    // start the network
    pNtkNew = Abc_NtkAlloc( Type, Func, 1 );
    pNtkNew->nConstrs   = pNtk->nConstrs;
    pNtkNew->nBarBufs   = pNtk->nBarBufs;
    // duplicate the name and the spec
    pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
    pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec);
    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // map the constant nodes
    if ( Abc_NtkIsStrash(pNtk) && Abc_NtkIsStrash(pNtkNew) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
    // clone CIs/CIs/boxes
    for ( i = 0; i < Abc_NtkPiNum(pNtk)-nLatches; i++ )
        Abc_NtkDupObj( pNtkNew, Abc_NtkPi(pNtk, i), fCopyNames );
    for ( i = 0; i < Abc_NtkPoNum(pNtk)-nLatches; i++ )
        Abc_NtkDupObj( pNtkNew, Abc_NtkPo(pNtk, i), fCopyNames );
    for ( i = 0; i < nLatches; i++ )
    {
        pObj = Abc_NtkCreateLatch(pNtkNew);
        Abc_LatchSetInit0( pObj );
        pNode0 = Abc_NtkCreateBi(pNtkNew);
        Abc_NtkPo(pNtk, Abc_NtkPoNum(pNtk)-nLatches+i)->pCopy = pNode0;
        pNode1 = Abc_NtkCreateBo(pNtkNew);
        Abc_NtkPi(pNtk, Abc_NtkPiNum(pNtk)-nLatches+i)->pCopy = pNode1;
        Abc_ObjAddFanin( pObj, pNode0 );
        Abc_ObjAddFanin( pNode1, pObj );
        Abc_ObjAssignName( pNode0, Abc_ObjName(pNode0), NULL );
        Abc_ObjAssignName( pNode1, Abc_ObjName(pNode1), NULL );
    }
    // transfer logic level
//    Abc_NtkForEachCi( pNtk, pObj, i )
//        pObj->pCopy->Level = pObj->Level;
    // transfer the names
//    Abc_NtkTrasferNames( pNtk, pNtkNew );
    Abc_ManTimeDup( pNtk, pNtkNew );
    if ( pNtk->vOnehots )
        pNtkNew->vOnehots = (Vec_Ptr_t *)Vec_VecDupInt( (Vec_Vec_t *)pNtk->vOnehots );
    if ( pNtk->pSeqModel )
        pNtkNew->pSeqModel = Abc_CexDup( pNtk->pSeqModel, Abc_NtkLatchNum(pNtk) );
    if ( pNtk->vObjPerm )
        pNtkNew->vObjPerm = Vec_IntDup( pNtk->vObjPerm );
    pNtkNew->AndGateDelay = pNtk->AndGateDelay;
    // initialize logic level of the CIs
    if ( pNtk->AndGateDelay != 0.0 && pNtk->pManTime != NULL && pNtk->ntkType != ABC_NTK_STRASH && Type == ABC_NTK_STRASH )
    {
        Abc_NtkForEachCi( pNtk, pObj, i )
            pObj->pCopy->Level = (int)(Abc_MaxFloat(0, Abc_NodeReadArrivalWorst(pObj)) / pNtk->AndGateDelay);
    }
    // check that the CI/CO/latches are copied correctly
    assert( Abc_NtkCiNum(pNtk)    == Abc_NtkCiNum(pNtkNew) );
    assert( Abc_NtkCoNum(pNtk)    == Abc_NtkCoNum(pNtkNew) );
    assert( nLatches              == Abc_NtkLatchNum(pNtkNew) );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Starts a new network using existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkStartFromNoLatches( Abc_Ntk_t * pNtk, Abc_NtkType_t Type, Abc_NtkFunc_t Func )
{
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj;
    int i;
    if ( pNtk == NULL )
        return NULL;
    assert( Type != ABC_NTK_NETLIST );
    // start the network
    pNtkNew = Abc_NtkAlloc( Type, Func, 1 );
    pNtkNew->nConstrs   = pNtk->nConstrs;
    pNtkNew->nBarBufs   = pNtk->nBarBufs;
    // duplicate the name and the spec
    pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
    pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec);
    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // map the constant nodes
    if ( Abc_NtkIsStrash(pNtk) && Abc_NtkIsStrash(pNtkNew) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 1 );
    Abc_NtkForEachPo( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 1 );
    Abc_NtkForEachBox( pNtk, pObj, i )
    {
        if ( Abc_ObjIsLatch(pObj) )
            continue;
        Abc_NtkDupBox(pNtkNew, pObj, 1);
    }
    if ( pNtk->vObjPerm )
        pNtkNew->vObjPerm = Vec_IntDup( pNtk->vObjPerm );
    pNtkNew->AndGateDelay = pNtk->AndGateDelay;
    // transfer the names
//    Abc_NtkTrasferNamesNoLatches( pNtk, pNtkNew );
    Abc_ManTimeDup( pNtk, pNtkNew );
    // check that the CI/CO/latches are copied correctly
    assert( Abc_NtkPiNum(pNtk) == Abc_NtkPiNum(pNtkNew) );
    assert( Abc_NtkPoNum(pNtk) == Abc_NtkPoNum(pNtkNew) );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Finalizes the network using the existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkFinalize( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew )
{
    Abc_Obj_t * pObj, * pDriver, * pDriverNew;
    int i;
    // set the COs of the strashed network
    Abc_NtkForEachCo( pNtk, pObj, i )
    {
        pDriver    = Abc_ObjFanin0Ntk( Abc_ObjFanin0(pObj) );
        pDriverNew = Abc_ObjNotCond(pDriver->pCopy, Abc_ObjFaninC0(pObj));
        Abc_ObjAddFanin( pObj->pCopy, pDriverNew );
    }
    // duplicate timing manager
    if ( pNtk->pManTime )
        Abc_NtkTimeInitialize( pNtkNew, pNtk );
    if ( pNtk->vPhases )
        Abc_NtkTransferPhases( pNtkNew, pNtk );
    if ( pNtk->pWLoadUsed )
        pNtkNew->pWLoadUsed = Abc_UtilStrsav( pNtk->pWLoadUsed );
}

/**Function*************************************************************

  Synopsis    [Starts a new network using existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkStartRead( char * pName )
{
    Abc_Ntk_t * pNtkNew; 
    // allocate the empty network
    pNtkNew = Abc_NtkAlloc( ABC_NTK_NETLIST, ABC_FUNC_SOP, 1 );
    // set the specs
    pNtkNew->pName = Extra_FileNameGeneric(pName);
    pNtkNew->pSpec = Extra_UtilStrsav(pName);
    if ( pNtkNew->pName == NULL || strlen(pNtkNew->pName) == 0 )
    {
        ABC_FREE( pNtkNew->pName );
        pNtkNew->pName = Extra_UtilStrsav("unknown");
    }
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Finalizes the network using the existing network as a model.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkFinalizeRead( Abc_Ntk_t * pNtk )
{
    Abc_Obj_t * pBox, * pObj, * pTerm, * pNet;
    int i;
    if ( Abc_NtkHasBlackbox(pNtk) && Abc_NtkBoxNum(pNtk) == 0 )
    {
        pBox = Abc_NtkCreateBlackbox(pNtk);
        Abc_NtkForEachPi( pNtk, pObj, i )
        {
            pTerm = Abc_NtkCreateBi(pNtk);
            Abc_ObjAddFanin( pTerm, Abc_ObjFanout0(pObj) );
            Abc_ObjAddFanin( pBox, pTerm );
        }
        Abc_NtkForEachPo( pNtk, pObj, i )
        {
            pTerm = Abc_NtkCreateBo(pNtk);
            Abc_ObjAddFanin( pTerm, pBox );
            Abc_ObjAddFanin( Abc_ObjFanin0(pObj), pTerm );
        }
        return;
    }
    assert( Abc_NtkIsNetlist(pNtk) );

    // check if constant 0 net is used
    pNet = Abc_NtkFindNet( pNtk, "1\'b0" );
    if ( pNet )
    {
        if ( Abc_ObjFanoutNum(pNet) == 0 )
            Abc_NtkDeleteObj(pNet);
        else if ( Abc_ObjFaninNum(pNet) == 0 )
            Abc_ObjAddFanin( pNet, Abc_NtkCreateNodeConst0(pNtk) );
    }
    // check if constant 1 net is used
    pNet = Abc_NtkFindNet( pNtk, "1\'b1" );
    if ( pNet )
    {
        if ( Abc_ObjFanoutNum(pNet) == 0 )
            Abc_NtkDeleteObj(pNet);
        else if ( Abc_ObjFaninNum(pNet) == 0 )
            Abc_ObjAddFanin( pNet, Abc_NtkCreateNodeConst1(pNtk) );
    }
    // fix the net drivers
    Abc_NtkFixNonDrivenNets( pNtk );

    // reorder the CI/COs to PI/POs first
    Abc_NtkOrderCisCos( pNtk );
}

/**Function*************************************************************

  Synopsis    [Duplicate the network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkDup( Abc_Ntk_t * pNtk )
{
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin;
    int i, k;
    if ( pNtk == NULL )
        return NULL;
    // start the network
    pNtkNew = Abc_NtkStartFrom( pNtk, pNtk->ntkType, pNtk->ntkFunc );
    // copy the internal nodes
    if ( Abc_NtkIsStrash(pNtk) )
    {
        // copy the AND gates
        Abc_AigForEachAnd( pNtk, pObj, i )
            pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
        // relink the choice nodes
        Abc_AigForEachAnd( pNtk, pObj, i )
            if ( pObj->pData )
                pObj->pCopy->pData = ((Abc_Obj_t *)pObj->pData)->pCopy;
        // relink the CO nodes
        Abc_NtkForEachCo( pNtk, pObj, i )
            Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
        // get the number of nodes before and after
        if ( Abc_NtkNodeNum(pNtk) != Abc_NtkNodeNum(pNtkNew) )
            printf( "Warning: Structural hashing during duplication reduced %d nodes (this is a minor bug).\n",
                Abc_NtkNodeNum(pNtk) - Abc_NtkNodeNum(pNtkNew) );
    }
    else
    {
        // duplicate the nets and nodes (CIs/COs/latches already dupped)
        Abc_NtkForEachObj( pNtk, pObj, i )
            if ( pObj->pCopy == NULL )
                Abc_NtkDupObj(pNtkNew, pObj, Abc_NtkHasBlackbox(pNtk) && Abc_ObjIsNet(pObj));
        // reconnect all objects (no need to transfer attributes on edges)
        Abc_NtkForEachObj( pNtk, pObj, i )
            if ( !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) )
                Abc_ObjForEachFanin( pObj, pFanin, k )
                    Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
    }
    // duplicate the EXDC Ntk
    if ( pNtk->pExdc )
        pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
    if ( pNtk->pExcare )
        pNtkNew->pExcare = Abc_NtkDup( (Abc_Ntk_t *)pNtk->pExcare );
    // duplicate timing manager
    if ( pNtk->pManTime )
        Abc_NtkTimeInitialize( pNtkNew, pNtk );
    if ( pNtk->vPhases )
        Abc_NtkTransferPhases( pNtkNew, pNtk );
    if ( pNtk->pWLoadUsed )
        pNtkNew->pWLoadUsed = Abc_UtilStrsav( pNtk->pWLoadUsed );
    // check correctness
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" );
    pNtk->pCopy = pNtkNew;
    return pNtkNew;
}
Abc_Ntk_t * Abc_NtkDupDfs( Abc_Ntk_t * pNtk )
{
    Vec_Ptr_t * vNodes;
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin;
    int i, k;
    if ( pNtk == NULL )
        return NULL;
    assert( !Abc_NtkIsStrash(pNtk) && !Abc_NtkIsNetlist(pNtk) );
    // start the network
    pNtkNew = Abc_NtkStartFrom( pNtk, pNtk->ntkType, pNtk->ntkFunc );
    // copy the internal nodes
    vNodes = Abc_NtkDfs( pNtk, 0 );
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Vec_PtrFree( vNodes );
    // reconnect all objects (no need to transfer attributes on edges)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) )
            Abc_ObjForEachFanin( pObj, pFanin, k )
                if ( pObj->pCopy && pFanin->pCopy )
                    Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
    // duplicate the EXDC Ntk
    if ( pNtk->pExdc )
        pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
    if ( pNtk->pExcare )
        pNtkNew->pExcare = Abc_NtkDup( (Abc_Ntk_t *)pNtk->pExcare );
    // duplicate timing manager
    if ( pNtk->pManTime )
        Abc_NtkTimeInitialize( pNtkNew, pNtk );
    if ( pNtk->vPhases )
        Abc_NtkTransferPhases( pNtkNew, pNtk );
    if ( pNtk->pWLoadUsed )
        pNtkNew->pWLoadUsed = Abc_UtilStrsav( pNtk->pWLoadUsed );
    // check correctness
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" );
    pNtk->pCopy = pNtkNew;
    return pNtkNew;
}
Abc_Ntk_t * Abc_NtkDupDfsNoBarBufs( Abc_Ntk_t * pNtk )
{
    Vec_Ptr_t * vNodes;
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin;
    int i, k;
    if ( pNtk == NULL )
        return NULL;
    assert( Abc_NtkIsLogic(pNtk) );
    assert( pNtk->nBarBufs2 > 0 );
    // start the network
    pNtkNew = Abc_NtkStartFrom( pNtk, pNtk->ntkType, pNtk->ntkFunc );
    // copy the internal nodes
    vNodes = Abc_NtkDfs2( pNtk );
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
        if ( Abc_ObjIsBarBuf(pObj) )
            pObj->pCopy = Abc_ObjFanin0(pObj)->pCopy;
        else
            Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Vec_PtrFree( vNodes );
    // reconnect all objects (no need to transfer attributes on edges)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) && !Abc_ObjIsBarBuf(pObj) )
            Abc_ObjForEachFanin( pObj, pFanin, k )
                if ( pObj->pCopy && pFanin->pCopy )
                    Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
    // duplicate the EXDC Ntk
    if ( pNtk->pExdc )
        pNtkNew->pExdc = Abc_NtkDup( pNtk->pExdc );
    if ( pNtk->pExcare )
        pNtkNew->pExcare = Abc_NtkDup( (Abc_Ntk_t *)pNtk->pExcare );
    // duplicate timing manager
    if ( pNtk->pManTime )
        Abc_NtkTimeInitialize( pNtkNew, pNtk );
    if ( pNtk->vPhases )
        Abc_NtkTransferPhases( pNtkNew, pNtk );
    if ( pNtk->pWLoadUsed )
        pNtkNew->pWLoadUsed = Abc_UtilStrsav( pNtk->pWLoadUsed );
    // check correctness
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" );
    pNtk->pCopy = pNtkNew;
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Duplicate the AIG while adding latches.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkRestrashWithLatches( Abc_Ntk_t * pNtk, int nLatches )
{
    Abc_Ntk_t * pNtkAig;
    Abc_Obj_t * pObj;
    int i;
    assert( Abc_NtkIsStrash(pNtk) );
    // start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
    pNtkAig = Abc_NtkStartFromWithLatches( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG, nLatches );
    // restrash the nodes (assuming a topological order of the old network)
    Abc_NtkForEachNode( pNtk, pObj, i )
        pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
    // finalize the network
    Abc_NtkFinalize( pNtk, pNtkAig );
    // make sure everything is okay
    if ( !Abc_NtkCheck( pNtkAig ) )
    {
        printf( "Abc_NtkStrash: The network check has failed.\n" );
        Abc_NtkDelete( pNtkAig );
        return NULL;
    }
    return pNtkAig;

}

/**Function*************************************************************

  Synopsis    [Duplicate the network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkDupTransformMiter( Abc_Ntk_t * pNtk )
{
    Abc_Ntk_t * pNtkNew;
    Abc_Obj_t * pObj, * pObj2, * pMiter;
    int i;
    assert( Abc_NtkIsStrash(pNtk) );
    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    pNtkNew->nConstrs   = pNtk->nConstrs;
    pNtkNew->nBarBufs   = pNtk->nBarBufs;
    // duplicate the name and the spec
    pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);
    pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec);
    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // map the constant nodes
     Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 1 );
    Abc_NtkForEachPo( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 1 ), i++;
    Abc_NtkForEachBox( pNtk, pObj, i )
        Abc_NtkDupBox( pNtkNew, pObj, 1 );
    // copy the AND gates
    Abc_AigForEachAnd( pNtk, pObj, i )
        pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
    // create new miters
    Abc_NtkForEachPo( pNtk, pObj, i )
    {
        pObj2 = Abc_NtkPo( pNtk, ++i );
        pMiter = Abc_AigXor( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild0Copy(pObj2) );
        Abc_ObjAddFanin( pObj->pCopy, pMiter );
    }
    Abc_NtkForEachLatchInput( pNtk, pObj, i )
        Abc_ObjAddFanin( pObj->pCopy, Abc_ObjChild0Copy(pObj) );
    // cleanup
    Abc_AigCleanup( (Abc_Aig_t *)pNtkNew->pManFunc );
    // check that the CI/CO/latches are copied correctly
    assert( Abc_NtkPiNum(pNtk) == Abc_NtkPiNum(pNtkNew) );
    assert( Abc_NtkPoNum(pNtk) == 2*Abc_NtkPoNum(pNtkNew) );
    assert( Abc_NtkLatchNum(pNtk) == Abc_NtkLatchNum(pNtkNew) );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Duplicate the network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkDouble( Abc_Ntk_t * pNtk )
{
    char Buffer[500];
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin;
    int i, k;
    assert( Abc_NtkIsLogic(pNtk) );

    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    sprintf( Buffer, "%s%s", pNtk->pName, "_2x" );
    pNtkNew->pName = Extra_UtilStrsav(Buffer);

    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Abc_NtkForEachPo( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Abc_NtkForEachBox( pNtk, pObj, i )
        Abc_NtkDupBox( pNtkNew, pObj, 0 );
    // copy the internal nodes
    // duplicate the nets and nodes (CIs/COs/latches already dupped)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( pObj->pCopy == NULL )
            Abc_NtkDupObj(pNtkNew, pObj, 0);
    // reconnect all objects (no need to transfer attributes on edges)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) )
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );

    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Abc_NtkForEachPo( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 0 );
    Abc_NtkForEachBox( pNtk, pObj, i )
        Abc_NtkDupBox( pNtkNew, pObj, 0 );
    // copy the internal nodes
    // duplicate the nets and nodes (CIs/COs/latches already dupped)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( pObj->pCopy == NULL )
            Abc_NtkDupObj(pNtkNew, pObj, 0);
    // reconnect all objects (no need to transfer attributes on edges)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) )
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );

    // assign names
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        Abc_ObjAssignName( Abc_NtkCi(pNtkNew,                      i), "1_", Abc_ObjName(pObj) );
        Abc_ObjAssignName( Abc_NtkCi(pNtkNew, Abc_NtkCiNum(pNtk) + i), "2_", Abc_ObjName(pObj) );
    }
    Abc_NtkForEachCo( pNtk, pObj, i )
    {
        Abc_ObjAssignName( Abc_NtkCo(pNtkNew,                      i), "1_", Abc_ObjName(pObj) );
        Abc_ObjAssignName( Abc_NtkCo(pNtkNew, Abc_NtkCoNum(pNtk) + i), "2_", Abc_ObjName(pObj) );
    }
    Abc_NtkOrderCisCos( pNtkNew );

    // perform the final check
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Duplicate the bottom levels of the network.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkBottom( Abc_Ntk_t * pNtk, int Level )
{
    char Buffer[500];
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin;
    int i, k;
    assert( Abc_NtkIsLogic(pNtk) );
    assert( Abc_NtkLatchNum(pNtk) == 0 );

    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    sprintf( Buffer, "%s%s", pNtk->pName, "_bot" );
    pNtkNew->pName = Extra_UtilStrsav(Buffer);

    // clean the node copy fields
    Abc_NtkCleanCopy( pNtk );
    // clone CIs/CIs/boxes
    Abc_NtkForEachPi( pNtk, pObj, i )
        Abc_NtkDupObj( pNtkNew, pObj, 1 );

    // copy the internal nodes
    // duplicate the nets and nodes (CIs/COs/latches already dupped)
    Abc_NtkForEachObj( pNtk, pObj, i )
        if ( pObj->pCopy == NULL && Abc_ObjIsNode(pObj) && Abc_ObjLevel(pObj) <= Level )
            Abc_NtkDupObj(pNtkNew, pObj, 0);
    // reconnect all objects (no need to transfer attributes on edges)
    Abc_NtkForEachObj( pNtk, pObj, i )
        Abc_ObjForEachFanin( pObj, pFanin, k )
            if ( pObj->pCopy && pFanin->pCopy )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );

    // create new primary outputs
    Abc_NtkForEachObj( pNtk, pObj, i )
        Abc_ObjForEachFanin( pObj, pFanin, k )
            if ( !pObj->pCopy && pFanin->pCopy && Abc_ObjIsNode(pFanin) )
            {
                Abc_Obj_t * pNodeNew = Abc_NtkCreatePo(pNtkNew);
                Abc_ObjAddFanin( pNodeNew, pFanin->pCopy );
                Abc_ObjAssignName( pNodeNew, Abc_ObjName(pNodeNew), NULL );
            }

    // perform the final check
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkBottom(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Attaches the second network at the bottom of the first.]

  Description [Returns the first network. Deletes the second network.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkAttachBottom( Abc_Ntk_t * pNtkTop, Abc_Ntk_t * pNtkBottom )
{
    Abc_Obj_t * pObj, * pFanin, * pBuffer;
    Vec_Ptr_t * vNodes;
    int i, k;
    assert( pNtkBottom != NULL );
    if ( pNtkTop == NULL )
        return pNtkBottom;
    // make sure the networks are combinational
    assert( Abc_NtkPiNum(pNtkTop) == Abc_NtkCiNum(pNtkTop) );
    assert( Abc_NtkPiNum(pNtkBottom) == Abc_NtkCiNum(pNtkBottom) );
    // make sure the POs of the bottom correspond to the PIs of the top
    assert( Abc_NtkPoNum(pNtkBottom) == Abc_NtkPiNum(pNtkTop) );
    assert( Abc_NtkPiNum(pNtkBottom) <  Abc_NtkPiNum(pNtkTop) );
    // add buffers for the PIs of the top - save results in the POs of the bottom
    Abc_NtkForEachPi( pNtkTop, pObj, i )
    {
        pBuffer = Abc_NtkCreateNodeBuf( pNtkTop, NULL );
        Abc_ObjTransferFanout( pObj, pBuffer );
        Abc_NtkPo(pNtkBottom, i)->pCopy = pBuffer;
    }
    // remove useless PIs of the top
    for ( i = Abc_NtkPiNum(pNtkTop) - 1; i >= Abc_NtkPiNum(pNtkBottom); i-- )
        Abc_NtkDeleteObj( Abc_NtkPi(pNtkTop, i) );
    assert( Abc_NtkPiNum(pNtkBottom) == Abc_NtkPiNum(pNtkTop) );
    // copy the bottom network
    Abc_NtkForEachPi( pNtkBottom, pObj, i )
        Abc_NtkPi(pNtkBottom, i)->pCopy = Abc_NtkPi(pNtkTop, i);
    // construct all nodes
    vNodes = Abc_NtkDfs( pNtkBottom, 0 );
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
    {
        Abc_NtkDupObj(pNtkTop, pObj, 0);
        Abc_ObjForEachFanin( pObj, pFanin, k )
            Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
    }
    Vec_PtrFree( vNodes );
    // connect the POs
    Abc_NtkForEachPo( pNtkBottom, pObj, i )
        Abc_ObjAddFanin( pObj->pCopy, Abc_ObjFanin0(pObj)->pCopy );
    // delete old network
    Abc_NtkDelete( pNtkBottom );
    // return the network
    if ( !Abc_NtkCheck( pNtkTop ) )
        fprintf( stdout, "Abc_NtkAttachBottom(): Network check has failed.\n" );
    return pNtkTop;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of one logic cone.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateCone( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, char * pNodeName, int fUseAllCis )
{
    Abc_Ntk_t * pNtkNew; 
    Vec_Ptr_t * vNodes;
    Abc_Obj_t * pObj, * pFanin, * pNodeCoNew;
    char Buffer[1000];
    int i, k;

    assert( Abc_NtkIsLogic(pNtk) || Abc_NtkIsStrash(pNtk) );
    assert( Abc_ObjIsNode(pNode) || (Abc_NtkIsStrash(pNtk) && (Abc_AigNodeIsConst(pNode) || Abc_ObjIsCi(pNode)))  ); 
    
    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    // set the name
    sprintf( Buffer, "%s_%s", pNtk->pName, pNodeName );
    pNtkNew->pName = Extra_UtilStrsav(Buffer);

    // establish connection between the constant nodes
    if ( Abc_NtkIsStrash(pNtk) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);

    // collect the nodes in the TFI of the output (mark the TFI)
    vNodes = Abc_NtkDfsNodes( pNtk, &pNode, 1 );
    // create the PIs
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        if ( fUseAllCis || Abc_NodeIsTravIdCurrent(pObj) ) // TravId is set by DFS
        {
            pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
            Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
        }
    }
    // add the PO corresponding to this output
    pNodeCoNew = Abc_NtkCreatePo( pNtkNew );
    Abc_ObjAssignName( pNodeCoNew, pNodeName, NULL );
    // copy the nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
    {
        // if it is an AIG, add to the hash table
        if ( Abc_NtkIsStrash(pNtk) )
        {
            pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
        }
        else
        {
            Abc_NtkDupObj( pNtkNew, pObj, 0 );
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
        }
    }
    // connect the internal nodes to the new CO
    Abc_ObjAddFanin( pNodeCoNew, pNode->pCopy );
    Vec_PtrFree( vNodes );

    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateCone(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of several logic cones.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateConeArray( Abc_Ntk_t * pNtk, Vec_Ptr_t * vRoots, int fUseAllCis )
{
    Abc_Ntk_t * pNtkNew; 
    Vec_Ptr_t * vNodes;
    Abc_Obj_t * pObj, * pFanin, * pNodeCoNew;
    char Buffer[1000];
    int i, k;

    assert( Abc_NtkIsLogic(pNtk) || Abc_NtkIsStrash(pNtk) );
    
    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    // set the name
    sprintf( Buffer, "%s_part", pNtk->pName );
    pNtkNew->pName = Extra_UtilStrsav(Buffer);

    // establish connection between the constant nodes
    if ( Abc_NtkIsStrash(pNtk) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);

    // collect the nodes in the TFI of the output (mark the TFI)
    vNodes = Abc_NtkDfsNodes( pNtk, (Abc_Obj_t **)Vec_PtrArray(vRoots), Vec_PtrSize(vRoots) );

    // create the PIs
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        if ( fUseAllCis || Abc_NodeIsTravIdCurrent(pObj) ) // TravId is set by DFS
        {
            pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
            Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
        }
    }

    // copy the nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
    {
        // if it is an AIG, add to the hash table
        if ( Abc_NtkIsStrash(pNtk) )
        {
            pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
        }
        else
        {
            Abc_NtkDupObj( pNtkNew, pObj, 0 );
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
        }
    }
    Vec_PtrFree( vNodes );

    // add the POs corresponding to the root nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vRoots, pObj, i )
    {
        // create the PO node
        pNodeCoNew = Abc_NtkCreatePo( pNtkNew );
        // connect the internal nodes to the new CO
        if ( Abc_ObjIsCo(pObj) )
            Abc_ObjAddFanin( pNodeCoNew, Abc_ObjChild0Copy(pObj) );
        else
            Abc_ObjAddFanin( pNodeCoNew, pObj->pCopy );
        // assign the name
        Abc_ObjAssignName( pNodeCoNew, Abc_ObjName(pObj), NULL );
    }

    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateConeArray(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Adds new nodes to the cone.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkAppendToCone( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk, Vec_Ptr_t * vRoots )
{
    Vec_Ptr_t * vNodes;
    Abc_Obj_t * pObj;
    int i, iNodeId;

    assert( Abc_NtkIsStrash(pNtkNew) );
    assert( Abc_NtkIsStrash(pNtk) );

    // collect the nodes in the TFI of the output (mark the TFI)
    vNodes = Abc_NtkDfsNodes( pNtk, (Abc_Obj_t **)Vec_PtrArray(vRoots), Vec_PtrSize(vRoots) );

    // establish connection between the constant nodes
    Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);

    // create the PIs
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        // skip CIs that are not used
        if ( !Abc_NodeIsTravIdCurrent(pObj) )
            continue;
        // find the corresponding CI in the new network
        iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PI, ABC_OBJ_BO );
        if ( iNodeId == -1 )
        {
            pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
            Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
        }
        else
            pObj->pCopy = Abc_NtkObj( pNtkNew, iNodeId );
    }

    // copy the nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
        pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
    Vec_PtrFree( vNodes );

    // do not add the COs
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkAppendToCone(): Network check has failed.\n" );
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of MFFC of one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateMffc( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, char * pNodeName )
{
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFanin, * pNodeCoNew;
    Vec_Ptr_t * vCone, * vSupp;
    char Buffer[1000];
    int i, k;

    assert( Abc_NtkIsLogic(pNtk) || Abc_NtkIsStrash(pNtk) );
    assert( Abc_ObjIsNode(pNode) ); 
    
    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    // set the name
    sprintf( Buffer, "%s_%s", pNtk->pName, pNodeName );
    pNtkNew->pName = Extra_UtilStrsav(Buffer);

    // establish connection between the constant nodes
    if ( Abc_NtkIsStrash(pNtk) )
        Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew);

    // collect the nodes in MFFC
    vCone = Vec_PtrAlloc( 100 );
    vSupp = Vec_PtrAlloc( 100 );
    Abc_NodeDeref_rec( pNode );
    Abc_NodeMffcConeSupp( pNode, vCone, vSupp );
    Abc_NodeRef_rec( pNode );
    // create the PIs
    Vec_PtrForEachEntry( Abc_Obj_t *, vSupp, pObj, i )
    {
        pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
        Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
    }
    // create the PO
    pNodeCoNew = Abc_NtkCreatePo( pNtkNew );
    Abc_ObjAssignName( pNodeCoNew, pNodeName, NULL );
    // copy the nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vCone, pObj, i )
    {
        // if it is an AIG, add to the hash table
        if ( Abc_NtkIsStrash(pNtk) )
        {
            pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
        }
        else
        {
            Abc_NtkDupObj( pNtkNew, pObj, 0 );
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy );
        }
    }
    // connect the topmost node
    Abc_ObjAddFanin( pNodeCoNew, pNode->pCopy );
    Vec_PtrFree( vCone );
    Vec_PtrFree( vSupp );

    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateMffc(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the miter composed of one multi-output cone.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateTarget( Abc_Ntk_t * pNtk, Vec_Ptr_t * vRoots, Vec_Int_t * vValues )
{
    Vec_Ptr_t * vNodes;
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pFinal, * pOther, * pNodePo;
    int i;

    assert( Abc_NtkIsLogic(pNtk) );
    
    // start the network
    Abc_NtkCleanCopy( pNtk );
    pNtkNew = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
    pNtkNew->pName = Extra_UtilStrsav(pNtk->pName);

    // collect the nodes in the TFI of the output
    vNodes = Abc_NtkDfsNodes( pNtk, (Abc_Obj_t **)vRoots->pArray, vRoots->nSize );
    // create the PIs
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
        Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
    }
    // copy the nodes
    Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
        pObj->pCopy = Abc_NodeStrash( pNtkNew, pObj, 0 );
    Vec_PtrFree( vNodes );

    // add the PO
    pFinal = Abc_AigConst1( pNtkNew );
    Vec_PtrForEachEntry( Abc_Obj_t *, vRoots, pObj, i )
    {
        if ( Abc_ObjIsCo(pObj) )
            pOther = Abc_ObjFanin0(pObj)->pCopy;
        else
            pOther = pObj->pCopy;
        if ( Vec_IntEntry(vValues, i) == 0 )
            pOther = Abc_ObjNot(pOther);
        pFinal = Abc_AigAnd( (Abc_Aig_t *)pNtkNew->pManFunc, pFinal, pOther );
    }

    // add the PO corresponding to this output
    pNodePo = Abc_NtkCreatePo( pNtkNew );
    Abc_ObjAddFanin( pNodePo, pFinal );
    Abc_ObjAssignName( pNodePo, "miter", NULL );
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateTarget(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateFromNode( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode )
{    
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pFanin, * pNodePo;
    int i;
    // start the network
    pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
    pNtkNew->pName = Extra_UtilStrsav(Abc_ObjName(pNode));
    // add the PIs corresponding to the fanins of the node
    Abc_ObjForEachFanin( pNode, pFanin, i )
    {
        pFanin->pCopy = Abc_NtkCreatePi( pNtkNew );
        Abc_ObjAssignName( pFanin->pCopy, Abc_ObjName(pFanin), NULL );
    }
    // duplicate and connect the node
    pNode->pCopy = Abc_NtkDupObj( pNtkNew, pNode, 0 );
    Abc_ObjForEachFanin( pNode, pFanin, i )
        Abc_ObjAddFanin( pNode->pCopy, pFanin->pCopy );
    // create the only PO
    pNodePo = Abc_NtkCreatePo( pNtkNew );
    Abc_ObjAddFanin( pNodePo, pNode->pCopy );
    Abc_ObjAssignName( pNodePo, Abc_ObjName(pNode), NULL );
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateFromNode(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateFromRange( Abc_Ntk_t * pNtk )
{    
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pObj, * pNodeNew, * pNodePo;
    Gia_Man_t * p = Abc_NtkClpGia( pNtk );  int i;
    Vec_Str_t * vStr = Gia_ManComputeRange( p );
    Gia_ManStop( p );
    pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 );
    pNtkNew->pName = Extra_UtilStrsav("range");
    Abc_NtkForEachCo( pNtk, pObj, i )
        Abc_ObjAssignName( Abc_NtkCreatePi(pNtkNew), Abc_ObjName(pObj), NULL );
    pNodeNew = Abc_NtkCreateObj( pNtkNew, ABC_OBJ_NODE );
    pNodeNew->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkNew->pManFunc, Vec_StrArray(vStr) );
    Vec_StrFree( vStr );
    Abc_NtkForEachCi( pNtkNew, pObj, i )
        Abc_ObjAddFanin( pNodeNew, pObj );
    pNodePo = Abc_NtkCreatePo( pNtkNew );
    Abc_ObjAddFanin( pNodePo, pNodeNew );
    Abc_ObjAssignName( pNodePo, "range", NULL );
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateFromNode(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of one node with the given SOP.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateWithNode( char * pSop )
{    
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pFanin, * pNode, * pNodePo;
    Vec_Ptr_t * vNames;
    int i, nVars;
    // start the network
    pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 );
    pNtkNew->pName = Extra_UtilStrsav("ex");
    // create PIs
    Vec_PtrPush( pNtkNew->vObjs, NULL );
    nVars = Abc_SopGetVarNum( pSop );
    vNames = Abc_NodeGetFakeNames( nVars );
    for ( i = 0; i < nVars; i++ )
        Abc_ObjAssignName( Abc_NtkCreatePi(pNtkNew), (char *)Vec_PtrEntry(vNames, i), NULL );
    Abc_NodeFreeNames( vNames );
    // create the node, add PIs as fanins, set the function
    pNode = Abc_NtkCreateNode( pNtkNew );
    Abc_NtkForEachPi( pNtkNew, pFanin, i )
        Abc_ObjAddFanin( pNode, pFanin );
    pNode->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkNew->pManFunc, pSop );
    // create the only PO
    pNodePo = Abc_NtkCreatePo(pNtkNew);
    Abc_ObjAddFanin( pNodePo, pNode );
    Abc_ObjAssignName( pNodePo, "F", NULL );
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateWithNode(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Creates the network composed of one node with the given SOP.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateWithNodes( Vec_Ptr_t * vSop )
{    
    Abc_Ntk_t * pNtkNew; 
    Abc_Obj_t * pFanin, * pNode, * pNodePo;
    Vec_Ptr_t * vNames;
    int i, k, nVars; char Buffer[100];
    char * pSop = (char *)Vec_PtrEntry(vSop, 0);
    // start the network
    pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 );
    pNtkNew->pName = Extra_UtilStrsav("ex");
    // create PIs
    Vec_PtrPush( pNtkNew->vObjs, NULL );
    nVars = Abc_SopGetVarNum( pSop );
    vNames = Abc_NodeGetFakeNames( nVars );
    for ( i = 0; i < nVars; i++ )
        Abc_ObjAssignName( Abc_NtkCreatePi(pNtkNew), (char *)Vec_PtrEntry(vNames, i), NULL );
    Abc_NodeFreeNames( vNames );
    // create the node, add PIs as fanins, set the function
    Vec_PtrForEachEntry( char *, vSop, pSop, i )
    {
        pNode = Abc_NtkCreateNode( pNtkNew );
        Abc_NtkForEachPi( pNtkNew, pFanin, k )
            Abc_ObjAddFanin( pNode, pFanin );
        pNode->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkNew->pManFunc, pSop );
        // create the only PO
        pNodePo = Abc_NtkCreatePo(pNtkNew);
        Abc_ObjAddFanin( pNodePo, pNode );
        sprintf( Buffer, "F%d", i );
        Abc_ObjAssignName( pNodePo, Buffer, NULL );
    }
    if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateWithNode(): Network check has failed.\n" );
    return pNtkNew;
}

/**Function*************************************************************

  Synopsis    [Deletes the Ntk.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkDelete( Abc_Ntk_t * pNtk )
{
    Abc_Obj_t * pObj;
    void * pAttrMan;
    int TotalMemory, i;
    int fWarning = 0;
//    int LargePiece = (4 << ABC_NUM_STEPS);
    if ( pNtk == NULL )
        return;
    // free EXDC Ntk
    if ( pNtk->pExdc )
        Abc_NtkDelete( pNtk->pExdc );
    if ( pNtk->pExcare )
        Abc_NtkDelete( (Abc_Ntk_t *)pNtk->pExcare );
    // dereference the BDDs
    if ( Abc_NtkHasBdd(pNtk) )
    {
#ifdef ABC_USE_CUDD
        Abc_NtkForEachNode( pNtk, pObj, i )
            Cudd_RecursiveDeref( (DdManager *)pNtk->pManFunc, (DdNode *)pObj->pData );
#endif
    }
    // make sure all the marks are clean
    Abc_NtkForEachObj( pNtk, pObj, i )
    {
        // free large fanout arrays
//        if ( pNtk->pMmObj && pObj->vFanouts.nCap * 4 > LargePiece )
//            ABC_FREE( pObj->vFanouts.pArray );
        // these flags should be always zero
        // if this is not true, something is wrong somewhere
//        assert( pObj->fMarkA == 0 );
//        assert( pObj->fMarkB == 0 );
//        assert( pObj->fMarkC == 0 );
        if ( !fWarning && (pObj->fMarkA || pObj->fMarkB || pObj->fMarkC) )
            { printf( "Flags A, B, or C are not zero.\n" ), fWarning = 1; }
    }
    // free the nodes
    if ( pNtk->pMmStep == NULL )
    {
        Abc_NtkForEachObj( pNtk, pObj, i )
        {
            ABC_FREE( pObj->vFanouts.pArray );
            ABC_FREE( pObj->vFanins.pArray );
        }
    }
    if ( pNtk->pMmObj == NULL )
    {
        Abc_NtkForEachObj( pNtk, pObj, i )
            ABC_FREE( pObj );
    }
        
    // free the arrays
    Vec_PtrFree( pNtk->vPios );
    Vec_PtrFree( pNtk->vPis );
    Vec_PtrFree( pNtk->vPos );
    Vec_PtrFree( pNtk->vCis );
    Vec_PtrFree( pNtk->vCos );
    Vec_PtrFree( pNtk->vObjs );
    Vec_PtrFree( pNtk->vBoxes );
    ABC_FREE( pNtk->vTravIds.pArray );
    if ( pNtk->vLevelsR ) Vec_IntFree( pNtk->vLevelsR );
    ABC_FREE( pNtk->pModel );
    ABC_FREE( pNtk->pSeqModel );
    if ( pNtk->vSeqModelVec )
        Vec_PtrFreeFree( pNtk->vSeqModelVec );
    TotalMemory  = 0;
    TotalMemory += pNtk->pMmObj? Mem_FixedReadMemUsage(pNtk->pMmObj)  : 0;
    TotalMemory += pNtk->pMmStep? Mem_StepReadMemUsage(pNtk->pMmStep) : 0;
//    fprintf( stdout, "The total memory allocated internally by the network = %0.2f MB.\n", ((double)TotalMemory)/(1<<20) );
    // free the storage 
    if ( pNtk->pMmObj )
        Mem_FixedStop( pNtk->pMmObj, 0 );
    if ( pNtk->pMmStep )
        Mem_StepStop ( pNtk->pMmStep, 0 );
    // name manager
    Nm_ManFree( pNtk->pManName );
    // free the timing manager
    if ( pNtk->pManTime )
        Abc_ManTimeStop( pNtk->pManTime );
    Vec_IntFreeP( &pNtk->vPhases );
    // start the functionality manager
    if ( Abc_NtkIsStrash(pNtk) )
        Abc_AigFree( (Abc_Aig_t *)pNtk->pManFunc );
    else if ( Abc_NtkHasSop(pNtk) || Abc_NtkHasBlifMv(pNtk) )
        Mem_FlexStop( (Mem_Flex_t *)pNtk->pManFunc, 0 );
#ifdef ABC_USE_CUDD
    else if ( Abc_NtkHasBdd(pNtk) )
        Extra_StopManager( (DdManager *)pNtk->pManFunc );
#endif
    else if ( Abc_NtkHasAig(pNtk) )
        { if ( pNtk->pManFunc ) Hop_ManStop( (Hop_Man_t *)pNtk->pManFunc ); }
    else if ( Abc_NtkHasMapping(pNtk) )
        pNtk->pManFunc = NULL;
    else if ( !Abc_NtkHasBlackbox(pNtk) )
        assert( 0 );
    // free the hierarchy
    if ( pNtk->pDesign )
    {
        Abc_DesFree( pNtk->pDesign, pNtk );
        pNtk->pDesign = NULL;
    }
//    if ( pNtk->pBlackBoxes ) 
//        Vec_IntFree( pNtk->pBlackBoxes );
    // free node attributes
    Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vAttrs, pAttrMan, i )
        if ( pAttrMan )
            Vec_AttFree( (Vec_Att_t *)pAttrMan, 1 );
    assert( pNtk->pSCLib == NULL );
    Vec_IntFreeP( &pNtk->vGates );
    Vec_PtrFree( pNtk->vAttrs );
    Vec_IntFreeP( &pNtk->vNameIds );
    ABC_FREE( pNtk->pWLoadUsed );
    ABC_FREE( pNtk->pName );
    ABC_FREE( pNtk->pSpec );
    ABC_FREE( pNtk->pLutTimes );
    if ( pNtk->vOnehots )
        Vec_VecFree( (Vec_Vec_t *)pNtk->vOnehots );
    Vec_PtrFreeP( &pNtk->vLtlProperties );
    Vec_IntFreeP( &pNtk->vObjPerm );
    Vec_IntFreeP( &pNtk->vTopo );
    Vec_IntFreeP( &pNtk->vFins );
    ABC_FREE( pNtk );
}

/**Function*************************************************************

  Synopsis    [Reads the verilog file.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkFixNonDrivenNets( Abc_Ntk_t * pNtk )
{ 
    Vec_Ptr_t * vNets;
    Abc_Obj_t * pNet, * pNode;
    int i;

    if ( Abc_NtkNodeNum(pNtk) == 0 && Abc_NtkBoxNum(pNtk) == 0 )
        return;

    // special case
    pNet = Abc_NtkFindNet( pNtk, "[_c1_]" );
    if ( pNet != NULL )
    {
        pNode = Abc_NtkCreateNodeConst1( pNtk );
        Abc_ObjAddFanin( pNet, pNode );
    }

    // check for non-driven nets
    vNets = Vec_PtrAlloc( 100 );
    Abc_NtkForEachNet( pNtk, pNet, i )
    {
        if ( Abc_ObjFaninNum(pNet) > 0 )
            continue;
        // add the constant 0 driver
        pNode = Abc_NtkCreateNodeConst0( pNtk );
        // add the fanout net
        Abc_ObjAddFanin( pNet, pNode );
        // add the net to those for which the warning will be printed
        Vec_PtrPush( vNets, pNet );
    }

    // print the warning
    if ( vNets->nSize > 0 )
    {
        printf( "Warning: Constant-0 drivers added to %d non-driven nets in network \"%s\":\n", Vec_PtrSize(vNets), pNtk->pName );
        Vec_PtrForEachEntry( Abc_Obj_t *, vNets, pNet, i )
        {
            printf( "%s%s", (i? ", ": ""), Abc_ObjName(pNet) );
            if ( i == 3 )
            {
                if ( Vec_PtrSize(vNets) > 3 )
                    printf( " ..." );
                break;
            }
        }
        printf( "\n" );
    }
    Vec_PtrFree( vNets );
}


/**Function*************************************************************

  Synopsis    [Converts the network to combinational.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkMakeComb( Abc_Ntk_t * pNtk, int fRemoveLatches )
{
    Abc_Obj_t * pObj;
    int i;

    if ( Abc_NtkIsComb(pNtk) )
        return;

    assert( !Abc_NtkIsNetlist(pNtk) );
    assert( Abc_NtkHasOnlyLatchBoxes(pNtk) );

    // detach the latches
//    Abc_NtkForEachLatch( pNtk, pObj, i )
    Vec_PtrForEachEntryReverse( Abc_Obj_t *, pNtk->vBoxes, pObj, i )
        Abc_NtkDeleteObj( pObj );
    assert( Abc_NtkLatchNum(pNtk) == 0 );
    assert( Abc_NtkBoxNum(pNtk) == 0 );

    // move CIs to become PIs
    Vec_PtrClear( pNtk->vPis );
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        if ( Abc_ObjIsBo(pObj) )
        {
            pObj->Type = ABC_OBJ_PI;
            pNtk->nObjCounts[ABC_OBJ_PI]++;
            pNtk->nObjCounts[ABC_OBJ_BO]--;
        }
        Vec_PtrPush( pNtk->vPis, pObj );
    }
    assert( Abc_NtkBoNum(pNtk) == 0 );

    if ( fRemoveLatches )
    {
        // remove registers
        Vec_Ptr_t * vBos;
        vBos = Vec_PtrAlloc( 100 );
        Vec_PtrClear( pNtk->vPos );
        Abc_NtkForEachCo( pNtk, pObj, i )
            if ( Abc_ObjIsBi(pObj) )
                Vec_PtrPush( vBos, pObj );
            else
                Vec_PtrPush( pNtk->vPos, pObj );
        // remove COs
        Vec_PtrFree( pNtk->vCos );
        pNtk->vCos = NULL;
        // remove the BOs
        Vec_PtrForEachEntry( Abc_Obj_t *, vBos, pObj, i )
            Abc_NtkDeleteObj( pObj );
        Vec_PtrFree( vBos );
        // create COs
        pNtk->vCos = Vec_PtrDup( pNtk->vPos );
        // cleanup
        if ( Abc_NtkIsLogic(pNtk) )
            Abc_NtkCleanup( pNtk, 0 );
        else if ( Abc_NtkIsStrash(pNtk) )
            Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc );
        else
            assert( 0 );
    }
    else
    {
        // move COs to become POs
        Vec_PtrClear( pNtk->vPos );
        Abc_NtkForEachCo( pNtk, pObj, i )
        {
            if ( Abc_ObjIsBi(pObj) )
            {
                pObj->Type = ABC_OBJ_PO;
                pNtk->nObjCounts[ABC_OBJ_PO]++;
                pNtk->nObjCounts[ABC_OBJ_BI]--;
            }
            Vec_PtrPush( pNtk->vPos, pObj );
        }
    }
    assert( Abc_NtkBiNum(pNtk) == 0 );

    if ( !Abc_NtkCheck( pNtk ) )
        fprintf( stdout, "Abc_NtkMakeComb(): Network check has failed.\n" );
}

/**Function*************************************************************

  Synopsis    [Converts the network to sequential.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkMakeSeq( Abc_Ntk_t * pNtk, int nLatchesToAdd )
{
    Abc_Obj_t * pObjLi, * pObjLo, * pObj;
    int i;
    assert( Abc_NtkBoxNum(pNtk) == 0 );
    if ( !Abc_NtkIsComb(pNtk) )
    {
        printf( "The network is a not a combinational one.\n" );
        return;
    }
    if ( nLatchesToAdd >= Abc_NtkPiNum(pNtk) )
    {
        printf( "The number of latches is more or equal than the number of PIs.\n" );
        return;
    }
    if ( nLatchesToAdd >= Abc_NtkPoNum(pNtk) )
    {
        printf( "The number of latches is more or equal than the number of POs.\n" );
        return;
    }

    // move the last PIs to become CIs
    Vec_PtrClear( pNtk->vPis );
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        if ( i < Abc_NtkCiNum(pNtk) - nLatchesToAdd )
        {
            Vec_PtrPush( pNtk->vPis, pObj );
            continue;
        }
        pObj->Type = ABC_OBJ_BO;
        pNtk->nObjCounts[ABC_OBJ_PI]--;
        pNtk->nObjCounts[ABC_OBJ_BO]++;
    }

    // move the last POs to become COs
    Vec_PtrClear( pNtk->vPos );
    Abc_NtkForEachCo( pNtk, pObj, i )
    {
        if ( i < Abc_NtkCoNum(pNtk) - nLatchesToAdd )
        {
            Vec_PtrPush( pNtk->vPos, pObj );
            continue;
        }
        pObj->Type = ABC_OBJ_BI;
        pNtk->nObjCounts[ABC_OBJ_PO]--;
        pNtk->nObjCounts[ABC_OBJ_BI]++;
    }

    // create latches
    for ( i = 0; i < nLatchesToAdd; i++ )
    {
        pObjLo = Abc_NtkCi( pNtk, Abc_NtkCiNum(pNtk) - nLatchesToAdd + i );
        pObjLi = Abc_NtkCo( pNtk, Abc_NtkCoNum(pNtk) - nLatchesToAdd + i );
        pObj = Abc_NtkCreateLatch( pNtk );
        Abc_ObjAddFanin( pObj, pObjLi );
        Abc_ObjAddFanin( pObjLo, pObj );
        Abc_LatchSetInit0( pObj );
    }

    if ( !Abc_NtkCheck( pNtk ) )
        fprintf( stdout, "Abc_NtkMakeSeq(): Network check has failed.\n" );
}


/**Function*************************************************************

  Synopsis    [Removes all POs, except one.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkMakeOnePo( Abc_Ntk_t * pNtkInit, int Output, int nRange )
{
    Abc_Ntk_t * pNtk;
    Vec_Ptr_t * vPosLeft;
    Vec_Ptr_t * vCosLeft;
    Abc_Obj_t * pNodePo;
    int i;
    assert( !Abc_NtkIsNetlist(pNtkInit) );
    assert( Abc_NtkHasOnlyLatchBoxes(pNtkInit) );
    if ( Output < 0 || Output >= Abc_NtkPoNum(pNtkInit) )
    {
        printf( "PO index is incorrect.\n" );
        return NULL;
    }

    pNtk = Abc_NtkDup( pNtkInit );
    if ( Abc_NtkPoNum(pNtk) == 1 )
        return pNtk;

    if ( nRange < 1 )
        nRange = 1;

    // filter POs
    vPosLeft = Vec_PtrAlloc( nRange );
    Abc_NtkForEachPo( pNtk, pNodePo, i )
        if ( i < Output || i >= Output + nRange )
            Abc_NtkDeleteObjPo( pNodePo );
        else
            Vec_PtrPush( vPosLeft, pNodePo );
    // filter COs
    vCosLeft = Vec_PtrDup( vPosLeft );
    for ( i = Abc_NtkPoNum(pNtk); i < Abc_NtkCoNum(pNtk); i++ )
        Vec_PtrPush( vCosLeft, Abc_NtkCo(pNtk, i) );
    // update arrays
    Vec_PtrFree( pNtk->vPos );  pNtk->vPos = vPosLeft;
    Vec_PtrFree( pNtk->vCos );  pNtk->vCos = vCosLeft;

    // clean the network
    if ( Abc_NtkIsStrash(pNtk) )
    {
        Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc );
        printf( "Run sequential cleanup (\"scl\") to get rid of dangling logic.\n" );
    }
    else
    {
        printf( "Run sequential cleanup (\"st; scl\") to get rid of dangling logic.\n" );
    }

    if ( !Abc_NtkCheck( pNtk ) )
        fprintf( stdout, "Abc_NtkMakeComb(): Network check has failed.\n" );
    return pNtk;
}

/**Function*************************************************************

  Synopsis    [Removes POs with suppsize less than 2 and PIs without fanout.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkTrim( Abc_Ntk_t * pNtk )
{
    Abc_Obj_t * pObj;
    int i, k, m;

    // filter POs
    k = m = 0;
    Abc_NtkForEachCo( pNtk, pObj, i )
    {  
        if ( Abc_ObjIsPo(pObj) )
        {
            // remove constant nodes and PI pointers
            if ( Abc_ObjFaninNum(Abc_ObjFanin0(pObj)) == 0 )
            {
                Abc_ObjDeleteFanin( pObj, Abc_ObjFanin0(pObj) );
                if ( Abc_ObjFanoutNum(Abc_ObjFanin0(pObj)) == 0 && !Abc_ObjIsPi(Abc_ObjFanin0(pObj)) )
                    Abc_NtkDeleteObj_rec( Abc_ObjFanin0(pObj), 1 );
                pNtk->vObjs->pArray[pObj->Id] = NULL;
                pObj->Id = (1<<26)-1;
                pNtk->nObjCounts[pObj->Type]--;
                pNtk->nObjs--;
                Abc_ObjRecycle( pObj );
                continue;
            }
            // remove buffers/inverters of PIs
            if ( Abc_ObjFaninNum(Abc_ObjFanin0(pObj)) == 1 )
            {
                if ( Abc_ObjIsPi(Abc_ObjFanin0(Abc_ObjFanin0(pObj))) )
                {
                    Abc_ObjDeleteFanin( pObj, Abc_ObjFanin0(pObj) );
                    if ( Abc_ObjFanoutNum(Abc_ObjFanin0(pObj)) == 0 )
                        Abc_NtkDeleteObj_rec( Abc_ObjFanin0(pObj), 1 );
                    pNtk->vObjs->pArray[pObj->Id] = NULL;
                    pObj->Id = (1<<26)-1;
                    pNtk->nObjCounts[pObj->Type]--;
                    pNtk->nObjs--;
                    Abc_ObjRecycle( pObj );
                    continue;
                }
            }
            Vec_PtrWriteEntry( pNtk->vPos, m++, pObj );
        }
        Vec_PtrWriteEntry( pNtk->vCos, k++, pObj );
    }
    Vec_PtrShrink( pNtk->vPos, m );
    Vec_PtrShrink( pNtk->vCos, k );

    // filter PIs
    k = m = 0;
    Abc_NtkForEachCi( pNtk, pObj, i )
    {
        if ( Abc_ObjIsPi(pObj) )
        {
            if ( Abc_ObjFanoutNum(pObj) == 0 )
            {
                pNtk->vObjs->pArray[pObj->Id] = NULL;
                pObj->Id = (1<<26)-1;
                pNtk->nObjCounts[pObj->Type]--;
                pNtk->nObjs--;
                Abc_ObjRecycle( pObj );
                continue;
            }
            Vec_PtrWriteEntry( pNtk->vPis, m++, pObj );
        }
        Vec_PtrWriteEntry( pNtk->vCis, k++, pObj );
    }
    Vec_PtrShrink( pNtk->vPis, m );
    Vec_PtrShrink( pNtk->vCis, k );

    return Abc_NtkDup( pNtk );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkDropSatOutputs( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCexes, int fVerbose )
{
    Abc_Obj_t * pObj, * pConst0, * pFaninNew;
    int i, Counter = 0;
    assert( Vec_PtrSize(vCexes) == Abc_NtkPoNum(pNtk) );
    pConst0 = Abc_ObjNot( Abc_AigConst1(pNtk) );
    Abc_NtkForEachPo( pNtk, pObj, i )
    {
        if ( Vec_PtrEntry( vCexes, i ) == NULL )
            continue;
        Counter++;
        pFaninNew = Abc_ObjNotCond( pConst0, Abc_ObjFaninC0(pObj) );
        Abc_ObjPatchFanin( pObj, Abc_ObjFanin0(pObj), pFaninNew );
        assert( Abc_ObjChild0(pObj) == pConst0 );
        // if a PO is driven by a latch, they have the same name...
//        if ( Abc_ObjIsBo(pObj) )
//            Nm_ManDeleteIdName( pNtk->pManName, Abc_ObjId(pObj) );
    }
    if ( fVerbose )
        printf( "Logic cones of %d POs have been replaced by constant 0.\n", Counter );
    Counter = Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc );
//    printf( "Cleanup removed %d nodes.\n", Counter );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkDropOneOutput( Abc_Ntk_t * pNtk, int iOutput, int fSkipSweep, int fUseConst1 )
{
    Abc_Obj_t * pObj, * pConst0, * pFaninNew;
    pObj = Abc_NtkPo( pNtk, iOutput );
    if ( Abc_ObjFanin0(pObj) == Abc_AigConst1(pNtk) )
    {
        if ( !Abc_ObjFaninC0(pObj) ^ fUseConst1 )
            Abc_ObjXorFaninC( pObj, 0 );
        return;
    }
    pConst0 = Abc_ObjNotCond( Abc_AigConst1(pNtk), !fUseConst1 );
    pFaninNew = Abc_ObjNotCond( pConst0, Abc_ObjFaninC0(pObj) );
    Abc_ObjPatchFanin( pObj, Abc_ObjFanin0(pObj), pFaninNew );
    assert( Abc_ObjChild0(pObj) == pConst0 );
    if ( fSkipSweep )
        return;
    Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkSwapOneOutput( Abc_Ntk_t * pNtk, int iOutput )
{
    Abc_Obj_t * pObj1, * pObj2;
    Abc_Obj_t * pChild1Old, * pChild2Old;
    Abc_Obj_t * pChild1, * pChild2;
    if ( iOutput == 0 )
        return;
    pObj1      = Abc_NtkPo( pNtk, 0 );
    pObj2      = Abc_NtkPo( pNtk, iOutput );
    if ( Abc_ObjFanin0(pObj1) == Abc_ObjFanin0(pObj2) )
    {
        if ( Abc_ObjFaninC0(pObj1) ^ Abc_ObjFaninC0(pObj2) )
        {
            Abc_ObjXorFaninC( pObj1, 0 );
            Abc_ObjXorFaninC( pObj2, 0 );
        }
        return;
    }
    pChild1Old = Abc_ObjChild0( pObj1 );
    pChild2Old = Abc_ObjChild0( pObj2 );
    pChild1    = Abc_ObjNotCond( pChild1Old, Abc_ObjFaninC0(pObj2) );
    pChild2    = Abc_ObjNotCond( pChild2Old, Abc_ObjFaninC0(pObj1) );
    Abc_ObjPatchFanin( pObj1, Abc_ObjFanin0(pObj1), pChild2 );
    Abc_ObjPatchFanin( pObj2, Abc_ObjFanin0(pObj2), pChild1 );
    assert( Abc_ObjChild0(pObj1) == pChild2Old );
    assert( Abc_ObjChild0(pObj2) == pChild1Old );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkRemovePo( Abc_Ntk_t * pNtk, int iOutput, int fRemoveConst0 )
{
    Abc_Obj_t * pObj = Abc_NtkPo(pNtk, iOutput);
    if ( Abc_ObjFanin0(pObj) == Abc_AigConst1(pNtk) && Abc_ObjFaninC0(pObj) == fRemoveConst0 )
        Abc_NtkDeleteObj( pObj );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Abc_NtkReadFlopPerm( char * pFileName, int nFlops )
{
    char Buffer[1000];
    FILE * pFile;
    Vec_Int_t * vFlops;
    int iFlop = -1;
    pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open input file \"%s\".\n", pFileName );
        return NULL;
    }
    vFlops = Vec_IntAlloc( nFlops );
    while ( fgets( Buffer, 1000, pFile ) != NULL )
    {
        if ( Buffer[0] == ' ' || Buffer[0] == '\r' || Buffer[0] == '\n' )
            continue;
        iFlop = atoi( Buffer );
        if ( iFlop < 0 || iFlop >= nFlops )
        {
            printf( "Flop ID (%d) is out of range.\n", iFlop );
            fclose( pFile );
            Vec_IntFree( vFlops );
            return NULL;
        }
        Vec_IntPush( vFlops, iFlop );
    }
    fclose( pFile );
    if ( Vec_IntSize(vFlops) != nFlops )
    {
        printf( "The number of flops read in from file (%d) is different from the number of flops in the circuit (%d).\n", iFlop, nFlops );
        Vec_IntFree( vFlops );
        return NULL;
    }
    return vFlops;    
}
/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, char * pFlopPermFile )
{
    Abc_Obj_t * pTemp;
    Vec_Int_t * vInputs, * vOutputs, * vFlops, * vTemp;
    int i, k, Entry;
    // start permutation arrays
    if ( pFlopPermFile )
    {
        vFlops = Abc_NtkReadFlopPerm( pFlopPermFile, Abc_NtkLatchNum(pNtk) );
        if ( vFlops == NULL )
            return;
        fInputs  = 0;
        fOutputs = 0;
        fFlops   = 0;
    }
    else
        vFlops   = Vec_IntStartNatural( Abc_NtkLatchNum(pNtk) );
    vInputs  = Vec_IntStartNatural( Abc_NtkPiNum(pNtk) );
    vOutputs = Vec_IntStartNatural( Abc_NtkPoNum(pNtk) );
    // permute inputs
    if ( fInputs )
    for ( i = 0; i < Abc_NtkPiNum(pNtk); i++ )
    {
        k = rand() % Abc_NtkPiNum(pNtk);
        // swap indexes
        Entry = Vec_IntEntry( vInputs, i );
        Vec_IntWriteEntry( vInputs, i, Vec_IntEntry(vInputs, k) );
        Vec_IntWriteEntry( vInputs, k, Entry );
        // swap PIs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPis, i );
        Vec_PtrWriteEntry( pNtk->vPis, i, Vec_PtrEntry(pNtk->vPis, k) );
        Vec_PtrWriteEntry( pNtk->vPis, k, pTemp );
        // swap CIs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, i );
        Vec_PtrWriteEntry( pNtk->vCis, i, Vec_PtrEntry(pNtk->vCis, k) );
        Vec_PtrWriteEntry( pNtk->vCis, k, pTemp );
//printf( "Swapping PIs %d and %d.\n", i, k );
    }
    // permute outputs
    if ( fOutputs )
    for ( i = 0; i < Abc_NtkPoNum(pNtk); i++ )
    {
        k = rand() % Abc_NtkPoNum(pNtk);
        // swap indexes
        Entry = Vec_IntEntry( vOutputs, i );
        Vec_IntWriteEntry( vOutputs, i, Vec_IntEntry(vOutputs, k) );
        Vec_IntWriteEntry( vOutputs, k, Entry );
        // swap POs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPos, i );
        Vec_PtrWriteEntry( pNtk->vPos, i, Vec_PtrEntry(pNtk->vPos, k) );
        Vec_PtrWriteEntry( pNtk->vPos, k, pTemp );
        // swap COs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, i );
        Vec_PtrWriteEntry( pNtk->vCos, i, Vec_PtrEntry(pNtk->vCos, k) );
        Vec_PtrWriteEntry( pNtk->vCos, k, pTemp );
//printf( "Swapping POs %d and %d.\n", i, k );
    }
    // permute flops
    assert( Abc_NtkBoxNum(pNtk) == Abc_NtkLatchNum(pNtk) );
    if ( fFlops )
    for ( i = 0; i < Abc_NtkLatchNum(pNtk); i++ )
    {
        k = rand() % Abc_NtkLatchNum(pNtk);
        // swap indexes
        Entry = Vec_IntEntry( vFlops, i );
        Vec_IntWriteEntry( vFlops, i, Vec_IntEntry(vFlops, k) );
        Vec_IntWriteEntry( vFlops, k, Entry );
        // swap flops
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vBoxes, i );
        Vec_PtrWriteEntry( pNtk->vBoxes, i, Vec_PtrEntry(pNtk->vBoxes, k) );
        Vec_PtrWriteEntry( pNtk->vBoxes, k, pTemp );
        // swap CIs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i );
        Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i, Vec_PtrEntry(pNtk->vCis, Abc_NtkPiNum(pNtk)+k) );
        Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+k, pTemp );
        // swap COs
        pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i );
        Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i, Vec_PtrEntry(pNtk->vCos, Abc_NtkPoNum(pNtk)+k) );
        Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+k, pTemp );

//printf( "Swapping flops %d and %d.\n", i, k );
    }
    // invert arrays
    vInputs = Vec_IntInvert( vTemp = vInputs, -1 );
    Vec_IntFree( vTemp );
    vOutputs = Vec_IntInvert( vTemp = vOutputs, -1 );
    Vec_IntFree( vTemp );
    vFlops = Vec_IntInvert( vTemp = vFlops, -1 );
    Vec_IntFree( vTemp );
    // pack the results into the output array
    Vec_IntFreeP( &pNtk->vObjPerm );
    pNtk->vObjPerm = Vec_IntAlloc( Abc_NtkPiNum(pNtk) + Abc_NtkPoNum(pNtk) + Abc_NtkLatchNum(pNtk) );
    Vec_IntForEachEntry( vInputs, Entry, i )
        Vec_IntPush( pNtk->vObjPerm, Entry );
    Vec_IntForEachEntry( vOutputs, Entry, i )
        Vec_IntPush( pNtk->vObjPerm, Entry );
    Vec_IntForEachEntry( vFlops, Entry, i )
        Vec_IntPush( pNtk->vObjPerm, Entry );
    // cleanup
    Vec_IntFree( vInputs );
    Vec_IntFree( vOutputs );
    Vec_IntFree( vFlops );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Abc_NodeCompareByFanoutCount( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 )
{
    int Diff = Abc_ObjFanoutNum(*pp2) - Abc_ObjFanoutNum(*pp1);
    if ( Diff < 0 )
        return -1;
    if ( Diff > 0 ) 
        return 1;
    Diff = strcmp( Abc_ObjName(*pp1), Abc_ObjName(*pp2) );
    if ( Diff < 0 )
        return -1;
    if ( Diff > 0 ) 
        return 1;
    return 0; 
}
void Abc_NtkPermutePiUsingFanout( Abc_Ntk_t * pNtk )
{
    Abc_Obj_t * pNode; int i;
    qsort( (void *)Vec_PtrArray(pNtk->vPis), (size_t)Vec_PtrSize(pNtk->vPis), sizeof(Abc_Obj_t *), 
        (int (*)(const void *, const void *)) Abc_NodeCompareByFanoutCount );
    Vec_PtrClear( pNtk->vCis );
    Vec_PtrForEachEntry( Abc_Obj_t *, pNtk->vPis, pNode, i )
        Vec_PtrPush( pNtk->vCis, pNode );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkUnpermute( Abc_Ntk_t * pNtk )
{
    Vec_Ptr_t * vTemp, * vTemp2, * vLatch;
    int i, * pInputs, * pOutputs, * pFlops;
    if ( pNtk->vObjPerm == NULL )
    {
        printf( "Abc_NtkUnpermute(): Initial permutation is not available.\n" );
        return;
    }
    assert( Abc_NtkBoxNum(pNtk) == Abc_NtkLatchNum(pNtk) );
    // get reverve permutation
    pInputs  = Vec_IntArray( pNtk->vObjPerm );
    pOutputs = pInputs  + Abc_NtkPiNum(pNtk);
    pFlops   = pOutputs + Abc_NtkPoNum(pNtk);
    // create new PI array
    vTemp = Vec_PtrAlloc( Abc_NtkPiNum(pNtk) );
    for ( i = 0; i < Abc_NtkPiNum(pNtk); i++ )
        Vec_PtrPush( vTemp, Abc_NtkPi(pNtk, pInputs[i]) );
    Vec_PtrFreeP( &pNtk->vPis );
    pNtk->vPis = vTemp;
    // create new PO array
    vTemp = Vec_PtrAlloc( Abc_NtkPoNum(pNtk) );
    for ( i = 0; i < Abc_NtkPoNum(pNtk); i++ )
        Vec_PtrPush( vTemp, Abc_NtkPo(pNtk, pOutputs[i]) );
    Vec_PtrFreeP( &pNtk->vPos );
    pNtk->vPos = vTemp;
    // create new CI/CO arrays
    vTemp  = Vec_PtrDup( pNtk->vPis );
    vTemp2 = Vec_PtrDup( pNtk->vPos );
    vLatch = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
    for ( i = 0; i < Abc_NtkLatchNum(pNtk); i++ )
    {
//printf( "Setting flop %d to be %d.\n", i, pFlops[i] );
        Vec_PtrPush( vTemp,  Abc_NtkCi(pNtk, Abc_NtkPiNum(pNtk) + pFlops[i]) );
        Vec_PtrPush( vTemp2, Abc_NtkCo(pNtk, Abc_NtkPoNum(pNtk) + pFlops[i]) );
        Vec_PtrPush( vLatch, Abc_NtkBox(pNtk, pFlops[i]) );
    }
    Vec_PtrFreeP( &pNtk->vCis );
    Vec_PtrFreeP( &pNtk->vCos );
    Vec_PtrFreeP( &pNtk->vBoxes );
    pNtk->vCis   = vTemp;
    pNtk->vCos   = vTemp2;
    pNtk->vBoxes = vLatch;
    // cleanup
    Vec_IntFreeP( &pNtk->vObjPerm );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkNodeDup( Abc_Ntk_t * pNtkInit, int nLimit, int fVerbose )
{
    Vec_Ptr_t * vNodes, * vFanouts;
    Abc_Ntk_t * pNtk;
    Abc_Obj_t * pObj, * pObjNew, * pFanin, * pFanout;
    int i, k;
    pNtk = Abc_NtkDup( pNtkInit );
    vNodes = Vec_PtrAlloc( 100 );
    vFanouts = Vec_PtrAlloc( 100 );
    do
    {
        Vec_PtrClear( vNodes );
        Abc_NtkForEachNode( pNtk, pObj, i )
            if ( Abc_ObjFanoutNum(pObj) >= nLimit )
                Vec_PtrPush( vNodes, pObj );
        Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
        {
            pObjNew = Abc_NtkDupObj( pNtk, pObj, 0 );
            Abc_ObjForEachFanin( pObj, pFanin, k )
                Abc_ObjAddFanin( pObjNew, pFanin );
            Abc_NodeCollectFanouts( pObj, vFanouts );
            Vec_PtrShrink( vFanouts, nLimit / 2 );
            Vec_PtrForEachEntry( Abc_Obj_t *, vFanouts, pFanout, k )
                Abc_ObjPatchFanin( pFanout, pObj, pObjNew );
        }
        if ( fVerbose )
            printf( "Duplicated %d nodes.\n", Vec_PtrSize(vNodes) );
    }
    while ( Vec_PtrSize(vNodes) > 0 );
    Vec_PtrFree( vFanouts );
    Vec_PtrFree( vNodes );
    return pNtk;
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateFromSops( char * pName, Vec_Ptr_t * vSops )
{
    int i, k, nObjBeg;
    char * pSop = (char *)Vec_PtrEntry(vSops, 0);
    Abc_Ntk_t * pNtk = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 );
    pNtk->pName = Extra_UtilStrsav( pName );
    for ( k = 0; pSop[k] != ' '; k++ )
        Abc_NtkCreatePi( pNtk );
    nObjBeg = Abc_NtkObjNumMax(pNtk);
    Vec_PtrForEachEntry( char *, vSops, pSop, i )
    {
        Abc_Obj_t * pObj = Abc_NtkCreateNode( pNtk );
        pObj->pData = Abc_SopRegister( (Mem_Flex_t*)pNtk->pManFunc, pSop );
        for ( k = 0; pSop[k] != ' '; k++ )
            Abc_ObjAddFanin( pObj, Abc_NtkCi(pNtk, k) );
    }
    for ( i = 0; i < Vec_PtrSize(vSops); i++ )
    {
        Abc_Obj_t * pObj = Abc_NtkObj( pNtk, nObjBeg + i );
        Abc_Obj_t * pObjPo = Abc_NtkCreatePo( pNtk );
        Abc_ObjAddFanin( pObjPo, pObj );
    }
    Abc_NtkAddDummyPiNames( pNtk );
    Abc_NtkAddDummyPoNames( pNtk );
    return pNtk;
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Abc_Ntk_t * Abc_NtkCreateFromGias( char * pName, Vec_Ptr_t * vGias, Gia_Man_t * pMulti )
{
    Gia_Man_t * pGia = pMulti ? pMulti : (Gia_Man_t *)Vec_PtrEntry(vGias, 0);
    Abc_Ntk_t * pNtk = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1 );
    Abc_Obj_t * pAbcObj, * pAbcObjPo;
    Gia_Obj_t * pObj; int i, k;
    pNtk->pName = Extra_UtilStrsav( pName );
    for ( k = 0; k < Gia_ManCiNum(pGia); k++ )
        Abc_NtkCreatePi( pNtk );
    if ( pMulti )
    {
        Gia_ManCleanValue(pGia);
        Gia_ManForEachCi( pGia, pObj, k )
            pObj->Value = Abc_ObjId( Abc_NtkCi(pNtk, k) );
        Gia_ManForEachAnd( pGia, pObj, k )
        {
            Abc_Obj_t * pAbcObj0 = Abc_NtkObj( pNtk, Gia_ObjFanin0(pObj)->Value );
            Abc_Obj_t * pAbcObj1 = Abc_NtkObj( pNtk, Gia_ObjFanin1(pObj)->Value );
            pAbcObj0 = Abc_ObjNotCond( pAbcObj0, Gia_ObjFaninC0(pObj) );
            pAbcObj1 = Abc_ObjNotCond( pAbcObj1, Gia_ObjFaninC1(pObj) );
            pAbcObj  = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, pAbcObj0, pAbcObj1 );
            pObj->Value = Abc_ObjId( pAbcObj ); 
        }
        Gia_ManForEachCo( pGia, pObj, k )
        {
            //pObj = Gia_ManCo(pGia, 0);
            if ( Gia_ObjFaninId0p(pGia, pObj) == 0 )
                pAbcObj = Abc_ObjNot( Abc_AigConst1(pNtk) );
            else
                pAbcObj = Abc_NtkObj( pNtk, Gia_ObjFanin0(pObj)->Value );
            pAbcObj = Abc_ObjNotCond( pAbcObj, Gia_ObjFaninC0(pObj) );
            pAbcObjPo = Abc_NtkCreatePo( pNtk );
            Abc_ObjAddFanin( pAbcObjPo, pAbcObj );
        }
    }
    else
    {
    Vec_PtrForEachEntry( Gia_Man_t *, vGias, pGia, i )
    {
        assert( Gia_ManCoNum(pGia) == 1 );
        Gia_ManCleanValue(pGia);
        Gia_ManForEachCi( pGia, pObj, k )
            pObj->Value = Abc_ObjId( Abc_NtkCi(pNtk, k) );
        Gia_ManForEachAnd( pGia, pObj, k )
        {
            Abc_Obj_t * pAbcObj0 = Abc_NtkObj( pNtk, Gia_ObjFanin0(pObj)->Value );
            Abc_Obj_t * pAbcObj1 = Abc_NtkObj( pNtk, Gia_ObjFanin1(pObj)->Value );
            pAbcObj0 = Abc_ObjNotCond( pAbcObj0, Gia_ObjFaninC0(pObj) );
            pAbcObj1 = Abc_ObjNotCond( pAbcObj1, Gia_ObjFaninC1(pObj) );
            pAbcObj  = Abc_AigAnd( (Abc_Aig_t *)pNtk->pManFunc, pAbcObj0, pAbcObj1 );
            pObj->Value = Abc_ObjId( pAbcObj ); 
        }
        pObj = Gia_ManCo(pGia, 0);
        if ( Gia_ObjFaninId0p(pGia, pObj) == 0 )
            pAbcObj = Abc_ObjNot( Abc_AigConst1(pNtk) );
        else
            pAbcObj = Abc_NtkObj( pNtk, Gia_ObjFanin0(pObj)->Value );
        pAbcObj = Abc_ObjNotCond( pAbcObj, Gia_ObjFaninC0(pObj) );
        pAbcObjPo = Abc_NtkCreatePo( pNtk );
        Abc_ObjAddFanin( pAbcObjPo, pAbcObj );
    }
    }
    Abc_NtkAddDummyPiNames( pNtk );
    Abc_NtkAddDummyPoNames( pNtk );
    return pNtk;
}


////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////


ABC_NAMESPACE_IMPL_END

