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

#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

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

#include "defaults.h"
// #include "TimeStamp.h"
#include "CovMatrix.h"
#include "HeurCover.h"
#include "AuraCover.h"
#include "Expand.h"

#include "Cover.h"
//---------------------------------------------------------------------------

Cover::Cover( PLA *_source, PLA *_implpool )
{
    source = _source;
    implpool = _implpool;
}

void Cover::GenerateOM(void)
// Generates OM values in the implicant pool (only from void "~" values)
{
    unsigned int i;
    TermList::iterator ti;

    for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ )
        for ( i = 0; i < implpool->GetOutputs(); i++ )
            if ( (*ti).GetOM(i) == '~' )
                if ( source->IsImplicant( (*ti), i ) ) (*ti).SetOM(i, '1');
                else (*ti).SetOM(i, '0');
}

void Cover::GenerateCoverVector( Term &t )
/*
	Generates CoverVector structure for a given term (if it is empty)
	It's size is equal to the # of 1's in the source OM (taken from PLA::GetOnSet)
*/
{
	vector<bitvector> *SO_covvct;
	CubeList::iterator ti;
	unsigned int o;
	bool covered;		// is the term covered (contained) by t?
	bitvector *covvct;
	
	if ( !t.GetCoverVector()->empty() && !t.GetSO_CoverVector(0)->empty() ) return;

	SO_covvct = t.GetSO_CoverVector();
	covvct = t.GetCoverVector();
	SO_covvct->resize( source->GetOutputs() );
	for ( o = 0; o < source->GetOutputs(); o++ )
		for ( ti = source->GetOnSet(o)->GetData()->begin(); ti != source->GetOnSet(o)->GetData()->end(); ti++ ) {
			covered = t.Cube::Contains((*ti).GetIM());
			if ( covered && t.GetOM(o) == '1' ) {		// covers this output and it is an implicant of o-th function
				covvct->push_back(true);
				(*SO_covvct)[o].push_back(true);
			} else {
				covvct->push_back(false);
				(*SO_covvct)[o].push_back(false);
			}
		}
}

void Cover::GenerateCoverVectors(void)
/*
	Generates CoverVectors for the whole implicant pool
*/
{
	TermList::iterator ti;

	for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ )
		GenerateCoverVector(*ti);
}

void Cover::RemoveAbsorbedByCover(void)
/*
	By comparing CoverVectors, remove clearly absorbed terms from the pool.
	If same terms are covered by two, the one with smaller dimension is removed.
*/
{
	TermList::iterator ti1, ti2;
	bool abs1, abs2;				// which one is absorbed
	bool deleted;

	ti1 = implpool->GetData()->begin();
	if ( (*ti1).GetCoverVector()->empty() ) GenerateCoverVectors();
	do {
		deleted = false;
		ti2 = ti1;
		ti2++;
		while ( ti2 != implpool->GetData()->end() ) {
			abs1 = true;
			abs2 = true;
			if ( !(*ti1).GetCoverVector()->contains( *(*ti2).GetCoverVector() )) abs2 = false;
			if ( !(*ti2).GetCoverVector()->contains( *(*ti1).GetCoverVector() )) abs1 = false;
			if ( abs1 && abs2 ) {
				if ( (*ti1).GetDim() >= (*ti1).GetDim() ) ti2 = implpool->DeleteTerm(ti2);
				else {
					ti1 = implpool->DeleteTerm(ti1);
					deleted = true;
					break;
				}
			}
			else if ( abs1 && !abs2 ) { 
				ti1 = implpool->DeleteTerm(ti1);
				deleted = true;
				break;
			}
			else if ( !abs1 && abs2 ) ti2 = implpool->DeleteTerm(ti2);
			else ti2++;
		}
		if ( !deleted ) ti1++;
	} while ( ti1 != implpool->GetData()->end() );
}

