#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

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

#include "defaults.h"
//#include "TimeStamp.h"
#include "Reduce.h"

Reduce::Reduce( PLA *_source, PLA *_implpool, TermQueue * tq, Cover * cp)
{
	source = _source;
	implpool = _implpool;
	method = DEFAULT_IR;
	this->tq = tq;
	this->cp = cp;
}

int Reduce::NewOutput( const Term &t )
//	Returns the output, for which is t newly created implicant or -1 if no such one
{
	unsigned int i;

	for ( i = 0; i < implpool->outputs(); i++ )
		if ( t.isOM_0(i) )
			if ( source->isImplicantNoOMCheck( t, i ) ) return i;
	return -1;
}
	
void Reduce::FastReduce(void)
//	Starting from a random position sequentially reduces each term, until one valid literal addition.
//	Produces |implpool| more implicants at most.
//	Good for iterative minimization
{
	TermList::iterator ti;
    //TermList newterms;          // newly created terms
	//Term t;					// term under construction
	//TermList::iterator ti1;		// constructed term
	
	PLA implpool2(*implpool);
	cp->GenerateCoverVectors();
	implptrs.reserve(implpool->getDataRef().size());
	implptrs.clear();
	for (ti = implpool2.getDataRef().begin(); ti != implpool2.getDataRef().end(); ++ti)
		implptrs.push_back(&(*ti));

	int n = implptrs.size(), k;
	#pragma omp parallel for default(none) \
		shared(n) private(k)
	for (k = 0; k < n; k++) {
		unsigned int i, i_start;
		int j;
		bool c;

		Term t = *implptrs[k];
		i_start = rand() % implpool->inputs();
		i = i_start;
		do {
			if ( t.isLit_dc(i) ) {

				c = ((rand() % 2) == 0);
				if (c) t.setLit_1(i);		// try to set to c
				else t.setLit_0(i);
				j = NewOutput( t );
				if ( j != -1 ) {
					t.setOM_1(j);
					//newterms.push_back(t);
					t.origin |= 8;
					tq->push(t);

					break;				// we have a term, go further
				}
				t.setLit_dc(i);		// return it back

			}
			i++;
			i %= implpool->inputs();
		} while ( i != i_start );
	}
	/*for ( ti = newterms.begin(); ti != newterms.end(); ti++ ) {
		(*ti).origin |= 8;
		ti1 = implpool->AppendTerm(*ti);
		for ( i = 0; i < (*ti).getOMSize(); i++ )                    // for a case the term is already present in TT, but having different OM
			if ( (*ti1).isOM_undef(i) && !(*ti).isOM_undef(i) )
				(*ti1).setOM(i, (*ti).getOM(i));
	}*/
}

void Reduce::MultipleReduce(void)
//	Sequentially reduces each term, until one valid literal addition. Starts independently from all positions
//	Produces |implpool| more implicants at most.
//	Good for iterative minimization
{
	TermList::iterator ti;
    //TermList newterms;          // newly created terms
	//Term t;					// term under construction
	//TermList::iterator ti1;				// constructed term
	
	int k, n;

	PLA implpool2(*implpool);
	cp->GenerateCoverVectors();
	implptrs.reserve(implpool->getDataRef().size());
	for (ti = implpool2.getDataRef().begin(); ti != implpool2.getDataRef().end(); ++ti)
		implptrs.push_back(&(*ti));
	n = implptrs.size();
	#pragma omp parallel for default(none) \
		shared(n) private(k)
	for (k = 0; k < n; k++) {
		unsigned int i;
		int j;
		Term t = *implptrs[k];
		for ( i = 0; i < implpool->inputs(); i++ )
			if ( t.isLit_dc(i) ) {
				t.setLit_1(i);		// try to set to '1'
				j = NewOutput( t );
				if ( j != -1 ) {
					t.setOM_1(j);
					//newterms.push_back(t);		// we have a term, go further
					t.origin |= 8;
					tq->push(t);
					t.setOM_0(j);
				}
				t.setLit_0(i);		// try to set to ZERO
				j = NewOutput( t );
				if ( j != -1 ) {
					t.setOM_1(j);
					//newterms.push_back(t);		// we have a term, go further
					t.origin |= 8;
					tq->push(t);
					t.setOM_0(j);
				}
				t.setLit( i, '-' );		// return it back
			}
	}
    /*for ( ti = newterms.begin(); ti != newterms.end(); ti++ ) {
        (*ti).origin |= 8;
		ti1 = implpool->AppendTerm(*ti);
        for ( i = 0; i < (*ti).getOMSize(); i++ )                    // for a case the term is already present in TT, but having different OM
            if ( (*ti1).isOM_undef(i) && !(*ti).isOM_undef(i) )
                (*ti1).setOM(i, (*ti).getOM(i));
    }*/
}

void Reduce::ExhaustiveReduce(void)
//	Generates all group implicants
{
	TermList::iterator ti;
	//Term t, tt;					// term under construction
	//TermList::iterator ti1;	// constructed term
	
	int k, n;

	PLA implpool2(*implpool);
	cp->GenerateCoverVectors();
	implptrs.reserve(implpool->getDataRef().size());
	for (ti = implpool2.getDataRef().begin(); ti != implpool2.getDataRef().end(); ++ti)
		implptrs.push_back(&(*ti));

	n = implptrs.size();
	#pragma omp parallel for default(none) \
		shared(n) private(k)
	for (k = 0; k < n; k++) {
		unsigned int i;
		int j;
		Term t = *implptrs[k];
		t.origin |= 8;
		for ( i = 0; i < implpool->inputs(); i++ )
			if ( t.isLit_dc(i) ) {
				t.setLit_1(i);		// try to set to 1
				j = NewOutput( t );
				if ( j != -1 ) {
					//ti1 = implpool->AppendTerm(t);
					Term tt = t;
					tt.setOM_1(j);
					tq->push(tt);
					
				}
				t.setLit_0(i);		// try to set to 0
				j = NewOutput( t );
				if ( j != -1 ) {
					Term tt = t;
					tt.setOM_1(j);
					tq->push(tt);
				}
				t.setLit_dc(i);		// return it back
			}
	}
}

void Reduce::Run(void)
{
//	TS.start(TS_IR);

	if ( implpool == NULL ) return;		// nothing to do
	if ( implpool->outputs() == 1 ) return;		// nothing to do
	switch ( method ) {
		case no_IR:
				break;
		case fast_IR:
				FastReduce();
				break;
		case multiple_IR:
				MultipleReduce();
				break;
		case exhaustive_IR:
				ExhaustiveReduce();
				break;
	}

//	TS.stop(TS_IR);
}
