#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 )
{
	source = _source;
	implpool = _implpool;
	method = DEFAULT_IR;
}

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->GetOutputs(); i++ )
		if ( t.GetOM(i) == '0' )
			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
	unsigned int i, i_start;
	int j;
	char c;

	for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ ) {
		t = (*ti);
		i_start = rand() % implpool->GetInputs();
		i = i_start;
		do {
			if ( t.GetIM(i) == '-' ) {
				c = (rand() % 2) + '0';
				t.SetIM( i, c );		// try to set to c
				j = NewOutput( t );
				if ( j != -1 ) {
					t.SetOM( j, '1' );
					newterms.push_back(t);
					break;				// we have a term, go further
				}
				t.SetIM( i, '-' );		// return it back
			}
			i++;
			i %= implpool->GetInputs();
		} 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).GetOM(i) == '~' && (*ti).GetOM(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
	unsigned int i;
	int j;

	for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ ) {
		t = (*ti);
		for ( i = 0; i < implpool->GetInputs(); i++ )
			if ( t.GetIM(i) == '-' ) {
				t.SetIM( i, '1' );		// try to set to '1'
				j = NewOutput( t );
				if ( j != -1 ) {
					t.SetOM( j, '1' );
					newterms.push_back(t);		// we have a term, go further
					t.SetOM( j, '0' );
				}
				t.SetIM( i, '0' );		// try to set to '0'
				j = NewOutput( t );
				if ( j != -1 ) {
					t.SetOM( j, '1' );
					newterms.push_back(t);		// we have a term, go further
					t.SetOM( j, '0' );
				}
				t.SetIM( 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).GetOM(i) == '~' && (*ti).GetOM(i) != '~' )
                (*ti1).SetOM(i, (*ti).GetOM(i));
    }
}

void Reduce::ExhaustiveReduce(void)
//	Generates all group implicants
{
	TermList::iterator ti;
	Term t;					// term under construction
	TermList::iterator ti1;	// constructed term
	unsigned int i;
	int j;

	for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ ) {
		t = (*ti);
		t.origin |= 8;
		for ( i = 0; i < implpool->GetInputs(); i++ )
			if ( t.GetIM(i) == '-' ) {
				t.SetIM( i, '1' );		// try to set to 1
				j = NewOutput( t );
				if ( j != -1 ) {
					ti1 = implpool->AppendTerm(t);
					(*ti1).SetOM(j, '1');
				}
				t.SetIM( i, '0' );		// try to set to 0
				j = NewOutput( t );
				if ( j != -1 ) {
					ti1 = implpool->AppendTerm(t);
					ti1->SetOM(j, '1');
				}
				t.SetIM( i, '-' );		// return it back
			}
	}
}

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

	if ( implpool == NULL ) return;		// nothing to do
	if ( implpool->GetOutputs() == 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);
}
