// This file is for general TPDA zone based emptiness checking with continuous implementation, pop and push also can happen at the same transition

#include<tpdaZone.h>
#include"timePushDown.h"
#include"treeBitOperations.h"
#include<iostream>


using namespace std;


// Considering w is edge weight matrix of a graph, find if there is any negative cycle in the graph after applying floyd warshal algorithm
bool isNegCycle(short **w, bool **open, int n) {
    for(char i=0; i < n; i++) {
        if( w[i][i] < 0 || open[i][i] ) // if diagonal weights are strictly less than zero
            return true;
    }
    return false;
}


short **WT1, **WT2; // used as temporary storage for weight matrix in floyd warshal algorithm
bool **open1, **open2; // temporary variable for storing some edge is open interval or not



// apply all pair shortest path algorithms for the graph with n number of nodes(edge weights given in 1d array w) 
void  allPairSP(int n) {
    char i,j,k; // counters
    
    // n iterations for floyd warshal algorithm
    for(k=0; k < n; k++) {
        for(i=0; i < n; i++) {
            for(j=0; j < n; j++){
                if(k & 1) { // if k is odd, transfer weights from WT2 to WT1
                    if( ( WT2[i][k] + WT2[k][j] ) < WT2[i][j] ) { // if using node k, we update distance from i to j
                        WT1[i][j] = WT2[i][k] + WT2[k][j];
                        open1[i][j] = open2[i][k] || open2[k][j] ;
                    }
                    
                    else if( ( WT2[i][k] + WT2[k][j] ) == WT2[i][j]) { // if any distance is open, then the new distance is also open
                        WT1[i][j] = WT2[i][j];
                        open1[i][j] = open2[i][k] || open2[k][j] || open2[i][j] ;
                    }
                    
                    else {
                        WT1[i][j] = WT2[i][j];
                        open1[i][j] = open2[i][j] ;
                    }
                }
                
                else{ // if k is even , transfer weights from WT1 to WT2
                    if( ( WT1[i][k] + WT1[k][j] ) < WT1[i][j] ) {
                        WT2[i][j] = WT1[i][k] + WT1[k][j];
                        open2[i][j] = open1[i][k] || open1[k][j] ;
                    }
                    
                    else if( ( WT1[i][k] + WT1[k][j] ) == WT1[i][j]) {
                        WT2[i][j] = WT1[i][j];
                        open2[i][j] = open1[i][k] || open1[k][j] || open1[i][j] ;
                    }
                    
                    else{
                        WT2[i][j] = WT1[i][j];
                        open2[i][j] = open1[i][j] ;
                    }
                }
            }
        }
    }
}



// used for checking if newly generated state was already generated earlier or not
unordered_map<string,bool> mapZone;

// this vector contains all the states generated for a TPDA paried with tracking states
vector<pair<stateZone*, trackZone*> > allStatesZone;


// return 1 iff state vs was not found earlier or vs is new state
bool identity(stateZone *vs) {
    
    string os=""; // output string
    short i; // looper
    short P = vs->P;
    
    
    for( i=0; i < P; i++ ) { // add transitions to the string os
        //cout << "i:" << int(i) << endl;
        os += (vs->del[i]);
    }
    
    P = P*P - P;
    //cout << P << endl;
    for(i=0; i < P; i++ ){
        
        os += char(vs->w[i]);
        os += char( (vs->w[i]) >> 8 ) ; //why this?
    }
    
    //cout << "ILIAS" <<  int(vs->f) << endl;
    os += char(vs->f); // L is also included in f
    
    // using hashmap : if os key was not there then mapGCPP[os]==false
    if( mapZone[os] ) // 'os' is there in hashmap
        return false;
    
    else{ // 'os' is not there in hashmap
        mapZone[os] = true;
        return true;;
    }
}
/*bool findVector(vector <int> vector1, int val)
 {
 int n = find(vector1.begin(),vector1.end(),val);
 if( n == vector1.end())
 return false;
 return true;
 }*/

