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

  Synopsis    [Performs UNSAT-core-based refinement.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Rnm_ManRefineCollect_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vVisited, Vec_Int_t * vFlops )
{
    Vec_Int_t * vLeaves;
    Gia_Obj_t * pFanin;
    int k;
    if ( Gia_ObjIsTravIdCurrent(p, pObj) )
        return;
    Gia_ObjSetTravIdCurrent(p, pObj);
    if ( Gia_ObjIsCi(pObj) )
    {
        if ( Gia_ObjIsRo(p, pObj) )
            Vec_IntPush( vFlops, Gia_ObjId(p, pObj) );
        return;
    }
    assert( Gia_ObjIsAnd(pObj) );
    vLeaves = Ga2_ObjLeaves( p, pObj );
    Gia_ManForEachObjVec( vLeaves, p, pFanin, k )
        Rnm_ManRefineCollect_rec( p, pFanin, vVisited, vFlops );
    Vec_IntPush( vVisited, Gia_ObjId(p, pObj) );
}
/**Function*************************************************************

  Synopsis    [Perform structural analysis.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ga2_StructAnalize( Gia_Man_t * p, Vec_Int_t * vFront, Vec_Int_t * vInter, Vec_Int_t * vNewPPis )
{
    Vec_Int_t * vFanins;
    Gia_Obj_t * pObj, * pFanin;
    int i, k;
    // clean labels
    Gia_ManForEachObj( p, pObj, i )
        pObj->fMark0 = pObj->fMark1 = 0;
    // label frontier
    Gia_ManForEachObjVec( vFront, p, pObj, i )
        pObj->fMark0 = 1, pObj->fMark1 = 0;
    // label objects
    Gia_ManForEachObjVec( vInter, p, pObj, i )
        pObj->fMark1 = 0, pObj->fMark1 = 1;
    // label selected
    Gia_ManForEachObjVec( vNewPPis, p, pObj, i )
        pObj->fMark1 = 1, pObj->fMark1 = 1;
    // explore selected
    Gia_ManForEachObjVec( vNewPPis, p, pObj, i )
    {
        printf( "Selected PPI %3d : ", i+1 );
        printf( "%6d ",  Gia_ObjId(p, pObj) );
        printf( "\n" );
        vFanins = Ga2_ObjLeaves( p, pObj );
        Gia_ManForEachObjVec( vFanins, p, pFanin, k )
        {
            printf( "    " );
            printf( "%6d ", Gia_ObjId(p, pFanin) );
            if ( pFanin->fMark0 && pFanin->fMark1 )
                printf( "selected PPI" );
            else if ( pFanin->fMark0 && !pFanin->fMark1 )
                printf( "frontier (original PI or PPI)" );
            else if ( !pFanin->fMark0 &&  pFanin->fMark1 )
                printf( "abstracted node" );
            else if ( !pFanin->fMark0 && !pFanin->fMark1 )
                printf( "free variable" );
            printf( "\n" );
        }
    Gia_ManIncrementTravId( p->pGia );
    Gia_ManForEachObjVec( vPPIs, p->pGia, pObj, i )
//        if ( !Gia_ObjIsRo(p->pGia, pObj) ) // SKIP PPIs that are flops
            Rnm_ManRefineCollect_rec( p->pGia, pObj, vVisited, vFlops );
    // create SAT variables and SAT solver
    Vec_IntFill( p->vSat2Ids, 1, -1 );
    assert( p->pSat == NULL );
    p->pSat = sat_solver2_new();
    Vec_IntFill( p->vSatVars, Gia_ManObjNum(p->pGia), 0 ); // NO NEED TO CLEAN EACH TIME
    // assign PPI variables
    Gia_ManForEachObjVec( vFlops, p->pGia, pObj, i )
        Rnm_ObjFindOrAddSatVar( p, pObj );
    // assign other variables
    Gia_ManForEachObjVec( vVisited, p->pGia, pObj, i )
    {
        vLeaves = Ga2_ObjLeaves( p->pGia, pObj );
        Gia_ManForEachObjVec( vLeaves, p->pGia, pFanin, k )
            pLits[k] = Rnm_ObjFindOrAddSatVar( p, pFanin );
        vCnf0 = Ga2_ManCnfCompute(  Ga2_ObjTruth(p->pGia, pObj), Vec_IntSize(vLeaves), p->vIsopMem );
        vCnf1 = Ga2_ManCnfCompute( ~Ga2_ObjTruth(p->pGia, pObj), Vec_IntSize(vLeaves), p->vIsopMem );
        Ga2_ManCnfAddStatic( p->pSat, vCnf0, vCnf1, pLits, Rnm_ObjFindOrAddSatVar(p, pObj), Rnm_ObjFindOrAddSatVar(p, pObj)/2 );
        Vec_IntFree( vCnf0 );
        Vec_IntFree( vCnf1 );
    }

//    printf( "\n" );

    p->pSat->pPrf2 = Prf_ManAlloc();
    Prf_ManRestart( p->pSat->pPrf2, NULL, sat_solver2_nlearnts(p->pSat), Vec_IntSize(p->vSat2Ids) );

    // iterate UNSAT core computation for each timeframe