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

  FileName    [mioSop.c]

  PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]

  Synopsis    [Derives SOP from Boolean expression.]

  Author      [MVSIS Group]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - September 8, 2003.]

  Revision    [$Id: mioSop.c,v 1.4 2004/06/28 14:20:25 alanmi Exp $]

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

#include "mioInt.h"
#include "exp.h"

ABC_NAMESPACE_IMPL_START


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

static inline unsigned Mio_CubeVar0( int v )                       { return (1<< (v<<1)   );                   }
static inline unsigned Mio_CubeVar1( int v )                       { return (1<<((v<<1)+1));                   }
static inline int      Mio_CubeHasVar0( unsigned x, int v )        { return (x & Mio_CubeVar0(v)) > 0;         }
static inline int      Mio_CubeHasVar1( unsigned x, int v )        { return (x & Mio_CubeVar1(v)) > 0;         }
static inline int      Mio_CubeEmpty( unsigned x )                 { return (x & (x>>1) & 0x55555555) != 0;    }
static inline unsigned Mio_CubeAnd( unsigned x, unsigned y )       { return x | y;                             }
static inline int      Mio_CubeContains( unsigned x, unsigned y )  { return (x | y) == y;                      } // x contains y

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

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

  Synopsis    [Push while performing SCC.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Mio_SopPushSCC( Vec_Int_t * p, unsigned c )
{
    unsigned Entry;
    int i, k = 0;
    Vec_IntForEachEntry( p, Entry, i )
    {
        if ( Mio_CubeContains( Entry, c ) ) // Entry contains c
        {
            assert( i == k );
            return;
        }
        if ( Mio_CubeContains( c, Entry ) ) // c contains Entry
            continue;
        Vec_IntWriteEntry( p, k++, Entry );
    }
    Vec_IntShrink( p, k );
    Vec_IntPush( p, c );
}

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

  Synopsis    [Make the OR of two covers.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopCoverOr( Vec_Int_t * p, Vec_Int_t * q )
{
    Vec_Int_t * r;
    unsigned Entry;
    int i;
    r = Vec_IntAlloc( Vec_IntSize(p) + Vec_IntSize(q) );
    Vec_IntForEachEntry( p, Entry, i )
        Vec_IntPush( r, Entry );
    Vec_IntForEachEntry( q, Entry, i )
        Mio_SopPushSCC( r, Entry );
    return r;
}

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

  Synopsis    [Make the AND of two covers.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopCoverAnd( Vec_Int_t * p, Vec_Int_t * q )
{
    Vec_Int_t * r;
    unsigned EntryP, EntryQ;
    int i, k;
    r = Vec_IntAlloc( Vec_IntSize(p) * Vec_IntSize(q) );
    Vec_IntForEachEntry( p, EntryP, i )
        Vec_IntForEachEntry( q, EntryQ, k )
            if ( !Mio_CubeEmpty( Mio_CubeAnd(EntryP, EntryQ) ) )
                Mio_SopPushSCC( r, Mio_CubeAnd(EntryP, EntryQ) );
    return r;
}

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

  Synopsis    [Create negative literal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopVar0( int i )
{
    Vec_Int_t * vSop;
    vSop = Vec_IntAlloc( 1 );
    Vec_IntPush( vSop, Mio_CubeVar0(i) );
    return vSop;
}

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

  Synopsis    [Create positive literal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopVar1( int i )
{
    Vec_Int_t * vSop;
    vSop = Vec_IntAlloc( 1 );
    Vec_IntPush( vSop, Mio_CubeVar1(i) );
    return vSop;
}

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

  Synopsis    [Create constant 0 literal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopConst0()
{
    Vec_Int_t * vSop;
    vSop = Vec_IntAlloc( 1 );
    return vSop;
}

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

  Synopsis    [Create constant 1 literal.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Mio_SopConst1()
{
    Vec_Int_t * vSop;
    vSop = Vec_IntAlloc( 1 );
    Vec_IntPush( vSop, 0 );
    return vSop;
}

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

  Synopsis    [Derives SOP representation as the char string.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
char * Mio_SopDeriveFromArray( Vec_Int_t * vSop, int nVars, Vec_Str_t * vStr, int fPolarity )
{
    unsigned Entry;
    int i, k;
    Vec_StrClear( vStr );
    if ( Vec_IntSize(vSop) == 0 )
    {
        Vec_StrPush( vStr, ' ' );
        Vec_StrPush( vStr, (char)('1'-fPolarity) );
        Vec_StrPush( vStr, '\n' );
        Vec_StrPush( vStr, '\0' );
        return Vec_StrArray( vStr );
    }
    if ( Vec_IntSize(vSop) == 1 && Vec_IntEntry(vSop, 0) == 0 )
    {
        Vec_StrPush( vStr, ' ' );
        Vec_StrPush( vStr, (char)('0'+fPolarity) );
        Vec_StrPush( vStr, '\n' );
        Vec_StrPush( vStr, '\0' );
        return Vec_StrArray( vStr );
    }
    // create cubes
    Vec_IntForEachEntry( vSop, Entry, i )
    {
        for ( k = 0; k < nVars; k++ )
        {
            if ( Mio_CubeHasVar0( Entry, k ) )
                Vec_StrPush( vStr, '0' );
            else if ( Mio_CubeHasVar1( Entry, k ) )
                Vec_StrPush( vStr, '1' );
            else 
                Vec_StrPush( vStr, '-' );
        }
        Vec_StrPush( vStr, ' ' );
        Vec_StrPush( vStr, (char)('0'+fPolarity) );
        Vec_StrPush( vStr, '\n' );
    }
    Vec_StrPush( vStr, '\0' );
    return Vec_StrArray( vStr );
}

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

  Synopsis    [Derives SOP representation.]

  Description [The SOP is guaranteed to be SCC-free but not minimal.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
char * Mio_LibDeriveSop( int nVars, Vec_Int_t * vExpr, Vec_Str_t * vStr )
{
    Vec_Int_t * vSop;
    Vec_Ptr_t * vSops0, * vSops1, * vTemp;
    int i, Index0, Index1, fCompl0, fCompl1;
    Vec_StrClear( vStr );
    if ( Exp_IsConst0(vExpr) )
    {
        Vec_StrPrintStr( vStr, " 0\n" );
        Vec_StrPush( vStr, '\0' );
        return Vec_StrArray( vStr );
    }
    if ( Exp_IsConst1(vExpr) )
    {
        Vec_StrPrintStr( vStr, " 1\n" );
        Vec_StrPush( vStr, '\0' );
        return Vec_StrArray( vStr );
    }
    if ( Exp_IsLit(vExpr) )
    {
        for ( i = 0; i < nVars; i++ )
            Vec_StrPush( vStr, '-' );
        Vec_StrPrintStr( vStr, " 1\n" );
        Vec_StrPush( vStr, '\0' );
        assert( (Vec_IntEntry(vExpr,0) >> 1) < nVars );
        Vec_StrWriteEntry( vStr, Vec_IntEntry(vExpr,0) >> 1, (char)('1' - (Vec_IntEntry(vExpr,0) & 1)) );
        return Vec_StrArray( vStr );
    }
    vSops0 = Vec_PtrAlloc( nVars + Exp_NodeNum(vExpr) );
    vSops1 = Vec_PtrAlloc( nVars + Exp_NodeNum(vExpr) );
    for ( i = 0; i < nVars; i++ )
    {
        Vec_PtrPush( vSops0, Mio_SopVar0(i) );
        Vec_PtrPush( vSops1, Mio_SopVar1(i) );
    }
    for ( i = 0; i < Exp_NodeNum(vExpr); i++ )
    {
        Index0  = Vec_IntEntry( vExpr, 2*i+0 ) >> 1;
        Index1  = Vec_IntEntry( vExpr, 2*i+1 ) >> 1;
        fCompl0 = Vec_IntEntry( vExpr, 2*i+0 ) & 1;
        fCompl1 = Vec_IntEntry( vExpr, 2*i+1 ) & 1;
        // positive polarity
        vSop = Mio_SopCoverAnd( fCompl0 ? (Vec_Int_t *)Vec_PtrEntry(vSops0, Index0) : (Vec_Int_t *)Vec_PtrEntry(vSops1, Index0),
                                fCompl1 ? (Vec_Int_t *)Vec_PtrEntry(vSops0, Index1) : (Vec_Int_t *)Vec_PtrEntry(vSops1, Index1) );
        Vec_PtrPush( vSops1, vSop );
        // negative polarity
        vSop = Mio_SopCoverOr( fCompl0 ? (Vec_Int_t *)Vec_PtrEntry(vSops1, Index0) : (Vec_Int_t *)Vec_PtrEntry(vSops0, Index0),
                               fCompl1 ? (Vec_Int_t *)Vec_PtrEntry(vSops1, Index1) : (Vec_Int_t *)Vec_PtrEntry(vSops0, Index1) );
        Vec_PtrPush( vSops0, vSop );
    }
    // complement
    if ( Vec_IntEntryLast(vExpr) & 1 )
    {
        vTemp  = vSops0;
        vSops0 = vSops1;
        vSops1 = vTemp;
    }
    // select the best polarity
    if ( Vec_IntSize( (Vec_Int_t *)Vec_PtrEntryLast(vSops0) ) < Vec_IntSize( (Vec_Int_t *)Vec_PtrEntryLast(vSops1) ) )
        vSop = (Vec_Int_t *)Vec_PtrEntryLast(vSops0);
    else
        vSop = (Vec_Int_t *)Vec_PtrEntryLast(vSops1);
    // convert positive polarity into SOP
    Mio_SopDeriveFromArray( vSop, nVars, vStr, (vSop == Vec_PtrEntryLast(vSops1)) );
    Vec_VecFree( (Vec_Vec_t *)vSops0 );
    Vec_VecFree( (Vec_Vec_t *)vSops1 );
    return Vec_StrArray( vStr );
}


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


ABC_NAMESPACE_IMPL_END