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

  FileName    [giaAig.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Scalable AIG package.]

  Synopsis    []

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "gia.h"

ABC_NAMESPACE_IMPL_START


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

#define AGI_PI ABC_CONST(0xFFFFFFFF00000000) 
#define AGI_RO ABC_CONST(0xFFFFFFFE00000000) 
#define AGI_PO ABC_CONST(0xFFFFFFFD00000000) 
#define AGI_RI ABC_CONST(0xFFFFFFFC00000000) 
#define AGI_C0 ABC_CONST(0xFFFFFFFBFFFFFFFA) 
#define AGI_M0 ABC_CONST(0x00000000FFFFFFFF) 
#define AGI_M1 ABC_CONST(0xFFFFFFFF00000000) 

typedef struct Agi_Man_t_ Agi_Man_t;
struct Agi_Man_t_
{
    char *             pName;       // name of the AIG
    char *             pSpec;       // name of the input file
    int                nCap;        // number of objects
    int                nObjs;       // number of objects
    int                nNodes;      // number of objects
    int                nRegs;       // number of registers
    unsigned           nTravIds;    // number of objects
    Vec_Int_t          vCis;        // comb inputs
    Vec_Int_t          vCos;        // comb outputs
    word *             pObjs;       // objects
    unsigned *         pThird;      // third input
    unsigned *         pTravIds;    // traversal IDs
    unsigned *         pNext;       // next values
    unsigned *         pTable;      // hash table
    unsigned *         pCopy;       // hash table
};

static inline int      Agi_ManObjNum( Agi_Man_t * p )                      { return p->nObjs;                                        } 
static inline int      Agi_ManCiNum( Agi_Man_t * p )                       { return Vec_IntSize( &p->vCis );                         } 
static inline int      Agi_ManCoNum( Agi_Man_t * p )                       { return Vec_IntSize( &p->vCos );                         } 
static inline int      Agi_ManNodeNum( Agi_Man_t * p )                     { return p->nNodes;                                       } 

static inline unsigned Agi_ObjLit0( Agi_Man_t * p, int i )                 { return (unsigned)(p->pObjs[i]);                         } 
static inline unsigned Agi_ObjLit1( Agi_Man_t * p, int i )                 { return (unsigned)(p->pObjs[i] >> 32);                   } 
static inline unsigned Agi_ObjLit2( Agi_Man_t * p, int i )                 { return p->pThird[i];                                    } 
static inline int      Agi_ObjVar0( Agi_Man_t * p, int i )                 { return Agi_ObjLit0(p, i) >> 1;                          } 
static inline int      Agi_ObjVar1( Agi_Man_t * p, int i )                 { return Agi_ObjLit1(p, i) >> 1;                          } 
static inline int      Agi_ObjVar2( Agi_Man_t * p, int i )                 { return Agi_ObjLit2(p, i) >> 1;                          } 
static inline void     Agi_ObjSetLit0( Agi_Man_t * p, int i, unsigned l )  { p->pObjs[i] = (p->pObjs[i] & AGI_M1) | (word)l;         } 
static inline void     Agi_ObjSetLit1( Agi_Man_t * p, int i, unsigned l )  { p->pObjs[i] = (p->pObjs[i] & AGI_M0) | ((word)l << 32); } 
static inline void     Agi_ObjSetLit2( Agi_Man_t * p, int i, unsigned l )  { p->pThird[i] = l;                                       }  

static inline int      Agi_ObjIsC0( Agi_Man_t * p, int i )                 { return (i == 0);                                        } 
static inline int      Agi_ObjIsPi( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_PI) == AGI_PI;                } 
static inline int      Agi_ObjIsRo( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_PI) == AGI_RO;                } 
static inline int      Agi_ObjIsPo( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_PI) == AGI_PO;                } 
static inline int      Agi_ObjIsRi( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_PI) == AGI_RI;                } 
static inline int      Agi_ObjIsCi( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_RO) == AGI_RO;                } 
static inline int      Agi_ObjIsCo( Agi_Man_t * p, int i )                 { return (p->pObjs[i] & AGI_RO) == AGI_PO;                } 
static inline int      Agi_ObjIsNode( Agi_Man_t * p, int i )               { return p->pObjs[i] < AGI_C0;                            } 
static inline int      Agi_ObjIsBuf( Agi_Man_t * p, int i )                { return Agi_ObjLit0(p, i) == Agi_ObjLit1(p, i);          } 
static inline int      Agi_ObjIsAnd( Agi_Man_t * p, int i )                { return Agi_ObjIsNode(p, i) && Agi_ObjLit0(p, i) < Agi_ObjLit1(p, i);  } 
static inline int      Agi_ObjIsXor( Agi_Man_t * p, int i )                { return Agi_ObjIsNode(p, i) && Agi_ObjLit0(p, i) > Agi_ObjLit1(p, i);  } 
static inline int      Agi_ObjIsMux( Agi_Man_t * p, int i )                { return Agi_ObjIsAnd(p, i) && ~Agi_ObjLit2(p, i);        }
static inline int      Agi_ObjIsMaj( Agi_Man_t * p, int i )                { return Agi_ObjIsXor(p, i) && ~Agi_ObjLit2(p, i);        } 

