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

  FileName    [acecCover.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [CEC for arithmetic circuits.]

  Synopsis    [Core procedures.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "acecInt.h"

ABC_NAMESPACE_IMPL_START


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

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_AcecMark_rec( Gia_Man_t * p, int iObj, int fFirst )
{
    Gia_Obj_t * pObj = Gia_ManObj( p, iObj );
    if ( pObj->fMark0 && !fFirst )
        return;
    assert( Gia_ObjIsAnd(pObj) );
    pObj->fMark1 = 1;
    Gia_AcecMark_rec( p, Gia_ObjFaninId0(pObj, iObj), 0 );
    Gia_AcecMark_rec( p, Gia_ObjFaninId1(pObj, iObj), 0 );
}
void Gia_AcecMarkFadd( Gia_Man_t * p, int * pSigs )
{
//    if ( Gia_ManObj(p, pSigs[3])->fMark1 || Gia_ManObj(p, pSigs[4])->fMark1 )
//        return;
    Gia_ManObj( p, pSigs[0] )->fMark0 = 1;
    Gia_ManObj( p, pSigs[1] )->fMark0 = 1;
    Gia_ManObj( p, pSigs[2] )->fMark0 = 1;
//    assert( !Gia_ManObj(p, pSigs[3])->fMark1 );
//    assert( !Gia_ManObj(p, pSigs[4])->fMark1 );
    Gia_AcecMark_rec( p, pSigs[3], 1 );
    Gia_AcecMark_rec( p, pSigs[4], 1 );
}
void Gia_AcecMarkHadd( Gia_Man_t * p, int * pSigs )
{
    Gia_Obj_t * pObj = Gia_ManObj( p, pSigs[0] );
    int iFan0 = Gia_ObjFaninId0( pObj, pSigs[0] );
    int iFan1 = Gia_ObjFaninId1( pObj, pSigs[0] );
    Gia_ManObj( p, iFan0 )->fMark0 = 1;
    Gia_ManObj( p, iFan1 )->fMark0 = 1;
    Gia_AcecMark_rec( p, pSigs[0], 1 );
    Gia_AcecMark_rec( p, pSigs[1], 1 );
}

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

  Synopsis    [Collect XORs reachable from the last output.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_AcecCollectXors_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Bit_t * vMap, Vec_Int_t * vXors )
{
    if ( !Gia_ObjIsXor(pObj) )//|| Vec_BitEntry(vMap, Gia_ObjId(p, pObj)) )
        return;
    Vec_IntPush( vXors, Gia_ObjId(p, pObj) );
    Gia_AcecCollectXors_rec( p, Gia_ObjFanin0(pObj), vMap, vXors );
    Gia_AcecCollectXors_rec( p, Gia_ObjFanin1(pObj), vMap, vXors );
}
Vec_Int_t * Gia_AcecCollectXors( Gia_Man_t * p, Vec_Bit_t * vMap )
{
    Vec_Int_t * vXors = Vec_IntAlloc( 100 );
    Gia_Obj_t * pObj = Gia_ObjFanin0( Gia_ManCo(p, Gia_ManCoNum(p)-1) );
    Gia_AcecCollectXors_rec( p, pObj, vMap, vXors );
    return vXors;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_AcecExplore( Gia_Man_t * p, int fVerbose )
{
    Vec_Int_t * vNodes = Vec_IntAlloc( 100 );
    Vec_Int_t * vFadds, * vHadds, * vXors;
    Vec_Bit_t * vMap = Vec_BitStart( Gia_ManObjNum(p) );
    Gia_Obj_t * pObj; 
    int i, nSupp, nCone, nHadds = 0;
    assert( p->pMuxes != NULL );
    vFadds = Gia_ManDetectFullAdders( p, fVerbose, NULL );
    vHadds = Gia_ManDetectHalfAdders( p, fVerbose );

    pObj = Gia_ManObj( p, 352 );
    printf( "Xor = %d.\n", Gia_ObjIsXor(pObj) );
    printf( "Fanin0 = %d.  Fanin1 = %d.\n", Gia_ObjFaninId0(pObj, 352), Gia_ObjFaninId1(pObj, 352) );
    printf( "Fan00 = %d.  Fan01 = %d.   Fan10 = %d.  Fan11 = %d.\n", 
        Gia_ObjFaninId0(Gia_ObjFanin0(pObj), Gia_ObjFaninId0(pObj, 352)), 
        Gia_ObjFaninId1(Gia_ObjFanin0(pObj), Gia_ObjFaninId0(pObj, 352)), 
        Gia_ObjFaninId0(Gia_ObjFanin1(pObj), Gia_ObjFaninId1(pObj, 352)), 
        Gia_ObjFaninId1(Gia_ObjFanin1(pObj), Gia_ObjFaninId1(pObj, 352)) );

    // create a map of all HADD/FADD outputs
    for ( i = 0; i < Vec_IntSize(vHadds)/2; i++ )
    {
        int * pSigs = Vec_IntEntryP(vHadds, 2*i);
        Vec_BitWriteEntry( vMap, pSigs[0], 1 );
        Vec_BitWriteEntry( vMap, pSigs[1], 1 );
    }
    for ( i = 0; i < Vec_IntSize(vFadds)/5; i++ )
    {
        int * pSigs = Vec_IntEntryP(vFadds, 5*i);
        Vec_BitWriteEntry( vMap, pSigs[3], 1 );
        Vec_BitWriteEntry( vMap, pSigs[4], 1 );
    }

    Gia_ManCleanMark01( p );

    // mark outputs
    Gia_ManForEachCo( p, pObj, i )
        Gia_ObjFanin0(pObj)->fMark0 = 1;

    // collect XORs
    vXors = Gia_AcecCollectXors( p, vMap );
    Vec_BitFree( vMap );

    printf( "Collected XORs: " );
    Vec_IntPrint( vXors );

    // mark their fanins
    Gia_ManForEachObjVec( vXors, p, pObj, i )
    {
        pObj->fMark1 = 1;
        Gia_ObjFanin0(pObj)->fMark0 = 1;
        Gia_ObjFanin1(pObj)->fMark0 = 1;
    }

    // mark FADDs
    for ( i = 0; i < Vec_IntSize(vFadds)/5; i++ )
        Gia_AcecMarkFadd( p, Vec_IntEntryP(vFadds, 5*i) );

    // iterate through HADDs and find those that fit in
    while ( 1 )
    {
        int fChange = 0;
        for ( i = 0; i < Vec_IntSize(vHadds)/2; i++ )
        {
            int * pSigs = Vec_IntEntryP(vHadds, 2*i);
            if ( !Gia_ManObj(p, pSigs[0])->fMark0 || !Gia_ManObj(p, pSigs[1])->fMark0 )
                continue;
            if ( Gia_ManObj(p, pSigs[0])->fMark1 || Gia_ManObj(p, pSigs[1])->fMark1 )
                continue;
            Gia_AcecMarkHadd( p, pSigs );
            fChange = 1;
            nHadds++;
        }
        if ( !fChange )
            break;
    }
    // print inputs to the adder network
    Gia_ManForEachAnd( p, pObj, i )
        if ( pObj->fMark0 && !pObj->fMark1 )
        {
            nSupp = Gia_ManSuppSize( p, &i, 1 );
            nCone = Gia_ManConeSize( p, &i, 1 );
            printf( "Node %5d : Supp = %5d.  Cone = %5d.\n", i, nSupp, nCone );
            Vec_IntPush( vNodes, i );
        }
    printf( "Fadds = %d. Hadds = %d.  Root nodes found = %d.\n", Vec_IntSize(vFadds)/5, nHadds, Vec_IntSize(vNodes) );

    Gia_ManCleanMark01( p );

    Gia_ManForEachObjVec( vNodes, p, pObj, i )
        pObj->fMark0 = 1;

    Vec_IntFree( vFadds );
    Vec_IntFree( vHadds );
    Vec_IntFree( vNodes );
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Gia_AcecCover( Gia_Man_t * p )
{
    int fVerbose = 1;
    int i, k, Entry;
    Gia_Obj_t * pObj;
    Vec_Int_t * vCutsXor2 = NULL;
    Vec_Int_t * vFadds = Gia_ManDetectFullAdders( p, fVerbose, &vCutsXor2 );

    // mark FADDs
    Gia_ManCleanMark01( p );
    for ( i = 0; i < Vec_IntSize(vFadds)/5; i++ )
        Gia_AcecMarkFadd( p, Vec_IntEntryP(vFadds, 5*i) );

    k = 0;
    Vec_IntForEachEntry( vCutsXor2, Entry, i )
    {
        if ( i % 3 != 2 )
            continue;
        pObj = Gia_ManObj( p, Entry );
        if ( pObj->fMark1 )
            continue;
        printf( "%d ", Entry );
    }
    printf( "\n" );

    Gia_ManCleanMark01( p );

    Vec_IntFree( vFadds );
    Vec_IntFree( vCutsXor2 );
}

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


ABC_NAMESPACE_IMPL_END