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

  FileName    [giaMap.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Scalable AIG package.]

  Synopsis    [Manipulation of mapping associated with the AIG.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "gia.h"
#include "aig/aig/aig.h"
#include "map/if/if.h"
#include "bool/kit/kit.h"

ABC_NAMESPACE_IMPL_START


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

extern int Kit_TruthToGia( Gia_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash );
extern int Abc_RecToGia3( Gia_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, Vec_Int_t * vLeaves, int fHash );

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

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

  Synopsis    [Load the network into FPGA manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManSetIfParsDefault( void * pp )
{
    If_Par_t * pPars = (If_Par_t *)pp;
//    extern void * Abc_FrameReadLibLut();
    If_Par_t * p = (If_Par_t *)pPars;
    // set defaults
    memset( p, 0, sizeof(If_Par_t) );
    // user-controlable paramters
    p->nLutSize    = -1;
//    p->nLutSize    =  6;
    p->nCutsMax    =  8;
    p->nFlowIters  =  1;
    p->nAreaIters  =  2;
    p->DelayTarget = -1;
    p->Epsilon     =  (float)0.005;
    p->fPreprocess =  1;
    p->fArea       =  0;
    p->fFancy      =  0;
    p->fExpRed     =  1; ////
    p->fLatchPaths =  0;
    p->fEdge       =  1;
    p->fPower      =  0;
    p->fCutMin     =  0;
    p->fSeqMap     =  0;
    p->fVerbose    =  0;
    p->pLutStruct  =  NULL;
    // internal parameters
    p->fTruth      =  0;
    p->nLatchesCi  =  0;
    p->nLatchesCo  =  0;
    p->fLiftLeaves =  0;
    p->fUseCoAttrs =  1;   // use CO attributes
    p->pLutLib     =  NULL;
    p->pTimesArr   =  NULL; 
    p->pTimesReq   =  NULL;   
    p->pFuncCost   =  NULL;   
}


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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManLutFaninCount( Gia_Man_t * p )
{
    int i, Counter = 0;
    Gia_ManForEachLut( p, i )
        Counter += Gia_ObjLutSize(p, i);
    return Counter;
}

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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManLutSizeMax( Gia_Man_t * p )
{
    int i, nSizeMax = -1;
    Gia_ManForEachLut( p, i )
        nSizeMax = Abc_MaxInt( nSizeMax, Gia_ObjLutSize(p, i) );
    return nSizeMax;
}

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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManLutNum( Gia_Man_t * p )
{
    int i, Counter = 0;
    Gia_ManForEachLut( p, i )
        Counter ++;
    return Counter;
}

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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManLutLevel( Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    int i, k, iFan, Level;
    int * pLevels = ABC_CALLOC( int, Gia_ManObjNum(p) );
    Gia_ManForEachLut( p, i )
    {
        Level = 0;
        Gia_LutForEachFanin( p, i, iFan, k )
            if ( Level < pLevels[iFan] )
                Level = pLevels[iFan];
        pLevels[i] = Level + 1;
    }
    Level = 0;
    Gia_ManForEachCo( p, pObj, k )
        if ( Level < pLevels[Gia_ObjFaninId0p(p, pObj)] )
            Level = pLevels[Gia_ObjFaninId0p(p, pObj)];
    ABC_FREE( pLevels );
    return Level;
}

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

  Synopsis    [Assigns levels.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManSetRefsMapped( Gia_Man_t * p )  
{
    Gia_Obj_t * pObj;
    int i, k, iFan;
    ABC_FREE( p->pRefs );
    p->pRefs = ABC_CALLOC( int, Gia_ManObjNum(p) );
    Gia_ManForEachCo( p, pObj, i )
        Gia_ObjRefInc( p, Gia_ObjFanin0(pObj) );
    Gia_ManForEachLut( p, i )
        Gia_LutForEachFanin( p, i, iFan, k )
            Gia_ObjRefInc( p, Gia_ManObj(p, iFan) );
}

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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManPrintMappingStats( Gia_Man_t * p )
{
    int * pLevels;
    int i, k, iFan, nLutSize = 0, nLuts = 0, nFanins = 0, LevelMax = 0;
    if ( !p->pMapping )
        return;
    pLevels = ABC_CALLOC( int, Gia_ManObjNum(p) );
    Gia_ManForEachLut( p, i )
    {
        nLuts++;
        nFanins += Gia_ObjLutSize(p, i);
        nLutSize = Abc_MaxInt( nLutSize, Gia_ObjLutSize(p, i) );
        Gia_LutForEachFanin( p, i, iFan, k )
            pLevels[i] = Abc_MaxInt( pLevels[i], pLevels[iFan] );
        pLevels[i]++;
        LevelMax = Abc_MaxInt( LevelMax, pLevels[i] );
    }
    ABC_FREE( pLevels );
    Abc_Print( 1, "Mapping (K=%d)  :  ", nLutSize );
    Abc_Print( 1, "lut =%7d  ", nLuts );
    Abc_Print( 1, "edge =%8d  ", nFanins );
    Abc_Print( 1, "lev =%5d  ", LevelMax );
    Abc_Print( 1, "mem =%5.2f MB", 4.0*(Gia_ManObjNum(p) + 2*nLuts + nFanins)/(1<<20) );
    Abc_Print( 1, "\n" );
}

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

  Synopsis    [Prints mapping statistics.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManPrintPackingStats( Gia_Man_t * p )
{
    int fVerbose = 0;
    int nObjToShow = 200;
    int nNumStr[5] = {0};
    int i, k, Entry, nEntries, nEntries2, MaxSize = -1;
    if ( p->vPacking == NULL )
        return;
    nEntries = Vec_IntEntry( p->vPacking, 0 );
    nEntries2 = 0;
    Vec_IntForEachEntryStart( p->vPacking, Entry, i, 1 )
    {
        assert( Entry > 0 && Entry < 4 );
        nNumStr[Entry]++;
        i++;
        if ( fVerbose && nEntries2 < nObjToShow ) Abc_Print( 1, "{ " );
        for ( k = 0; k < Entry; k++, i++ )
            if ( fVerbose && nEntries2 < nObjToShow ) Abc_Print( 1, "%d ", Vec_IntEntry(p->vPacking, i) );
        if ( fVerbose && nEntries2 < nObjToShow ) Abc_Print( 1, "}\n" );
        i--;
        nEntries2++;
    }
    assert( nEntries == nEntries2 );
    if ( nNumStr[3] > 0 )
        MaxSize = 3;
    else if ( nNumStr[2] > 0 )
        MaxSize = 2;
    else if ( nNumStr[1] > 0 )
        MaxSize = 1;
    Abc_Print( 1, "Packing (N=%d)  :  ", MaxSize );
    for ( i = 1; i <= MaxSize; i++ )
        Abc_Print( 1, "%d x LUT = %d   ", i, nNumStr[i] );
    Abc_Print( 1, "Total = %d", nEntries2 );
    Abc_Print( 1, "\n" );
}



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

  Synopsis    [Converts GIA into IF manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline If_Obj_t * If_ManFanin0Copy( If_Man_t * pIfMan, Gia_Obj_t * pObj ) { return If_NotCond( If_ManObj(pIfMan, Gia_ObjValue(Gia_ObjFanin0(pObj))), Gia_ObjFaninC0(pObj) ); }
static inline If_Obj_t * If_ManFanin1Copy( If_Man_t * pIfMan, Gia_Obj_t * pObj ) { return If_NotCond( If_ManObj(pIfMan, Gia_ObjValue(Gia_ObjFanin1(pObj))), Gia_ObjFaninC1(pObj) ); }
If_Man_t * Gia_ManToIf( Gia_Man_t * p, If_Par_t * pPars )
{
    If_Man_t * pIfMan;
    If_Obj_t * pIfObj;
    Gia_Obj_t * pObj;
    int i;
    // create levels with choices
    Gia_ManChoiceLevel( p );
    // mark representative nodes
    Gia_ManMarkFanoutDrivers( p );
    // start the mapping manager and set its parameters
    pIfMan = If_ManStart( pPars );
    pIfMan->pName = Abc_UtilStrsav( Gia_ManName(p) );
    // print warning about excessive memory usage
    if ( 1.0 * Gia_ManObjNum(p) * pIfMan->nObjBytes / (1<<30) > 1.0 )
        printf( "Warning: The mapper will allocate %.1f GB for to represent the subject graph with %d AIG nodes.\n", 
            1.0 * Gia_ManObjNum(p) * pIfMan->nObjBytes / (1<<30), Gia_ManObjNum(p) );
    // load the AIG into the mapper
    Gia_ManFillValue( p );
    Gia_ManConst0(p)->Value = If_ObjId( If_ManConst1(pIfMan) );
    Gia_ManForEachObj1( p, pObj, i )
    {
        if ( Gia_ObjIsAnd(pObj) )
            pIfObj = If_ManCreateAnd( pIfMan, If_ManFanin0Copy(pIfMan, pObj), If_ManFanin1Copy(pIfMan, pObj) );
        else if ( Gia_ObjIsCi(pObj) )
        {
            pIfObj = If_ManCreateCi( pIfMan );
            If_ObjSetLevel( pIfObj, Gia_ObjLevel(p, pObj) );
//            Abc_Print( 1, "pi%d=%d\n ", If_ObjId(pIfObj), If_ObjLevel(pIfObj) );
            if ( pIfMan->nLevelMax < (int)pIfObj->Level )
                pIfMan->nLevelMax = (int)pIfObj->Level;
        }
        else if ( Gia_ObjIsCo(pObj) )
        {
            pIfObj = If_ManCreateCo( pIfMan, If_NotCond( If_ManFanin0Copy(pIfMan, pObj), Gia_ObjIsConst0(Gia_ObjFanin0(pObj))) );
//            Abc_Print( 1, "po%d=%d\n ", If_ObjId(pIfObj), If_ObjLevel(pIfObj) );
        }
        else assert( 0 );
        assert( i == If_ObjId(pIfObj) );
        Gia_ObjSetValue( pObj, If_ObjId(pIfObj) );
        // set up the choice node
        if ( Gia_ObjSibl(p, i) && pObj->fMark0 )
        {
            Gia_Obj_t * pSibl, * pPrev;
            for ( pPrev = pObj, pSibl = Gia_ObjSiblObj(p, i); pSibl; pPrev = pSibl, pSibl = Gia_ObjSiblObj(p, Gia_ObjId(p, pSibl)) )
                If_ObjSetChoice( If_ManObj(pIfMan, Gia_ObjValue(pObj)), If_ManObj(pIfMan, Gia_ObjValue(pSibl)) );
            If_ManCreateChoice( pIfMan, If_ManObj(pIfMan, Gia_ObjValue(pObj)) );
            pPars->fExpRed = 0;
        }
//        assert( If_ObjLevel(pIfObj) == Gia_ObjLevel(pNode) );
    }
    Gia_ManCleanMark0( p );
    return pIfMan;
}


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

  Synopsis    [Derives node's AIG after SOP balancing]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManNodeIfSopToGiaInt( Gia_Man_t * pNew, Vec_Wrd_t * vAnds, int nVars, Vec_Int_t * vLeaves, int fHash )
{
    Vec_Int_t * vResults;
    int iRes0, iRes1, iRes = -1;
    If_And_t This;
    word Entry;
    int i;
    if ( Vec_WrdSize(vAnds) == 0 )
        return 0;
    if ( Vec_WrdSize(vAnds) == 1 && Vec_WrdEntry(vAnds,0) == 0 )
        return 1;
    vResults = Vec_IntAlloc( Vec_WrdSize(vAnds) );
    for ( i = 0; i < nVars; i++ )
        Vec_IntPush( vResults, Vec_IntEntry(vLeaves, i) );
    Vec_WrdForEachEntryStart( vAnds, Entry, i, nVars )
    {
        This  = If_WrdToAnd( Entry );
        iRes0 = Abc_LitNotCond( Vec_IntEntry(vResults, This.iFan0), This.fCompl0 ); 
        iRes1 = Abc_LitNotCond( Vec_IntEntry(vResults, This.iFan1), This.fCompl1 ); 
        if ( fHash )
            iRes  = Gia_ManHashAnd( pNew, iRes0, iRes1 );
        else if ( iRes0 == iRes1 )
            iRes = iRes0;
        else
            iRes  = Gia_ManAppendAnd( pNew, iRes0, iRes1 );
        Vec_IntPush( vResults, iRes );
    }
    Vec_IntFree( vResults );
    return Abc_LitNotCond( iRes, This.fCompl );
}
int Gia_ManNodeIfSopToGia( Gia_Man_t * pNew, If_Man_t * p, If_Cut_t * pCut, Vec_Int_t * vLeaves, int fHash )
{
    int iResult;
    Vec_Wrd_t * vArray;
    vArray  = If_CutDelaySopArray( p, pCut );
    iResult = Gia_ManNodeIfSopToGiaInt( pNew, vArray, If_CutLeaveNum(pCut), vLeaves, fHash );
//    Vec_WrdFree( vArray );
    return iResult;
}

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

  Synopsis    [Recursively derives the local AIG for the cut.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManNodeIfToGia_rec( Gia_Man_t * pNew, If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Ptr_t * vVisited, int fHash )
{
    If_Cut_t * pCut;
    If_Obj_t * pTemp;
    int iFunc, iFunc0, iFunc1;
    // get the best cut
    pCut = If_ObjCutBest(pIfObj);
    // if the cut is visited, return the result
    if ( If_CutDataInt(pCut) )
        return If_CutDataInt(pCut);
    // mark the node as visited
    Vec_PtrPush( vVisited, pCut );
    // insert the worst case
    If_CutSetDataInt( pCut, ~0 );
    // skip in case of primary input
    if ( If_ObjIsCi(pIfObj) )
        return If_CutDataInt(pCut);
    // compute the functions of the children
    for ( pTemp = pIfObj; pTemp; pTemp = pTemp->pEquiv )
    {
        iFunc0 = Gia_ManNodeIfToGia_rec( pNew, pIfMan, pTemp->pFanin0, vVisited, fHash );
        if ( iFunc0 == ~0 )
            continue;
        iFunc1 = Gia_ManNodeIfToGia_rec( pNew, pIfMan, pTemp->pFanin1, vVisited, fHash );
        if ( iFunc1 == ~0 )
            continue;
        // both branches are solved
        if ( fHash )
            iFunc = Gia_ManHashAnd( pNew, Abc_LitNotCond(iFunc0, pTemp->fCompl0), Abc_LitNotCond(iFunc1, pTemp->fCompl1) ); 
        else
            iFunc = Gia_ManAppendAnd( pNew, Abc_LitNotCond(iFunc0, pTemp->fCompl0), Abc_LitNotCond(iFunc1, pTemp->fCompl1) ); 
        if ( pTemp->fPhase != pIfObj->fPhase )
            iFunc = Abc_LitNot(iFunc);
        If_CutSetDataInt( pCut, iFunc );
        break;
    }
    return If_CutDataInt(pCut);
}
int Gia_ManNodeIfToGia( Gia_Man_t * pNew, If_Man_t * pIfMan, If_Obj_t * pIfObj, Vec_Int_t * vLeaves, int fHash )
{
    If_Cut_t * pCut;
    If_Obj_t * pLeaf;
    int i, iRes;
    // get the best cut
    pCut = If_ObjCutBest(pIfObj);
    assert( pCut->nLeaves > 1 );
    // set the leaf variables
    If_CutForEachLeaf( pIfMan, pCut, pLeaf, i )
        If_CutSetDataInt( If_ObjCutBest(pLeaf), Vec_IntEntry(vLeaves, i) );
    // recursively compute the function while collecting visited cuts
    Vec_PtrClear( pIfMan->vTemp );
    iRes = Gia_ManNodeIfToGia_rec( pNew, pIfMan, pIfObj, pIfMan->vTemp, fHash ); 
    if ( iRes == ~0 )
    {
        Abc_Print( -1, "Gia_ManNodeIfToGia(): Computing local AIG has failed.\n" );
        return ~0;
    }
    // clean the cuts
    If_CutForEachLeaf( pIfMan, pCut, pLeaf, i )
        If_CutSetDataInt( If_ObjCutBest(pLeaf), 0 );
    Vec_PtrForEachEntry( If_Cut_t *, pIfMan->vTemp, pCut, i )
        If_CutSetDataInt( pCut, 0 );
    return iRes;
}

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

  Synopsis    [Converts IF into GIA manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Gia_Man_t * Gia_ManFromIf( If_Man_t * pIfMan )
{
    int fHash = 0;
    Gia_Man_t * pNew;
    If_Obj_t * pIfObj, * pIfLeaf;
    If_Cut_t * pCutBest;
    Vec_Int_t * vLeaves;
    Vec_Int_t * vCover;
    unsigned * pTruth;
    int Counter, iOffset, nItems = 0;
    int i, k, w, GiaId;
    assert( pIfMan->pPars->pLutStruct == NULL );
    // create new manager
    pNew = Gia_ManStart( If_ManObjNum(pIfMan) );
    Gia_ManHashAlloc( pNew );
    // iterate through nodes used in the mapping
    vCover = Vec_IntAlloc( 1 << 16 );
    vLeaves = Vec_IntAlloc( 16 );
    If_ManCleanCutData( pIfMan );
    If_ManForEachObj( pIfMan, pIfObj, i )
    {
        if ( pIfObj->nRefs == 0 && !If_ObjIsTerm(pIfObj) )
            continue;
        if ( If_ObjIsAnd(pIfObj) )
        {
            pCutBest = If_ObjCutBest( pIfObj );
            // collect leaves of the best cut
            Vec_IntClear( vLeaves );
            If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, k )
                Vec_IntPush( vLeaves, pIfLeaf->iCopy );
            // get the functionality
            if ( pIfMan->pPars->pLutStruct )
                pIfObj->iCopy = Kit_TruthToGia( pNew, If_CutTruth(pCutBest), If_CutLeaveNum(pCutBest), vCover, vLeaves, fHash );
            else if ( pIfMan->pPars->fDelayOpt )
                pIfObj->iCopy = Gia_ManNodeIfSopToGia( pNew, pIfMan, pCutBest, vLeaves, fHash );
            else if ( pIfMan->pPars->fUserRecLib )
                pIfObj->iCopy = Abc_RecToGia3( pNew, pIfMan, pCutBest, vLeaves, fHash );
            else
                pIfObj->iCopy = Gia_ManNodeIfToGia( pNew, pIfMan, pIfObj, vLeaves, fHash );
            // complement the node if the TT was used and the cut was complemented
            if ( pIfMan->pPars->pLutStruct )
                pIfObj->iCopy = Abc_LitNotCond( pIfObj->iCopy, pCutBest->fCompl );
            // count entries in the mapping array
            nItems += 2 + If_CutLeaveNum( pCutBest );
        }
        else if ( If_ObjIsCi(pIfObj) )
            pIfObj->iCopy = Gia_ManAppendCi(pNew);
        else if ( If_ObjIsCo(pIfObj) )
            pIfObj->iCopy = Gia_ManAppendCo( pNew, Abc_LitNotCond(If_ObjFanin0(pIfObj)->iCopy, If_ObjFaninC0(pIfObj)) );
        else if ( If_ObjIsConst1(pIfObj) )
        {
            pIfObj->iCopy = 1;
            nItems += 2; 
        }
        else assert( 0 );
    }
    Vec_IntFree( vCover );
    Vec_IntFree( vLeaves );
    Gia_ManHashStop( pNew );

    // GIA after mapping with choices may end up with dangling nodes
    // which participate as leaves of some cuts used in the mapping
    // such nodes are marked here and skipped when mapping is derived
    Counter = Gia_ManMarkDangling(pNew);
//    if ( pIfMan->pPars->fVerbose && Counter )
    if ( Counter )
        printf( "GIA after mapping has %d dangling nodes.\n", Counter );

    // create mapping
    iOffset = Gia_ManObjNum(pNew);
    pNew->pMapping = ABC_CALLOC( int, iOffset + nItems );
    assert( pNew->vTruths == NULL );
    if ( pIfMan->pPars->pLutStruct )
        pNew->vTruths = Vec_IntAlloc( 1000 );
    If_ManForEachObj( pIfMan, pIfObj, i )
    {
        if ( pIfObj->nRefs == 0 && !If_ObjIsTerm(pIfObj) )
            continue;
        if ( If_ObjIsAnd(pIfObj) )
        { 
            GiaId = Abc_Lit2Var( pIfObj->iCopy );
            if ( !Gia_ObjIsAnd(Gia_ManObj(pNew, GiaId)) ) // skip trivial node
                continue;
            assert( Gia_ObjIsAnd(Gia_ManObj(pNew, GiaId)) );
            if ( !Gia_ManObj(pNew, GiaId)->fMark0 ) // skip dangling node
                continue;
            // get the best cut
            pCutBest = If_ObjCutBest( pIfObj );
            // copy the truth tables
            pTruth = NULL;
            if ( pNew->vTruths )
            { 
                // copy truth table
                for ( w = 0; w < pIfMan->nTruthWords; w++ )
                    Vec_IntPush( pNew->vTruths, If_CutTruth(pCutBest)[w] );
                pTruth = (unsigned *)(Vec_IntArray(pNew->vTruths) + Vec_IntSize(pNew->vTruths) - pIfMan->nTruthWords);
                // complement 
                if ( pCutBest->fCompl ^ Abc_LitIsCompl(pIfObj->iCopy) )
                    for ( w = 0; w < pIfMan->nTruthWords; w++ )
                        pTruth[w] = ~pTruth[w];
            }
            // create node
            pNew->pMapping[GiaId]     = iOffset;
            pNew->pMapping[iOffset++] = If_CutLeaveNum(pCutBest);
            If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, k )
            {
                int FaninId = Abc_Lit2Var(pIfLeaf->iCopy);
                if ( pTruth && Abc_LitIsCompl(pIfLeaf->iCopy) )
                    Kit_TruthChangePhase( pTruth, If_CutLeaveNum(pCutBest), k );
                if ( !Gia_ManObj(pNew, FaninId)->fMark0 ) // skip dangling node
                {
                    // update truth table
                    if ( pTruth )
                    {
                        extern void If_CluSwapVars( word * pTruth, int nVars, int * V2P, int * P2V, int iVar, int jVar );
                        if ( If_CutLeaveNum(pCutBest) >= 6 )
                            If_CluSwapVars( (word*)pTruth, If_CutLeaveNum(pCutBest), NULL, NULL, k, If_CutLeaveNum(pCutBest)-1 );
                        else
                        {
                            word Truth = ((word)pTruth[0] << 32) | (word)pTruth[0];
                            If_CluSwapVars( &Truth, 6, NULL, NULL, k, If_CutLeaveNum(pCutBest)-1 );
                            pTruth[0] = (Truth & 0xFFFFFFFF);
                        }
                    }
                    pNew->pMapping[iOffset-k-1]--;
                    continue;
                }
                assert( FaninId < GiaId );
                pNew->pMapping[iOffset++] = FaninId;
            }
            pNew->pMapping[iOffset++] = GiaId;
        }
        else if ( If_ObjIsConst1(pIfObj) )
        {
            // create node
            pNew->pMapping[0] = iOffset;
            pNew->pMapping[iOffset++] = 0;
            pNew->pMapping[iOffset++] = 0;
/*
            if ( pNew->vTruths )
            {
                printf( "%d ", nLeaves );
                for ( w = 0; w < pIfMan->nTruthWords; w++ )
                    Vec_IntPush( pNew->vTruths, 0 );
            }
*/
        }
    }
    pNew->nOffset = iOffset;
    Gia_ManCleanMark0( pNew );
//    assert( iOffset == Gia_ManObjNum(pNew) + nItems );
//    if ( pIfMan->pManTim )
//        pNew->pManTime = Tim_ManDup( pIfMan->pManTim, 0 );
    // verify that COs have mapping
    {
        Gia_Obj_t * pObj;
        Gia_ManForEachCo( pNew, pObj, i )
        {
            if ( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) )
                assert( pNew->pMapping[Gia_ObjFaninId0p(pNew, pObj)] != 0 );
        }
    }
    return pNew;
}


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

  Synopsis    [Write mapping for LUT with given fanins.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManFromIfStrCreateLut( Gia_Man_t * pNew, word * pRes, Vec_Int_t * vLeaves, Vec_Int_t * vCover, Vec_Int_t * vMapping, Vec_Int_t * vMapping2 )
{
    int i, iLit, iObjLit1;
    iObjLit1 = Kit_TruthToGia( pNew, (unsigned *)pRes, Vec_IntSize(vLeaves), vCover, vLeaves, 0 );
    // write mapping
    Vec_IntSetEntry( vMapping, Abc_Lit2Var(iObjLit1), Vec_IntSize(vMapping2) );
    Vec_IntPush( vMapping2, Vec_IntSize(vLeaves) );
    Vec_IntForEachEntry( vLeaves, iLit, i )
        assert( Abc_Lit2Var(iLit) < Abc_Lit2Var(iObjLit1) );
    Vec_IntForEachEntry( vLeaves, iLit, i )
        Vec_IntPush( vMapping2, Abc_Lit2Var(iLit)  );
    Vec_IntPush( vMapping2, Abc_Lit2Var(iObjLit1) );
    return iObjLit1;
}


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

  Synopsis    [Write the node into a file.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManFromIfStrNode( Gia_Man_t * pNew, int iObj, Vec_Int_t * vLeaves, Vec_Int_t * vLeavesTemp, 
    word * pRes, char * pStr, Vec_Int_t * vCover, Vec_Int_t * vMapping, Vec_Int_t * vMapping2, Vec_Int_t * vPacking )
{
    int nLeaves = Vec_IntSize(vLeaves);
    int i, Length, nLutLeaf, nLutLeaf2, nLutRoot, iObjLit1, iObjLit2, iObjLit3;

    // quit if parameters are wrong
    Length = strlen(pStr);
    if ( Length != 2 && Length != 3 )
    {
        printf( "Wrong LUT struct (%s)\n", pStr );
        return -1;
    }
    for ( i = 0; i < Length; i++ )
        if ( pStr[i] - '0' < 3 || pStr[i] - '0' > 6 )
        {
            printf( "The LUT size (%d) should belong to {3,4,5,6}.\n", pStr[i] - '0' );
            return -1;
        }

    nLutLeaf  =                   pStr[0] - '0';
    nLutLeaf2 = ( Length == 3 ) ? pStr[1] - '0' : 0;
    nLutRoot  =                   pStr[Length-1] - '0';
    if ( nLeaves > nLutLeaf - 1 + (nLutLeaf2 ? nLutLeaf2 - 1 : 0) + nLutRoot )
    {
        printf( "The node size (%d) is too large for the LUT structure %s.\n", nLeaves, pStr );
        return -1;
    }

    // consider easy case
    if ( nLeaves <= Abc_MaxInt( nLutLeaf2, Abc_MaxInt(nLutLeaf, nLutRoot) ) )
    {
        // create mapping
        iObjLit1 = Gia_ManFromIfStrCreateLut( pNew, pRes, vLeaves, vCover, vMapping, vMapping2 );
        // write packing
        Vec_IntPush( vPacking, 1 );
        Vec_IntPush( vPacking, Abc_Lit2Var(iObjLit1) );
        Vec_IntAddToEntry( vPacking, 0, 1 );
        return iObjLit1;
    }
    else
    {
        extern int If_CluMinimumBase( word * t, int * pSupp, int nVarsAll, int * pnVars );

        static word TruthStore[16][1<<10] = {{0}}, * pTruths[16];
        word Func0, Func1, Func2;
        char pLut0[32], pLut1[32], pLut2[32] = {0};

        if ( TruthStore[0][0] == 0 )
        {
            static word Truth6[6] = {
                0xAAAAAAAAAAAAAAAA,
                0xCCCCCCCCCCCCCCCC,
                0xF0F0F0F0F0F0F0F0,
                0xFF00FF00FF00FF00,
                0xFFFF0000FFFF0000,
                0xFFFFFFFF00000000
            };
            int nVarsMax = 16;
            int nWordsMax = (1 << 10);
            int i, k;
            assert( nVarsMax <= 16 );
            for ( i = 0; i < nVarsMax; i++ )
                pTruths[i] = TruthStore[i];
            for ( i = 0; i < 6; i++ )
                for ( k = 0; k < nWordsMax; k++ )
                    pTruths[i][k] = Truth6[i];
            for ( i = 6; i < nVarsMax; i++ )
                for ( k = 0; k < nWordsMax; k++ )
                    pTruths[i][k] = ((k >> (i-6)) & 1) ? ~(word)0 : 0;
        }
        // derive truth table
        if ( Kit_TruthIsConst0((unsigned *)pRes, nLeaves) || Kit_TruthIsConst1((unsigned *)pRes, nLeaves) )
        {
            assert( 0 );
//            fprintf( pFile, ".names %s\n %d\n", Abc_ObjName(Abc_ObjFanout0(pObj)), Kit_TruthIsConst1((unsigned *)pRes, nLeaves) );
            return -1;
        }

        // perform decomposition
        if ( Length == 2 )
        {
            if ( !If_CluCheckExt( NULL, pRes, nLeaves, nLutLeaf, nLutRoot, pLut0, pLut1, &Func0, &Func1 ) )
            {
                Extra_PrintHex( stdout, (unsigned *)pRes, nLeaves );  printf( "    " );
                Kit_DsdPrintFromTruth( (unsigned*)pRes, nLeaves );  printf( "\n" );
                printf( "Node %d is not decomposable. Deriving LUT structures has failed.\n", iObj );
                return -1;
            }
        }
        else
        {
            if ( !If_CluCheckExt3( NULL, pRes, nLeaves, nLutLeaf, nLutLeaf2, nLutRoot, pLut0, pLut1, pLut2, &Func0, &Func1, &Func2 ) )
            {
                Extra_PrintHex( stdout, (unsigned *)pRes, nLeaves );  printf( "    " );
                Kit_DsdPrintFromTruth( (unsigned*)pRes, nLeaves );  printf( "\n" );
                printf( "Node %d is not decomposable. Deriving LUT structures has failed.\n", iObj );
                return -1;
            }
        }

/*
        // write leaf node
        Id = Abc2_NtkAllocObj( pNew, pLut1[0], Abc2_ObjType(pObj) );
        iObjLit1 = Abc_Var2Lit( Id, 0 );
        pObjNew = Abc2_NtkObj( pNew, Id );
        for ( i = 0; i < pLut1[0]; i++ )
            Abc2_ObjSetFaninLit( pObjNew, i, Abc2_ObjFaninCopy(pObj, pLut1[2+i]) );
        Abc2_ObjSetTruth( pObjNew, Func1 );
*/
        // write leaf node
        Vec_IntClear( vLeavesTemp );
        for ( i = 0; i < pLut1[0]; i++ )
            Vec_IntPush( vLeavesTemp, Vec_IntEntry(vLeaves, pLut1[2+i]) );
        iObjLit1 = Gia_ManFromIfStrCreateLut( pNew, &Func1, vLeavesTemp, vCover, vMapping, vMapping2 );

        if ( Length == 3 && pLut2[0] > 0 )
        {
        /*
            Id = Abc2_NtkAllocObj( pNew, pLut2[0], Abc2_ObjType(pObj) );
            iObjLit2 = Abc_Var2Lit( Id, 0 );
            pObjNew = Abc2_NtkObj( pNew, Id );
            for ( i = 0; i < pLut2[0]; i++ )
                if ( pLut2[2+i] == nLeaves )
                    Abc2_ObjSetFaninLit( pObjNew, i, iObjLit1 );
                else
                    Abc2_ObjSetFaninLit( pObjNew, i, Abc2_ObjFaninCopy(pObj, pLut2[2+i]) );
            Abc2_ObjSetTruth( pObjNew, Func2 );
        */

            // write leaf node
            Vec_IntClear( vLeavesTemp );
            for ( i = 0; i < pLut2[0]; i++ )
                if ( pLut2[2+i] == nLeaves )
                    Vec_IntPush( vLeavesTemp, iObjLit1 );
                else
                    Vec_IntPush( vLeavesTemp, Vec_IntEntry(vLeaves, pLut2[2+i]) );
            iObjLit2 = Gia_ManFromIfStrCreateLut( pNew, &Func2, vLeavesTemp, vCover, vMapping, vMapping2 );

            // write packing
            Vec_IntPush( vPacking, 3 );
            Vec_IntPush( vPacking, Abc_Lit2Var(iObjLit1) );
            Vec_IntPush( vPacking, Abc_Lit2Var(iObjLit2) );
        }
        else
        {
            // write packing
            Vec_IntPush( vPacking, 2 );
            Vec_IntPush( vPacking, Abc_Lit2Var(iObjLit1) );
            iObjLit2 = -1;
        }
/*
        // write root node
        Id = Abc2_NtkAllocObj( pNew, pLut0[0], Abc2_ObjType(pObj) );
        iObjLit3 = Abc_Var2Lit( Id, 0 );
        pObjNew = Abc2_NtkObj( pNew, Id );
        for ( i = 0; i < pLut0[0]; i++ )
            if ( pLut0[2+i] == nLeaves )
                Abc2_ObjSetFaninLit( pObjNew, i, iObjLit1 );
            else if ( pLut0[2+i] == nLeaves+1 )
                Abc2_ObjSetFaninLit( pObjNew, i, iObjLit2 );
            else
                Abc2_ObjSetFaninLit( pObjNew, i, Abc2_ObjFaninCopy(pObj, pLut0[2+i]) );
        Abc2_ObjSetTruth( pObjNew, Func0 );
        Abc2_ObjSetCopy( pObj, iObjLit3 );
*/
        // write root node
        Vec_IntClear( vLeavesTemp );
        for ( i = 0; i < pLut0[0]; i++ )
            if ( pLut0[2+i] == nLeaves )
                Vec_IntPush( vLeavesTemp, iObjLit1 );
            else if ( pLut0[2+i] == nLeaves+1 )
                Vec_IntPush( vLeavesTemp, iObjLit2 );
            else
                Vec_IntPush( vLeavesTemp, Vec_IntEntry(vLeaves, pLut0[2+i]) );
        iObjLit3 = Gia_ManFromIfStrCreateLut( pNew, &Func0, vLeavesTemp, vCover, vMapping, vMapping2 );

        // write packing
        Vec_IntPush( vPacking, Abc_Lit2Var(iObjLit3) );
        Vec_IntAddToEntry( vPacking, 0, 1 );
    }
    return iObjLit3;
}


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

  Synopsis    [Converts IF into GIA manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Gia_Man_t * Gia_ManFromIfStr( If_Man_t * pIfMan )
{
    Gia_Man_t * pNew;
    If_Cut_t * pCutBest;
    If_Obj_t * pIfObj, * pIfLeaf;
    Vec_Int_t * vMapping, * vMapping2, * vPacking;
    Vec_Int_t * vLeaves, * vLeaves2, * vCover;
    int i, k, Entry;
    assert( pIfMan->pPars->pLutStruct != NULL );
    assert( pIfMan->pPars->nLutSize >= 6 ); // if 5, need to change (word *)If_CutTruth(pCutBest) below
    // start mapping and packing
    vMapping  = Vec_IntStart( If_ManObjNum(pIfMan) );
    vMapping2 = Vec_IntStart( 1 );
    vPacking  = Vec_IntAlloc( 1000 );
    Vec_IntPush( vPacking, 0 );
    // create new manager
    pNew = Gia_ManStart( If_ManObjNum(pIfMan) );
    // iterate through nodes used in the mapping
    vCover   = Vec_IntAlloc( 1 << 16 );
    vLeaves  = Vec_IntAlloc( 16 );
    vLeaves2 = Vec_IntAlloc( 16 );
    If_ManCleanCutData( pIfMan );
    If_ManForEachObj( pIfMan, pIfObj, i )
    {
        if ( pIfObj->nRefs == 0 && !If_ObjIsTerm(pIfObj) )
            continue;
        if ( If_ObjIsAnd(pIfObj) )
        {
            pCutBest = If_ObjCutBest( pIfObj );
            // collect leaves of the best cut
            Vec_IntClear( vLeaves );
            If_CutForEachLeaf( pIfMan, pCutBest, pIfLeaf, k )
                Vec_IntPush( vLeaves, pIfLeaf->iCopy );
            // perform decomposition of the cut
            pIfObj->iCopy = Gia_ManFromIfStrNode( pNew, i, vLeaves, vLeaves2, (word *)If_CutTruth(pCutBest), pIfMan->pPars->pLutStruct, vCover, vMapping, vMapping2, vPacking );
            pIfObj->iCopy = Abc_LitNotCond( pIfObj->iCopy, pCutBest->fCompl );
        }
        else if ( If_ObjIsCi(pIfObj) )
            pIfObj->iCopy = Gia_ManAppendCi(pNew);
        else if ( If_ObjIsCo(pIfObj) )
            pIfObj->iCopy = Gia_ManAppendCo( pNew, Abc_LitNotCond(If_ObjFanin0(pIfObj)->iCopy, If_ObjFaninC0(pIfObj)) );
        else if ( If_ObjIsConst1(pIfObj) )
        {
            pIfObj->iCopy = 1;
            // create const LUT
            Vec_IntWriteEntry( vMapping, 0, Vec_IntSize(vMapping2) );
            Vec_IntPush( vMapping2, 0 );
            Vec_IntPush( vMapping2, 0 );
        }
        else assert( 0 );
    }
    Vec_IntFree( vCover );
    Vec_IntFree( vLeaves );
    Vec_IntFree( vLeaves2 );
//    printf( "Mapping array size:  IfMan = %d. Gia = %d. Increase = %.2f\n", 
//        If_ManObjNum(pIfMan), Gia_ManObjNum(pNew), 1.0 * Gia_ManObjNum(pNew) / If_ManObjNum(pIfMan) );
    // finish mapping 
    if ( Vec_IntSize(vMapping) > Gia_ManObjNum(pNew) )
        Vec_IntShrink( vMapping, Gia_ManObjNum(pNew) );
    else
        Vec_IntFillExtra( vMapping, Gia_ManObjNum(pNew), 0 );
    assert( Vec_IntSize(vMapping) == Gia_ManObjNum(pNew) );
    Vec_IntForEachEntry( vMapping, Entry, i )
        if ( Entry > 0 )
            Vec_IntAddToEntry( vMapping, i, Gia_ManObjNum(pNew) );
    Vec_IntAppend( vMapping, vMapping2 );
    Vec_IntFree( vMapping2 );
    // attach mapping and packing
    pNew->nOffset  = Vec_IntSize(vMapping);
    pNew->pMapping = Vec_IntReleaseArray(vMapping);
    pNew->vPacking = vPacking;
    Vec_IntFree( vMapping );
    // verify that COs have mapping
    {
        Gia_Obj_t * pObj;
        Gia_ManForEachCo( pNew, pObj, i )
        {
            if ( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) )
                assert( pNew->pMapping[Gia_ObjFaninId0p(pNew, pObj)] != 0 );
        }
    }
    return pNew;
}


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

  Synopsis    [Verifies mapping.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Gia_ManMappingVerify_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
{
    int Id, iFan, k, Result = 1;
    if ( Gia_ObjIsTravIdCurrent(p, pObj) )
        return 1;
    Gia_ObjSetTravIdCurrent(p, pObj);
    if ( !Gia_ObjIsAnd(pObj) )
        return 1;
    if ( !Gia_ObjIsLut(p, Gia_ObjId(p, pObj)) )
    {
        Abc_Print( -1, "Gia_ManMappingVerify: Internal node %d does not have mapping.\n", Gia_ObjId(p, pObj) );
        return 0;
    }
    Id = Gia_ObjId(p, pObj);
    Gia_LutForEachFanin( p, Id, iFan, k )
        if ( Result )
            Result &= Gia_ManMappingVerify_rec( p, Gia_ManObj(p, iFan) );
    return Result;
}
void Gia_ManMappingVerify( Gia_Man_t * p )
{
    Gia_Obj_t * pObj, * pFanin;
    int i, Result = 1;
/*
    if ( p->pMapping )
    {
        assert( p->nOffset != 0 );
        Vec_IntFreeP( p->vMapping );
        Vec_IntAlloc( p->vMapping, p->nOffset );
        memmove( Vec_IntArray(p->vMapping), p->pMapping, p->nOffset );
    }
    assert( p->vMapping );
*/
    assert( p->pMapping );
    Gia_ManIncrementTravId( p );
    Gia_ManForEachCo( p, pObj, i )
    {
        pFanin = Gia_ObjFanin0(pObj);
        if ( !Gia_ObjIsAnd(pFanin) )
            continue;
        if ( !Gia_ObjIsLut(p, Gia_ObjId(p, pFanin)) )
        {
            Abc_Print( -1, "Gia_ManMappingVerify: CO driver %d does not have mapping.\n", Gia_ObjId(p, pFanin) );
            Result = 0;
            continue;
        }
        Result &= Gia_ManMappingVerify_rec( p, pFanin );
    }
//    if ( Result && Gia_NtkIsRoot(p) )
//        Abc_Print( 1, "Mapping verified correctly.\n" );
}


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

  Synopsis    [Transfers mapping from hie GIA to normalized GIA.]

  Description [Hie GIA (pGia) points to normalized GIA (p).]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManTransferMapping( Gia_Man_t * pGia, Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    int i, k, iFan;
    assert( pGia->pMapping != NULL );
    Gia_ManMappingVerify( pGia );
    Vec_IntFreeP( &p->vMapping );
    p->vMapping = Vec_IntAlloc( 2 * Gia_ManObjNum(p) );
    Vec_IntFill( p->vMapping, Gia_ManObjNum(p), 0 );
    Gia_ManForEachLut( pGia, i )
    {
        assert( !Abc_LitIsCompl(Gia_ObjValue(Gia_ManObj(pGia, i))) );
        pObj = Gia_ManObj( p, Abc_Lit2Var(Gia_ObjValue(Gia_ManObj(pGia, i))) );
        Vec_IntWriteEntry( p->vMapping, Gia_ObjId(p, pObj), Vec_IntSize(p->vMapping) );
        Vec_IntPush( p->vMapping, Gia_ObjLutSize(pGia, i) );
        Gia_LutForEachFanin( pGia, i, iFan, k )
            Vec_IntPush( p->vMapping, Abc_Lit2Var(Gia_ObjValue(Gia_ManObj(pGia, iFan))) );
        Vec_IntPush( p->vMapping, Gia_ObjId(p, pObj) );
    }
    // create standard mapping
    assert( p->pMapping == NULL );
    p->pMapping = Vec_IntArray( p->vMapping );
    p->vMapping->pArray = NULL;
    p->nOffset = Vec_IntSize(p->vMapping);
    p->vMapping->nSize = 0;
    Gia_ManMappingVerify( p );
}

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

  Synopsis    [Transfers packing from hie GIA to normalized GIA.]

  Description [Hie GIA (pGia) points to normalized GIA (p).]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManTransferPacking( Gia_Man_t * pGia, Gia_Man_t * p )
{
    Vec_Int_t * vPackingNew;
    Gia_Obj_t * pObj, * pObjNew;
    int i, k, Entry, nEntries, nEntries2;
    if ( pGia->vPacking == NULL )
        return;
    nEntries = Vec_IntEntry( pGia->vPacking, 0 );
    nEntries2 = 0;
    // create new packing info
    vPackingNew = Vec_IntAlloc( Vec_IntSize(pGia->vPacking) );
    Vec_IntPush( vPackingNew, nEntries );
    Vec_IntForEachEntryStart( pGia->vPacking, Entry, i, 1 )
    {
        assert( Entry > 0 && Entry < 4 );
        Vec_IntPush( vPackingNew, Entry );
        i++;
        for ( k = 0; k < Entry; k++, i++ )
        {
            pObj = Gia_ManObj(pGia, Vec_IntEntry(pGia->vPacking, i));
            pObjNew = Gia_ManObj(p, Abc_Lit2Var(Gia_ObjValue(pObj)));
            assert( Gia_ObjIsLut(pGia, Gia_ObjId(pGia, pObj)) );
            assert( Gia_ObjIsLut(p, Gia_ObjId(p, pObjNew)) );
            Vec_IntPush( vPackingNew, Gia_ObjId(p, pObjNew) );
//            printf( "%d -> %d  ", Vec_IntEntry(pGia->vPacking, i), Gia_ObjId(p, pObjNew) );
        }
        i--;
        nEntries2++;
    }
    assert( nEntries == nEntries2 );
    // attach packing info
    assert( p->vPacking == NULL );
    p->vPacking = vPackingNew;
}


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

  Synopsis    [Interface of LUT mapping package.]

  Description []
               
  SideEffects []

  SeeAlso     [] 

***********************************************************************/
Gia_Man_t * Gia_ManPerformMapping( Gia_Man_t * p, void * pp )
{
    Gia_Man_t * pNew;
    If_Man_t * pIfMan;
    If_Par_t * pPars = (If_Par_t *)pp;
    // reconstruct GIA according to the hierarchy manager
    assert( pPars->pTimesArr == NULL );
    assert( pPars->pTimesReq == NULL );
    if ( p->pManTime )
    {
        pNew = Gia_ManDupUnnormalize( p );
        if ( pNew == NULL )
            return NULL;
        pNew->pManTime   = p->pManTime;   p->pManTime  = NULL;
        pNew->pAigExtra  = p->pAigExtra;  p->pAigExtra = NULL;
        pNew->nAnd2Delay = p->nAnd2Delay; p->nAnd2Delay = 0;
        p = pNew;
        // set arrival and required times
        pPars->pTimesArr = Tim_ManGetArrTimes( (Tim_Man_t *)p->pManTime );
        pPars->pTimesReq = Tim_ManGetReqTimes( (Tim_Man_t *)p->pManTime );
    }
    else 
        p = Gia_ManDup( p );
    // translate into the mapper
    pIfMan = Gia_ManToIf( p, pPars );    
    if ( pIfMan == NULL )
    {
        Gia_ManStop( p );
        return NULL;
    }
    if ( p->pManTime )
        pIfMan->pManTim = Tim_ManDup( (Tim_Man_t *)p->pManTime, 0 );
    if ( !If_ManPerformMapping( pIfMan ) )
    {
        If_ManStop( pIfMan );
        Gia_ManStop( p );
        return NULL;
    }
    // transform the result of mapping into the new network
    if ( pIfMan->pPars->pLutStruct )
        pNew = Gia_ManFromIfStr( pIfMan );
    else
        pNew = Gia_ManFromIf( pIfMan );
    If_ManStop( pIfMan );
    // transfer name
    assert( pNew->pName == NULL );
    pNew->pName = Abc_UtilStrsav( p->pName );
    pNew->pSpec = Abc_UtilStrsav( p->pSpec );
    Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
    // unmap in case of SOP balancing
//    if ( pIfMan->pPars->fDelayOpt )
//        Vec_IntFreeP( &pNew->vMapping );
    // return the original (unmodified by the mapper) timing manager
    pNew->pManTime   = p->pManTime;   p->pManTime   = NULL;
    pNew->pAigExtra  = p->pAigExtra;  p->pAigExtra  = NULL;
    pNew->nAnd2Delay = p->nAnd2Delay; p->nAnd2Delay = 0;
    Gia_ManStop( p );
    // normalize and transfer mapping
    pNew = Gia_ManDupNormalize( p = pNew );
    Gia_ManTransferMapping( p, pNew );
    Gia_ManTransferPacking( p, pNew );
    pNew->pManTime   = p->pManTime;   p->pManTime   = NULL;
    pNew->pAigExtra  = p->pAigExtra;  p->pAigExtra  = NULL;
    pNew->nAnd2Delay = p->nAnd2Delay; p->nAnd2Delay = 0;
//    pNew->vPacking  = p->vPacking;  p->vPacking = NULL;
    Gia_ManStop( p );

//    printf( "PERFORMING VERIFICATION:\n" );
//    Gia_ManVerifyWithBoxes( pNew, NULL );

    return pNew;
}

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


ABC_NAMESPACE_IMPL_END

