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

#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

#include "../../Kernel/kernelincludes.h"

//#include <pthread.h>

#include "defaults.h"
//#include "TimeStamp.h"
#include "CD_search.h"
//---------------------------------------------------------------------------

CD_Search::CD_Search( PLA *_pla, PLA *_implpool, int iterations, TermQueue * tq, TermQueue * tq2, bool useIE )
{
	source = _pla;
	implpool = _implpool;
	mutations = DEFAULT_CD_MUTATIONS;
	implcheck = DEFAULT_CD_IMPLCHECK;
	all_PIs = DEFAULT_CD_ALLPIS;
	this->tq_cds_ie = tq;
	this->tq_ie_gom = tq2;
	this->iterations = iterations;
	this->useIE = useIE;
	for (unsigned i = 0; i < source->outputs(); i++) {
		source->GenerateOnSet(i);
		source->GenerateOffSet(i);
	}
}

/*CD_Search::~CD_Search(void)
{
}*/

void CD_Search::Create_u_F( const unsigned int ov )
{
	
}

void CD_Search::Run(void)
{
	for (int iter = 0; iter < iterations; iter++) {

		int inputs, outputs;		// local copy of source->inputs, outputs
		int ov;

		//   TS.start(TS_CDS);
		inputs = (int) source->inputs();
		outputs = (int) source->outputs();

		#pragma omp parallel for default(none) \
			shared(outputs, inputs) private(ov)
		for ( ov = 0; ov < outputs; ov++ ) {
			enum { ok, NA, no } implOk;            // implicant check
			list<CubeList::iterator>::iterator ti, ti1;
			Term t(source->inputs(), source->outputs());                    // term under construction
			TermList::iterator ti2;               // the constructed term
			unsigned int i, j;
			vector<int> candidates, candidates2;
			vector<int>::iterator vi;
			unsigned int cnt_p, cnt_n;    // counts of 1 and 0 literals in r_F
			unsigned int maxval;
			unsigned int var;        // selected split variable
			bool pol;                      // and its polarity (true = 1)
			

			list<CubeList::iterator> u_F;                    // uncovered on-set. contains iterators to terms
			list<CubeList::iterator> r_F;                    // reduced on-set. contains iterators to terms
			//Create_u_F( ov );
			CubeList::iterator cti;
			CubeList *onset;

			u_F.clear();
			onset = source->getOnSet(ov)->getData();
			for ( cti = onset->begin(); cti != onset->end(); cti++ )
				u_F.push_back(cti);

			while ( !u_F.empty() ) {             // main loop
				//Term t(source->inputs(), source->outputs());
				r_F = u_F;
				t.init( inputs, outputs );		// set t as dc-cube (all-dc)
				t.origin = 1;
				do {          // term generation loop
					candidates.clear();
					// mutations
					i = rand() % 100;
					if ( i < mutations ) {
						for ( i = 0; i < (unsigned) inputs; i++ )       // mutate
							if ( t.isLit_dc(i) )
								for ( ti = r_F.begin(); ti != r_F.end(); ti++ )
									if ( (*(*ti)).isLit_1(i) ) {
										candidates.push_back( i+1 );
										break;
									} else if ( (*(*ti)).isLit_0(i) ) {
										candidates.push_back( -int(i+1) );
										break;
									}
					} else                  // find the most frequent literal in the reduced on-set
					{
						maxval = 0;
						for ( i = 0; i < (unsigned) inputs; i++ )
							if ( t.isLit_dc(i) ) {
								cnt_p = 0;
								cnt_n = 0;
								for ( ti = r_F.begin(); ti != r_F.end(); ti++ )
									if ( (*(*ti)).isLit_1(i) ) cnt_p++;
									else if ( (*(*ti)).isLit_0(i) ) cnt_n++;
									if ( cnt_p > maxval ) {
										maxval = cnt_p;
										candidates.clear();
										candidates.push_back( i+1 );
									} else if ( cnt_p == maxval && maxval > 0 ) candidates.push_back( i+1 );
									if ( cnt_n > maxval ) {
										maxval = cnt_n;
										candidates.clear();
										candidates.push_back( -int(i+1) );
									} else if ( cnt_n == maxval && maxval > 0 ) candidates.push_back( -int(i+1) );
							}
					}
					if ( candidates.empty() ) throw BoomException( "CD-Search: on-set and off-set are not orthogonal" );

					// perform implicant check
					if ( implcheck && candidates.size() > 1 ) {
						candidates2.clear();
						vi = candidates.begin();
						do {
							var = abs((*vi))-1;
							pol = ((*vi) > 0);
							if (pol) t.setLit_1(var); else t.setLit_0(var);
							if ( source->isImplicant( t, ov ) ) {
								if ( pol ) candidates2.push_back( var+1 );
								else candidates2.push_back( -int(var+1) );
							}
							vi++;
							t.setLit_dc(var);
						} while ( vi != candidates.end() );
						if ( !candidates2.empty() ) {
							candidates = candidates2;
							implOk = ok;
						} else implOk = no;
					} else implOk = NA;

					i = rand() % candidates.size();	// select one

					if ( all_PIs && implOk == ok ) {		// put all the found PIs in the pool (except i)
						for ( j = 0; j < candidates.size(); j++ )
							if ( j != i ) {
								var = abs(candidates[j])-1;
								pol = (candidates[j] > 0);
								if ( pol ) t.setLit_1(var);
								else t.setLit_0(var);
								//ti2 = implpool->AppendTerm( t );
								Term tt = t;
								tt.setOM_1(ov);
								//(*ti2).setOM_1(ov);
								//ti2 = implpool->AppendTerm( tt );
								if (useIE)
									tq_cds_ie->push(tt);
								tq_ie_gom->push(tt);
								t.setLit_dc( var );
							}
					}

					var = abs(candidates[i])-1;
					pol = (candidates[i] > 0);

					// append literal to a term under construction
					if ( pol ) t.setLit_1(var);
					else t.setLit_0(var);

					// is t an implicant?
					if ( implOk == NA ) {
						if ( source->isImplicant( t, ov ) ) implOk = ok; else implOk = no;
					}
					if ( implOk == ok ) {          // add term to the pool
						Term tt = t;
						tt.setOM_1(ov);
						//ti2 = implpool->AppendTerm( tt );
						if (useIE)
							tq_cds_ie->push(tt);
						tq_ie_gom->push(tt);
						ti = u_F.begin();                           // remove covered on-set
						do {
							if ( t.Cube::contains(**ti) ) ti = u_F.erase( ti );
							else ti++;
						} while ( ti != u_F.end() );
						break;
					} else {                                      // reduce on-set
						ti = r_F.begin();
						do {
							if ( (*(*ti)).getLit(var) != t.getLit(var) ) ti = r_F.erase( ti );
							else ti++;
						} while ( ti != r_F.end() );
					}
				} while ( true );
			}
		}
		//	TS.stop(TS_CDS);
	}
}
