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

  FileName    [giaMinLut.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Scalable AIG package.]

  Synopsis    [Collapsing AIG.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "gia.h"
#include "giaAig.h"
#include "base/main/mainInt.h"
#include "opt/sfm/sfm.h"

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

ABC_NAMESPACE_IMPL_START

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

extern Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pMan );

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

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Wec_t * Vec_WrdReadLayerText( char * pFileName, int * pnIns, int * pnOuts )
{
    char * pThis, pLine[1000];
    Vec_Wec_t * vRes; int iLine;
    FILE * pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open file \"%s\" for reading.\n", pFileName );
        return NULL;
    }
    vRes = Vec_WecAlloc(100);
    for ( iLine = 0; fgets( pLine, 1000, pFile ); iLine++ )
    {
        if ( iLine == 0 )
        {
            pThis = strstr( pLine, "[" );
            *pnIns = atoi( pThis+1 ) + 1;
            pThis = strstr( pThis+1, "[" );
            *pnOuts = atoi( pThis+1 ) + 1;
        }
        else
        {
            Vec_Int_t * vLevel = NULL;
            for ( pThis = pLine; (pThis = strstr(pThis, "M0[")); pThis++ )
            {
                if ( vLevel == NULL )
                    vLevel = Vec_WecPushLevel( vRes );
                Vec_IntPush( vLevel, atoi( pThis+3 ) );
            }
            if ( vLevel )
                Vec_IntReverseOrder( vLevel );
        }
    }
    fclose( pFile );
    //Vec_WecPrint( vRes, 0 );
    return vRes;
}
int Vec_WrdReadTruthTextOne( char * pFileName, int nIns, int nOuts, word * pRes )
{
    int i, nWords = Abc_TtWordNum( nIns );
    char * pStart, * pBuffer = Extra_FileReadContents( pFileName );
    if ( pBuffer == NULL )
    {
        printf( "Cannot read file \"%s\".\n", pFileName );
        return 0;
    }
    pStart = pBuffer;
    for ( i = 0; i < nOuts; i++ )
    {
        pStart = strstr( pStart + 1, "0x" );
        if ( !Extra_ReadHex( (unsigned *)(pRes + i*nWords), pStart + 2, nWords*16 ) )
        {
            printf( "Cannot read truth table %d (out of %d) in file \"%s\".\n", i, nOuts, pFileName );
            ABC_FREE( pBuffer );
            return 0;
        }
    }
    ABC_FREE( pBuffer );
    return 1;
}
word * Vec_WrdReadTruthText( char * pFileName, int nIns, int nOuts, int nFiles )
{
    char FileName[1000];
    int i, nWords = Abc_TtWordNum( nIns );
    word * pRes = ABC_CALLOC( word, nOuts*nFiles*nWords );
    for ( i = 0; i < nFiles; i++ )
    {
        assert( strlen(pFileName) < 900 );
        strcpy( FileName, pFileName );
        sprintf( FileName + strlen(FileName) - 2, "_N%d.bench", i );
        if ( !Vec_WrdReadTruthTextOne( FileName, nIns, nOuts, pRes + i*nOuts*nWords ) )
        {
            ABC_FREE( pRes );
            return NULL;
        }
    }
    return pRes;
}
Gia_Man_t * Vec_WrdReadTest( char * pFileName )
{
    extern int Gia_ManPerformLNetOpt_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj );
    extern Gia_Man_t * Gia_TryPermOptCare( word * pTruths, int nIns, int nOuts, int nWords, int nRounds, int fVerbose );
    Gia_Man_t * pPart, * pNew = NULL; Gia_Obj_t * pObj;
    int i, k, nIns, nOuts, iLit;
    Vec_Wec_t * vRes = Vec_WrdReadLayerText( pFileName, &nIns, &nOuts );
    int nBitsI = vRes ? Vec_WecMaxLevelSize(vRes) : 0;
    int nBitsO = vRes ? nOuts / Vec_WecSize(vRes) : 0;
    int nWords = Abc_TtWordNum(nBitsI);
    word * pFuncs = vRes ? Vec_WrdReadTruthText( pFileName, nBitsI, nBitsO, Vec_WecSize(vRes) ) : NULL;
    Vec_Int_t * vPart, * vLits = Vec_IntAlloc( nOuts );
    if ( vRes == NULL || pFuncs == NULL )
    {
        Vec_WecFreeP( &vRes );
        Vec_IntFreeP( &vLits );
        ABC_FREE( pFuncs );
        return NULL;
    }
    assert( nOuts % Vec_WecSize(vRes) == 0 );
    pNew = Gia_ManStart( 10000 );
    pNew->pName = Abc_UtilStrsav( pFileName );
    pNew->pSpec = NULL;
    for ( i = 0; i < nIns; i++ )
        Gia_ManAppendCi(pNew);
    Gia_ManHashStart( pNew );
    Vec_WecForEachLevel( vRes, vPart, i )
    {
        assert( Vec_IntSize(vPart) <= nBitsI );
        pPart = Gia_TryPermOptCare( pFuncs + i * nBitsO * nWords, nBitsI, nBitsO, nWords, 20, 0 );
        Gia_ManFillValue( pPart );
        Gia_ManConst0(pPart)->Value = 0;
        Gia_ManForEachCi( pPart, pObj, k )
            pObj->Value = Abc_Var2Lit( 1+Vec_IntEntry(vPart, k), 0 );
        Gia_ManForEachCo( pPart, pObj, k )
        {
            Gia_ManPerformLNetOpt_rec( pNew, pPart, Gia_ObjFanin0(pObj) );
            Vec_IntPush( vLits, Gia_ObjFanin0Copy(pObj) );
        }
        Gia_ManStop( pPart );
    }
    Gia_ManHashStop( pNew );
    Vec_IntForEachEntry( vLits, iLit, i )
        Gia_ManAppendCo( pNew, iLit );
    ABC_FREE( pFuncs );
    Vec_WecFree( vRes );
    Vec_IntFree( vLits );
    return pNew;
}

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
void Vec_WrdReadText( char * pFileName, Vec_Wrd_t ** pvSimI, Vec_Wrd_t ** pvSimO, int nIns, int nOuts )
{
    int i, nSize, iLine, nLines, nWords;
    char pLine[1000];
    Vec_Wrd_t * vSimI, * vSimO;
    FILE * pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open file \"%s\" for reading.\n", pFileName );
        return;
    }
    fseek( pFile, 0, SEEK_END );  
    nSize = ftell( pFile );  
    if ( nSize % (nIns + nOuts + 1) > 0 )
    {
        printf( "Cannot read file with simulation data that is not aligned at 8 bytes (remainder = %d).\n", nSize % (nIns + nOuts + 1) );
        fclose( pFile );
        return;
    }
    rewind( pFile );
    nLines = nSize / (nIns + nOuts + 1);
    nWords = (nLines + 63)/64;
    vSimI  = Vec_WrdStart( nIns *nWords );
    vSimO  = Vec_WrdStart( nOuts*nWords );
    for ( iLine = 0; fgets( pLine, 1000, pFile ); iLine++ )
    {
        for ( i = 0; i < nIns; i++ )
            if ( pLine[nIns-1-i] == '1' )
                Abc_TtXorBit( Vec_WrdArray(vSimI) + i*nWords, iLine );
            else assert( pLine[nIns-1-i] == '0' );
        for ( i = 0; i < nOuts; i++ )
            if ( pLine[nIns+nOuts-1-i] == '1' )
                Abc_TtXorBit( Vec_WrdArray(vSimO) + i*nWords, iLine );
            else assert( pLine[nIns+nOuts-1-i] == '0' );
    }
    fclose( pFile );
    *pvSimI = vSimI;
    *pvSimO = vSimO;
    printf( "Read %d words of simulation data for %d inputs and %d outputs (padded %d zero-patterns).\n", nWords, nIns, nOuts, nWords*64-nLines );
}
int Vec_WrdReadText2( char * pFileName, Vec_Wrd_t ** pvSimI )
{
    int i, nSize, iLine, nLines, nWords, nIns;
    char pLine[1000];
    Vec_Wrd_t * vSimI;
    FILE * pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open file \"%s\" for reading.\n", pFileName );
        return 0;
    }
    if ( !fgets(pLine, 1000, pFile) || (nIns = strlen(pLine)-1) < 1 )
    {
        printf( "Cannot find the number of inputs in file \"%s\".\n", pFileName );
        fclose( pFile );
        return 0;
    }
    fseek( pFile, 0, SEEK_END );  
    nSize = ftell( pFile );  
    if ( nSize % (nIns + 1) > 0 )
    {
        printf( "Cannot read file with simulation data that is not aligned at 8 bytes (remainder = %d).\n", nSize % (nIns + 1) );
        fclose( pFile );
        return 0;
    }
    rewind( pFile );
    nLines = nSize / (nIns + 1);
    nWords = (nLines + 63)/64;
    vSimI  = Vec_WrdStart( nIns *nWords );
    for ( iLine = 0; fgets( pLine, 1000, pFile ); iLine++ )
    {
        for ( i = 0; i < nIns; i++ )
            if ( pLine[nIns-1-i] == '1' )
                Abc_TtXorBit( Vec_WrdArray(vSimI) + i*nWords, iLine );
            else assert( pLine[nIns-1-i] == '0' );
    }
    fclose( pFile );
    *pvSimI = vSimI;
    printf( "Read %d words of simulation data for %d inputs (padded to 64-bit boundary with %d zero-patterns).\n", nWords, nIns, nWords*64-nLines );
    return nIns;
}
Vec_Int_t * Vec_WrdReadNumsOut( char * pFileName, int fVerbose )
{
    char pLine[1000]; 
    Vec_Int_t * vNums; int iLine;
    FILE * pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open file \"%s\" for reading.\n", pFileName );
        return NULL;
    }
    vNums = Vec_IntAlloc( 1000 );
    for ( iLine = 0; fgets( pLine, 1000, pFile ); iLine++ )
        Vec_IntPush( vNums, atoi(pLine) );
    fclose( pFile );
    if ( fVerbose )
    printf( "Finished reading %d output values from file \"%s\".\n", Vec_IntSize(vNums), pFileName );
    return vNums;
}
Vec_Wrd_t * Vec_WrdReadTextOut( char * pFileName, int nOuts )
{
    int i, iLine, nLines, nWords;
    Vec_Wrd_t * vSimO;
    Vec_Int_t * vNums = Vec_WrdReadNumsOut( pFileName, 1 );
    if ( vNums == NULL )
        return NULL;
    nLines = Vec_IntSize(vNums);
    nWords = (nLines + 63)/64;
    vSimO  = Vec_WrdStart( nOuts*nWords );
    Vec_IntForEachEntry( vNums, i, iLine )
        Abc_TtXorBit( Vec_WrdArray(vSimO) + i*nWords, iLine );
    Vec_IntFree( vNums );
    printf( "Read %d words of simulation data for %d outputs (padded %d zero-patterns).\n", nWords, nOuts, nWords*64-nLines );
    return vSimO;
}
void Gia_ManReadSimInfoInputs( char * pFileName, char * pFileOut1, int fVerbose )
{
    Vec_Wrd_t * vSimI;
    Vec_WrdReadText2( pFileName, &vSimI );
    Vec_WrdDumpBin( pFileOut1, vSimI, fVerbose );
    Vec_WrdFree( vSimI );
}
void Gia_ManReadSimInfoOutputs( char * pFileName, char * pFileOut, int nOuts )
{
    Vec_Wrd_t * vSimO = Vec_WrdReadTextOut( pFileName, nOuts );
    Vec_WrdDumpBin( pFileOut, vSimO, 1 );
    Vec_WrdFree( vSimO );
}

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Wrd_t * Vec_WrdZoneExtract( int ZoneSize, Vec_Wrd_t * p, int iWord, int nWords )
{
    int z, nZones = Vec_WrdSize(p)/ZoneSize;
    int w, Limit = Abc_MinInt( nWords, ZoneSize-iWord );
    Vec_Wrd_t * pNew = Vec_WrdStart( nZones*nWords );
    for ( z = 0; z < nZones; z++ )
        for ( w = 0; w < Limit; w++ )
            Vec_WrdWriteEntry( pNew, z*nWords + w, Vec_WrdEntry(p, z*ZoneSize + iWord + w) );
    return pNew;
}
void Vec_WrdZoneInsert( Vec_Wrd_t * pNew, int ZoneSize, Vec_Wrd_t * p, int iWord, int nWords )
{
    int z, nZones = Vec_WrdSize(pNew)/ZoneSize;
    int w, Limit = Abc_MinInt( nWords, ZoneSize-iWord );
    for ( z = 0; z < nZones; z++ )
        for ( w = 0; w < Limit; w++ )
            Vec_WrdWriteEntry( pNew, z*ZoneSize + iWord + w, Vec_WrdEntry(p, z*nWords + w) );
}

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_ManSimInfoPrintOne( Gia_Man_t * p, Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nWords, int nPats )
{
    int Id, i, k;
    for ( k = 0; k < nPats; k++ )
    {
        Gia_ManForEachCiId( p, Id, i )
    //        printf( "%d", Vec_WrdEntry(p->vSims, p->nSimWords*Id) & 1 );
            printf( "%d", (int)(Vec_WrdEntry(vSimsIn,  nWords*i) >> k) & 1 );
        printf( " " );
        Gia_ManForEachCoId( p, Id, i )
    //        printf( "%d", Vec_WrdEntry(p->vSims, p->nSimWords*Id) & 1 );
            printf( "%d", (int)(Vec_WrdEntry(vSimsOut, nWords*i) >> k) & 1 );
        printf( "\n" );
    }
}
Vec_Wrd_t * Gia_ManSimInfoTryOne( Gia_Man_t * p, Vec_Wrd_t * vSimI, int fPrint )
{
    extern Vec_Wrd_t * Gia_ManSimulateWordsOut( Gia_Man_t * p, Vec_Wrd_t * vSimsIn );
    Vec_Wrd_t * vSimsOut = Gia_ManSimulateWordsOut( p, vSimI );
    int nWords = Vec_WrdSize(vSimI) / Gia_ManCiNum(p);
    assert( Vec_WrdSize(vSimI) % Gia_ManCiNum(p) == 0 );
    if ( fPrint )
        Gia_ManSimInfoPrintOne( p, vSimI, vSimsOut, nWords, 6 );
    return vSimsOut;
}
int Gia_ManSimEvalOne( Gia_Man_t * p, Vec_Wrd_t * vSimO, Vec_Wrd_t * vSimO_new )
{
    int i, Count = 0, nWords = Vec_WrdSize(vSimO) / Gia_ManCoNum(p);
    word * pSim0 = ABC_CALLOC( word, nWords );
    assert( Vec_WrdSize(vSimO) == Vec_WrdSize(vSimO_new) );
    for ( i = 0; i < Gia_ManCoNum(p); i++ )
    {
        word * pSimGold = Vec_WrdEntryP( vSimO,     i * nWords );
        word * pSimImpl = Vec_WrdEntryP( vSimO_new, i * nWords );
        Abc_TtOrXor( pSim0, pSimImpl, pSimGold, nWords );
    }
    Count = Abc_TtCountOnesVec( pSim0, nWords );
    printf( "Number of failed patterns is %d (%8.4f %% of %d). The first one is %d.\n", 
        Count, 100.0*Count/(64*nWords), 64*nWords, Abc_TtFindFirstBit2(pSim0, nWords) );
    ABC_FREE( pSim0 );
    return Count;
}
int Gia_ManSimEvalOne2( Gia_Man_t * p, Vec_Wrd_t * vSimO, Vec_Wrd_t * vSimO_new )
{
    int i, Count = 0, nWords = Vec_WrdSize(vSimO) / Gia_ManCoNum(p);
    word * pSim0 = ABC_CALLOC( word, nWords );
    assert( Vec_WrdSize(vSimO) == Vec_WrdSize(vSimO_new) );
    for ( i = 0; i < Gia_ManCoNum(p); i++ )
    {
        word * pSimGold = Vec_WrdEntryP( vSimO,     i * nWords );
        word * pSimImpl = Vec_WrdEntryP( vSimO_new, i * nWords );
        Abc_TtXor( pSim0, pSimImpl, pSimGold, nWords, 0 );
        Count += Abc_TtCountOnesVec( pSim0, nWords );
    }
    printf( "Number of failed patterns is %d (%8.4f %% of %d). The first one is %d.\n", 
        Count, 100.0*Count/(64*nWords*Gia_ManCoNum(p)), 64*nWords*Gia_ManCoNum(p), Abc_TtFindFirstBit2(pSim0, nWords) );
    ABC_FREE( pSim0 );
    return Count;
}
int Gia_ManSimEvalMaxValue( Vec_Wrd_t * vSimO, int nWords, int nOuts, int nBits, int iPat )
{
    int o, ValueMax = -1, OutMax = -1;
    for ( o = 0; o < nOuts; o++ )
    {
        int i, Value = 0;
        for ( i = 0; i < nBits; i++ )
        {
            word * pSim = Vec_WrdEntryP( vSimO, (o*nBits+i) * nWords );
            if ( Abc_TtGetBit(pSim, iPat) )
                Value |= 1 << i;
        }
        if ( ValueMax <= Value )
        {
            ValueMax = Value;
            OutMax = o;
        }
    }
    return OutMax;
}
int Gia_ManSimEvalOne3( Gia_Man_t * p, Vec_Wrd_t * vSimO, Vec_Int_t * vValues, int nBits )
{
    int i, Value, nOuts = Gia_ManCoNum(p) / nBits;
    int First = -1, Count = 0, nWords = Vec_WrdSize(vSimO) / Gia_ManCoNum(p);
    assert( Gia_ManCoNum(p) % nBits == 0 );
    assert( 64*(nWords-1) < Vec_IntSize(vValues) && Vec_IntSize(vValues) <= 64*nWords );
    Vec_IntForEachEntry( vValues, Value, i )
        if ( Value == Gia_ManSimEvalMaxValue(vSimO, nWords, nOuts, nBits, i) )
        {
            Count++;
            if ( First == -1 )
                First = i;
        }
    printf( "The accuracy is %8.4f %% (%d out of %d output are correct, for example, output number %d).\n", 
        100.0*Count/Vec_IntSize(vValues), Count, Vec_IntSize(vValues), First );
    if ( 0 )
    {
        FILE * pTable = fopen( "stats.txt", "a+" );
        fprintf( pTable, "%0.2f \n", 100.0*Count/Vec_IntSize(vValues) );
        fclose( pTable );
    }
    return Count;
}
Vec_Wrd_t * Gia_ManSimInfoTry( Gia_Man_t * p, Vec_Wrd_t * vSimI )
{
    int nWords = Vec_WrdSize(vSimI) / Gia_ManCiNum(p);
    int w, nWordsOne = 200, nWordBatches = (nWords + nWordsOne - 1)/nWordsOne;
    Vec_Wrd_t * vSimO_new = Vec_WrdStart( nWords * Gia_ManCoNum(p) );
    for ( w = 0; w < nWordBatches; w++ )
    {
        //int Value = printf( "%3d / %3d : ", w, nWordBatches );
        Vec_Wrd_t * vSimI_ = Vec_WrdZoneExtract( nWords, vSimI, w*nWordsOne, nWordsOne );
        Vec_Wrd_t * vSimO_ = Gia_ManSimInfoTryOne( p, vSimI_, 0 );
        Vec_WrdZoneInsert( vSimO_new, nWords, vSimO_, w*nWordsOne, nWordsOne );
        Vec_WrdFree( vSimI_ );
        Vec_WrdFree( vSimO_ );
        //Value = 0;
    }
    return vSimO_new;
}
int Gia_ManSimInfoEval_old( Gia_Man_t * p, Vec_Wrd_t * vSimO, Vec_Wrd_t * vSimO_new )
{
    int nResult = Gia_ManSimEvalOne2(p, vSimO, vSimO_new);
    //Vec_WrdDumpBin( "temp.simo", vSimO_new, 1 );
    printf( "Total errors = %d.  ", nResult );
    printf( "Density of output patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSimO_new), Vec_WrdSize(vSimO_new))/(64*Vec_WrdSize(vSimO_new)) );
    return nResult;
}
void Gia_ManSimInfoPassTest( Gia_Man_t * p, char * pFileName, char * pFileName2, int fVerbose )
{
    abctime clk = Abc_Clock();
    Vec_Wrd_t * vSimI = Vec_WrdReadBin( pFileName, fVerbose );
    Vec_Wrd_t * vSimO = Gia_ManSimInfoTry( p, vSimI );
    if ( fVerbose )
    printf( "Density of input  patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSimI), Vec_WrdSize(vSimI))/(64*Vec_WrdSize(vSimI)) );
    if ( fVerbose )
    printf( "Density of output patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSimO), Vec_WrdSize(vSimO))/(64*Vec_WrdSize(vSimO)) );
    Vec_WrdDumpBin( pFileName2, vSimO, fVerbose );
    Vec_WrdFree( vSimI );
    Vec_WrdFree( vSimO );
    if ( fVerbose )
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
void Gia_ManSimInfoEval( Gia_Man_t * p, char * pFileName, char * pFileName2, int nOuts, int fVerbose )
{
    abctime clk = Abc_Clock();
    Vec_Wrd_t * vSim1 = Vec_WrdReadBin( pFileName, fVerbose );
    Vec_Int_t * vNums = Vec_WrdReadNumsOut( pFileName2, fVerbose );
    assert( nOuts > 0 );
    if ( fVerbose )
    printf( "Density of input  patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSim1), Vec_WrdSize(vSim1))/(64*Vec_WrdSize(vSim1)) );
    Gia_ManSimEvalOne3( p, vSim1, vNums, nOuts );
    Vec_WrdFree( vSim1 );
    Vec_IntFree( vNums );
    if ( fVerbose )
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
word * Gia_ManCountFraction( Gia_Man_t * p, Vec_Wrd_t * vSimI, Vec_Int_t * vSupp, int Thresh, int fVerbose, int * pCare )
{
    Gia_Obj_t * pObj;
    int i, k, nUsed = 0, nGood = 0;
    int nWords = Vec_WrdSize(vSimI) / Gia_ManCiNum(p);
    int nMints = 1 << Vec_IntSize(vSupp);
    word ** pSims = ABC_ALLOC( word *, Vec_IntSize(vSupp) );
    word * pRes   = ABC_CALLOC( word, Abc_Truth6WordNum(Vec_IntSize(vSupp)) );
    int * pCounts = ABC_CALLOC( int, nMints );
    Gia_ManForEachObjVec( vSupp, p, pObj, i )
        pSims[i] = Vec_WrdEntryP( vSimI, Gia_ObjCioId(pObj) * nWords );
    for ( k = 0; k < 64*nWords; k++ )
    {
        int iMint = 0;
        for ( i = 0; i < Vec_IntSize(vSupp); i++ )
            if ( Abc_TtGetBit(pSims[i], k) )
                iMint |= 1 << i;
        assert( iMint < nMints );
        pCounts[iMint]++;
    }
    for ( k = 0; k < nMints; k++ )
    {
        nUsed += (pCounts[k] > 0);
        nGood += (pCounts[k] >= Thresh);
        if ( pCounts[k] >= Thresh )
            Abc_TtXorBit( pRes, k );
        //printf( "%d ", pCounts[k] );
    }
    if ( Vec_IntSize(vSupp) < 6 )
        pRes[0] = Abc_Tt6Stretch( pRes[0], Vec_IntSize(vSupp) );
    //printf( "\n" );
    if ( fVerbose )
    printf( "Used %4d and good %4d (out of %4d).\n", nUsed, nGood, nMints ); 
    ABC_FREE( pSims );
    ABC_FREE( pCounts );
    *pCare = nGood;
    return pRes;
}
void Gia_ManPermuteSupp_rec( Gia_Man_t * p, int iObj, Vec_Int_t * vLevels, Vec_Int_t * vCounts )
{
    Gia_Obj_t * pObj; int n;
    if ( !iObj || Gia_ObjIsTravIdCurrentId(p, iObj) )
        return;
    Gia_ObjSetTravIdCurrentId(p, iObj);
    pObj = Gia_ManObj( p, iObj );
    if ( Gia_ObjIsCi(pObj) )
        return;
    assert( Gia_ObjIsAnd(pObj) );
    Gia_ManPermuteSupp_rec( p, Gia_ObjFaninId0(pObj, iObj), vLevels, vCounts );
    Gia_ManPermuteSupp_rec( p, Gia_ObjFaninId1(pObj, iObj), vLevels, vCounts );
    for ( n = 0; n < 2; n++ )
    {
        Gia_Obj_t * pFanin = n ? Gia_ObjFanin1(pObj) : Gia_ObjFanin0(pObj);
        if ( !Gia_ObjIsCi(pFanin) )
            continue;
        Vec_IntAddToEntry( vLevels, Gia_ObjCioId(pFanin), Gia_ObjLevel(p, pObj) );
        Vec_IntAddToEntry( vCounts, Gia_ObjCioId(pFanin), 1 );
    }
}
void Gia_ManPermuteSupp( Gia_Man_t * p, int iOut, int nOuts, Vec_Int_t * vSupp )
{
    Vec_Int_t * vLevels = Vec_IntStart( Gia_ManCiNum(p) );
    Vec_Int_t * vCounts = Vec_IntStart( Gia_ManCiNum(p) ); 
    int i, * pCost = ABC_CALLOC( int, Gia_ManCiNum(p) );
    Gia_Obj_t * pObj;
    Gia_ManIncrementTravId( p );
    for ( i = 0; i < nOuts; i++ )
        Gia_ManPermuteSupp_rec( p, Gia_ObjFaninId0p(p, Gia_ManCo(p, iOut+i)), vLevels, vCounts );
    Gia_ManForEachObjVec( vSupp, p, pObj, i )
        pCost[i] = 10000 * Vec_IntEntry(vLevels, Gia_ObjCioId(pObj)) / Abc_MaxInt(1, Vec_IntEntry(vCounts, Gia_ObjCioId(pObj)));
    Vec_IntFree( vCounts );
    Vec_IntFree( vLevels );
    Vec_IntSelectSortCost2( Vec_IntArray(vSupp), Vec_IntSize(vSupp), pCost );
    assert( Vec_IntSize(vSupp) < 2 || pCost[0] <= pCost[1] );
    ABC_FREE( pCost );
}
void Gia_ManCollectSupp_rec( Gia_Man_t * p, int iObj, Vec_Int_t * vSupp )
{
    Gia_Obj_t * pObj;
    if ( !iObj || Gia_ObjIsTravIdCurrentId(p, iObj) )
        return;
    Gia_ObjSetTravIdCurrentId(p, iObj);
    pObj = Gia_ManObj( p, iObj );
    if ( Gia_ObjIsCi(pObj) )
    {
        //Vec_IntPush( vSupp, Gia_ObjCioId(pObj) );
        Vec_IntPush( vSupp, Gia_ObjId(p, pObj) );
        return;
    }
    assert( Gia_ObjIsAnd(pObj) );
    Gia_ManCollectSupp_rec( p, Gia_ObjFaninId0(pObj, iObj), vSupp );
    Gia_ManCollectSupp_rec( p, Gia_ObjFaninId1(pObj, iObj), vSupp );
}
Vec_Int_t * Gia_ManCollectSupp( Gia_Man_t * p, int iOut, int nOuts )
{
    Vec_Int_t * vSupp = Vec_IntAlloc( 16 ); int i;
    Gia_ManIncrementTravId( p );
    for ( i = 0; i < nOuts; i++ )
        Gia_ManCollectSupp_rec( p, Gia_ObjFaninId0p(p, Gia_ManCo(p, iOut+i)), vSupp );
    return vSupp;
}
Vec_Int_t * Gia_ManCollectSuppNew( Gia_Man_t * p, int iOut, int nOuts )
{
    Vec_Int_t * vRes = Gia_ManCollectSupp( p, iOut, nOuts );
    Gia_ManPermuteSupp( p, iOut, nOuts, vRes );
    return vRes;
}
int Gia_ManPerformLNetOpt_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj )
{
    if ( ~pObj->Value )
        return pObj->Value;
    assert( Gia_ObjIsAnd(pObj) );
    Gia_ManPerformLNetOpt_rec( pNew, p, Gia_ObjFanin0(pObj) );
    Gia_ManPerformLNetOpt_rec( pNew, p, Gia_ObjFanin1(pObj) );
    return pObj->Value = Gia_ManHashAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
}
Gia_Man_t * Gia_ManPerformLNetOpt( Gia_Man_t * p, int fTryNew, char * pFileName, int nIns, int nOuts, int Thresh, int nRounds, int fVerbose )
{
    extern Gia_Man_t * Gia_TryPermOpt( word * pTruths, int nIns, int nOuts, int nWords, int nRounds, int fVerbose );
    extern Gia_Man_t * Gia_TryPermOptCare( word * pTruths, int nIns, int nOuts, int nWords, int nRounds, int fVerbose );
    extern int Kit_TruthToGia2( Gia_Man_t * p, unsigned * pTruth0, unsigned * pTruth1, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash );
    abctime clk = Abc_Clock();
    Gia_Man_t * pNew; Gia_Obj_t * pObj;
    Vec_Int_t * vMemory = Vec_IntAlloc( 1 << 18 );
    Vec_Int_t * vLeaves = Vec_IntAlloc( nIns );
    Vec_Wrd_t * vSimI = pFileName ? Vec_WrdReadBin( pFileName, fVerbose ) : NULL;  
    word * pTruth0 = ABC_CALLOC( word, Abc_Truth6WordNum(nIns) );
    word * pTruth1 = ABC_CALLOC( word, Abc_Truth6WordNum(nIns) ); int g, k; float CareAve = 0;
    word * pTruthsTry = ABC_CALLOC( word, 2*nOuts*Abc_Truth6WordNum(nIns) );
    if ( vSimI && fVerbose )
    {
        //int nPats = 64*Vec_WrdSize(vSimI)/Gia_ManCiNum(p);
        printf( "Density of input  patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSimI), Vec_WrdSize(vSimI))/(64*Vec_WrdSize(vSimI)) );
        printf( "Using patterns with count %d and higher as cares.\n", Thresh );
    }
    Gia_ManLevelNum( p );
    Gia_ManFillValue( p );
    pNew = Gia_ManStart( Gia_ManObjNum(p) );
    pNew->pName = Abc_UtilStrsav( p->pName );
    pNew->pSpec = Abc_UtilStrsav( p->pSpec );
    Gia_ManConst0(p)->Value = 0;
    Gia_ManForEachCi( p, pObj, k )
        pObj->Value = Gia_ManAppendCi(pNew);
    Gia_ObjComputeTruthTableStart( p, nIns );
    Gia_ManHashStart( pNew );
    for ( g = 0; g < Gia_ManCoNum(p); g += nOuts )
    {
        Vec_Int_t * vSupp = Gia_ManCollectSuppNew( p, g, nOuts );
        int Care = 1 << Vec_IntSize(vSupp), Temp = fVerbose ? printf( "Group %3d / %3d / %3d : Supp = %3d   %s", g, nOuts, Gia_ManCoNum(p), Vec_IntSize(vSupp), vSimI ? "":"\n" ) : 0;
        word * pCare = vSimI ? Gia_ManCountFraction( p, vSimI, vSupp, Thresh, fVerbose, &Care ) : ABC_FALLOC( word, Abc_Truth6WordNum(Vec_IntSize(vSupp)) );
        int nWords = Abc_Truth6WordNum( Vec_IntSize(vSupp) );
        CareAve += 100.0*Care/(1 << Vec_IntSize(vSupp));
        assert( Vec_IntSize(vSupp) <= nIns );
        Vec_IntClear( vLeaves );
        Gia_ManForEachObjVec( vSupp, p, pObj, k )
            Vec_IntPush( vLeaves, pObj->Value );        
        for ( k = 0; k < nOuts; k++ )
        {
            Gia_Obj_t * pObj = Gia_ManCo( p, g+k );
            word * pTruth = Gia_ObjComputeTruthTableCut( p, Gia_ObjFanin0(pObj), vSupp );
            Abc_TtSharp( pTruth0, pCare, pTruth, nWords );
            Abc_TtAnd( pTruth1, pCare, pTruth, nWords, 0 );
            if ( vSimI )
            {
                Abc_TtCopy( pTruthsTry + (2*k+0)*nWords, pTruth1, nWords, 0 );
                Abc_TtCopy( pTruthsTry + (2*k+1)*nWords, pTruth0, nWords, 0 );
            }
            else
                Abc_TtCopy( pTruthsTry + k*nWords, pTruth1, nWords, 0 );
            if ( !fTryNew )
            {
                pObj->Value = Kit_TruthToGia2( pNew, (unsigned *)pTruth0, (unsigned *)pTruth1, Vec_IntSize(vLeaves), vMemory, vLeaves, 1 );
                pObj->Value ^= Gia_ObjFaninC0(pObj);
            }
        }
        if ( fTryNew )
        {
            Gia_Man_t * pMin;
            if ( vSimI )
                pMin = Gia_TryPermOpt( pTruthsTry, Vec_IntSize(vSupp), 2*nOuts, nWords, nRounds, fVerbose );
            else
                pMin = Gia_TryPermOptCare( pTruthsTry, Vec_IntSize(vSupp), nOuts, nWords, nRounds, fVerbose );
            Gia_ManFillValue( pMin );
            Gia_ManConst0(pMin)->Value = 0;
            Gia_ManForEachCi( pMin, pObj, k )
                pObj->Value = Vec_IntEntry( vLeaves, k );
            for ( k = 0; k < nOuts; k++ )
            {
                Gia_Obj_t * pObj  = Gia_ManCo( p, g+k );
                Gia_Obj_t * pObj2 = Gia_ManCo( pMin, k );
                pObj->Value  = Gia_ManPerformLNetOpt_rec( pNew, pMin, Gia_ObjFanin0(pObj2) );
                pObj->Value ^= Gia_ObjFaninC0(pObj2);
                pObj->Value ^= Gia_ObjFaninC0(pObj);
            }
            Gia_ManStop( pMin );
        }
        ABC_FREE( pCare );
        Vec_IntFree( vSupp );
        Temp = 0;
    }
    CareAve /= Gia_ManCoNum(p)/nOuts;
    Gia_ManHashStop( pNew );
    Gia_ManForEachCo( p, pObj, k )
        pObj->Value = Gia_ManAppendCo( pNew, pObj->Value );
    Gia_ObjComputeTruthTableStop( p );
    ABC_FREE( pTruth0 );
    ABC_FREE( pTruth1 );
    Vec_IntFree( vLeaves );
    Vec_IntFree( vMemory );
    Vec_WrdFreeP( &vSimI );
    Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
    printf( "Using patterns with count %d and higher as cares. Average care set is %8.4f %%.  ", Thresh, CareAve );
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
    if ( 0 )
    {
        FILE * pTable = fopen( "stats.txt", "a+" );
        fprintf( pTable, "%0.2f ", CareAve );
        fclose( pTable );
    }
    ABC_FREE( pTruthsTry );
    return pNew;
}
Gia_Man_t * Gia_ManPerformLNetOptNew( Gia_Man_t * p, char * pFileName, int nIns, int nOuts, int Thresh, int nRounds, int fVerbose )
{
    extern Gia_Man_t * Gia_TryPermOptNew( word * pTruths, int nIns, int nOuts, int nWords, int nRounds, int fVerbose );
    abctime clk = Abc_Clock();
    Gia_Man_t * pNew, * pMin;  Gia_Obj_t * pObj;
    Vec_Int_t * vLeaves = Vec_IntAlloc( nIns );
    Vec_Wrd_t * vSimI = pFileName ? Vec_WrdReadBin( pFileName, fVerbose ) : NULL;  
    word * pTruthsTry = ABC_CALLOC( word, (nOuts+1)*Abc_Truth6WordNum(nIns) );
    int k, g;  float CareAve = 0;
    if ( vSimI && fVerbose )
    {
        //int nPats = 64*Vec_WrdSize(vSimI)/Gia_ManCiNum(p);
        printf( "Density of input  patterns %8.4f.\n", (float)Abc_TtCountOnesVec(Vec_WrdArray(vSimI), Vec_WrdSize(vSimI))/(64*Vec_WrdSize(vSimI)) );
        printf( "Using patterns with count %d and higher as cares.\n", Thresh );
    }
    Gia_ManLevelNum( p );
    Gia_ManFillValue( p );
    pNew = Gia_ManStart( Gia_ManObjNum(p) );
    pNew->pName = Abc_UtilStrsav( p->pName );
    pNew->pSpec = Abc_UtilStrsav( p->pSpec );
    Gia_ManConst0(p)->Value = 0;
    Gia_ManForEachCi( p, pObj, k )
        pObj->Value = Gia_ManAppendCi(pNew);
    Gia_ObjComputeTruthTableStart( p, nIns );
    Gia_ManHashStart( pNew );
    for ( g = 0; g < Gia_ManCoNum(p); g += nOuts )
    {
        for ( k = 0; k < nOuts; k++ )
            if ( Gia_ObjIsAnd(Gia_ObjFanin0(Gia_ManCo( p, g+k ))) )
                break;
        if ( k == nOuts )
        {
            for ( k = 0; k < nOuts; k++ )
            {
                Gia_Obj_t * pObj = Gia_ManCo( p, g+k );
                pObj->Value = Gia_ObjFanin0Copy(pObj);
            }
            continue;
        }
        else
        {

        Vec_Int_t * vSupp = Gia_ManCollectSuppNew( p, g, nOuts );
        int Care = 1 << Vec_IntSize(vSupp), Temp = fVerbose ? printf( "Group %3d / %3d / %3d : Supp = %3d   %s", g, nOuts, Gia_ManCoNum(p), Vec_IntSize(vSupp), vSimI ? "":"\n" ) : 0;
        word * pCare = vSimI ? Gia_ManCountFraction( p, vSimI, vSupp, Thresh, fVerbose, &Care ) : ABC_FALLOC( word, Abc_Truth6WordNum(Vec_IntSize(vSupp)) );
        int nWords = Abc_Truth6WordNum( Vec_IntSize(vSupp) );
        CareAve += 100.0*Care/(1 << Vec_IntSize(vSupp));
        assert( Vec_IntSize(vSupp) <= nIns );
        Vec_IntClear( vLeaves );
        Gia_ManForEachObjVec( vSupp, p, pObj, k )
            Vec_IntPush( vLeaves, pObj->Value );        
        for ( k = 0; k < nOuts; k++ )
        {
            Gia_Obj_t * pObj = Gia_ManCo( p, g+k );
            word * pTruth = Gia_ObjComputeTruthTableCut( p, Gia_ObjFanin0(pObj), vSupp );
            Abc_TtCopy( pTruthsTry + k*nWords, pTruth, nWords, Gia_ObjFaninC0(pObj) );
        }
        Abc_TtCopy( pTruthsTry + nOuts*nWords, pCare, nWords, 0 );
        ABC_FREE( pCare );
        pMin = Gia_TryPermOptNew( pTruthsTry, Vec_IntSize(vSupp), nOuts, nWords, nRounds, fVerbose );
        Gia_ManFillValue( pMin );
        Gia_ManConst0(pMin)->Value = 0;
        Gia_ManForEachCi( pMin, pObj, k )
            pObj->Value = Vec_IntEntry( vLeaves, k );
        Gia_ManForEachCo( pMin, pObj, k )
        {
            Gia_Obj_t * pObj0 = Gia_ManCo( p, g+k );
            pObj0->Value  = Gia_ManPerformLNetOpt_rec( pNew, pMin, Gia_ObjFanin0(pObj) );
            pObj0->Value ^= Gia_ObjFaninC0(pObj);
        }
        Gia_ManStop( pMin );
        Vec_IntFree( vSupp );
        Temp = 0;
        
        }
    }
    CareAve /= Gia_ManCoNum(p)/nOuts;
    Gia_ManHashStop( pNew );
    Gia_ManForEachCo( p, pObj, k )
        pObj->Value = Gia_ManAppendCo( pNew, pObj->Value );
    Gia_ObjComputeTruthTableStop( p );
    Vec_IntFree( vLeaves );
    Vec_WrdFreeP( &vSimI );
    Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
    printf( "Using patterns with count %d and higher as cares. Average care set is %8.4f %%.  ", Thresh, CareAve );
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
    if ( 0 )
    {
        FILE * pTable = fopen( "stats.txt", "a+" );
        fprintf( pTable, "%0.2f ", CareAve );
        fclose( pTable );
    }
    ABC_FREE( pTruthsTry );
    return pNew;
}

#ifdef ABC_USE_CUDD

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

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

***********************************************************************/
Gia_Man_t * Gia_ManDoMuxMapping( Gia_Man_t * p )
{
    extern Gia_Man_t * Gia_ManPerformMfs( Gia_Man_t * p, Sfm_Par_t * pPars );
    Gia_Man_t * pTemp, * pNew = Gia_ManDup( p );
    Jf_Par_t Pars, * pPars = &Pars; int c, nIters = 2;
    Sfm_Par_t Pars2, * pPars2 = &Pars2;
    Lf_ManSetDefaultPars( pPars );
    Sfm_ParSetDefault( pPars2 );
    pPars2->nTfoLevMax  =    5;
    pPars2->nDepthMax   =  100;
    pPars2->nWinSizeMax = 2000;
    for ( c = 0; c < nIters; c++ )
    {
        pNew = Lf_ManPerformMapping( pTemp = pNew, pPars );
        Gia_ManStop( pTemp );
        pNew = Gia_ManPerformMfs( pTemp = pNew, pPars2 );
        Gia_ManStop( pTemp );
        if ( c == nIters-1 )
            break;
        pNew = (Gia_Man_t *)Dsm_ManDeriveGia( pTemp = pNew, 0 );
        Gia_ManStop( pTemp );
    }
    return pNew;
}
Gia_Man_t * Gia_ManDoMuxTransform( Gia_Man_t * p, int fReorder )
{
    extern Gia_Man_t * Abc_NtkStrashToGia( Abc_Ntk_t * pNtk );
    extern int Abc_NtkBddToMuxesPerformGlo( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNtkNew, int Limit, int fReorder, int fUseAdd );
    Gia_Man_t * pRes = NULL;
    Aig_Man_t * pMan = Gia_ManToAig( p, 0 );
    Abc_Ntk_t * pNtk = Abc_NtkFromAigPhase( pMan );
    Abc_Ntk_t * pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_SOP );
    pNtk->pName = Extra_UtilStrsav( pMan->pName );
    Aig_ManStop( pMan );
    //pNtkNew = Abc_NtkBddToMuxes( pNtk, 1, 1000000, 1 );
    if ( Abc_NtkBddToMuxesPerformGlo( pNtk, pNtkNew, 1000000, fReorder, 0 ) )
    {
        Abc_Ntk_t * pStrash = Abc_NtkStrash( pNtkNew, 1, 1, 0 );
        pRes = Abc_NtkStrashToGia( pStrash );
        Abc_NtkDelete( pStrash );
    }
    Abc_NtkDelete( pNtkNew );
    Abc_NtkDelete( pNtk );
    return pRes;
}
int Gia_ManDoTest1( Gia_Man_t * p, int fReorder )
{
    Gia_Man_t * pTemp, * pNew; int Res;
    pNew = Gia_ManDoMuxTransform( p, fReorder );
    pNew = Gia_ManDoMuxMapping( pTemp = pNew );
    Gia_ManStop( pTemp );
    Res = Gia_ManLutNum( pNew );
    Gia_ManStop( pNew );
    return Res;
}
Abc_Ntk_t * Gia_ManDoTest2( Gia_Man_t * p, int fReorder, int fTryNew )
{
    extern Abc_Ntk_t * Abc_NtkFromMappedGia( Gia_Man_t * p, int fFindEnables, int fUseBuffs );
    Abc_Ntk_t * pNtkNew;
    Gia_Man_t * pTemp, * pNew;
    pNew = fTryNew ? Gia_ManDup(p) : Gia_ManDoMuxTransform( p, fReorder );
    pNew = Gia_ManDoMuxMapping( pTemp = pNew );
    Gia_ManStop( pTemp );
    pNtkNew = Abc_NtkFromMappedGia( pNew, 0, 0 );
    pNtkNew->pName = Extra_UtilStrsav(p->pName);
    Gia_ManStop( pNew );
    Abc_NtkToSop( pNtkNew, 1, ABC_INFINITY );
    return pNtkNew;
}
Abc_Ntk_t * Abc_NtkMapTransform( Gia_Man_t * p, int nOuts, int fUseFixed, int fTryNew, int fVerbose )
{
    extern Abc_Ntk_t * Abc_NtkSpecialMapping( Abc_Ntk_t * pNtk, int fVerbose );
    int i, k, g, nGroups = Gia_ManCoNum(p) / nOuts, CountsAll[3] = {0}; 
    Abc_Obj_t * pObjNew, * pFaninNew;  Gia_Obj_t * pObj;
    Abc_Ntk_t * pNtkNew = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 );
    assert( Gia_ManCoNum(p) % nOuts == 0 );
    pNtkNew->pName = Extra_UtilStrsav(p->pName);
    pNtkNew->pSpec = Extra_UtilStrsav(p->pSpec);
    Gia_ManFillValue( p );
    Gia_ManForEachPi( p, pObj, i )
        Abc_NtkCreatePi( pNtkNew );
    Gia_ManForEachPo( p, pObj, i )
        Abc_NtkCreatePo( pNtkNew );
    assert( nOuts <= 64 );
    for ( g = 0; g < nGroups; g++ )
    {
        Gia_Man_t * pNew;   Aig_Man_t * pMan;
        Abc_Ntk_t * pNtk, * pNtkRes, * pNtkMap;
        int pPos[64], Counter = 0, Counts[3] = {0};
        for ( i = 0; i < nOuts; i++ )
            pPos[i] = g*nOuts+i;
        pNew = Gia_ManDupCones( p, pPos, nOuts, 1 );
        if ( !fUseFixed )
            pNtkMap = Gia_ManDoTest2( pNew, 1, fTryNew );
        else
        {
            pMan = Gia_ManToAig( pNew, 0 );
            pNtk = Abc_NtkFromAigPhase( pMan );
            Aig_ManStop( pMan );
            pNtkRes = Abc_NtkBddToMuxes( pNtk, 1, 1000000, 1 );
            Abc_NtkDelete( pNtk );
            pNtkMap = Abc_NtkSpecialMapping( pNtkRes, 0 );
            Abc_NtkDelete( pNtkRes );
        }
        Gia_ManStop( pNew );
        Gia_ManForEachCi( p, pObj, i )
            if ( ~pObj->Value )
                Abc_NtkCi(pNtkMap, Counter++)->pCopy = Abc_NtkCi(pNtkNew, i);
        assert( Counter == Abc_NtkCiNum(pNtkMap) );
        Abc_NtkForEachNode( pNtkMap, pObjNew, i )
        {
            pObjNew->pCopy = Abc_NtkDupObj( pNtkNew, pObjNew, 0 );
            pObjNew->pCopy->fPersist = pObjNew->fPersist;
            if ( pObjNew->fPersist )
                Counts[1]++;
            else
                Counts[0]++;
            Abc_ObjForEachFanin( pObjNew, pFaninNew, k )
                Abc_ObjAddFanin( pObjNew->pCopy, pFaninNew->pCopy );
        }
        Abc_NtkForEachCo( pNtkMap, pObjNew, i )
            Abc_ObjAddFanin( Abc_NtkCo(pNtkNew, g*nOuts+i), Abc_ObjFanin0(pObjNew)->pCopy );
        Abc_NtkDelete( pNtkMap );

        if ( fVerbose )
        {
        printf( "%3d / %3d :  ", g, nGroups );
        printf( "Test   = %4d   ", Counts[0] );
        printf( "MarkA  = %4d   ", Counts[1] );
        printf( "MarkB  = %4d   ", Counts[2] );
        printf( "\n" );
        }

        CountsAll[0] += Counts[0];
        CountsAll[1] += Counts[1];
        CountsAll[2] += Counts[2];
    }
    if ( fVerbose )
    printf( "Total LUT count = %5d.  MarkA = %5d. MarkB = %5d.\n", CountsAll[0], CountsAll[1], CountsAll[2] );
    // create names
    Abc_NtkAddDummyPiNames( pNtkNew );
    Abc_NtkAddDummyPoNames( pNtkNew );
    Abc_NtkAddDummyBoxNames( pNtkNew );
    // check the resulting AIG
    if ( !Abc_NtkCheck( pNtkNew ) )
        Abc_Print( 1, "Abc_NtkFromMappedGia(): Network check has failed.\n" );
    return pNtkNew;
}

Abc_Ntk_t * Gia_ManPerformLNetMap( Gia_Man_t * p, int GroupSize, int fUseFixed, int fTryNew, int fVerbose )
{
    int fPrintOnly = 0;
    int Res1, Res2, Result = 0;
    int g, nGroups = Gia_ManCoNum(p) / GroupSize;
    assert( Gia_ManCoNum(p) % GroupSize == 0 );
    assert( GroupSize <= 64 );
    if ( fPrintOnly )
    {
        for ( g = 0; g < nGroups; g++ )
        {
            Gia_Man_t * pNew;
            int o, pPos[64];
            for ( o = 0; o < GroupSize; o++ )
                pPos[o] = g*GroupSize+o;
            pNew = Gia_ManDupCones( p, pPos, GroupSize, 0 );
            printf( "%3d / %3d :  ", g, nGroups );
            printf( "Test1 = %4d   ", Res1 = Gia_ManDoTest1(pNew, 0) );
            printf( "Test2 = %4d   ", Res2 = Gia_ManDoTest1(pNew, 1) );
            printf( "Test  = %4d   ", Abc_MinInt(Res1, Res2) );
            printf( "\n" );
            Result += Abc_MinInt(Res1, Res2);
            //Gia_ManPrintStats( pNew, NULL );
            Gia_ManStop( pNew );
        }
        printf( "Total LUT count = %d.\n", Result );
        return NULL;

    }
    return Abc_NtkMapTransform( p, GroupSize, fUseFixed, fTryNew, fVerbose );
}

#else

Abc_Ntk_t * Gia_ManPerformLNetMap( Gia_Man_t * p, int GroupSize, int fUseFixed, int fTryNew, int fVerbose )
{
    return NULL;
}

#endif

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


ABC_NAMESPACE_IMPL_END