static inline int Agi_ManAppendObj( Agi_Man_t * p )
{
    assert( p->nObjs < p->nCap );
    return p->nObjs++; // return var
}
static inline int Agi_ManAppendCi( Agi_Man_t * p )
{
    int iObj = Agi_ManAppendObj( p );
    p->pObjs[iObj] = AGI_PI | (word)Vec_IntSize(&p->vCis);
    Vec_IntPush( &p->vCis, iObj );
    return Abc_Var2Lit( iObj, 0 ); // return lit
}
static inline int Agi_ManAppendCo( Agi_Man_t * p, int iLit0 )
{
    int iObj = Agi_ManAppendObj( p );
    p->pObjs[iObj] = AGI_PO | (word)iLit0;
    Vec_IntPush( &p->vCos, iObj );
    return Abc_Var2Lit( iObj, 0 ); // return lit
}
static inline int Agi_ManAppendAnd( Agi_Man_t * p, int iLit0, int iLit1 )
{
    int iObj = Agi_ManAppendObj( p );
    assert( iLit0 < iLit1 );
    p->pObjs[iObj] = ((word)iLit1 << 32) | (word)iLit0;
    p->nNodes++;
    return Abc_Var2Lit( iObj, 0 ); // return lit
}

#define Agi_ManForEachCi( p, iCi, i )   Vec_IntForEachEntry( &p->vCis, iCi, i )
#define Agi_ManForEachCo( p, iCo, i )   Vec_IntForEachEntry( &p->vCos, iCo, i )
#define Agi_ManForEachObj( p, i )       for ( i = 0; i < Agi_ManObjNum(p); i++ )
#define Agi_ManForEachObj1( p, i )      for ( i = 1; i < Agi_ManObjNum(p); i++ )
#define Agi_ManForEachNode( p, i )      for ( i = 1; i < Agi_ManObjNum(p); i++ ) if ( !Agi_ObjIsNode(p, i) ) {} else

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Agi_Man_t * Agi_ManAlloc( int nCap )
{
    Agi_Man_t * p;
    nCap = Abc_MaxInt( nCap, 16 );
    p = ABC_CALLOC( Agi_Man_t, 1 );
    p->nCap     = nCap;
    p->pObjs    = ABC_CALLOC( word, nCap );
    p->pTravIds = ABC_CALLOC( unsigned, nCap );
    p->pObjs[0] = AGI_C0;
    p->nObjs    = 1;
    return p;
}
void Agi_ManFree( Agi_Man_t * p )
{
    ABC_FREE( p->pObjs );
    ABC_FREE( p->pTravIds );
    ABC_FREE( p->vCis.pArray );
    ABC_FREE( p->vCos.pArray );
    ABC_FREE( p );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Agi_Man_t * Agi_ManFromGia( Gia_Man_t * p )
{
    Agi_Man_t * pNew;
    Gia_Obj_t * pObj;
    int i;
    pNew = Agi_ManAlloc( Gia_ManObjNum(p) );
    Gia_ManForEachObj1( p, pObj, i )
        if ( Gia_ObjIsAnd(pObj) )
            pObj->Value = Agi_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
        else if ( Gia_ObjIsCo(pObj) )
            pObj->Value = Agi_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) );
        else if ( Gia_ObjIsCi(pObj) )
            pObj->Value = Agi_ManAppendCi( pNew );
        else assert( 0 );
    return pNew;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Agi_ManSuppSize_rec( Agi_Man_t * p, int i )
{
    if ( p->pTravIds[i] == p->nTravIds )
        return 0;
    p->pTravIds[i] = p->nTravIds;
    if ( Agi_ObjIsCi(p, i) )
        return 1;
    assert( Agi_ObjIsAnd(p, i) );
    return Agi_ManSuppSize_rec( p, Agi_ObjVar0(p, i) ) +  Agi_ManSuppSize_rec( p, Agi_ObjVar1(p, i) );
}
int Agi_ManSuppSizeOne( Agi_Man_t * p, int i )
{
    p->nTravIds++;
    return Agi_ManSuppSize_rec( p, i );
}
int Agi_ManSuppSizeTest( Agi_Man_t * p )
{
    abctime clk = Abc_Clock();
    int i, Counter = 0;
    Agi_ManForEachNode( p, i )
        Counter += (Agi_ManSuppSizeOne(p, i) <= 16);
    printf( "Nodes with small support %d (out of %d)\n", Counter, Agi_ManNodeNum(p) );
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
    return Counter;

}
void Agi_ManTest( Gia_Man_t * pGia )
{
    extern int Gia_ManSuppSizeTest( Gia_Man_t * p );
    Agi_Man_t * p;
    Gia_ManSuppSizeTest( pGia );
    p = Agi_ManFromGia( pGia );
    Agi_ManSuppSizeTest( p );
    Agi_ManFree( p );
}

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


ABC_NAMESPACE_IMPL_END