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

  FileName    [satTruth.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [SAT solver.]

  Synopsis    [Truth table computation package.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

  Revision    [$Id: satTruth.c,v 1.4 2005/09/16 22:55:03 casem Exp $]

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

#include "satTruth.h"
#include "misc/vec/vecSet.h"

ABC_NAMESPACE_IMPL_START


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

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

struct Tru_Man_t_
{
    int              nVars;        // the number of variables
    int              nWords;       // the number of words in the truth table
    int              nEntrySize;   // the size of one entry in 'int'
    int              nTableSize;   // hash table size
    int *            pTable;       // hash table
    Vec_Set_t *      pMem;         // memory for truth tables
    word *           pZero;        // temporary truth table 
    int              hIthVars[16]; // variable handles
    int              nTableLookups;
};

typedef struct Tru_One_t_ Tru_One_t; // 16 bytes minimum
struct Tru_One_t_
{
    int              Handle;       // support
    int              Next;         // next one in the table
    word             pTruth[0];    // truth table
};

static inline Tru_One_t * Tru_ManReadOne( Tru_Man_t * p, int h ) { return h ? (Tru_One_t *)Vec_SetEntry(p->pMem, h) : NULL; }

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

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

  Synopsis    [Returns the hash key.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline unsigned Tru_ManHash( word * pTruth, int nWords, int nBins, int * pPrimes )
{
    int i;
    unsigned uHash = 0;
    for ( i = 0; i < nWords; i++ )
        uHash ^= pTruth[i] * pPrimes[i & 0x7];
    return uHash % nBins;
}

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

  Synopsis    [Returns the given record.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int * Tru_ManLookup( Tru_Man_t * p, word * pTruth )
{
    static int s_Primes[10] = { 1291, 1699, 2357, 4177, 5147, 5647, 6343, 7103, 7873, 8147 };
    Tru_One_t * pEntry;
    int * pSpot;
    assert( (pTruth[0] & 1) == 0 );
    pSpot = p->pTable + Tru_ManHash( pTruth, p->nWords, p->nTableSize, s_Primes );
    for ( pEntry = Tru_ManReadOne(p, *pSpot); pEntry; pSpot = &pEntry->Next, pEntry = Tru_ManReadOne(p, *pSpot) )
        if ( Tru_ManEqual(pEntry->pTruth, pTruth, p->nWords) )
            return pSpot;
    return pSpot;
}

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

  Synopsis    [Returns the given record.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tru_ManResize( Tru_Man_t * p )
{
    Tru_One_t * pThis;
    int * pTableOld, * pSpot;
    int nTableSizeOld, iNext, Counter, i;
    assert( p->pTable != NULL );
    // replace the table
    pTableOld = p->pTable;
    nTableSizeOld = p->nTableSize;
    p->nTableSize = 2 * p->nTableSize + 1; 
    p->pTable = ABC_CALLOC( int, p->nTableSize );
    // rehash the entries from the old table
    Counter = 0;
    for ( i = 0; i < nTableSizeOld; i++ )
    for ( pThis = Tru_ManReadOne(p, pTableOld[i]),
          iNext = (pThis? pThis->Next : 0);  
          pThis;  pThis = Tru_ManReadOne(p, iNext),   
          iNext = (pThis? pThis->Next : 0)  )
    {
        assert( pThis->Handle );
        pThis->Next = 0;
        pSpot = Tru_ManLookup( p, pThis->pTruth );
        assert( *pSpot == 0 ); // should not be there
        *pSpot = pThis->Handle;
        Counter++;
    }
    assert( Counter == Vec_SetEntryNum(p->pMem) );
    ABC_FREE( pTableOld );
}

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

  Synopsis    [Adds entry to the hash table.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Tru_ManInsert( Tru_Man_t * p, word * pTruth )
{
    int fCompl, * pSpot;
    if ( Tru_ManEqual0(pTruth, p->nWords) )
        return 0;
    if ( Tru_ManEqual1(pTruth, p->nWords) )
        return 1;
    p->nTableLookups++;
    if ( Vec_SetEntryNum(p->pMem) > 2 * p->nTableSize )
        Tru_ManResize( p );
    fCompl = pTruth[0] & 1;
    if ( fCompl )  
        Tru_ManNot( pTruth, p->nWords );
    pSpot = Tru_ManLookup( p, pTruth );
    if ( *pSpot == 0 )
    {
        Tru_One_t * pEntry;
        *pSpot = Vec_SetAppend( p->pMem, NULL, p->nEntrySize );
        assert( (*pSpot & 1) == 0 );
        pEntry = Tru_ManReadOne( p, *pSpot );
        Tru_ManCopy( pEntry->pTruth, pTruth, p->nWords );
        pEntry->Handle = *pSpot;
        pEntry->Next = 0;
    }
    if ( fCompl )  
        Tru_ManNot( pTruth, p->nWords );
    return *pSpot ^ fCompl;
}

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

  Synopsis    [Start the truth table logging.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Tru_Man_t * Tru_ManAlloc( int nVars )
{
    word Masks[6] = 
    { 
        ABC_CONST(0xAAAAAAAAAAAAAAAA), 
        ABC_CONST(0xCCCCCCCCCCCCCCCC), 
        ABC_CONST(0xF0F0F0F0F0F0F0F0), 
        ABC_CONST(0xFF00FF00FF00FF00), 
        ABC_CONST(0xFFFF0000FFFF0000), 
        ABC_CONST(0xFFFFFFFF00000000) 
    };
    Tru_Man_t * p;
    int i, w;
    assert( nVars > 0 && nVars <= 16 );
    p = ABC_CALLOC( Tru_Man_t, 1 );
    p->nVars      = nVars;
    p->nWords     = (nVars < 6) ? 1 : (1 << (nVars-6));
    p->nEntrySize = (sizeof(Tru_One_t) + p->nWords * sizeof(word))/sizeof(int);
    p->nTableSize = 8147;
    p->pTable     = ABC_CALLOC( int, p->nTableSize );
    p->pMem       = Vec_SetAlloc( 16 );
    // initialize truth tables
    p->pZero = ABC_ALLOC( word, p->nWords );
    for ( i = 0; i < nVars; i++ )
    {
        for ( w = 0; w < p->nWords; w++ )
            if ( i < 6 )
                p->pZero[w] = Masks[i];
            else if ( w & (1 << (i-6)) )
                p->pZero[w] = ~(word)0;
            else
                p->pZero[w] = 0;
        p->hIthVars[i] = Tru_ManInsert( p, p->pZero );
        assert( !i || p->hIthVars[i] > p->hIthVars[i-1] );
    }
    Tru_ManClear( p->pZero, p->nWords );
    return p;
}

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

  Synopsis    [Stop the truth table logging.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tru_ManFree( Tru_Man_t * p )
{
    printf( "Lookups = %d. Entries = %d.\n", p->nTableLookups, Vec_SetEntryNum(p->pMem) );
    Vec_SetFree( p->pMem );
    ABC_FREE( p->pZero );
    ABC_FREE( p->pTable );
    ABC_FREE( p );
}

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

  Synopsis    [Returns elementary variable.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
word * Tru_ManVar( Tru_Man_t * p, int v )
{
    assert( v >= 0 && v < p->nVars );
    return Tru_ManReadOne( p, p->hIthVars[v] )->pTruth;
}

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

  Synopsis    [Returns stored truth table]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
word * Tru_ManFunc( Tru_Man_t * p, int h )
{
    assert( (h & 1) == 0 );
    if ( h == 0 )
        return p->pZero;
    return Tru_ManReadOne( p, h )->pTruth;
}

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


ABC_NAMESPACE_IMPL_END