stateZone* stateZone::reduceShuffle(stateZone* s2) {
    
    char *del2 = s2->del;
    short *w2 = s2->w;
    char P2 = s2->P;
    short f2 = s2->f;
    short L = f&127;
    short L2 = f2 & 127;
    short curReset, reset, tempReset; // temp variables to keep reset for a range of points 
    char count=0; // used for storing #points in new state
    char  indexNew; // looping invariant
    int lb,ub,openl,openu;
    
    count = P + P2 - (L2+1); //total number of points before reducing the state, the point P1 and L2 are same so reduced by 1.
    
    stateZone *vs = new stateZone(); // new Shuffled state but not reduced.
    
    vs->del = new char[count]; // allocate memory for the transitions in the state
    
    vs->w = new short[count*(count-1)]; //this will hold the matrix without the diagonal element the index will be given by the macro
    
    vs->f = f; //f contains the push complete command flag bit along with the value of L
    
    for(int i = 0; i < count*count ; i++) //initially fill the matrix WT1 with 0 and infinity as usual, later values will get replaced.
        for(int j = 0; j < count*count ; j++)
        {
            if ( i == j)   ////Initializing all edge values
                WT1[i][j] = 0;
            else if( i < j)
                WT1[i][j]=INF16;
            else
                WT1[i][j] = 0;
        }
    
    
    /*copying the transitions for both the states to this new state*/
    indexNew = count - 1; // index of the last transition of the new state.
    
    //first I want to copy the transitions of the state 1.
    for(int i=0; i <P; i++) {
        vs->del[i] = del[i]; // copy (i+1)-th transition to (j+1) transition of new state
        for(int m =0; m <P; m++)
        {
            if(i==m) {  //same transition points 
                WT1[i][i] = 0;
                open1[i][i] = false;
            }
            else if(i < m) {  
                WT1[i][m] = min(int(WT1[i][m]),int(w[index((i-P), (m-P), P2)] & (~a32[15]))); // 15-TH bit is used for open or not
                
                if( w[index((i-P), (m-P), P2)] & a32[15] ) // as 15th bit is used for open and close interval
                    open1[i][m] = true;
                else
                    open1[i][m] = false;
            }
            
            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
                WT1[i][m] = - ( min(int(w[index((i-P), (m-P), P2)] & (~a32[15])),-int(WT1[i][m]) )); // 15-TH bit is used for open or not
                
                if( w[index((i-P), (m-P), P2)] & a32[15] )
                    open1[i][m] = true;
                else
                    open1[i][m] = false;
            }
        }
    }
    
    char indexNew1 = indexNew;
    // Here we are copying points of state 2.
    for(int j=P2-1; j >=0; j--,indexNew--) {
        vs->del[indexNew] = del2[j];
        for(int i =P2-1 ; i >=0 ; i--,indexNew1--)
        {
            if(i==j) {  //same transition points 
                WT1[indexNew][indexNew1] = 0;
                open1[indexNew][indexNew1] = false;
            }
            else if(j < i) {  
                WT1[indexNew][indexNew1] = min(int(w2[index(j, i, P)] & (~a32[15])),int(WT1[indexNew][indexNew1])); // 15-TH bit is used for open or not
                
                if( w2[index(j, i, P)] & a32[15] ) // as 15th bit is used for open and close interval
                    open1[indexNew][indexNew1] = true;
                else
                    open1[indexNew][indexNew1] = false;
            }
            
            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
                WT1[indexNew][indexNew1] = - (min(int( w2[index(j, i, P)] & (~a32[15])),int(WT1[indexNew][indexNew1])) ); // 15-TH bit is used for open or not
                
                if( w2[index(j, i, P)] & a32[15] )
                    open1[indexNew][indexNew1] = true;
                else
                    open1[indexNew][indexNew1] = false;
            }
        }
        //vs->w[j] = w[j];
        // same reasons as above
        // if distance (j+1)->(j+2) of 1st state is accurate, then distance (j+1)->(j+2) of new state is accurate
        //nf |= ( f & a32[j+1] ); // here f means some thing different
    }
    
    //Now before reducing the state we want to check if the state is at all feasible..
    // so we run the APSP algo.
    allPairSP(count); //this is the Floyd–Warshall algorithm implementation
    
    
    
    short **WT;
    bool **open;
    
    if(count & 1) { // if P is odd, the shortest path stored in WT1 and open1
        WT = WT1;
        open = open1;
    }
    else{ // if P is even, the shortest path stored in WT2 and open2
        WT = WT2;
        open = open2;
    }
    
    /*
     cout << "After" << endl;
     for(i=0; i <= P; i++){
     for(j=0; j <= P; j++) {
     cout << WT[i][j] << "." << open[i][j] << "\t";
     }
     cout << endl << endl;
     }
     */	
    
    // checking if there is any negative cycle by applying floyd warshal algorithm
    for(int i=0; i <= count; i++){
        
        if(WT[i][i] < 0 || open[i][i])
            return nullptr;
    }
    
    short countNew = 1; // var for storing #points in new state after applying forget operation
    int forgetFlag = 0; // i-th bit of forgetFlag is 1 iff i-th point is forgotten
    
    curReset = 0, reset = 0;
    int prevPoints = 0;
    for(int i=L2; i < P2; i++)
        curReset |= ( transitions[ del2[i] ].reset ); 
    
    for(int i=P-1; i >= L; i--,prevPoints++) { 
        reset = ( transitions[ del[i] ].reset );
        
        /* there is a bit '1' of 'reset' but '0' of 'curReset' at same position => there is a clock
         reset at (i+1) point of 1st state which has not reset to any of its right points for both state */
        if( reset & (~curReset) & (~1) ) { // (~)  : ignore the 0-th bit, used for stack operation
            countNew++; // this point should be in new state, so increase the counter
            curReset |= reset; // union reset set at this point with earlier set
        }
        else{
            forgetFlag |= a32[i+1]; // i+1-th point will be forgotten in new state
        }
    }
    
    char newcount = count - prevPoints + countNew;
    
    char *newToOldRef = new char[newcount];
    
    for(int i =0, j = 0; i < count; i++) { // find the reference from old point to new point
        if( (forgetFlag & a32[i+1] ) == 0 )   {
            newToOldRef[j] = i;
            j++;
        }
    }
    
    
    stateZone *vs1 = new stateZone(); // new TA state
    
    vs1->del = new char[newcount]; // allocate memory
    vs1->w = new short[newcount*newcount - newcount];
    vs1->f = f; // **** must edit this for tpda
    //clearly the left point is the same as the left point of the state vs1.
    // if the last point 
    vs1->P = newcount;
    
    
    for(int i=0; i < newcount; i++) {
        vs1->del[i]= vs->del[newToOldRef[i]];
    }
    //vs->del[count-1] = dn;
    
    
    
    //I have doubt on this part... have to think about it.....
    ///date 14/7/2017
    
    for(int i=0;i < newcount; i++){
        for(int j=0; j < newcount; j++){
            if(i < j) {
                vs1->w[index(i, j, newcount)] = WT[ newToOldRef[i] ][ newToOldRef[j] ];
                //cout << int(newToOldRef[i]) << "," << int(newToOldRef[j]) << endl;
                if( open[ newToOldRef[i] ][ newToOldRef[j] ] )
                    vs1->w[index(i, j, newcount)] |= a32[15];
            }
            else if(i > j) {
                vs1->w[index(i, j, newcount)] = - WT[ newToOldRef[i] ][ newToOldRef[j] ];
                //cout << int(newToOldRef[i]) << "," << int(newToOldRef[j]) << endl;
                if( open[ newToOldRef[i] ][ newToOldRef[j] ] )
                    vs1->w[index(i, j, newcount)] |= a32[15];
            }
        }
    }
    
    //for(i=P-1; i >= L; i--) { //iterating on the points of the first state
    // current point reset set
    
    /* j = (count - 1) - (P2 - L2);//this is the start of hanging points of state 2
     
     for(int k = 0; k < P2 ; k++) //iterating through the points of second state to find any clock constraint check
     {
     for(int x=1; x <= X; x++) { // iterate for every clocks
     
     if( isChecked(x, del2[k]) ) { // if there is a constraint for clock x in the transition k of second state
     
     
     lb = transitions[del2[k]].lbs[x];//storing the value of the upper bound of the constraint
     ub = transitions[del2[k]].ubs[x]; // storing the lower bound of the constraint
     openl = (transitions[del2[k]].openl) & a32[x]; // lower bound for clock x is open or not
     openu = (transitions[del2[k]].openu) & a32[x]; // upper bound of the clock x is open or not
     
     for(i=P-1; i >= L; i--) { // find reset point for clock x in the first state
     reset = ( transitions[ del[i] ].reset ); //storing the reset information for this transition
     if( (reset & (~curReset) & (~1))  && (isReset(x, del[i])) ) { // if current point has more reset then seen earlier
     //and if this point have the a reset point of the clock x
     vs->del[j] = del[i]; //copy the transition number 
     //if(  ) { // if clock x is reset at point i+1
     
     // tighten the lower and upper bounds
     if( (-lb) < WT1[P][i] ) {
     WT1[P][i] = -lb;
     open1[P][i] = (openl & a32[x]);
     }
     
     else if( (-lb) == WT1[i][P] )
     open1[P][i] |= (openl & a32[x]);
     
     if(ub != INF) {
     if(ub < WT1[i][P]) {
     WT1[i][P] = ub;
     open1[i][P] = (openu & a32[x]);
     }
     
     else if( ub == WT1[i][P] )
     open1[i][P] |= (openu & a32[x]);
     }
     i = -1;
     }
     //curReset |= reset;
     j--;
     //lastindex = i;
     }
     }
     }
     }
     
     */  
    //vs->P = count; // #points in new state
    free(vs);
    return vs1;	
}

