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

  FileName    [simUtils.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Network and node package.]

  Synopsis    [Various simulation utilities.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "base/abc/abc.h"
#include "sim.h"

ABC_NAMESPACE_IMPL_START


////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////
 
static int bit_count[256] = {
  0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};

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

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

  Synopsis    [Allocates simulation information for all nodes.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Sim_UtilInfoAlloc( int nSize, int nWords, int fClean )
{
    Vec_Ptr_t * vInfo;
    int i;
    assert( nSize > 0 && nWords > 0 );
    vInfo = Vec_PtrAlloc( nSize );
    vInfo->pArray[0] = ABC_ALLOC( unsigned, (long)nSize * (long)nWords );
    assert( vInfo->pArray[0]);
    if ( fClean )
        memset( vInfo->pArray[0], 0, sizeof(unsigned) * nSize * nWords );
    for ( i = 1; i < nSize; i++ )
        vInfo->pArray[i] = ((unsigned *)vInfo->pArray[i-1]) + nWords;
    vInfo->nSize = nSize;
    return vInfo;
}

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

  Synopsis    [Allocates simulation information for all nodes.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilInfoFree( Vec_Ptr_t * p )
{
    ABC_FREE( p->pArray[0] );
    Vec_PtrFree( p );
}

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

  Synopsis    [Adds the second supp-info the first.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilInfoAdd( unsigned * pInfo1, unsigned * pInfo2, int nWords )
{
    int w;
    for ( w = 0; w < nWords; w++ )
        pInfo1[w] |= pInfo2[w];
}

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

  Synopsis    [Returns the positions where pInfo2 is 1 while pInfo1 is 0.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilInfoDetectDiffs( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs )
{
    int w, b;
    unsigned uMask;
    vDiffs->nSize = 0;
    for ( w = 0; w < nWords; w++ )
        if ( (uMask = (pInfo2[w] ^ pInfo1[w])) )
            for ( b = 0; b < 32; b++ )
                if ( uMask & (1 << b) )
                    Vec_IntPush( vDiffs, 32*w + b );
}

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

  Synopsis    [Returns the positions where pInfo2 is 1 while pInfo1 is 0.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilInfoDetectNews( unsigned * pInfo1, unsigned * pInfo2, int nWords, Vec_Int_t * vDiffs )
{
    int w, b;
    unsigned uMask;
    vDiffs->nSize = 0;
    for ( w = 0; w < nWords; w++ )
        if ( (uMask = (pInfo2[w] & ~pInfo1[w])) )
            for ( b = 0; b < 32; b++ )
                if ( uMask & (1 << b) )
                    Vec_IntPush( vDiffs, 32*w + b );
}

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

  Synopsis    [Flips the simulation info of the node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilInfoFlip( Sim_Man_t * p, Abc_Obj_t * pNode )
{
    unsigned * pSimInfo1, * pSimInfo2;
    int k;
    pSimInfo1 = (unsigned *)p->vSim0->pArray[pNode->Id];
    pSimInfo2 = (unsigned *)p->vSim1->pArray[pNode->Id];
    for ( k = 0; k < p->nSimWords; k++ )
        pSimInfo2[k] = ~pSimInfo1[k];
}

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

  Synopsis    [Returns 1 if the simulation infos are equal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilInfoCompare( Sim_Man_t * p, Abc_Obj_t * pNode )
{
    unsigned * pSimInfo1, * pSimInfo2;
    int k;
    pSimInfo1 = (unsigned *)p->vSim0->pArray[pNode->Id];
    pSimInfo2 = (unsigned *)p->vSim1->pArray[pNode->Id];
    for ( k = 0; k < p->nSimWords; k++ )
        if ( pSimInfo2[k] != pSimInfo1[k] )
            return 0;
    return 1;
}

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

  Synopsis    [Simulates the internal nodes.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSimulate( Sim_Man_t * p, int fType )
{
    Abc_Obj_t * pNode;
    int i;
    // simulate the internal nodes
    Abc_NtkForEachNode( p->pNtk, pNode, i )
        Sim_UtilSimulateNode( p, pNode, fType, fType, fType );
    // assign simulation info of the CO nodes
    Abc_NtkForEachCo( p->pNtk, pNode, i )
        Sim_UtilSimulateNode( p, pNode, fType, fType, fType );
}

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

  Synopsis    [Simulates one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSimulateNode( Sim_Man_t * p, Abc_Obj_t * pNode, int fType, int fType1, int fType2 )
{
    unsigned * pSimmNode, * pSimmNode1, * pSimmNode2;
    int k, fComp1, fComp2;
    // simulate the internal nodes
    if ( Abc_ObjIsNode(pNode) )
    {
        if ( fType )
            pSimmNode  = (unsigned *)p->vSim1->pArray[ pNode->Id ];
        else
            pSimmNode  = (unsigned *)p->vSim0->pArray[ pNode->Id ];

        if ( fType1 )
            pSimmNode1 = (unsigned *)p->vSim1->pArray[ Abc_ObjFaninId0(pNode) ];
        else
            pSimmNode1 = (unsigned *)p->vSim0->pArray[ Abc_ObjFaninId0(pNode) ];

        if ( fType2 )
            pSimmNode2 = (unsigned *)p->vSim1->pArray[ Abc_ObjFaninId1(pNode) ];
        else
            pSimmNode2 = (unsigned *)p->vSim0->pArray[ Abc_ObjFaninId1(pNode) ];

        fComp1 = Abc_ObjFaninC0(pNode);
        fComp2 = Abc_ObjFaninC1(pNode);
        if ( fComp1 && fComp2 )
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] = ~pSimmNode1[k] & ~pSimmNode2[k];
        else if ( fComp1 && !fComp2 )
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] = ~pSimmNode1[k] &  pSimmNode2[k];
        else if ( !fComp1 && fComp2 )
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] =  pSimmNode1[k] & ~pSimmNode2[k];
        else // if ( fComp1 && fComp2 )
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] =  pSimmNode1[k] &  pSimmNode2[k];
    }
    else 
    {
        assert( Abc_ObjFaninNum(pNode) == 1 );
        if ( fType )
            pSimmNode  = (unsigned *)p->vSim1->pArray[ pNode->Id ];
        else
            pSimmNode  = (unsigned *)p->vSim0->pArray[ pNode->Id ];

        if ( fType1 )
            pSimmNode1 = (unsigned *)p->vSim1->pArray[ Abc_ObjFaninId0(pNode) ];
        else
            pSimmNode1 = (unsigned *)p->vSim0->pArray[ Abc_ObjFaninId0(pNode) ];

        fComp1 = Abc_ObjFaninC0(pNode);
        if ( fComp1 )
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] = ~pSimmNode1[k];
        else 
            for ( k = 0; k < p->nSimWords; k++ )
                pSimmNode[k] =  pSimmNode1[k];
    }
}

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

  Synopsis    [Simulates one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSimulateNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset )
{
    unsigned * pSimmNode, * pSimmNode1, * pSimmNode2;
    int k, fComp1, fComp2;
    // simulate the internal nodes
    assert( Abc_ObjIsNode(pNode) );
    pSimmNode  = (unsigned *)Vec_PtrEntry(vSimInfo, pNode->Id);
    pSimmNode1 = (unsigned *)Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode));
    pSimmNode2 = (unsigned *)Vec_PtrEntry(vSimInfo, Abc_ObjFaninId1(pNode));
    pSimmNode  += nOffset;
    pSimmNode1 += nOffset;
    pSimmNode2 += nOffset;
    fComp1 = Abc_ObjFaninC0(pNode);
    fComp2 = Abc_ObjFaninC1(pNode);
    if ( fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] = ~pSimmNode1[k] & ~pSimmNode2[k];
    else if ( fComp1 && !fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] = ~pSimmNode1[k] &  pSimmNode2[k];
    else if ( !fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] =  pSimmNode1[k] & ~pSimmNode2[k];
    else // if ( fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] =  pSimmNode1[k] &  pSimmNode2[k];
}

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

  Synopsis    [Simulates one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilTransferNodeOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords, int nOffset, int fShift )
{
    unsigned * pSimmNode, * pSimmNode1;
    int k, fComp1;
    // simulate the internal nodes
    assert( Abc_ObjIsCo(pNode) );
    pSimmNode  = (unsigned *)Vec_PtrEntry(vSimInfo, pNode->Id);
    pSimmNode1 = (unsigned *)Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode));
    pSimmNode  += nOffset + (fShift > 0)*nSimWords;
    pSimmNode1 += nOffset;
    fComp1 = Abc_ObjFaninC0(pNode);
    if ( fComp1 )
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] = ~pSimmNode1[k];
    else 
        for ( k = 0; k < nSimWords; k++ )
            pSimmNode[k] =  pSimmNode1[k];
}

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

  Synopsis    [Returns 1 if the simulation infos are equal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilCountSuppSizes( Sim_Man_t * p, int fStruct )
{
    Abc_Obj_t * pNode, * pNodeCi;
    int i, v, Counter;
    Counter = 0;
    if ( fStruct )
    {
        Abc_NtkForEachCo( p->pNtk, pNode, i )
            Abc_NtkForEachCi( p->pNtk, pNodeCi, v )
                Counter += Sim_SuppStrHasVar( p->vSuppStr, pNode, v );
    }
    else
    {
        Abc_NtkForEachCo( p->pNtk, pNode, i )
            Abc_NtkForEachCi( p->pNtk, pNodeCi, v )
                Counter += Sim_SuppFunHasVar( p->vSuppFun, i, v );
    }
    return Counter;
}

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

  Synopsis    [Counts the number of 1's in the bitstring.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilCountOnes( unsigned * pSimInfo, int nSimWords )
{
    unsigned char * pBytes;
    int nOnes, nBytes, i;
    pBytes = (unsigned char *)pSimInfo;
    nBytes = 4 * nSimWords;
    nOnes  = 0;
    for ( i = 0; i < nBytes; i++ )
        nOnes += bit_count[ pBytes[i] ];
    return nOnes;    
}

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

  Synopsis    [Counts the number of 1's in the bitstring.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Sim_UtilCountOnesArray( Vec_Ptr_t * vInfo, int nSimWords )
{
    Vec_Int_t * vCounters;
    unsigned * pSimInfo;
    int i;
    vCounters = Vec_IntStart( Vec_PtrSize(vInfo) );
    Vec_PtrForEachEntry( unsigned *, vInfo, pSimInfo, i )
        Vec_IntWriteEntry( vCounters, i, Sim_UtilCountOnes(pSimInfo, nSimWords) );
    return vCounters;
}

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

  Synopsis    [Returns random patterns.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSetRandom( unsigned * pPatRand, int nSimWords )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        pPatRand[k] = SIM_RANDOM_UNSIGNED;
}

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

  Synopsis    [Returns complemented patterns.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSetCompl( unsigned * pPatRand, int nSimWords )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        pPatRand[k] = ~pPatRand[k];
}

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

  Synopsis    [Returns constant patterns.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilSetConst( unsigned * pPatRand, int nSimWords, int fConst1 )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        pPatRand[k] = 0;
    if ( fConst1 )
        Sim_UtilSetCompl( pPatRand, nSimWords );
}

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

  Synopsis    [Returns 1 if equal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilInfoIsEqual( unsigned * pPats1, unsigned * pPats2, int nSimWords )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        if ( pPats1[k] != pPats2[k] )
            return 0;
    return 1;
}

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

  Synopsis    [Returns 1 if Node1 implies Node2.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilInfoIsImp( unsigned * pPats1, unsigned * pPats2, int nSimWords )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        if ( pPats1[k] & ~pPats2[k] )
            return 0;
    return 1;
}

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

  Synopsis    [Returns 1 if Node1 v Node2 is always true.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilInfoIsClause( unsigned * pPats1, unsigned * pPats2, int nSimWords )
{
    int k;
    for ( k = 0; k < nSimWords; k++ )
        if ( ~pPats1[k] & ~pPats2[k] )
            return 0;
    return 1;
}

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

  Synopsis    [Counts the total number of pairs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilCountAllPairs( Vec_Ptr_t * vSuppFun, int nSimWords, Vec_Int_t * vCounters )
{
    unsigned * pSupp;
    int Counter, nOnes, nPairs, i;
    Counter = 0;
    Vec_PtrForEachEntry( unsigned *, vSuppFun, pSupp, i )
    {
        nOnes  = Sim_UtilCountOnes( pSupp, nSimWords );
        nPairs = nOnes * (nOnes - 1) / 2;
        Vec_IntWriteEntry( vCounters, i, nPairs );
        Counter += nPairs;
    }
    return Counter;
}

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

  Synopsis    [Counts the number of entries in the array of matrices.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilCountPairsOne( Extra_BitMat_t * pMat, Vec_Int_t * vSupport )
{
    int i, k, Index1, Index2;
    int Counter = 0;
//    int Counter2;
    Vec_IntForEachEntry( vSupport, i, Index1 )
    Vec_IntForEachEntryStart( vSupport, k, Index2, Index1+1 )
        Counter += Extra_BitMatrixLookup1( pMat, i, k );
//    Counter2 = Extra_BitMatrixCountOnesUpper(pMat);
//    assert( Counter == Counter2 );
    return Counter;
}

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

  Synopsis    [Counts the number of entries in the array of matrices.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilCountPairsOnePrint( Extra_BitMat_t * pMat, Vec_Int_t * vSupport )
{
    int i, k, Index1, Index2;
    Vec_IntForEachEntry( vSupport, i, Index1 )
    Vec_IntForEachEntryStart( vSupport, k, Index2, Index1+1 )
        if ( Extra_BitMatrixLookup1( pMat, i, k ) )
            printf( "(%d,%d) ", i, k );
    return 0;
}

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

  Synopsis    [Counts the number of entries in the array of matrices.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilCountPairsAllPrint( Sym_Man_t * p )
{
    int i;
    abctime clk;
clk = Abc_Clock();
    for ( i = 0; i < p->nOutputs; i++ )
    {
        printf( "Output %2d :", i );
        Sim_UtilCountPairsOnePrint( (Extra_BitMat_t *)Vec_PtrEntry(p->vMatrSymms, i), Vec_VecEntryInt(p->vSupports, i) );
        printf( "\n" );
    }
p->timeCount += Abc_Clock() - clk;
}

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

  Synopsis    [Counts the number of entries in the array of matrices.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Sim_UtilCountPairsAll( Sym_Man_t * p )
{
    int nPairsTotal, nPairsSym, nPairsNonSym, i;
    abctime clk;
clk = Abc_Clock();
    p->nPairsSymm    = 0;
    p->nPairsNonSymm = 0;
    for ( i = 0; i < p->nOutputs; i++ )
    {
        nPairsTotal  = Vec_IntEntry(p->vPairsTotal, i);
        nPairsSym    = Vec_IntEntry(p->vPairsSym,   i);
        nPairsNonSym = Vec_IntEntry(p->vPairsNonSym,i);
        assert( nPairsTotal >= nPairsSym + nPairsNonSym ); 
        if ( nPairsTotal == nPairsSym + nPairsNonSym )
        {
            p->nPairsSymm    += nPairsSym;
            p->nPairsNonSymm += nPairsNonSym;
            continue;
        }
        nPairsSym    = Sim_UtilCountPairsOne( (Extra_BitMat_t *)Vec_PtrEntry(p->vMatrSymms,   i), Vec_VecEntryInt(p->vSupports, i) );
        nPairsNonSym = Sim_UtilCountPairsOne( (Extra_BitMat_t *)Vec_PtrEntry(p->vMatrNonSymms,i), Vec_VecEntryInt(p->vSupports, i) );
        assert( nPairsTotal >= nPairsSym + nPairsNonSym ); 
        Vec_IntWriteEntry( p->vPairsSym,    i, nPairsSym );
        Vec_IntWriteEntry( p->vPairsNonSym, i, nPairsNonSym );
        p->nPairsSymm    += nPairsSym;
        p->nPairsNonSymm += nPairsNonSym;
//        printf( "%d ", nPairsTotal - nPairsSym - nPairsNonSym );
    }
//printf( "\n" );
    p->nPairsRem = p->nPairsTotal-p->nPairsSymm-p->nPairsNonSymm;
p->timeCount += Abc_Clock() - clk;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Sim_UtilMatrsAreDisjoint( Sym_Man_t * p )
{
    int i;
    for ( i = 0; i < p->nOutputs; i++ )
        if ( !Extra_BitMatrixIsDisjoint( (Extra_BitMat_t *)Vec_PtrEntry(p->vMatrSymms,i), (Extra_BitMat_t *)Vec_PtrEntry(p->vMatrNonSymms,i) ) )
            return 0;
    return 1;
}

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


ABC_NAMESPACE_IMPL_END