PLA *Cover::Run(void)
// Runs the CP
{
	CovMatrix *CM;
	PLA *solution;
	unsigned int i;
	TermList::iterator ti;
	unsigned int rownum;
	list<unsigned int> sol;
	list<unsigned int>::iterator sol_it;
	float t1;
	ofstream trialfile;

//	TS.start(TS_CP);

	ti = implpool->GetData()->begin();		// determine vector size by the first one
	if ( (*ti).GetCoverVector()->empty() ) GenerateCoverVectors();
	rownum = (*ti).GetCoverVector()->size();
	CM = new CovMatrix( rownum, implpool->GetData()->size() );
	if ( CM == NULL) throw RuntimeException( "Cover: Not enough memory" );
	for ( ti = implpool->GetData()->begin(); ti != implpool->GetData()->end(); ti++ ) {
		if ( (*ti).GetCoverVector()->size() != rownum ) throw RuntimeException( "Cover::Run:: Bad size of cover vector" );
		for ( i = 0; i < rownum; i++ )
			CM->SetValue(i, implpool->GetIndex(ti), (*(*ti).GetCoverVector())[i]);
		CM->SetCost(implpool->GetIndex(ti), implpool->GetInputs() - (*ti).GetDim() + 1);
	}
	
//	CM->DumpMatrix( "matrix.dat" );

	trialfile.open("trials.csv", ios::app);
	t1 = GetMyCPUTime();
	sol = HeurCover(CM).Run();
//	sol = AuraCover(CM).Run();

	trialfile << GetMyCPUTime()-t1 << "; ";
	trialfile.close();

	solution = new PLA(implpool);
	if ( solution == NULL) throw RuntimeException( "Cover: Not enough memory" );
	for ( sol_it = sol.begin(); sol_it != sol.end(); sol_it++ )
		solution->AppendTerm( *implpool->GetTermByIndex(*sol_it) );

	delete CM;

//	TS.stop(TS_CP);
	return solution;
}

void Cover::Sparse_output( PLA *pla )
// Removes unnecessary 1's from the output matrix
// (by solving m separate covering problems)
// Input of sparsed terms is expanded
// Does not modify the number of terms
{
	CovMatrix *CM;
	unsigned int i, j, k;
	TermList::iterator ti;
	unsigned int rownum, colnum;
	list<unsigned int> sol;
	list<unsigned int>::iterator sol_it;
	vector<bool> solvector;

//	TS.start(TS_Sparse);
	for ( ti = pla->GetData()->begin(); ti != pla->GetData()->end(); ti++ )
		(*ti).tmp = 0;			// candidates for input expansion

	for ( i = 0; i < pla->GetOutputs(); i++ ) {	// generate cover matrix for this output		
			// determine the number of rows by the first one
		ti = implpool->GetData()->begin();		// determine vector size by the first one
		if ( (*ti).GetSO_CoverVector(i)->empty() ) GenerateCoverVectors();
		rownum = (*ti).GetSO_CoverVector(i)->size();
			// count the number of 1's in the OM[i]
		colnum = 0;
		for ( ti = pla->GetData()->begin(); ti != pla->GetData()->end(); ti++ )
			if ( (*ti).GetOM(i) == '1' ) colnum++;
		CM = new CovMatrix( rownum, colnum );
		if ( CM == NULL) throw RuntimeException( "Cover: Not enough memory" );
		k = 0;
		for ( ti = pla->GetData()->begin(); ti != pla->GetData()->end(); ti++ ) {
			if ( (*ti).GetSO_CoverVector(i)->size() != rownum )
				throw RuntimeException( "Cover::Sparse_output:: Bad size of cover vector" );
			if ( (*ti).GetOM(i) == '1' ) {
				for ( j = 0; j < rownum; j++ )
					CM->SetValue( j, k, (*(*ti).GetSO_CoverVector(i))[j] );
				k++;
			}
		}
			// solve it
		sol = HeurCover(CM).Run();

			// substitute unnecessary 1's by ~
		solvector.clear();
		solvector.resize( colnum, false );
		for ( sol_it = sol.begin(); sol_it != sol.end(); sol_it++ )
			solvector[*sol_it] = true;
		k = 0;
		for ( ti = pla->GetData()->begin(); ti != pla->GetData()->end(); ti++ )
			if ( (*ti).GetOM(i) == '1')
				if ( !solvector[k++] ) {
					(*ti).SetOM( i, '~' );
					(*ti).tmp = 1;
				}
		delete CM;
	}
			// expand input for sparsed terms
	for ( ti = pla->GetData()->begin(); ti != pla->GetData()->end(); ti++ )
		if ( (*ti).tmp == 1 ) Expand(source).ExpandTerm(*ti);

//	TS.stop(TS_Sparse);
}