// reduce the #points after shuffle by using forget operation if possible and return the new state
//stateZone* stateZone::reduceShuffle(stateZone* s2) {
//    
//    char *del2 = s2->del, *w2 = s2->w;
//    char P2 = s2->P;
//    short f2 = s2->f;
//    short L = f&127;
//    short L2 = f2 & 127;
//    short curReset, reset, tempReset; // temp variables to keep reset for a range of points 
//    char count=0; // used for storing #points in new state
//    char i, j; // loopers
//    int lb,ub,openl,openu;
////    char mappingS1ToNew[P];
////    char mappingS2ToNew[P2];
////    vector <int> indexNotPresentIn1;
//    // we have to take all the points from s2->L+1 to s2->P, point s2->L may not be there
//    // all the points from 1 to L of first state will be there in new state, last point P may not be there
//    
//    // take union of resets for points between s2->L+1(including) and s2->P(including)
//    curReset = 0;
//    for(i=L2; i < P2; i++)
//        curReset |= ( transitions[ del2[i] ].reset ); //this contain union of the resets in the second state
//    
//    tempReset = curReset; // store this value for later use
//    
//    for( i=P-1; i >= L; i--) { 
//        reset = ( transitions[ del[i] ].reset );
//        
//        // there is a bit '1' of 'reset' but '0' of 'curReset' at same position => there is a clock
//        //reset at (i+1) point of 1st state which has not reset to any of its right points for both state 
//        if( reset & (~curReset) & (~1) ) { // (~1)  : ignore the 0-th bit, used for stack operation
//            count++; // this point should be in new state, so increase the counter
//            //storethe index
//            
//            curReset |= reset; // union reset set at this point with earlier set
//        }
////        else
////            indexNotPresentIn1.push_back(i);
//    }
//    
//    // addition of 'L' below comes from the fact that all point from 1 to L of first state is there in new state
//    // (s2->P - s2-> L) comes from : all points s2->L+1 to s2->P are there in new state
//    count += L + (P2 - L2); // #points in new state
////    int indexOfNewState = 0;
////    for(i = 0; i < P; i++)
////    {
////        if(! findVector(indexNotPresentIn1,i))
////        {
////            mappingS1ToNew[i]=indexOfNewState;
////            indexOfNewState++;
////        }
////        else
////            mappingS1ToNew[i]= -1;
////        
////    }
//    
////    for(i = 0 ; i < P2; i++)
////    {
////        
////    }
//    
//    stateZone *vs = new stateZone(); // new TA state
//    
//    vs->del = new char[count]; // allocate memory
//    vs->w = new char[count*(count-1)]; //this will hold the matrix without the diagonal element
//    vs->f = f; //f contains the push complete command flag bit along with the value of L
//    for(int i = 0; i < count*count ; i++)
//        for(int j = 0; j < count*count ; j++)
//        {
//            if ( i == j)   ////Initializing all edge values
//                WT1[i][j] = 0;
//            else if( i < j)
//                WT1[i][j]=INF16;
//            else
//                WT1[i][j] = 0;
//        }
//    //short nf = 0; // initially flag is zero
//    //short dis; // distance variable
//    /*copying the transitions for both the states to this new state*/
//    j = count - 1; // index of the rightmost point of new state
//    // Here we are copying points from s2->L+1 to s2->P of 2nd state to new state
//    for(i=P2 - 1; i >= L2; i--, j--) {
//        vs->del[j] = del2[i]; // copy (i+1)-th transition to (j+1) transition of new state
//        //vs->w[j] = w2[i]; // copy (i+1)-th tsm to (j+1) tsm of new state
//        //for zone the W contains the details of matrix which we need to copy and check for negetive cycle
//        // if distance (i+1)->(i+2) of 2nd state is accurate, then distance (j+1)->(j+2) of new state is accurate
//        //if( f2 & a32[i+1] ) 
//        //	nf |= a32[j+1];
//        for(int m =P2 - 1; m >= L2; i--)
//        {
//            if(i==m) {  //same transition points 
//                WT1[i][i] = 0;
//                open1[i][i] = false;
//            }
//            else if(i < m) {  
//                WT1[i][m] = w2[index((i-P), (m-P), P2)] & (~a32[15]); // 15-TH bit is used for open or not
//                
//                if( w2[index((i-P), (m-P), P2)] & a32[15] ) // as 15th bit is used for open and close interval
//                    open1[i][m] = true;
//                else
//                    open1[i][m] = false;
//            }
//            
//            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
//                WT1[i][m] = - ( w2[index((i-P), (m-P), P2)] & (~a32[15]) ); // 15-TH bit is used for open or not
//                
//                if( w2[index((i-P), (m-P), P2)] & a32[15] )
//                    open1[i][m] = true;
//                else
//                    open1[i][m] = false;
//            }
//        }
//    }
//    
//    // Here we are copying points from 1 to L-1 of 1st state to new state
//    for(j=0; j < (L-1); j++) {
//        vs->del[j] = del[j];
//        for(int i = 0; i < (L-1); i++)
//        {
//            if(i==j) {  //same transition points 
//                WT1[i][i] = 0;
//                open1[i][i] = false;
//            }
//            else if(j < i) {  
//                WT1[j][i] = w[index(j, i, P)] & (~a32[15]); // 15-TH bit is used for open or not
//                
//                if( w[index(j, i, P)] & a32[15] ) // as 15th bit is used for open and close interval
//                    open1[j][i] = true;
//                else
//                    open1[j][i] = false;
//            }
//            
//            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
//                WT1[j][i] = - ( w[index(j, i, P)] & (~a32[15]) ); // 15-TH bit is used for open or not
//                
//                if( w[index(j, i, P)] & a32[15] )
//                    open1[j][i] = true;
//                else
//                    open1[j][i] = false;
//            }
//        }
//        //vs->w[j] = w[j];
//        // same reasons as above
//        // if distance (j+1)->(j+2) of 1st state is accurate, then distance (j+1)->(j+2) of new state is accurate
//        //nf |= ( f & a32[j+1] ); // here f means some thing different
//    }
//    
//    //copy the point L, doing it separately because of the flag variable which is not applicable for L-th point
//    vs->del[L-1] = del[L-1];
//    for(int x = 0; x < X ; x++) // checking if L have any checking or not?
//    {
//        if(isChecked(x,del[L-1]))
//        {
//            lb = transitions[del[L-1]].lbs[x];
//            ub = transitions[del[L-1]].ubs[x];
//            openl = (transitions[del[L-1]].openl) & a32[x]; // lower bound for clock x is open or not
//            openu = (transitions[del[L-1]].openu) & a32[x];
//            
//            for(i=L-2; i >=0; i--) { // find reset point for clock x
//                
//                if( isReset(x, del[i]) ) { // if clock x is reset at point i+1
//                    
//                    // tighten the lower and upper bounds
//                    if( (-lb) < WT1[L-1][i] ) {
//                        WT1[L-1][i] = -lb;
//                        open1[L-1][i] = (openl & a32[x]);
//                    }
//                    
//                    else if( (-lb) == WT1[i][L-1] )
//                        open1[L-1][i] |= (openl & a32[x]);
//                    
//                    if(ub != INF) {
//                        if(ub < WT1[i][L-1]) {
//                            WT1[i][L-1] = ub;
//                            open1[i][L-1] = (openu & a32[x]);
//                        }
//                        
//                        else if( ub == WT1[i][L-1] )
//                            open1[i][L-1] |= (openu & a32[x]);
//                    }
//                    i = -1; //stopping the loop cause there is only one recent reset point
//                }
//            }
//        }
//    }
//    
//    /* //vs->w[L-1] = w[L-1]; w doesnot contains time stamps any more it contains the matrix 
//    /*copying transition details done*/
//    //Here goes the logic of creating the matrix altogether with given values.
//    /*copying matrix details to the new state*/
//    // copy weights of first state to WT1
////    for(i=0; i < P; i++) {
////        for(j=0; j < P; j++) {
////        if(i==j) {  //same transition points 
////                WT1[i][i] = 0;
////                open1[i][i] = false;
////            }
////            else if(i < j) {  
////                WT1[i][j] = w[index(i, j, P)] & (~a32[15]); // 15-TH bit is used for open or not
////                
////                if( w[index(i, j, P)] & a32[15] ) // as 15th bit is used for open and close interval
////                    open1[i][j] = true;
////                else
////                    open1[i][j] = false;
////            }
////            
////            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
////                WT1[i][j] = - ( w[index(i, j, P)] & (~a32[15]) ); // 15-TH bit is used for open or not
////                
////                if( w[index(i, j, P)] & a32[15] )
////                    open1[i][j] = true;
////                else
////                    open1[i][j] = false;
////            }    
////            
////        }
////    }
//    //copy weights of second state to WT1
//    // copy weights of current state to WT1
////    for(i=P; i < count; i++) {
////        for(j=P; j < count; j++) {
////            if(i==j) {  //same transition points 
////                WT1[i][i] = 0;
////                open1[i][i] = false;
////            }
////            else if(i < j) {  
////                WT1[i][j] = w[index((i-P), (j-P), P2)] & (~a32[15]); // 15-TH bit is used for open or not
////                
////                if( w[index((i-P), (j-P), P2)] & a32[15] ) // as 15th bit is used for open and close interval
////                    open1[i][j] = true;
////                else
////                    open1[i][j] = false;
////            }
////            
////            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
////                WT1[i][j] = - ( w[index((i-P), (j-P), P2)] & (~a32[15]) ); // 15-TH bit is used for open or not
////                
////                if( w[index((i-P), (j-P), P2)] & a32[15] )
////                    open1[i][j] = true;
////                else
////                    open1[i][j] = false;
////            }
////            
////        }
////    }
//    
//    //both the matrices is copied to the variable,
//    //here P = L2 Now we have to check the check points and their 
//    //recent reset points 
//    //now there are some hangng edges which are
//    // Now we watch out for points from L+1 to P of 1st state
//    //char lastindex = P;// last index of the point we have taken so far, although P might not be included
//    
//    curReset = tempReset; //get the union of resets for points between s2->L+1 and s2->P
//    
//    // current indices j of new state we have to take care
//   
//    
//    
//    //for(i=P-1; i >= L; i--) { //iterating on the points of the first state
//    // current point reset set
//    
//    j = (count - 1) - (P2 - L2);//this is the start of hanging points of state 2
//    
//    for(int k = 0; k < P2 ; k++) //iterating through the points of second state to find any clock constraint check
//    {
//        for(int x=1; x <= X; x++) { // iterate for every clocks
//            
//            if( isChecked(x, del2[k]) ) { // if there is a constraint for clock x in the transition k of second state
//                
//                
//                lb = transitions[del2[k]].lbs[x];//storing the value of the upper bound of the constraint
//                ub = transitions[del2[k]].ubs[x]; // storing the lower bound of the constraint
//                openl = (transitions[del2[k]].openl) & a32[x]; // lower bound for clock x is open or not
//                openu = (transitions[del2[k]].openu) & a32[x]; // upper bound of the clock x is open or not
//                
//                for(i=P-1; i >= L; i--) { // find reset point for clock x in the first state
//                    reset = ( transitions[ del[i] ].reset ); //storing the reset information for this transition
//                    if( (reset & (~curReset) & (~1))  && (isReset(x, del[i])) ) { // if current point has more reset then seen earlier
//                        //and if this point have the a reset point of the clock x
//                        vs->del[j] = del[i]; //copy the transition number 
//                        //if(  ) { // if clock x is reset at point i+1
//                        
//                        // tighten the lower and upper bounds
//                        if( (-lb) < WT1[P][i] ) {
//                            WT1[P][i] = -lb;
//                            open1[P][i] = (openl & a32[x]);
//                        }
//                        
//                        else if( (-lb) == WT1[i][P] )
//                            open1[P][i] |= (openl & a32[x]);
//                        
//                        if(ub != INF) {
//                            if(ub < WT1[i][P]) {
//                                WT1[i][P] = ub;
//                                open1[i][P] = (openu & a32[x]);
//                            }
//                            
//                            else if( ub == WT1[i][P] )
//                                open1[i][P] |= (openu & a32[x]);
//                        }
//                        i = -1;
//                    }
//                    //curReset |= reset;
//                    j--;
//                    //lastindex = i;
//                }
//            }
//        }
//    }
//    /*  //vs->w[j] = w[i];
//     
//     
//     //                     if( lastindex == P ) { // if (i+1) is the first point we are considering after starting the loop
//     //				// In if : first check is for accuracy check from L to P of left state
//     //				// In if : second check is for cheking accuracy from L2 to L2+1 of right state, L2 is not choosen
//     //                        if( !big(i+1, P) && ( i == (P-1) || (f2 & a32[L2]) ) ) {
//     //                            dis = dist(i+1, P) + mod( w2[L2] - w[P-1], M);
//     //                            if( dis < M ) // if total distance from i+1-th point to s2->L+1 is accurate
//     //                                nf |= a32[j+1];
//     //                        }
//     //                     }
//     
//     //	        else {
//     //	            if( !big(i+1, lastindex+1) )
//     //	                nf |= a32[j+1];
//     //	        } */
//    
//    vs->P = count; // #points in new state
//    
//    return vs;	
//}


