#include "stdafx.h"

#pragma hdrstop



using namespace std;


#include "kernel/bitvector.h"
#include "kernel/myExcept.h"

#include "kernel/Term.h"




#include "kernel/PLA_type.h"

#include "kernel/TTree.h"
#include "kernel/PLA.h"




// -----------------------------------------------------------------

list<Term> TermSharp( const Term& t1, const Term& t2 )
/* performs t1 # t2
	I.e., returns a list of terms covered by t1 and not not by t2
	Resolves outputs as well
*/
{
	unsigned int i, j;
	list<Term> res;		// the result
	Term newterm;
	bool copies;
	string om;

	if ( !t1.Intersects(t2) ) {
		res.push_back(t1);
		return res;
	}
	
	copies = false;			// if contained in t1 and not in t2, copy it to the result for the resp. variable
	om.assign( t1.GetOMSize(), '~' );
	for ( j = 0; j < t1.GetOMSize(); j++ )
		if ( t1.GetOM(j) == '1' && t2.GetOM(j) != '1' ) {
			copies = true;
			om[j] = '1';
		}
	if ( copies ) {
		newterm = t1;
		newterm.SetOM(om);
		res.push_back(newterm);
	}

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

PLA *PLATermSharp( PLA &pla, const Term &t )
/* returns PLA obtained as pla # t
	I.e., in the resulting pla are terms in pla and not in t
*/
{
	PLA *res;
	TermList::const_iterator ti;
	TermList terms;

	res = new PLA(&pla);
	if ( res == NULL) throw RuntimeException( "PLA_operations: Not enough memory" );
	for ( ti = pla.GetData()->begin(); ti != pla.GetData()->end(); ti++ ) {
		terms = TermSharp(*ti, t);
		res->AppendTermList(terms);
	}
	return res;
}

PLA *PLASharp( PLA &pla1, PLA &pla2 )
/* // Returns PLA obtained as pla1 # pla2
	I.e., in the resulting pla are terms that are in pla1 and not in pla2
*/
{
	PLA *res, *res2 = NULL;
	TermList::const_iterator ti, ti1;
	TermList terms;

	if ( pla1.GetTerms() == 0 ) return new PLA(&pla1);	// empty PLA
	if ( pla2.GetTerms() == 0 ) return new PLA(pla1);	// copying constructor

	res = &pla1;
	res->SetType(PLA_type("f"));
	for ( ti1 = pla2.GetData()->begin(); ti1 != pla2.GetData()->end(); ti1++ ) {
		res2 = PLATermSharp(*res, *ti1);
		if ( res != &pla1 ) delete res;
		res = res2;
	}
	return res2;
}

PLA *PLAComplement( PLA &pla )
//	Returns a complement of a PLA, computed by Sharp
{
	PLA *tautology;
	PLA *res;
	string iv, ov;

	tautology = new PLA(&pla);
	if ( tautology == NULL) throw RuntimeException( "PLA_operations: Not enough memory" );
	iv.assign(pla.GetInputs(), '-');
	ov.assign(pla.GetOutputs(), '1');
	tautology->AppendTerm(iv, ov);

	res = PLASharp(*tautology, pla );
	delete tautology;
	return res;
}

PLA *Cofactor( PLA &pla, const Term &t )
// Computes a cofactor of pla wrt. t. The resulting PLA is of the same size as pla
{
	PLA *res;
	TermList::iterator ti;
	Term newterm;
	unsigned int i;

	if ( pla.GetInputs() != t.GetIMSize() ) throw RuntimeException( "PLA_operations::Cofactor: PLA and the term are incompatible" );
	if ( pla.GetOutputs() != t.GetOMSize() ) throw RuntimeException( "PLA_operations::Cofactor: PLA and the term are incompatible" );
	res = new PLA(&pla);
	for ( ti = pla.GetData()->begin(); ti != pla.GetData()->end(); ti++ ) {
		newterm = t;
		for ( i = 0; i < pla.GetInputs(); i++ )
			if ( (*ti).GetIM(i) != '-' )
				if ( t.GetIM(i) != (*ti).GetIM(i) ) break;
		if ( i == pla.GetInputs() ) res->AppendTerm(newterm);
	}
	return res;
}
		



PLA TermSort( PLA &pla)
/*
Term Sort 
*/
{ 
    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(sizeof(int)*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++;
     }           

    /* 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);
               }     
               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;
}


		
		



list<Term> TermDisjointSharp( const Term& t1, const Term& t2 )
/*  
Term Disjoint sharp
*/
{
	unsigned int j, i;
	list<Term> res; // the result
	Term newterm;
	  
    /* Test zda se termy protinaji ci ne*/
    if (! t1.Intersects(t2)) {
       
       /* neprotinaji se*/ 
       res.push_back(t2);  
       return res;                       
    }
         
    /* Jestli se termy protinaji -> provedeni 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);  
		}
    }	
		
    return res;  
}




PLA *Orto( PLA &pla)
/*
Orthogonalization 
*/
{ 
                 
    PLA *res;
    PLA *ort_result;
    
    /* for term builder */
    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;
    Term tx1, tx2;
    
    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" );
	

   /* Term Sort */
    pla = TermSort(pla); // serazeni a ulozeni do pomocne promene use

  
  
   /* main loop of orthogonalization */   
   while (continue_process) {
           
       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->RemoveAbsorbed(); // append result from term builder operation to PLA use_res
           use_res->MergeNeighbors(); // append result from term builder operation to PLA use_r
           
           use = *use_res;
           t1 = use.GetData()->begin();
           t4 = t1; 
           t4++;
           
           end_process = false;
   
           /* 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); // append result from disjoint sharp operation to PLA res
                 end_process = true;
          }
                  
            
        } 
        result.push_back(**& t1);
        
        pla = *res; // replace old PLA 
 
        t3 = pla.GetData()->begin(); // auxiliary valuable
        t3++; 
 
        /* Is next line end? */
        if(t3 == pla.GetData()->end()) {
       	      ort_result->AppendTermList(result); // save result of orthogonalization
       	      
       	      /* if last operations was disjoint sharp */
              if(end_process == true)             
                 ort_result->AppendTermList(result_djs); // save last step of orthogonalization
              
              continue_process = false; // set end of iterations
        }
   }     
       
   return ort_result;
}





