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

  FileName    [saigWnd.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Sequential AIG package.]

  Synopsis    [Sequential windowing.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

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

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

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

#include "saig.h"

ABC_NAMESPACE_IMPL_START


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

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

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

  Synopsis    [Returns the array of PI/internal nodes.]

  Description [Marks all the visited nodes with the current ID.
  Does not collect constant node and PO/LI nodes.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Saig_ManWindowOutline_rec( Aig_Man_t * p, Aig_Obj_t * pObj, int nDist, Vec_Ptr_t * vNodes, int * pDists )
{
    Aig_Obj_t * pMatch, * pFanout;
    int fCollected, iFanout = -1, i;
    if ( nDist == 0 )
        return;
    if ( pDists[pObj->Id] >= nDist )
        return;
    pDists[pObj->Id] = nDist;
    fCollected = Aig_ObjIsTravIdCurrent( p, pObj );
    Aig_ObjSetTravIdCurrent( p, pObj );    
    if ( Aig_ObjIsConst1(pObj) )
        return;
    if ( Saig_ObjIsPo(p, pObj) )
        return;
    if ( Saig_ObjIsLi(p, pObj) )
    {
        pMatch = Saig_ObjLiToLo( p, pObj );
        if ( !Aig_ObjIsTravIdCurrent( p, pMatch ) )
            Saig_ManWindowOutline_rec( p, pMatch, nDist, vNodes, pDists );
        Saig_ManWindowOutline_rec( p, Aig_ObjFanin0(pObj), nDist-1, vNodes, pDists );
        return;
    }
    if ( !fCollected )
        Vec_PtrPush( vNodes, pObj );
    if ( Saig_ObjIsPi(p, pObj) )
        return;
    if ( Saig_ObjIsLo(p, pObj) )
    {
        pMatch = Saig_ObjLoToLi( p, pObj );
        if ( !Aig_ObjIsTravIdCurrent( p, pMatch ) )
            Saig_ManWindowOutline_rec( p, pMatch, nDist, vNodes, pDists );
        Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, i )
            Saig_ManWindowOutline_rec( p, pFanout, nDist-1, vNodes, pDists );
        return;
    }
    assert( Aig_ObjIsNode(pObj) );
    Saig_ManWindowOutline_rec( p, Aig_ObjFanin0(pObj), nDist-1, vNodes, pDists );
    Saig_ManWindowOutline_rec( p, Aig_ObjFanin1(pObj), nDist-1, vNodes, pDists );
    Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, i )
        Saig_ManWindowOutline_rec( p, pFanout, nDist-1, vNodes, pDists );
}

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

  Synopsis    [Returns the array of PI/internal nodes.]

  Description [Marks all the visited nodes with the current ID.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Saig_ManWindowOutline( Aig_Man_t * p, Aig_Obj_t * pObj, int nDist )
{
    Vec_Ptr_t * vNodes;
    Aig_Obj_t * pObjLi, * pObjLo;
    int * pDists, i;
    pDists = ABC_CALLOC( int, Aig_ManObjNumMax(p) );
    vNodes = Vec_PtrAlloc( 1000 );
    Aig_ManIncrementTravId( p );
    Saig_ManWindowOutline_rec( p, pObj, nDist, vNodes, pDists );
    Vec_PtrSort( vNodes, (int (*)(const void *, const void *))Aig_ObjCompareIdIncrease );
    // make sure LI/LO are labeled/unlabeled mutually
    Saig_ManForEachLiLo( p, pObjLi, pObjLo, i )
        assert( Aig_ObjIsTravIdCurrent(p, pObjLi) == 
                Aig_ObjIsTravIdCurrent(p, pObjLo) );
    ABC_FREE( pDists );
    return vNodes;
}

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

  Synopsis    [Returns 1 if the node has unlabeled fanout.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Obj_t * Saig_ObjHasUnlabeledFanout( Aig_Man_t * p, Aig_Obj_t * pObj )
{
    Aig_Obj_t * pFanout;
    int iFanout = -1, i;
    Aig_ObjForEachFanout( p, pObj, pFanout, iFanout, i )
        if ( Saig_ObjIsPo(p, pFanout) || !Aig_ObjIsTravIdCurrent(p, pFanout) )
            return pFanout;
    return NULL;
}

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

  Synopsis    [Collects primary inputs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Saig_ManWindowCollectPis( Aig_Man_t * p, Vec_Ptr_t * vNodes )
{
    Vec_Ptr_t * vNodesPi;
    Aig_Obj_t * pObj, * pMatch, * pFanin;
    int i;
    vNodesPi = Vec_PtrAlloc( 1000 );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
    {
        if ( Saig_ObjIsPi(p, pObj) )
        {
            assert( pObj->pData == NULL );
            Vec_PtrPush( vNodesPi, pObj );
        }
        else if ( Saig_ObjIsLo(p, pObj) )
        {
            pMatch = Saig_ObjLoToLi( p, pObj );
            pFanin = Aig_ObjFanin0(pMatch);
            if ( !Aig_ObjIsTravIdCurrent(p, pFanin) && pFanin->pData == NULL )
                Vec_PtrPush( vNodesPi, pFanin );
        }
        else
        {
            assert( Aig_ObjIsNode(pObj) );
            pFanin = Aig_ObjFanin0(pObj);
            if ( !Aig_ObjIsTravIdCurrent(p, pFanin) && pFanin->pData == NULL )
                Vec_PtrPush( vNodesPi, pFanin );
            pFanin = Aig_ObjFanin1(pObj);
            if ( !Aig_ObjIsTravIdCurrent(p, pFanin) && pFanin->pData == NULL )
                Vec_PtrPush( vNodesPi, pFanin );
        }
    }
    return vNodesPi;
}

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

  Synopsis    [Collects primary outputs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Saig_ManWindowCollectPos( Aig_Man_t * p, Vec_Ptr_t * vNodes, Vec_Ptr_t ** pvPointers )
{
    Vec_Ptr_t * vNodesPo;
    Aig_Obj_t * pObj, * pPointer;
    int i;
    vNodesPo = Vec_PtrAlloc( 1000 );
    if ( pvPointers )
        *pvPointers = Vec_PtrAlloc( 1000 );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
    {
        if ( (pPointer = Saig_ObjHasUnlabeledFanout(p, pObj)) )
        {
            Vec_PtrPush( vNodesPo, pObj );
            if ( pvPointers )
                Vec_PtrPush( *pvPointers, pPointer );
        }
    }
    return vNodesPo;
}

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

  Synopsis    [Extracts the window AIG from the AIG manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowExtractNodes( Aig_Man_t * p, Vec_Ptr_t * vNodes )
{
    Aig_Man_t * pNew;
    Aig_Obj_t * pObj, * pMatch;
    Vec_Ptr_t * vNodesPi, * vNodesPo;
    int i, nRegCount;
    Aig_ManCleanData( p ); 
    // create the new manager
    pNew = Aig_ManStart( Vec_PtrSize(vNodes) );
    pNew->pName = Abc_UtilStrsav( "wnd" );
    pNew->pSpec = NULL;
    // map constant nodes
    pObj = Aig_ManConst1( p );
    pObj->pData = Aig_ManConst1( pNew );
    // create real PIs
    vNodesPi = Saig_ManWindowCollectPis( p, vNodes );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodesPi, pObj, i )
        pObj->pData = Aig_ObjCreateCi(pNew);
    Vec_PtrFree( vNodesPi );
    // create register outputs
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
    {
        if ( Saig_ObjIsLo(p, pObj) )
            pObj->pData = Aig_ObjCreateCi(pNew);
    }
    // create internal nodes
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
    {
        if ( Aig_ObjIsNode(pObj) )
            pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
    }
    // create POs
    vNodesPo = Saig_ManWindowCollectPos( p, vNodes, NULL );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodesPo, pObj, i )
        Aig_ObjCreateCo( pNew, (Aig_Obj_t *)pObj->pData );
    Vec_PtrFree( vNodesPo );
    // create register inputs
    nRegCount = 0;
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
    {
        if ( Saig_ObjIsLo(p, pObj) )
        {
            pMatch = Saig_ObjLoToLi( p, pObj );
            Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch) );
            nRegCount++;
        }
    }
    Aig_ManSetRegNum( pNew, nRegCount );
    Aig_ManCleanup( pNew );
    return pNew;
}

static void Saig_ManWindowInsertSmall_rec( Aig_Man_t * pNew, Aig_Obj_t * pObjSmall, 
     Vec_Ptr_t * vBigNode2SmallPo, Vec_Ptr_t * vSmallPi2BigNode );

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

  Synopsis    [Adds nodes for the big manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Saig_ManWindowInsertBig_rec( Aig_Man_t * pNew, Aig_Obj_t * pObjBig, 
         Vec_Ptr_t * vBigNode2SmallPo, Vec_Ptr_t * vSmallPi2BigNode )
{
    Aig_Obj_t * pMatch;
    if ( pObjBig->pData )
        return;
    if ( (pMatch = (Aig_Obj_t *)Vec_PtrEntry( vBigNode2SmallPo, pObjBig->Id )) )
    {
        Saig_ManWindowInsertSmall_rec( pNew, Aig_ObjFanin0(pMatch), vBigNode2SmallPo, vSmallPi2BigNode );
        pObjBig->pData = Aig_ObjChild0Copy(pMatch);
        return;        
    }
    assert( Aig_ObjIsNode(pObjBig) );
    Saig_ManWindowInsertBig_rec( pNew, Aig_ObjFanin0(pObjBig), vBigNode2SmallPo, vSmallPi2BigNode );
    Saig_ManWindowInsertBig_rec( pNew, Aig_ObjFanin1(pObjBig), vBigNode2SmallPo, vSmallPi2BigNode );
    pObjBig->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObjBig), Aig_ObjChild1Copy(pObjBig) );
}

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

  Synopsis    [Adds nodes for the small manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Saig_ManWindowInsertSmall_rec( Aig_Man_t * pNew, Aig_Obj_t * pObjSmall, 
         Vec_Ptr_t * vBigNode2SmallPo, Vec_Ptr_t * vSmallPi2BigNode )
{
    Aig_Obj_t * pMatch;
    if ( pObjSmall->pData )
        return;
    if ( (pMatch = (Aig_Obj_t *)Vec_PtrEntry( vSmallPi2BigNode, pObjSmall->Id )) )
    {
        Saig_ManWindowInsertBig_rec( pNew, pMatch, vBigNode2SmallPo, vSmallPi2BigNode );
        pObjSmall->pData = pMatch->pData;
        return;        
    }
    assert( Aig_ObjIsNode(pObjSmall) );
    Saig_ManWindowInsertSmall_rec( pNew, Aig_ObjFanin0(pObjSmall), vBigNode2SmallPo, vSmallPi2BigNode );
    Saig_ManWindowInsertSmall_rec( pNew, Aig_ObjFanin1(pObjSmall), vBigNode2SmallPo, vSmallPi2BigNode );
    pObjSmall->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObjSmall), Aig_ObjChild1Copy(pObjSmall) );
}

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

  Synopsis    [Extracts the network from the AIG manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowInsertNodes( Aig_Man_t * p, Vec_Ptr_t * vNodes, Aig_Man_t * pWnd )
{
    Aig_Man_t * pNew;
    Vec_Ptr_t * vBigNode2SmallPo, * vSmallPi2BigNode;
    Vec_Ptr_t * vNodesPi, * vNodesPo;
    Aig_Obj_t * pObj;
    int i;

    // set mapping of small PIs into big nodes
    vSmallPi2BigNode = Vec_PtrStart( Aig_ManObjNumMax(pWnd) ); 
    vNodesPi = Saig_ManWindowCollectPis( p, vNodes );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodesPi, pObj, i )
        Vec_PtrWriteEntry( vSmallPi2BigNode, Aig_ManCi(pWnd, i)->Id, pObj );
    assert( i == Saig_ManPiNum(pWnd) );
    Vec_PtrFree( vNodesPi );

    // set mapping of big nodes into small POs
    vBigNode2SmallPo = Vec_PtrStart( Aig_ManObjNumMax(p) ); 
    vNodesPo = Saig_ManWindowCollectPos( p, vNodes, NULL );
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodesPo, pObj, i )
        Vec_PtrWriteEntry( vBigNode2SmallPo, pObj->Id, Aig_ManCo(pWnd, i) );
    assert( i == Saig_ManPoNum(pWnd) );
    Vec_PtrFree( vNodesPo );

    // create the new manager
    Aig_ManCleanData( p ); 
    Aig_ManCleanData( pWnd ); 
    pNew = Aig_ManStart( Aig_ManObjNumMax(p) );
    pNew->pName = Abc_UtilStrsav( p->pName );
    pNew->pSpec = Abc_UtilStrsav( p->pSpec );
    // map constant nodes
    pObj = Aig_ManConst1( p );
    pObj->pData = Aig_ManConst1( pNew );
    pObj = Aig_ManConst1( pWnd );
    pObj->pData = Aig_ManConst1( pNew );

    // create real PIs
    Aig_ManForEachCi( p, pObj, i )
        if ( Saig_ObjIsPi(p, pObj) || !Aig_ObjIsTravIdCurrent(p, pObj) )
            pObj->pData = Aig_ObjCreateCi(pNew);
    // create additional latch outputs
    Saig_ManForEachLo( pWnd, pObj, i )
        pObj->pData = Aig_ObjCreateCi(pNew);

    // create internal nodes starting from the big
    Aig_ManForEachCo( p, pObj, i )
        if ( Saig_ObjIsPo(p, pObj) || !Aig_ObjIsTravIdCurrent(p, pObj) )
        {
            Saig_ManWindowInsertBig_rec( pNew, Aig_ObjFanin0(pObj), vBigNode2SmallPo, vSmallPi2BigNode );
            pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
        }
    // create internal nodes starting from the small
    Saig_ManForEachLi( pWnd, pObj, i )
    {
        Saig_ManWindowInsertSmall_rec( pNew, Aig_ObjFanin0(pObj), vBigNode2SmallPo, vSmallPi2BigNode );
        pObj->pData = Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
    }
    Vec_PtrFree( vBigNode2SmallPo );
    Vec_PtrFree( vSmallPi2BigNode );
    // set the new number of registers
    assert( Aig_ManCiNum(pNew) - Aig_ManCiNum(p) == Aig_ManCoNum(pNew) - Aig_ManCoNum(p) );
    Aig_ManSetRegNum( pNew, Aig_ManRegNum(p) + (Aig_ManCiNum(pNew) - Aig_ManCiNum(p)) );
    Aig_ManCleanup( pNew );
    return pNew;
}

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

  Synopsis    [Find a good object.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Obj_t * Saig_ManFindPivot( Aig_Man_t * p )
{
    Aig_Obj_t * pObj;
    int i, Counter;
    if ( Aig_ManRegNum(p) > 0 )
    {
        if ( Aig_ManRegNum(p) == 1 )
            return Saig_ManLo( p, 0 );
        Saig_ManForEachLo( p, pObj, i )
        {
            if ( i == Aig_ManRegNum(p)/2 )
                return pObj;
        }
    }
    else
    {
        Counter = 0;
        assert( Aig_ManNodeNum(p) > 1 );
        Aig_ManForEachNode( p, pObj, i )
        {
            if ( Counter++ == Aig_ManNodeNum(p)/2 )
                return pObj;
        }
    }
    return NULL;
}

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

  Synopsis    [Computes sequential window of the node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowExtract( Aig_Man_t * p, Aig_Obj_t * pObj, int nDist )
{
    Aig_Man_t * pWnd;
    Vec_Ptr_t * vNodes;
    Aig_ManFanoutStart( p );
    vNodes = Saig_ManWindowOutline( p, pObj, nDist );
    pWnd = Saig_ManWindowExtractNodes( p, vNodes );
    Vec_PtrFree( vNodes );
    Aig_ManFanoutStop( p );
    return pWnd;
}

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

  Synopsis    [Computes sequential window of the node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowInsert( Aig_Man_t * p, Aig_Obj_t * pObj, int nDist, Aig_Man_t * pWnd )
{
    Aig_Man_t * pNew, * pWndTest;
    Vec_Ptr_t * vNodes;
    Aig_ManFanoutStart( p );

    vNodes = Saig_ManWindowOutline( p, pObj, nDist );
    pWndTest = Saig_ManWindowExtractNodes( p, vNodes );
    if ( Saig_ManPiNum(pWndTest) != Saig_ManPiNum(pWnd) ||
         Saig_ManPoNum(pWndTest) != Saig_ManPoNum(pWnd) )
    {
        printf( "The window cannot be reinserted because PI/PO counts do not match.\n" );
        Aig_ManStop( pWndTest );
        Vec_PtrFree( vNodes );
        Aig_ManFanoutStop( p );
        return NULL;
    }
    Aig_ManStop( pWndTest );
    Vec_PtrFree( vNodes );

    // insert the nodes
    Aig_ManCleanData( p ); 
    vNodes = Saig_ManWindowOutline( p, pObj, nDist );
    pNew = Saig_ManWindowInsertNodes( p, vNodes, pWnd );
    Vec_PtrFree( vNodes );
    Aig_ManFanoutStop( p );
    return pNew;
}

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

  Synopsis    [Tests the above computation.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowTest( Aig_Man_t * p )
{
    int nDist = 3;
    Aig_Man_t * pWnd, * pNew;
    Aig_Obj_t * pPivot;
    pPivot = Saig_ManFindPivot( p );
    assert( pPivot != NULL );
    pWnd = Saig_ManWindowExtract( p, pPivot, nDist );
    pNew = Saig_ManWindowInsert( p, pPivot, nDist, pWnd );
    Aig_ManStop( pWnd );
    return pNew;
}

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

  Synopsis    [Collects the nodes that are not linked to each other.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Saig_ManCollectedDiffNodes( Aig_Man_t * p0, Aig_Man_t * p1 )
{
    Vec_Ptr_t * vNodes;
    Aig_Obj_t * pObj0, * pObj1;
    int i;
    // collect nodes that are not linked
    Aig_ManIncrementTravId( p0 );
    vNodes = Vec_PtrAlloc( 1000 );
    Aig_ManForEachObj( p0, pObj0, i )
    {
        pObj1 = Aig_ObjRepr( p0, pObj0 );
        if ( pObj1 != NULL )
        {
            assert( pObj0 == Aig_ObjRepr( p1, pObj1 ) );   
            continue;
        }
        // mark and collect unmatched objects
        Aig_ObjSetTravIdCurrent( p0, pObj0 ); 
        if ( Aig_ObjIsNode(pObj0) || Aig_ObjIsCi(pObj0) )
            Vec_PtrPush( vNodes, pObj0 );
    }
    // make sure LI/LO are labeled/unlabeled mutually
    Saig_ManForEachLiLo( p0, pObj0, pObj1, i )
        assert( Aig_ObjIsTravIdCurrent(p0, pObj0) == 
                Aig_ObjIsTravIdCurrent(p0, pObj1) );
    return vNodes;
}
         
/**Function*************************************************************

  Synopsis    [Creates PIs of the miter.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Saig_ManWindowCreatePis( Aig_Man_t * pNew, Aig_Man_t * p0, Aig_Man_t * p1, Vec_Ptr_t * vNodes0 )
{
    Aig_Obj_t * pObj, * pMatch, * pFanin;
    int i, Counter = 0;
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes0, pObj, i )
    {
        if ( Saig_ObjIsLo(p0, pObj) )
        {
            pMatch = Saig_ObjLoToLi( p0, pObj );
            pFanin = Aig_ObjFanin0(pMatch);
            if ( !Aig_ObjIsTravIdCurrent(p0, pFanin) && pFanin->pData == NULL )
            {
                pFanin->pData = Aig_ObjCreateCi(pNew);
                pMatch = Aig_ObjRepr( p0, pFanin );
                assert( pFanin == Aig_ObjRepr( p1, pMatch ) );
                assert( pMatch != NULL );
                pMatch->pData = pFanin->pData;
                Counter++;
            }
        }
        else
        {
            assert( Aig_ObjIsNode(pObj) );
            pFanin = Aig_ObjFanin0(pObj);
            if ( !Aig_ObjIsTravIdCurrent(p0, pFanin) && pFanin->pData == NULL )
            {
                pFanin->pData = Aig_ObjCreateCi(pNew);
                pMatch = Aig_ObjRepr( p0, pFanin );
                assert( pFanin == Aig_ObjRepr( p1, pMatch ) );
                assert( pMatch != NULL );
                pMatch->pData = pFanin->pData;
                Counter++;
            }
            pFanin = Aig_ObjFanin1(pObj);
            if ( !Aig_ObjIsTravIdCurrent(p0, pFanin) && pFanin->pData == NULL )
            {
                pFanin->pData = Aig_ObjCreateCi(pNew);
                pMatch = Aig_ObjRepr( p0, pFanin );
                assert( pFanin == Aig_ObjRepr( p1, pMatch ) );
                assert( pMatch != NULL );
                pMatch->pData = pFanin->pData;
                Counter++;
            }
        }
    }
//    printf( "Added %d primary inputs.\n", Counter );
}
        
/**Function*************************************************************

  Synopsis    [Creates POs of the miter.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Saig_ManWindowCreatePos( Aig_Man_t * pNew, Aig_Man_t * p0, Aig_Man_t * p1 )
{
    Aig_Obj_t * pObj0, * pObj1, * pMiter;
    Aig_Obj_t * pFanin0, * pFanin1;
    int i;
    Aig_ManForEachObj( p0, pObj0, i )
    {
        if ( Aig_ObjIsTravIdCurrent(p0, pObj0) )
            continue;
        if ( Aig_ObjIsConst1(pObj0) )
            continue;
        if ( Aig_ObjIsCi(pObj0) )
            continue;
        pObj1 = Aig_ObjRepr( p0, pObj0 );
        assert( pObj0 == Aig_ObjRepr( p1, pObj1 ) );
        if ( Aig_ObjIsCo(pObj0) )
        {
            pFanin0 = Aig_ObjFanin0(pObj0);
            pFanin1 = Aig_ObjFanin0(pObj1);
            assert( Aig_ObjIsTravIdCurrent(p0, pFanin0) ==
                    Aig_ObjIsTravIdCurrent(p1, pFanin1) );
            if ( Aig_ObjIsTravIdCurrent(p0, pFanin0) )
            {
                pMiter = Aig_Exor( pNew, (Aig_Obj_t *)pFanin0->pData, (Aig_Obj_t *)pFanin1->pData );
                Aig_ObjCreateCo( pNew, pMiter );
            }
        }
        else
        {
            assert( Aig_ObjIsNode(pObj0) );

            pFanin0 = Aig_ObjFanin0(pObj0);
            pFanin1 = Aig_ObjFanin0(pObj1);
            assert( Aig_ObjIsTravIdCurrent(p0, pFanin0) ==
                    Aig_ObjIsTravIdCurrent(p1, pFanin1) );
            if ( Aig_ObjIsTravIdCurrent(p0, pFanin0) )
            {
                pMiter = Aig_Exor( pNew, (Aig_Obj_t *)pFanin0->pData, (Aig_Obj_t *)pFanin1->pData );
                Aig_ObjCreateCo( pNew, pMiter );
            }

            pFanin0 = Aig_ObjFanin1(pObj0);
            pFanin1 = Aig_ObjFanin1(pObj1);
            assert( Aig_ObjIsTravIdCurrent(p0, pFanin0) ==
                    Aig_ObjIsTravIdCurrent(p1, pFanin1) );
            if ( Aig_ObjIsTravIdCurrent(p0, pFanin0) )
            {
                pMiter = Aig_Exor( pNew, (Aig_Obj_t *)pFanin0->pData, (Aig_Obj_t *)pFanin1->pData );
                Aig_ObjCreateCo( pNew, pMiter );
            }
        }
    }
}


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

  Synopsis    [Extracts the window AIG from the AIG manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Aig_Man_t * Saig_ManWindowExtractMiter( Aig_Man_t * p0, Aig_Man_t * p1 )
{
    Aig_Man_t * pNew;
    Aig_Obj_t * pObj0, * pObj1, * pMatch0, * pMatch1;
    Vec_Ptr_t * vNodes0, * vNodes1;
    int i, nRegCount;
    // add matching of POs and LIs
    Saig_ManForEachPo( p0, pObj0, i )
    {
        pObj1 = Aig_ManCo( p1, i );
        Aig_ObjSetRepr( p0, pObj0, pObj1 );
        Aig_ObjSetRepr( p1, pObj1, pObj0 );
    }
    Saig_ManForEachLi( p0, pObj0, i )
    {
        pMatch0 = Saig_ObjLiToLo( p0, pObj0 );
        pMatch1 = Aig_ObjRepr( p0, pMatch0 );
        if ( pMatch1 == NULL )
            continue;
        assert( pMatch0 == Aig_ObjRepr( p1, pMatch1 ) );
        pObj1 = Saig_ObjLoToLi( p1, pMatch1 );
        Aig_ObjSetRepr( p0, pObj0, pObj1 );
        Aig_ObjSetRepr( p1, pObj1, pObj0 );
    }
    // clean the markings
    Aig_ManCleanData( p0 ); 
    Aig_ManCleanData( p1 ); 
    // collect nodes that are not linked
    vNodes0 = Saig_ManCollectedDiffNodes( p0, p1 );
    vNodes1 = Saig_ManCollectedDiffNodes( p1, p0 );
    // create the new manager
    pNew = Aig_ManStart( Vec_PtrSize(vNodes0) + Vec_PtrSize(vNodes1) );
    pNew->pName = Abc_UtilStrsav( "wnd" );
    pNew->pSpec = NULL;
    // map constant nodes
    pObj0 = Aig_ManConst1( p0 );
    pObj0->pData = Aig_ManConst1( pNew );
    pObj1 = Aig_ManConst1( p1 );
    pObj1->pData = Aig_ManConst1( pNew );
    // create real PIs
    Saig_ManWindowCreatePis( pNew, p0, p1, vNodes0 );
    Saig_ManWindowCreatePis( pNew, p1, p0, vNodes1 );
    // create register outputs
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes0, pObj0, i )
    {
        if ( Saig_ObjIsLo(p0, pObj0) )
            pObj0->pData = Aig_ObjCreateCi(pNew);
    }
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes1, pObj1, i )
    {
        if ( Saig_ObjIsLo(p1, pObj1) )
            pObj1->pData = Aig_ObjCreateCi(pNew);
    }
    // create internal nodes
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes0, pObj0, i )
    {
        if ( Aig_ObjIsNode(pObj0) )
            pObj0->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj0), Aig_ObjChild1Copy(pObj0) );
    }
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes1, pObj1, i )
    {
        if ( Aig_ObjIsNode(pObj1) )
            pObj1->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj1), Aig_ObjChild1Copy(pObj1) );
    }
    // create POs
    Saig_ManWindowCreatePos( pNew, p0, p1 );
//    Saig_ManWindowCreatePos( pNew, p1, p0 );
    // create register inputs
    nRegCount = 0;
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes0, pObj0, i )
    {
        if ( Saig_ObjIsLo(p0, pObj0) )
        {
            pMatch0 = Saig_ObjLoToLi( p0, pObj0 );
            Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch0) );
            nRegCount++;
        }
    }
    Vec_PtrForEachEntry( Aig_Obj_t *, vNodes1, pObj1, i )
    {
        if ( Saig_ObjIsLo(p1, pObj1) )
        {
            pMatch1 = Saig_ObjLoToLi( p1, pObj1 );
            Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch1) );
            nRegCount++;
        }
    }
    Aig_ManSetRegNum( pNew, nRegCount );
    Aig_ManCleanup( pNew );
    Vec_PtrFree( vNodes0 );
    Vec_PtrFree( vNodes1 );
    return pNew;
}

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


ABC_NAMESPACE_IMPL_END