// one accuracy we yet have to compute which starts from L-th point of first state
//	if( lastindex == P ) { // if we have not taken any point from L+1  to P of 1st state
//		// In if : first check is for accuracy check from L to P of left state
//		// In if : second check is for cheking accuracy from L2 to L2+1 of right state, L2 is not choosen
//		if( !big(L, P) && (f2 & a32[L2] )  ) { // if distance between L and R of 1st state is accurate
//            dis = dist(L, P) + mod( w2[L2] - w[P-1], M);
//            if( dis < M ) // if total distance from i+1-th point to s2->L+1 is accurate
//                nf |= a32[L];
//        }
//	}
//	
//	else{
//		// if distance from L-th point to lastindex+1-th of 1st state is accurate
//		if( !big(L, lastindex+1) )
//			nf |= a32[L];
//	}
//	
//	if(f & 1) // push info from left state will be same
//		nf |= 1;
//		
//	nf |= a3215; // pop at right(R) is done
//	
//	vs->f = nf; // add the flag variable also




// check if shuffle of this state with s2 is possible
bool stateZone::shuffleCheck(stateZone *s2) {
    if( (f&127) == P || ((s2->f)&127) == ((s2->f)&127) ) // both state should have non-trival block
        return false;	
    
    if( !isPush(del[P-1]) ) // there should be a push at last transition of left state
        return false;
    
    // there should be a push at L of s2 and pop at R of s2, note : del[P-1] = del2[P2-1]
    if( !isPush( s2->del[((s2->f)&127)-1] ) || !isPop( s2->del[((s2->f)&127)-1] ) )
        return false;
    
    
    //why this condition?
    //if( !( (s2->f) & 1 ) || !( (s2->f) & a3215 )  ) // push-pop edge should be connected in right state
    //	return false;
    
    if( getKeyLeft() != (s2->getKeyRight() ) )
    	return false;
    
    return true;	
}


// shuffle of this state with state s2 and return the new state
stateZone* stateZone::shuffle(stateZone *s2){ // shuffle  with state s2
    
    if(! shuffleCheck(s2) )	
        return nullptr;
    
    return reduceShuffle(s2);
}



