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

  FileName    [abcEspresso.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Network and node package.]

  Synopsis    [Procedures to minimize SOPs using Espresso.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "base/abc/abc.h"
#include "misc/espresso/espresso.h"

ABC_NAMESPACE_IMPL_START


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

static void        Abc_NodeEspresso( Abc_Obj_t * pNode );
static pset_family Abc_SopToEspresso( char * pSop );
static char *      Abc_SopFromEspresso( Extra_MmFlex_t * pMan, pset_family Cover );
static pset_family Abc_EspressoMinimize( pset_family pOnset, pset_family pDcset );
 
////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

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

  Synopsis    [Minimizes SOP representations using Espresso.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkEspresso( Abc_Ntk_t * pNtk, int fVerbose )
{
    Abc_Obj_t * pNode;
    int i;
    assert( Abc_NtkIsLogic(pNtk) );
    // convert the network to have SOPs
    if ( Abc_NtkHasMapping(pNtk) )
        Abc_NtkMapToSop(pNtk);
    else if ( Abc_NtkHasBdd(pNtk) )
    {
        if ( !Abc_NtkBddToSop(pNtk, 0) )
        {
            printf( "Abc_NtkEspresso(): Converting to SOPs has failed.\n" );
            return;
        }
    }
    // minimize SOPs of all nodes
    Abc_NtkForEachNode( pNtk, pNode, i )
        if ( i ) Abc_NodeEspresso( pNode );
}

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

  Synopsis    [Minimizes SOP representation of one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NodeEspresso( Abc_Obj_t * pNode )
{
    extern void define_cube_size( int n );
    pset_family Cover;
    int fCompl;

    assert( Abc_ObjIsNode(pNode) );
    // define the cube for this node
    define_cube_size( Abc_ObjFaninNum(pNode) );
    // create the Espresso cover
    fCompl = Abc_SopIsComplement( pNode->pData );
    Cover = Abc_SopToEspresso( pNode->pData );
    // perform minimization
    Cover = Abc_EspressoMinimize( Cover, NULL ); // deletes also cover
    // convert back onto the node's SOP representation
    pNode->pData = Abc_SopFromEspresso( pNode->pNtk->pManFunc, Cover );
    if ( fCompl ) Abc_SopComplement( pNode->pData );
    sf_free(Cover);
}

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

  Synopsis    [Converts SOP in ABC into SOP representation in Espresso.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
pset_family Abc_SopToEspresso( char * pSop )
{
    char *      pCube;
    pset_family Cover;
    pset        set;
    int         nCubes, nVars, Value, v;
    
    if ( pSop == NULL ) 
        return NULL;
    
    nVars  = Abc_SopGetVarNum(pSop);
    nCubes = Abc_SopGetCubeNum(pSop);
    assert( cube.size == 2 * nVars );
    
    if ( Abc_SopIsConst0(pSop) ) 
    {
        Cover = sf_new(0, cube.size);
        return Cover;
    }
    if ( Abc_SopIsConst1(pSop) ) 
    {
        Cover = sf_new(1, cube.size);
        set = GETSET(Cover, Cover->count++);
        set_copy( set, cube.fullset );
        return Cover;
    }

    // create the cover
    Cover = sf_new(nCubes, cube.size);
    // fill in the cubes
    Abc_SopForEachCube( pSop, nVars, pCube )
    {
        set = GETSET(Cover, Cover->count++);
        set_copy( set, cube.fullset );
        Abc_CubeForEachVar( pCube, Value, v )
        {
            if ( Value == '0' )
                set_remove(set, 2*v+1);
            else if ( Value == '1' )
                set_remove(set, 2*v);
        }
    }
    return Cover;
}

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

  Synopsis    [Converts SOP representation in Espresso into SOP in ABC.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
char * Abc_SopFromEspresso( Extra_MmFlex_t * pMan, pset_family Cover )
{
    pset set;
    char * pSop, * pCube;
    int Lit, nVars, nCubes, i, k;

    nVars  = Cover->sf_size/2;
    nCubes = Cover->count;

    pSop = Abc_SopStart( pMan, nCubes, nVars );

    // go through the cubes
    i = 0;
    Abc_SopForEachCube( pSop, nVars, pCube )
    {
        set = GETSET(Cover, i++);
        for ( k = 0; k < nVars; k++ )
        {
            Lit = GETINPUT(set, k);
            if ( Lit == ZERO )
                pCube[k] = '0';
            else if ( Lit == ONE )
                pCube[k] = '1';
        }
    }
    return pSop;
}


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

  Synopsis    [Minimizes the cover using Espresso.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
pset_family Abc_EspressoMinimize( pset_family pOnset, pset_family pDcset )
{
    pset_family pOffset;
    int fNewDcset, i;
    int fSimple = 0;
    int fSparse = 0;

    if ( fSimple )
    {
        for ( i = 0; i < cube.num_vars; i++ )
            pOnset = d1merge( pOnset, i );
        pOnset = sf_contain( pOnset );
        return pOnset;
    }

    // create the dcset
    fNewDcset = (pDcset == NULL);
    if ( pDcset == NULL )
        pDcset = sf_new( 1, cube.size );
    pDcset->wsize   = pOnset->wsize;
    pDcset->sf_size = pOnset->sf_size;

    // derive the offset
    if ( pDcset->sf_size == 0 || pDcset->count == 0 )
        pOffset = complement(cube1list(pOnset));
    else
        pOffset = complement(cube2list(pOnset, pDcset)); 

    // perform minimization
    skip_make_sparse = !fSparse;
    pOnset = espresso( pOnset, pDcset, pOffset );

    // free covers
    sf_free( pOffset ); 
    if ( fNewDcset )
        sf_free( pDcset );
    return pOnset;
}

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


ABC_NAMESPACE_IMPL_END