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

#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

//#include <fstream>

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

#include "CD_search.h"
#include "FC_Min.h"
#include "Expand.h"
#include "Cover.h"
#include "Reduce.h"

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

BoomOpts::BoomOpts(void)
{
	CD_FC = DEFAULT_CD_FC;
	iterations = DEFAULT_iterations;
	CD_mutations = DEFAULT_CD_MUTATIONS;
	CD_implcheck = DEFAULT_CD_IMPLCHECK;
	IE = DEFAULT_IE;
	IR = DEFAULT_IR;
	DF = DEFAULT_DF;

	lagrange_total_iter = DEFAULT_LAG_TOTALITER;
	lagrange_iter = DEFAULT_LAG_ITER;
	lagrange_iter_dual = DEFAULT_LAG_ITER_DUAL;
	lagrange_heur_iter = DEFAULT_LAG_HEURITER;
	lagrange_init_coef = DEFAULT_LAG_KOEFINIT;
	lagrange_min_coef = DEFAULT_LAG_KOEFMIN;
	lagrange_init_coef_dual = DEFAULT_LAG_KOEFINIT_DUAL;
	lagrange_min_coef_dual = DEFAULT_LAG_KOEFMIN_DUAL;
	lagrange_simple_dual = DEFAULT_LAG_SDUAL;
	lagrange_run_lagrange = false;
	matrixFile = NULL;
	dominance=2;
	use_contribAdd = false;
}

BoomAlg::BoomAlg(void)
{
	implpool = NULL;
	FC_pool = NULL;
	result = NULL;
}

BoomAlg::BoomAlg( PLA *_pla )
{
    source = _pla;
    result = NULL;
	implpool = new PLA( source->GetInputs(), source->GetOutputs(), PLA_type("f") );
	if ( implpool == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
    // implpool->SetUnique();
	// implpool->KeepTT();		// slows it down (?)
	FC_pool = new PLA( source->GetInputs(), source->GetOutputs(), PLA_type("f") );
	if ( FC_pool == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
//    FC_pool->SetUnique();
//	FC_pool->KeepTT();
}

BoomAlg::~BoomAlg(void)
{
	delete implpool;
}

PLA *BoomAlg::Run(void)
{
    CD_Search *CDS_alg = NULL;
	FC_Min *FC_alg = NULL;
	Expand *IE_alg = NULL;
	Expand *IE_FC_alg = NULL;
	Reduce *IR_alg = NULL;
	Cover *CP_alg = NULL;
	unsigned int it;
	PLA *sol;
	CoverOpts opts;
		
	opts.SetRunLag(options.lagrange_run_lagrange);
	opts.SetLagTotalIter(options.lagrange_total_iter);
	opts.SetLagHeurIter(options.lagrange_heur_iter);
	opts.SetLagIter(options.lagrange_iter);
	opts.SetLagDualIter(options.lagrange_iter_dual);
	opts.SetLagInitCoef(options.lagrange_init_coef);
	opts.SetLagMinCoef(options.lagrange_min_coef);
	opts.SetLagDualInitCoef(options.lagrange_init_coef_dual);
	opts.SetLagDualMinCoef(options.lagrange_min_coef_dual);
	opts.SetLagSimpleDual(options.lagrange_simple_dual);
	opts.SetMatrixFile(options.matrixFile);
	opts.SetDominance(options.dominance);
	opts.SetContribAdd(options.use_contribAdd);
	opts.SetServit(options.use_servit);

		
	if(options.matrixFile!=NULL) {
		cout << "going to run from matrix" << endl;
		sol = CP_alg->Run(&opts);
		return sol;
	} 

	cout << "creating matrix" << endl;
	
	// initialize algorithms
	if ( options.CD_FC != 100 ) {
		CDS_alg = new CD_Search( source, implpool );
		if ( CDS_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
	}
	if ( options.CD_FC != 0 ) {
		FC_alg = new FC_Min( source, FC_pool );
		if ( FC_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		FC_alg->SetDF(options.DF);
		IE_FC_alg = new Expand( source, FC_pool );
		if ( IE_FC_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IE_FC_alg->SetMethod(scatter_IE);
	}
	if ( options.IE != no_IE ) {
		IE_alg = new Expand( source, implpool );
		if ( IE_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IE_alg->SetMethod(options.IE);
	}
	if ( options.IR != no_IR ) {
		IR_alg = new Reduce( source, implpool );
		if ( IR_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IR_alg->SetMethod(options.IR);
	}
	CP_alg = new Cover( source, implpool );
	if ( CP_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );

	// Run CD-S and FC-Min
	for ( it = 0; it < options.iterations; it++ ) {
		if ( rand() % 100 >= (int)options.CD_FC ) CDS_alg->Run();
		else {
			FC_alg->Run();
			IE_FC_alg->Run();
			implpool->Splice( *FC_pool );
		}
	}
	//	implpool->SavePLA("implpool.pla");

	// Reductions, Expansions, CP
	if ( options.IE != no_IE ) IE_alg->Run();

	CP_alg->GenerateOM();
	implpool->RemoveAbsorbed();

	if ( options.IR != no_IR ) IR_alg->Run();

	CP_alg->RemoveAbsorbedByCover();

	//	implpool->SavePLA( "implpool.pla" );
	//	implpool->DumpOrigin( "pool_origin.csv" );

	sol = CP_alg->Run(&opts);
	CP_alg->Sparse_output(sol);

	//	TS.DumpTimeStamps("timestamps.txt");

	//	sol->DumpOrigin( "sol_origin.csv" );

	delete CP_alg;
	delete IR_alg;
	delete IE_alg;
	delete IE_FC_alg;
	delete FC_alg;
	delete CDS_alg;

	return sol;
}

PLA *BoomAlg::FC_Run(void)
{
    CD_Search *CDS_alg = NULL;
	FC_Min *FC_alg = NULL;
	Expand *IE_alg = NULL;
	Expand *IE_FC_alg = NULL;
	Reduce *IR_alg = NULL;
	Cover *CP_alg = NULL;
	unsigned int it, DF;
	PLA *sol;
	ofstream report;
	float t1, t2, t1_tot, t2_tot;

	report.open("FC-DF.csv");

	for ( DF = 0; DF < 100; DF++ ) {
			// initialize algorithms
		FC_pool->clear();
		implpool->clear();
		delete result;
		result = NULL;
		FC_alg = new FC_Min( source, FC_pool );
		FC_alg->SetDF(DF);
		IE_FC_alg = new Expand( source, FC_pool );
		IE_FC_alg->SetMethod(scatter_IE);
		CP_alg = new Cover( source, implpool );

		t1 = GetMyCPUTime();
		t1_tot = t1;
		for ( it = 0; it < options.iterations; it++ ) {
			FC_alg->Run();
		}
		t2 = GetMyCPUTime();

		IE_FC_alg->Run();
		implpool->Splice( *FC_pool );

		CP_alg->GenerateOM();
		implpool->RemoveAbsorbed();
		CP_alg->RemoveAbsorbedByCover();

		sol = CP_alg->Run();
		CP_alg->Sparse_output(sol);
		
		t2_tot = GetMyCPUTime();

		report << DF << "; " << FC_alg->GetTrials() << "; " << FC_alg->GetHits() << "; " << sol->GetLiterals() << "; " << sol->GetTerms() << "; " << t2-t1 << "; " << t2_tot-t1_tot << endl;

		delete CP_alg;
		delete IE_FC_alg;
		delete FC_alg;
	}
	report.close();
    
	return sol;
}