/*
 // add transition 'dn' to current state and then forget some points if possible, return the new state
 stateGCPP* stateGCPP::reduce(char dn){
 
 short reset; // variable for reset bit vector
 short nf = 0; // flag variable for new state
 char count = 0; // #points in new state
 char i; // looper
 
 short curReset = transitions[dn].reset; // set of clocks reset at transition 'dn'
 
 for( i=P-1; i >= L; i-- ) {
 reset = transitions[ del[i] ].reset; // reset at transition at the (i+1)-th point
 if( reset & (~curReset) & (~1) ) { // if (i+1)-th point has more reset than found so far at right
 curReset |= reset; // the 'curReset' will have more bit with value '1'
 count++; // we have to take (i+1)-th point
 }
 }
 
 // all the hanging points and point L and point for transition 'dn' also be there 
 count += (L+1); // number of points in new state
 
 // pointer to the new state
 stateGCPP* vs = new stateGCPP();
 
 vs->P = count; // #points in new state
 vs->L = L; // left point remain same
 
 vs->del = new char[count]; // memory allocation for new state transition
 vs->w = new char[count]; // memory allocation for new state tsm values
 
 for(i=0; i < L; i++) { // hanging points and left point(L) remain same
 vs->del[i] = del[i];
 vs->w[i] = w[i];
 }
 
 for(i=1; i < L; i++) { // distances between points upto point L remain same
 nf |= ( f & a32[i] );
 }
 
 vs->del[count-1] = dn; // trans at last point, till now we don't know the weight
 
 char lastindex = P; // 'lastindex' used for accuracy between two points in new state
 char firstindex;
 char j = count-2; // assgin trans and tsm from index count-2 upto L
 short dis; // variable for distance calculation
 // **** edit last bit of accuracy when u know the tsm of dn
 curReset = transitions[dn].reset; // set of clocks reset at transition 'dn'
 for(i=P-1; i >= L; i--) {
 reset = transitions[ del[i] ].reset; // reset at i+1-th point
 
 if( reset & (~curReset) & (~1) ) {
 vs->del[j] = del[i]; // i-th index trans will be part of new state at j-th index
 vs->w[j] = w[i]; // i-th index tsm will be part of new state at j-th index
 
 if( lastindex != P ) {			
 if( !big(i+1, lastindex+1) )
 nf |= a32[j+1]; // set the accuracy for (j+1)-th bit of new state
 }
 
 // store the accuracy from last point(active in new state) before dn and P in  i+1-th bit of nf
 // store the distance from last point(active in new state) before dn and P in vs->w[count-1]
 // we yet don't know the tsm for 'dn', so full calculation is not done in this function
 else{ 
 firstindex = i;
 if( !big(i+1, P) )
 nf |= a32[j+1];
 vs->w[count-1] = dist(i+1, P);
 }
 
 lastindex = i; // this is now the last index
 j--; // go to previous point
 }
 }
 
 // we have to set the accuracy for point L to L+1 in new state
 if( lastindex != P ) {
 if( !big(L, lastindex+1) ) {
 //	vs->w[count-1] = dist(L, lastindex+1) ;
 nf |= a32[L]; // set the accuracy for (j+1)-th bit of new state
 }
 }
 
 // store the accuracy from last point(active in new state) before dn and P in  i+1-th bit of nf
 // store the distance from last point(active in new state) before dn and P in vs->w[count-1]
 // we yet don't know the tsm for 'dn', so full calculation is not done in this function
 else{  // if you have not choosed any point in the middle starting from point P**
 if( !big(L, P) )
 nf |= a32[L];
 vs->w[count-1] = dist(L, P);
 }
 
 if(isPop(dn) ) // if dn has a pop, then push-pop has been added to L and R repectively
 nf |= (1 | a3215) ;
 else
 nf |= (f & 1) ; // previous push information remain same
 
 // last distance accuracy
 vs->f = nf; // add partial flag variable to new state
 
 return vs; // return the partially new state, **** last tsm missing with partial nf as given
 }
 
 */




// Add all possible upcoming transition just after the last transition of this state if all clock and stack constraints are satisfied
stateZone* stateZone::addNextTPDA(char dn) {
    char i, j; // counters
    char x; // used for clocks
    char L = f & 127; //the left point the 7th bit of f is used to denote if push is done in the L.
    
    
    // copy weights of current state to WT1
    for(i=0; i < P; i++) {
        for(j=0; j < P; j++) {
            if(i==j) {  //same transition points 
                WT1[i][i] = 0;
                open1[i][i] = false;
            }
            else if(i < j) {  
                WT1[i][j] = w[index(i, j, P)] & (~a32[15]); // 15-TH bit is used for open or not
                
                if( w[index(i, j, P)] & a32[15] ) // as 15th bit is used for open and close interval
                    open1[i][j] = true;
                else
                    open1[i][j] = false;
            }
            
            else{ ///when i > j i.e the edges coming from j to i it must be negetive.
                WT1[i][j] = - ( w[index(i, j, P)] & (~a32[15]) ); // 15-TH bit is used for open or not
                
                if( w[index(i, j, P)] & a32[15] )
                    open1[i][j] = true;
                else
                    open1[i][j] = false;
            }
            
        }
    }
    
    
    // the temporary new state has P+1 points as of now before applying forget operations
    for(i=0; i <= P; i++) {
        WT1[i][P] = INF16; // forward edge weight from point i to point P is infinite
        WT1[P][i] = 0; // backward edge weight from point i to point P is zero
        open1[i][P] = false;
        open1[P][i] = false;
    }
    
    
    
    int lb, ub; // lower and upper bounds temprary variables
    bool openl, openu; // lower and upper bound is open or not
    
    // *** TODO : change weight using pop constraint also
    // according to the constraint of every clocks, change the weight of the edges
    for(x=1; x <= X; x++) { // iterate for every clocks
        
        if( isChecked(x, dn) ) { // if there is a constraint for clock x in the transition dn
            
            
            lb = transitions[dn].lbs[x];
            ub = transitions[dn].ubs[x];
            openl = (transitions[dn].openl) & a32[x]; // lower bound for clock x is open or not
            openu = (transitions[dn].openu) & a32[x];
            
            for(i=P-1; i >= 0; i--) { // find reset point for clock x
                
                if( isReset(x, del[i]) ) { // if clock x is reset at point i+1
                    
                    // tighten the lower and upper bounds
                    if( (-lb) < WT1[P][i] ) {
                        WT1[P][i] = -lb;
                        open1[P][i] = (openl & a32[x]);
                    }
                    
                    else if( (-lb) == WT1[i][P] )
                        open1[P][i] |= (openl & a32[x]);
                    
                    if(ub != INF) {
                        if(ub < WT1[i][P]) {
                            WT1[i][P] = ub;
                            open1[i][P] = (openu & a32[x]);
                        }
                        
                        else if( ub == WT1[i][P] )
                            open1[i][P] |= (openu & a32[x]);
                    }
                    i = -1;
                }
            }
        }
    }
    
    /*
     cout << "Before" << endl;
     for(i=0; i <= P; i++){
     for(j=0; j <= P; j++) {
     cout << WT1[i][j] << "." << open1[i][j] << "\t";
     }
     cout << endl << endl;
     }
     
     */
    
    allPairSP(P+1); //this is the Floyd–Warshall algorithm implementation
    
    
    
    short **WT;
    bool **open;
    
    if(P & 1) { // if P is odd, the shortest path stored in WT1 and open1
        WT = WT1;
        open = open1;
    }
    else{ // if P is even, the shortest path stored in WT2 and open2
        WT = WT2;
        open = open2;
    }
    
    /*
     cout << "After" << endl;
     for(i=0; i <= P; i++){
     for(j=0; j <= P; j++) {
     cout << WT[i][j] << "." << open[i][j] << "\t";
     }
     cout << endl << endl;
     }
     */	
    
    // checking if there is any negative cycle by applying floyd warshal algorithm
    for(i=0; i <= P; i++){
        
        if(WT[i][i] < 0 || open[i][i])
            return nullptr;
    }
    
    
    
    short count = 1; // var for storing #points in new state after applying forget operation
    int forgetFlag = 0; // i-th bit of forgetFlag is 1 iff i-th point is forgotten
    
    int curReset = 0, reset = 0;
    curReset = transitions[dn].reset;
    
    for( i=P-1; i >= L; i--) { 
        reset = ( transitions[ del[i] ].reset );
        
        /* there is a bit '1' of 'reset' but '0' of 'curReset' at same position => there is a clock
         reset at (i+1) point of 1st state which has not reset to any of its right points for both state */
        if( reset & (~curReset) & (~1) ) { // (~)  : ignore the 0-th bit, used for stack operation
            count++; // this point should be in new state, so increase the counter
            curReset |= reset; // union reset set at this point with earlier set
        }
        else{
            forgetFlag |= a32[i+1]; // i+1-th point will be forgotten in new state
        }
    }
    
    count += L; // all points from 1 to L will be there
    char *newToOldRef = new char[count];
    
    i = 0;
    j = 0;
    for(; i < P; i++) { // find the reference from old point to new point
        if( (forgetFlag & a32[i+1] ) == 0 )   {
            newToOldRef[j] = i;
            j++;
        }
    }
    
    
    newToOldRef[count-1] = P; // last point in the new state refer to new point
    
    stateZone *vs = new stateZone(); // new TA state
    
    vs->del = new char[count]; // allocate memory
    vs->w = new short[count*count - count];
    vs->f = f; // **** must edit this for tpda
    vs->P = count;
    
    
    for(i=0; i < (count-1); i++) {
        vs->del[i]= del[newToOldRef[i]];
    }
    vs->del[count-1] = dn;
    
    
    
    for(i=0;i < count; i++){
        for(j=0; j < count; j++){
            if(i < j) {
                vs->w[index(i, j, count)] = WT[ newToOldRef[i] ][ newToOldRef[j] ];
                //cout << int(newToOldRef[i]) << "," << int(newToOldRef[j]) << endl;
                if( open[ newToOldRef[i] ][ newToOldRef[j] ] )
                    vs->w[index(i, j, count)] |= a32[15];
            }
            else if(i > j) {
                vs->w[index(i, j, count)] = - WT[ newToOldRef[i] ][ newToOldRef[j] ];
                //cout << int(newToOldRef[i]) << "," << int(newToOldRef[j]) << endl;
                if( open[ newToOldRef[i] ][ newToOldRef[j] ] )
                    vs->w[index(i, j, count)] |= a32[15];
            }
        }
    }
    
    
    // ***TO DO :
    // Take open guard as input
    //vs->print();
    return vs;
}

