#include "stdafx.h"

#pragma hdrstop


using namespace std;


#include "kernel/kernelincludes.h"


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




PLA SizeSortInc( PLA &pla)
/*
Term size sort Incremmentally
*/
{ 
    PLA sort_result; // result PLA             
    PLA *list_result; // result PLA
    list_result = new PLA(&pla);	

    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2;
    
   	Term useterm; // working term 
    int counter = 0; // counter of terms
    int t_size = 0; // counter of terms
    
    int * array_dc; // array of dc values
    array_dc = (int*)malloc(90000*sizeof(int));
      
    /* find term size */
    t1 = pla.GetData()->begin();
    useterm = *t1;
    t_size = useterm.GetIMSize(); // term size
    
    /* counter dc for terms */ 
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
          useterm = *t1;
          array_dc[counter] = 0;
          
          /* count dc for invidual term*/ 
          for ( int j = 0; j <= t_size; j++ ) {
              if (useterm.GetIM(j) == '-') { 
                 array_dc[counter]++;
              }   
          }
          counter++;
     }           

    int pointer_counter = 0; // pointer counter position
    
    /* create new sort pla */
    for ( int j = 0; j <= t_size; j++ ) {
      
         counter = 0;

         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare dc with grade term */      
               if (j == array_dc[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_dc); // deallocate memory (array of dc values)     
   return sort_result;
}



PLA SizeSortDec( PLA &pla)
/*
Term size sort Decremmentally
*/
{ 
    PLA sort_result; // result PLA             
    PLA *list_result; // result PLA
    list_result = new PLA(&pla);	

    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2;
    
   	Term useterm; // working term 
    int counter = 0; // counter of terms
    int t_size = 0; // counter of terms
    
    int * array_dc; // array of dc values
    array_dc = (int*)malloc(90000*sizeof(int));
      
    /* find term size */
    t1 = pla.GetData()->begin();
    useterm = *t1;
    t_size = useterm.GetIMSize(); // term size
    
    /* counter dc for terms */ 
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
          useterm = *t1;
          array_dc[counter] = 0;
          
          /* count dc for invidual term*/ 
          for ( int j = 0; j <= t_size; j++ ) {
              if (useterm.GetIM(j) == '-') { 
                 array_dc[counter]++;
              }   
          }
          counter++;
     }           


    int pointer_counter = 0; // pointer counter position
    
    /* create new sort pla */
    for ( int j = t_size; 0 <= j; j-- ) {
      
         counter = 0;

         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare dc with grade term */      
               if (j == array_dc[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_dc); // deallocate memory (array of dc values)   
   return sort_result;
}



PLA IntersectionSortInc( PLA &pla)
/*
Term Intersect Sort incrementally
*/
{ 
    PLA sort_result; // result PLA             
    PLA *list_result; // result PLA
    list_result = new PLA(&pla);	

    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2;
    
   	Term useterm; // working term 
    int counter = 0; // counter of terms
    int i_max = 0; // max value
    
    int * array_ints; // array of dc values
    array_ints = (int*)malloc(90000*sizeof(int));
          
     /* counter intersects */  
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
     
       array_ints[counter] = 0;
       useterm = *t1;
          
       for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
         
          /* counts ints for invidual term*/ 
          if(t1 != t2) {
             if(useterm.Intersects(*t2)) {
                 array_ints[counter]++;
                
                 if(i_max < array_ints[counter]) 
                    i_max = array_ints[counter];
             }
          } 
       }
       counter++;
    }           

    int pointer_counter = 0; // pointer counter position
    
    /* create new sort pla */
    for ( int j = 0; j <= i_max; j++ ) {
      
         counter = 0;
         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare ints with grade term */      
               if (j == array_ints[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_ints); // deallocate memory (array of ints values) 
   return sort_result;
}
		
		

PLA IntersectionSortDec( PLA &pla)
/*
Term Intersect Sort decrementally
*/
{ 
    PLA sort_result; // result PLA             
    PLA *list_result; // result PLA
    list_result = new PLA(&pla);	

    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2;
    
   	Term useterm; // working term 
    int counter = 0; // counter of terms
    int i_max = 0; // max value
    
    int * array_ints; // array of dc values
    array_ints = (int*)malloc(90000*sizeof(int));
         
    /* counter intersects */ 
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
     
       array_ints[counter] = 0;
       useterm = *t1;
          
       for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
         
          /* counts ints for invidual term*/ 
          if(t1 != t2) {
             if(useterm.Intersects(*t2)) {
                 array_ints[counter]++;

                 if(i_max < array_ints[counter]) 
                    i_max = array_ints[counter];
             }
          } 
       }    
       counter++;
    }           

    int pointer_counter = 0; // pointer counter position
    
    /* create new sort pla */
    for ( int j = i_max; 0 <= j; j-- ) {
      
         counter = 0;
         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare ints with grade term */      
               if (j == array_ints[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_ints); // deallocate memory (array of ints values) 
   return sort_result;
}



PLA SortByMergeInc( PLA &pla)
/*
Term MergeNeighbors Sort incrementally
*/
{ 
    PLA sort_result; // result PLA             
    PLA use;
    PLA *list_result; // result PLA
    PLA *use_res;
    
    list_result = new PLA(&pla);	
    
    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2, t3;

	Term newterm;    
   	Term useterm; // working term 
 
    int t_sizeIn = 0; // term output size
    int t_sizeOu = 0; // term output size
      
    /* find term input and output size */
    t1 = pla.GetData()->begin();
    useterm = *t1;
    t_sizeIn = useterm.GetIMSize(); // term size
    t_sizeOu = useterm.GetOMSize(); // term size
 
    int counter = 0; // counter of terms
    int i_max = 0; // max value
    bool sameOu;
        
    int * array_ints; // array of dc values
    array_ints = (int*)malloc(90000*sizeof(int));
    
      
    /* counter intersects */  
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
     
       array_ints[counter] = 0;
       useterm = *t1;
    
       for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
                
          /* counts ints for invidual term*/ 
          if(t1 != t2) {
         
             sameOu = true; // default 
             newterm = *t2;
             
             for (int j = 0; j < t_sizeOu; j++ ) {
                /* if terms have at least same one "1" on output */
               	if (newterm.GetOM(j) != useterm.GetOM(j)) {                      
                    sameOu = false;  
                }
             } 
   
            /* check the neighbors*/         
            if (sameOu == true) {
               int count_another = 0;      
               bool merge = true;
                 
               for (int j = 0; j < t_sizeIn; j++ ) {
                  /* if terms have at least same one "1" on output */
                   if (((newterm.GetIM(j) == '1') && (useterm.GetIM(j) == '0')) || 
                       ((newterm.GetIM(j) == '0') && (useterm.GetIM(j) == '1'))) {                       
                     count_another++;     
                     
                  }
                  /* if can't be merge */
                  if (((newterm.GetIM(j) == '-') && (useterm.GetIM(j) != '-')) || 
                      ((newterm.GetIM(j) != '-') && (useterm.GetIM(j) == '-'))) {                                            
                     merge = false;     
                  }
               } 
               if ((count_another == 1) && (merge == true)) {
                                   
                  array_ints[counter]++;
                
                  if(i_max < array_ints[counter]) 
                     i_max = array_ints[counter];
               }     
            }                                     
          } 
       }
       counter++;
    }           
  
    int pointer_counter = 0; // pointer counter position
   
    /* create new sort pla */
    for ( int j = 0; j <= i_max; j++ ) {   
         counter = 0;
         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare ints with grade term */      
               if (j == array_ints[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_ints); // deallocate memory (array of ints values)     
   return sort_result;
}



PLA SortByMergeDec( PLA &pla)
/*
Term MergeNeighbors Sort decrementally
*/
{ 
    PLA sort_result; // result PLA             
    PLA use;
    PLA *list_result; // result PLA
    PLA *use_res;
    
    list_result = new PLA(&pla);	
    
    list<Term> res; // result of operations    
	TermList::const_iterator t1, t2, t3;

	Term newterm;    
   	Term useterm; // working term 
 
    int t_sizeIn = 0; // term output size
    int t_sizeOu = 0; // term output size
 
      
    /* find term input and output size */
    t1 = pla.GetData()->begin();
    useterm = *t1;
    t_sizeIn = useterm.GetIMSize(); // term size
    t_sizeOu = useterm.GetOMSize(); // term size
 
    int counter = 0; // counter of terms
    int i_max = 0; // max value
    bool sameOu;
        
    int * array_ints; // array of dc values
    array_ints = (int*)malloc(90000*sizeof(int));


    /* counter intersects */  
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
     
       array_ints[counter] = 0;
       useterm = *t1;
    
       for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {

          /* counts ints for invidual term*/ 
          if(t1 != t2) {
         
             sameOu = true; // default 
             newterm = *t2;
             
             for (int j = 0; j < t_sizeOu; j++ ) {
                /* if terms have at least same one "1" on output */
               	if (newterm.GetOM(j) != useterm.GetOM(j)) {                      
                    sameOu = false;  
                }
             } 
   
            /* check the neighbors*/         
            if (sameOu == true) {
               int count_another = 0;      
               bool merge = true;
                 
               for (int j = 0; j < t_sizeIn; j++ ) {
                  /* if terms have at least same one "1" on output */
                   if (((newterm.GetIM(j) == '1') && (useterm.GetIM(j) == '0')) || 
                       ((newterm.GetIM(j) == '0') && (useterm.GetIM(j) == '1'))) {                       
                     count_another++;     
                     
                  }
                  /* if can't be merge */
                  if (((newterm.GetIM(j) == '-') && (useterm.GetIM(j) != '-')) || 
                      ((newterm.GetIM(j) != '-') && (useterm.GetIM(j) == '-'))) {                                            
                     merge = false;     
                  }
               } 
               if ((count_another == 1) && (merge == true)) {
                                   
                  array_ints[counter]++;
                
                  if(i_max < array_ints[counter]) 
                     i_max = array_ints[counter];
               }     
            }                                     
          } 
       }
       counter++;
    }           
  
    
    int pointer_counter = 0; // pointer counter position
    
    /* create new sort pla */
    for ( int j = i_max; 0 <= j; j-- ) {
      
         counter = 0;
         for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {
               useterm = *t2;          
                   
               /* compare ints with grade term */      
               if (j == array_ints[counter]) {
                    /* save term */
                    res.push_back(useterm);
                    
                    /* change term order position */
                    pointer_counter++;
               }     
               counter++;
         }
    }                
     
   list_result->AppendTermList(res); // save result to termlist       	     
   sort_result = *list_result; // sort result

   free(array_ints); // deallocate memory (array of ints values)    
   return sort_result;
}
		


list<Term> TermDisjointSharp( const Term& t1, const Term& t2)
/*  
Term Disjoint sharp
*/
{
	unsigned int j, i;
	list<Term> res; // the result
	Term newterm;
	string om;
	

    /* term t1 intersects term t2? */
    if (!t1.Intersects(t2)) {
       /* no */ 
       res.push_back(t2);  
  
       return res;                       
    }
     
    bool copies = false;
  
    /* output for intersection term */ 
    om.assign( t2.GetOMSize(), '~' ); 
   	for ( j = 0; j <= t1.GetOMSize(); j++ ) {
   
      	if ((t1.GetOM(j) != '1') && (t2.GetOM(j) == '1')) {
          om[j] = '1';                 
          copies = true; 
        }
    } 
 
    
    /* if terms dont itersect ->  t1 disjoint sharp t2 */   
    for ( j = 0; j <= t2.GetIMSize(); j++ ) {

	if ((t2.GetIM(j) == '-') && (t1.GetIM(j) != '-')) {
           newterm = t2;
         
           for ( i = 0; i < j; i++ ) {
              if ((newterm.GetIM(i) == '-'))                   
                 newterm.SetIM(i,t1.GetIM(i));
           }
           
           if (t1.GetIM(j) == '0')
              newterm.SetIM(j,'1');
           if (t1.GetIM(j) == '1')
              newterm.SetIM(j,'0');
                 
           res.push_back(newterm); 
        }
    }	


    /* create intersection term */
    if(copies == true) {
         newterm = t2;
         newterm.SetOM(om); // set output
               
         for ( j = 0; j <= t2.GetIMSize(); j++ ) {
             // set input
             if (t1.GetIM(j) == '1') {
                newterm.SetIM(j,'1');
             }   
             
             if (t1.GetIM(j) == '0') {
                newterm.SetIM(j,'0');
             }
         }      
 
         res.push_back(newterm);   
    }
 
    return res;  
}



void BackMerge( PLA &pla)
/*
MergeNeighbors with orthogonal terms
*/
{ 
    
    PLA *use_pla; 
    use_pla = new PLA(&pla);
 
    PLA use; 
    PLA *use_res; 
    use_res = new PLA(&pla);	       
	TermList::const_iterator t1, t2, t3, t4;
 
    bool continue_process = true;
      
    while (continue_process) {
 
          t1 = pla.GetData()->end();
          t1--;
 
          continue_process = false; // default

          for( t2 = pla.GetData()->begin(); t2 != pla.GetData()->end(); t2++ ) {

              t2++;
              
              if(t2 != pla.GetData()->end()){
                    
                 t2--;
                 use_res = new PLA(&pla);
     
                 use_res->AppendTerm(*t1);
                 use_res->AppendTerm(*t2);
	
	             /* Merge Neighbors terms */
                 use_res->MergeNeighbors();      
                  
                 use = *use_res;          
                 t3 = use.GetData()->begin();
                 t3++;
                
                                 
                 /* if term is merged */
                 if(t3 != use.GetData()->end()) { 
                     /* no */ 
                     use_pla->AppendTerm(*t2);

                 } else {
                      /* yes */  
                      t3--;    
                      t1 = t3;
                      continue_process = true;  
                 }
                        
               } else {
               t2--;
               }        
            }
            use_pla->AppendTerm(*t1);
            
            pla = *use_pla;         
            use_pla = new PLA(&pla);
     }
}



PLA EliminateUndefined( PLA &pla)
/*
Remove terms where aren't any "1" in output.
*/
{ 
    PLA *result; // result PLA 
    result = new PLA(&pla);            
        
	TermList::const_iterator t1;
    
   	Term useterm; // working term 
    int t_size = 0; // term output size
    bool remove_term;    
      
    /* find term size */
    t1 = pla.GetData()->begin();
    useterm = *t1;
    t_size = useterm.GetOMSize(); // term size
    
    /* cycle of terms */
    for( t1 = pla.GetData()->begin(); t1 != pla.GetData()->end(); t1++ ) {
          useterm = *t1;
          
          remove_term = true;
          
          /* does output have "1"? */ 
          for ( int j = 0; j <= t_size; j++ ) {
              if (useterm.GetOM(j) == '1') {
                remove_term = false;                
              }   
          }
       
          /* if output has "1" */
          if(remove_term == false) {
              result->AppendTerm(*t1);
          }
     }           
   
   return *result;
}




PLA *Orto( PLA &pla, int op)
/* 
Orthogonalization 
*/
{ 
                 
    PLA *res;
    PLA *ort_result;
    PLA pla_end;
    
    PLA use;
    PLA *use_res;
  
    list<Term> result; // the result
    list<Term> result_djs; // the result - after disjoint sharp
    list<Term> r_empty; // empty
    
	TermList::const_iterator t1, t2, t3, t4;
 
    bool continue_process  = true;
    bool end_process  = false;
    
	res = new PLA(&pla);
	ort_result = new PLA(&pla);	
	if (( res == NULL) && (ort_result == NULL)) 
        throw RuntimeException( "PLA_operations: Not enough memory" );


   /* Eliminate terms where aren't any "1" in output. */
    if (op >= 10) {   
          pla = EliminateUndefined(pla);
    }
 
   
   /* main loop of orthogonalization */   
   while (continue_process) {
    
    /* Term Sort */
    if( op == 1) { pla = SizeSortInc(pla); }
    if( op == 2) { pla = SizeSortDec(pla); }
    if( op == 3) { pla = IntersectionSortInc(pla); }
    if( op == 4) { pla = IntersectionSortDec(pla); }
    if( op == 5) { pla = IntersectionSortInc(pla); pla = SizeSortDec(pla); }
    if( op == 6) { pla = IntersectionSortDec(pla); pla = SizeSortDec(pla); }
    if( op == 7) { pla = SortByMergeInc(pla); }
    if( op == 8) { pla = SortByMergeDec(pla); }

    if( op > 8) { pla = SizeSortDec(pla); }
        
       t1 = pla.GetData()->begin();
       res = new PLA(&pla); 
                  
       t3 = pla.GetData()->begin(); // auxiliary valuable
       t3++; 
       
       /* orthogonalization remaining terms */
       for( t2 = t3; t2 != pla.GetData()->end(); t2++ ) {
           
            use_res = new PLA(&pla);
            use_res->AppendTerm(*t1);
            use_res->AppendTerm(*t2);
      	
	        use_res->MergeNeighbors(); // Merge Neighbors terms              
       
            use = *use_res;          
            t4 = use.GetData()->begin();
            t4++;
               
            end_process = false; // default
   
            /* Did term builder collect terms? If not = run term disjoint sharp */
            if(t4 != use.GetData()->end()) {     
                 result_djs = r_empty; // assign empty value   
                 result_djs = TermDisjointSharp(*t1,*t2); // disjoint sharp for term t1 and t2
                 res->AppendTermList(result_djs);
                 end_process = true;            
           } else {
              /* after MergeNeighbors and RemoveAbsorbed */
              t4--;
              Term ts1, ts2;
              ts1 = **&t1;
              ts2 = **&t4;

              /* if size of term isn't same */
              if(ts1.GetDim() != ts2.GetDim()) {    

                   t1 = t4;
                   t2 =  pla.GetData()->begin();
  
                   res = new PLA(&pla); 
                  
              } 
           }  
       } 
             
        ort_result->AppendTerm(*t1);
        
        /* MergeNeighbors for complete terms*/
        if( op >= 9 ) {
             BackMerge(*ort_result);
        }
        
        pla = *res; // replace old PLA
   
        t3 = pla.GetData()->begin(); // auxiliary valuable
        t3++; 

        /* Is next line end? */
        if(t3 == pla.GetData()->end()) {
       
              /* if last operations was disjoint sharp */
              if(end_process == true) {
                 t3--; 
                 
                 /* is result exists? */
                 if(t3 != pla.GetData()->end()) {
                     ort_result->AppendTerm(*t3);            
                 }
              } 
              //ort_result->AppendTermList(result); // save result of orthogonalization   
              continue_process = false; // set end of iterations
        }
   }     

   return ort_result;
}