// not applied by ilias 

// Return template successor state whose descendent states will be right states for shuffle operation with this state
stateZone* stateZone::sucState(){
    
    short curReset, reset; // temp vars for keeping reset bit vector
    char count; // will contain #points in the new state
    //char i,j; // counters
    //vector<char> targetToSuc;
    // iterate through all points right to left except the last point 
    curReset = transitions[ del[P-1] ].reset;
    count = 1; //we have to take the last point, so initialize 'count' to 1
    
    for(char i=P-2; i >= 0; i--) {
        reset = transitions[ del[i] ].reset; // reset bit vector for point i+1
        if( reset & (~curReset) & (~1) ) { // if (i+1)-th point has additional reset for some clock
            count++;
            curReset |= reset;
            //targetToSuc.push_back(i);
        }		
    }
    count++;
    char * newToOldRef = new char[count];
    newToOldRef[count-1] = P-1;
    //targetToSuc.push_back(P-1);
    for(char i=P-2,j=count-2; i >= 0; i--,j--) {
        reset = transitions[ del[i] ].reset; // reset bit vector for point i+1
        if( reset & (~curReset) & (~1) ) { // if (i+1)-th point has additional reset for some clock
            count++;
            curReset |= reset;
            newToOldRef[j]= i;
        }		
    }

    stateZone* vs = new stateZone(); // new template state
    
    vs->P = count; //#points
    //vs->L = count; // no non-trivial block is there there is no L in the zone class
    
    vs->del = new char[count]; //allocate space for transition
    vs->w = new short[count*(count-1)]; // allocate space for the upper and lower limits
    for(char i =0; i< count;i++)
    {
        for(char j =0 ; j< count ; j++)
        {
            vs->w[index(i,j,count)]=w[index(newToOldRef[i],newToOldRef[j],P)];
        }
    }
   
    vs->del[count-1] = del[P-1]; // the last point is the last transition
    //vs->w[count-1] = w[P-1]; // have to apply the upper and lower bounds
    
    // copy the necessary points into the template state
    char lastindex = P-1;
    //short nf = 0; // flag variable for new state
    curReset = transitions[ del[P-1] ].reset;
    
    for(char i=P-2, j = count-2; i >= 0; i--) {
        reset = transitions[ del[i] ].reset; // reset bit vector for point i+1
        
        if(reset & (~curReset) & (~1) ) { // found a new necessary point, copy this point to new state
            vs->del[j] = del[i];
            
            // vs->w[j] = w[i];
            // if( !big(i+1, lastindex+1) ) //from current needy point to the last found needy point distance small
            // nf |= a32[j+1]; // distance (j+1->(j+2)) is small
            curReset |= reset;
            j--;
            lastindex = i; // this point is the last point selected till now
        }
    }
    
    // vs->f = nf; // copy flag information, no stack info is there till now for the template state
    vs->f = f;
    delete[] newToOldRef;
    return vs;
}




// print a validity state
void stateZone::print() {
    char i, j;
    char L = f & 127; // 7-th bit is used for push pop operation
    cout << endl << "Abstract state of the on the fly tree automata(TA):" << endl;
    
    cout << "\tPoints in the automaton:\n\t\t";
    cout << 1 ;
    for(i=2; i <= L; i++)
        cout <<  "    " << int(i) ;
    for(i=L+1; i <= P; i++)
        cout << "----" << int(i) ;
    cout << endl;
    
    cout << "\t\tL : " << int(L) << endl;
    
    cout << "\tTransitions:";
    
    cout << "\t";
    for(i=0; i < P; i++)
        cout << int(del[i]) << "\t";
    cout << endl;
    
    cout << "\tWeight Matrix : " << endl << "\t";
    //for(i=0; i < P; i++)
    //cout << int(i+1) << "\t";
    cout << endl;
    
    for(i=0;i < P; i++) {
        cout << "\t\t\t";
        for(j=0; j < P; j++) {
            if(i==j)
                cout << "0,0" << "\t";
            else if(i < j)
                cout << (w[index(i, j, P)] & (~a32[15]) ) << "," << bool((w[index(i, j, P)] & (a32[15]) )) << "\t";
            else
                cout << ( -short(w[index(i, j, P)] & (~a32[15]) ) ) << "," << bool((w[index(i, j, P)] & (a32[15]) )) << "\t";
        }
        cout << endl;
    }
    
    
    cout << endl << endl;
    
    cout << "\tPush done at L : " << ( (f & 128)? 1 : 0 ) << endl;
}


// if this state is a final state
bool stateZone::isFinal(){
    char L = f & 127 ; // ignore the leftmost bit
    
    if(L != 1) // there should not be any hanging point
        return false;
    
    // transition at first point must be 0-th transition
    if( del[0] != 0)
        return false;
    
    // there will not any push at the last transition
    if( isPush( del[P-1] ) ) 
        return false;
    
    // target state of the transiton at point R should be the final state
    if( transitions[del[P-1]].target != SF ) 
        return false;
    
    return true;
}



 // return the partial run corresponding the tree automata state 'vs', ignore the hanging points
 // copy only transitions between L(left) and R(right)
runZone* getRunZone(stateZone* vs) {
    
    runZone *pr = new runZone(); // new partial run stored in variable pr
    
    char L = vs->f&127;
    pr->P =  vs->P - L + 1 ; // transitions in new partial run will be from left(L) point to right(R) point
    
    // allocate memory for transitions and tsm vlaues for new run
    pr->del = new char[pr->P]; 
    pr->w = new short*[(pr->P)];
    //allocate memory for weight matrix
    for(int i = 0; i < pr->P; i++)
    {
        pr->w[i]=new short[pr->P];
    }
    // loopers : i used to index transition of the tree automata state and j is used to index trans in the run
    
    // copy transitions and tsm values from earlier partial run to new partial run
    for(char i = L - 1, j=0; i < (vs->P); i++, j++) {
        pr->del[j] = vs->del[i];
        for(char m= L-1,n = 0; m <(vs->P); m++, n++)
        {
            if(j == n)
            {
                pr->w[j][n]=0;
            }
            else
                pr->w[j][n] = vs->w[index(i,m,vs->P)];
        }
    }
    
    return pr; // return the new run
}

 
 // GIVEN the current partial run, append the transition 'dn' with tsm value 'wn'
// runZone* runZone::addNext(char dn, short wn) {
// 
// runZone *pr = new runZone(); // new partial run stored in variable pr
// 
// pr->P =  P + 1; // #transitions in new partial run will be one more than the earlier
// 
// // allocate memory for transitions and tsm vlaues for new run
// pr->del = new char[pr->P]; 
// pr->w = new short[pr->P];
// 
// // copy transitions and tsm values from earlier partial run to new partial run
// for(char i=0; i < P; i++) {
// pr->del[i] = del[i];
// pr->w[i] = w[i];
// }
// 
// pr->del[P] = dn; // add the new transition and tsm value to the last position of new partial run
// pr->w[P] = wn;
// 
// return pr; // return the new run
// }
 
 /*
 // shuffle two partial runs and return the new partial run
 runCGPP* runCGPP::shuffle(runCGPP *s2) {
 
 runCGPP *pr = new runCGPP(); // new partial run stored in variable pr
 
 // rightmost transition of left state is equal to leftmost transition of right state
 so new run will be concatenation of two runs and #points in new run is calculated as below//
 pr->P =  P + (s2->P) - 1; 
 
 // allocate memory for transitions and tsm vlaues for new run
 pr->del = new char[pr->P]; 
 pr->w = new char[pr->P];
 
 char i, j; // loopers
 
 // copy the transitions and tsm values of first run except for the last position
 for(i=0, j=0; i < (P-1); i++, j++) {
 pr->w[j] = w[i];
 pr->del[j] = del[i];
 }
 
 // copy the transitions and tsm values of 2nd run
 for(i=0; i < (s2->P); i++, j++) {
 pr->w[j] = s2->w[i];
 pr->del[j] = s2->del[i];
 }
 
 return pr; // return the new run
 }
 
 */

// this will return a state with only 0-th transition with tsm value 0
stateZone* getZeroStateZone() {
    
    stateZone* vs = new stateZone(); //initialize a stateZone object
    
    vs->P = 1; //the first point
    vs->f = 1; // no push pop info yet and L = 1 cause the last bit of the flag denotes the push complete information
    
    vs->del = new char[1]; // memory allocation for the transitions 
    vs->w = nullptr; //the 2-dimentional array projected in to one dimentional arry initially empty
    
    vs->del[0] = 0; // 0th transition has tsm value 0
    
    return vs;
}


// return unique string for last reset points of current state participating in a combine operation as a left state
string stateZone::getKeyLeft() {
    
    string s = ""; // return this string
    
    short resetSoFar, reset; // used for calculating union of resets
    
    s += del[P-1]; // include rightmost transition in the string
    
    //sparsa's editing
    //s += w[P-1]; // tsm value also be part of the key in zone we dont have any tsm values
    char lastindex = P-1; // last index we have taken
    
    //char nf = 0; // distance info DO we need it??
    char i=P-2; //list 
    char j=0;
    
    resetSoFar = transitions[ del[P-1] ].reset; // set of clocks reset at rightmost point
    
    for(; i >= 0; i--) {
        reset = transitions[ del[i] ].reset; // take (i+1)-th point transition reset set
        
        if( reset & (~resetSoFar) & (~1) ) { // if there are some new clocks reset at point (i+1)
            s += del[i]; //then add the transition to the string
            //s += w[i]; // but we dont have 
            resetSoFar |= reset;
            //if( !big(i+1, lastindex+1) )
            //	nf |= a32[j];
            j++;
        }
    }
    
    //s += nf;
    return s; // return the key
}


// return unique string for hanging points of a state participating in a combine operation as a right state
string stateZone::getKeyRight() {
    
    string s = ""; // return this string as a key for current state
    
    // take the transition at point L and all hanging points
    
    //char nf = 0; // this contains distance information between points distance information not needed
    
    s+= del[(f&127)-1]; // L-th poiint transition
    //s+= w[L-1]; // L-th point tsm dont need in Zone
    
    //char j = 0; // used for distance counter no distance in zone
    char i = (f&127)-2; // counter for points from right to left starting from L-1 point
    
    for(; i >= 0; i--)  //j++) 
    {
        s += del[i];
        //s += w[i]; not needed in zone cause for zone it is not a time stamp
        
        //if(f & a32[i+1] )
        //nf |= a32[j];
    }
    
    // add distance info in the key
    //s+= nf;
    
    return s;
}


// print a run as witness of the given TPDA if the language is non-empty
void runZone::print() {
    short int lt = 0, ct=0; // lt : last timestamps, ct : current time stamps
    
    cout << endl << "A run of the automation as a witness for the language to be non-empty.\nThe run given as a sequence of pairs (Transition, Time stamp) : " << endl;
    
    for(char i=0; i < P; i++) {
        // 
        // if( w[i] < lt ) // if current time stamps less than last time stamps
        // ct = M + ct + (w[i] - lt);
        // else
        // ct = ct + (w[i] - lt);
        // 
        // lt = w[i];
        
        cout << "(" << int(del[i]) << ", " << int(ct)  << ".0" << "), ";
    }
    
    cout << endl << endl;
}


// return a backtracking state with the info given in the parameters
trackZone* getTrackZone(char t, int l, int r) {
    trackZone* xrs = new trackZone();
    xrs->type = t; // this string is empty because vs is atomic state type of state, if = 0 then atomic or child
    // 1 if its add operation
    //2 if its generated by shuffle
    xrs->left = l;  // if no left parameter then -1
    xrs->right = r; // if no right parameter then -1
    return xrs;
}


// get the run of the timed system
// if sm == "", this means. we are backtracking from the state reside in i-th index of main vector 'allStates'
// if sm != "", then sm string is the key for shuffle operation of the state reside in i-th index of allStates
runZone* printRunZone(int i) {
    
    stateZone* vs; // tree automata state variable
    trackZone *bp; // back tracking state
    
    vs = allStatesZone[i].first;
    bp = allStatesZone[i].second;
    
    runZone *rs, *rs1, *rs2;
    
    // if the i-th state is an atomic state
    if( (bp->type) == 0 ) {
        cout << endl << i << ":";
        vs->print();
        return getRunZone(vs); // return the run generated from atomic state
    }
    
    // if the considerted state is generated by an addNext operation from a state in the main vector
    else if( (bp->type) == 1 ) {
        rs1 = printRunZone( bp->left );
        //rs = rs1->addNext(vs->del[vs->P - 1], vs->w[vs->P - 1]);
        
        cout << endl << i << " : " << (bp->left);
        vs->print();
        
        return rs;
    }
    
    else{
        rs1 = printRunZone( bp->left);
        rs2 = printRunZone(bp->right);
        //rs = rs1->shuffle(rs2);
        
        cout << endl << i << " : " << (bp->left) << ", " << (bp->right);
        vs->print();
        
        return rs;
    }
}



// return true iff language recognized by the TPDA is empty
bool isEmptyZone() {
    
    // we are assuming that non-emptiness for a TPDA means there is a non-trivial run(length of the run is non-zero)
    if(SI == SF) {
        cout << "Initial state is same as final state " << endl;
        return false;
    }
    
    //int i,j; // counters
    bool pushl, pushr, popl, popr, ppDone;
    // allocate memory for two weight matrix and their corresponding open vars used shortest path operations
    // K : maximum #points in a state
    WT1 = new short*[K+2]; // size is K(tree-width), so that we can use for any #points in a state
    WT2 = new short*[K+2];
    
    open1 = new bool*[K+2]; // size is K(tree-width), so that we can use for any #points in a state
    open2 = new bool*[K+2];
    
    for(int i=0; i < (K+2); i++) { // allocate memory for inner 1d arrays
        WT1[i] = new short[K+2];
        WT2[i] = new short[K+2];
        
        open1[i] = new bool[K+2];
        open2[i] = new bool[K+2];
    }
    
    int count=0; //count point to the index of the state currently being processed in the vector 'allStates' declared as global variable
    int N=0; // total number of unique states generated so far
    
    string s; // temporary string for finding a unique key corresponding to a TA state, the key points to compatible states for combine operation
    
    stateZone *rs, *vs, *vs1, *vs2; // some state variables required for track 
    
    trackZone *xrs; // back propagation state variable
    
    runZone *prs; // variable for partial run of the TPDA
    
    char *del, *w, P, L; // variables for keeping current state transitions, tsm values, #points and left point
    char dn; // var for upcoming transition might be added to the right of a state
    char f; // flag variable
    
    //for(int k= 0; k < 12870; k++) {
    
    vs = getZeroStateZone(); // 'vs' state is the first Tree automata state with only 0-th transition with tsm value 0 
    identity(vs); // insert this state in the hashmap
    
    xrs = getTrackZone(0, -1, -1);
    allStatesZone.push_back( make_pair(vs, xrs) ); // insert the state into the main vector along with its back tracking information
    N++; // increment #states
    
    //cout << k << endl;
    
    
    
    for(count = 0; count < N; count++) {  //start looping on the vector of transtions 
	
        //if( count %5000 == 0 ) // Below of this string, #states will be shown
        //cout << "#States" << endl;
	
        if( (count % 100) == 0 || count <= 200) // print state number currently being processed(note : all numbers will not be printed)
            cout << count << endl;
        
        
        rs = allStatesZone[count].first; // get the state at index count, process this state now
        
        
        // printing the current state information and its parents
        
        //This line is very important for debugging
        rs->print();
        //This line is very important for debugging
        xrs = allStatesZone[count].second;
        // priting parents :
        // shuffle  : left and right index shows left and right parent
        // add : first index is the real parent, second index is -1
        // atomic(generated by sucState()) : right index is the real parent
        // atomic(0-th state) : both index are -1
        //cout << "Parents: " << (xrs->left) << ", " << (xrs->right) << endl << "--------------" << endl;
        
        
	del = rs->del;// getting the transitions of the point
	P = rs->P; // getting the number of points of the point
	f = rs->f; // getting the L and the push flag
	L = f & 127;// extracting the value of L.
        pushl = isPush( del[L - 1] ); // pushl = 1 iff there is a push at L
	pushr = isPush( del[P - 1] ); // pushr = 1 iff there is a push at R
	popl = isPop( del[L - 1] ); // popl = 1 iff there is a pop at L
	popr = isPop( del[P - 1] ); // popr = 1 iff there is a pop at R
	ppDone = (f & 1) ; // if push at L and pop at R is done in rs
	// iterate through all the generated states and process them to generate new state
        
        if(L < P && pushr)// if there exists a non trivial block and the point L have a push
        {
            for(int i =0; i < count ; i++)
            {
                vs = rs->shuffle(allStatesZone[i].first); //trying to shuffle with all possible
                if(vs != nullptr)
                {
                    if(identity(vs)) //if already not present in the all states
                    {
                        xrs = getTrackZone(2,count,i); // 2 is the shuffle operation, with count and i
                        allStatesZone.push_back(make_pair(vs,xrs)); // push it in the vector
                        N++; //increase the number of states
                        if( vs->isFinal())
                        {
                            vs->print();
                            prs = printRunZone(N-1);
                            prs->print();
                            return false;
                        }
                    }
                }
            }
            vs = rs->sucState();
            //cout << "hello bug";
            //getchar();
            if(identity(vs))
            {
                xrs = getTrackZone(0,-1,count);
                allStatesZone.push_back(make_pair(vs,xrs));
                N++;
            }
            
        }
        else if (L < P && pushl && popr && ppDone)
        {
            for(int i = 0; i < count ; i++)
            {
                vs = (allStatesZone[i].first)->shuffle(rs);
                if(vs != nullptr)
                {
                    if(identity(vs))
                    {
                        xrs = getTrackZone(2,i,count);
                        allStatesZone.push_back(make_pair(vs,xrs));
                        N++;
                        if(vs->isFinal())
                        {
                            vs->print();
                            prs = printRunZone(N-1);
                            prs->print();
                            return false;
                        }
                    }
                }
            }
        }
        else
        {
            
            char q = transitions[ del[P-1] ].target; // target state of last transition
            
            // iterate through all the upcoming transitions
            //this is only add operations we have to find way to suffle and 
            
            for(int i=0; i < nexttrans[q].size(); i++) { 
                
                dn = nexttrans[q][i]; // i-th upcoming transition
                vs = rs->addNextTPDA(dn); // get set of states after doing the add operation
                
                if(vs != nullptr) { // if new state is valid
                    //vs->print();
                    if( identity(vs) ) {
                        xrs = getTrackZone(1, count, -1); // key for the new state
                        allStatesZone.push_back( make_pair(vs, xrs) );
                        N++;
                        if( vs->isFinal() ) {
                            vs->print();
                            //prs = printRun(N-1);
                            //prs->print();
                            return false;
                        }
                        
                    }
                }
            }
        }
        
    }
    
    //	vs = allStatesZone[0].first; 
    //N = 0'
    //mapZone.clear();
    //}
    /*
     vs = allStatesZone[0].first;
     rs = vs->addNextTPDA(1);
     rs->print();
     
     vs = rs->addNextTPDA(2);
     vs->print();
     
     rs= vs->addNextTPDA(3);
     rs->print();
     
     rs->f = 3;
     rs->print();
     
     vs = rs->addNextTPDA(4);
     vs->print();
     
     rs = vs->addNextTPDA(5);
     rs->print();
     
     vs = rs->addNextTPDA(6);
     rs = vs->addNextTPDA(7);
     vs = rs->addNextTPDA(8);
     rs = vs->addNextTPDA(9);
     
     rs->print();
     */	
    
    
    //freeing up the space allocated dynamically.
    
    for(int i = 0; i < (K+2) ; i++)
    {
        delete[] WT1[i];
        delete[] WT2[i];
        
        delete[] open1[i];
        delete[] open2[i];
    }
    delete[] WT1;
    delete[] WT2;
    delete[] open1;
    delete[] open2;
    
    
    return true;
}




