#include "project.h"
#include "minmax.h"
#include "randomNum.h"
#include <iostream>
using namespace std;
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>
#include <stdlib.h>


double energy(project);
double energyM(project);
double calcEnergy(project, double, double, double, double);
double prob(double, double, double);
project neighbour(project, double[], int, bool);
double temp(int, int);
void outStats(project);
void partition(double[], int, int, int&, int&);
void quicksort(double[], int, int);
void sort(double[], int);
void commandLine(int, char*[], double*, double*, int*, bool*, bool*, bool*, bool*, bool*, bool*, project*, bool*, bool*, bool*, bool*, bool *, int *, string *, string *, string *, string *);
int SA(double[], bool[], project*, project*, project*, int, double*, double*, double*, double*, double*, bool, bool, ofstream*, ofstream*, int, double, double[][25], bool);
void tenBinBore(ifstream *, ofstream *, double, double, bool, double, int*, int*, int[][25], int[][25], int[][15], int[][15], int, project);
void score(int[][25], int[][25], double[][25], int[][15], int[][15], double[][15], int, int);
void BackSelSim(int, project, project, bool[], double[][25], double[][15], ofstream *, randomNum, bool, bool, string, bool);
void EBackSelSim(int, project, project, bool[], bool, double[][25], double[][15], ofstream *, randomNum, bool, bool, string, bool);
string itos(int);
string dtos(double);
double roundX(double);

///////////////////////////////////////////////////////////////////////////////////
//Model normalization globals. They are modified according to project files.
///////////////////////////////////////////////////////////////////////////////////
double cocomoMax = 0.0;
double cocomoMin = 100000000000000000000.0;
double coqualmoMax = 0.0;
double coqualmoMin = 100000000000000000000.0;
double threatMax = 0.0;
double threatMin = 100000000000000000000.0;
double tdevMax = 0.0;
double tdevMin= 100000000000000000000.0;
///////////////////////////////////////////////////////////////////////////////////
//Utility weights variables
///////////////////////////////////////////////////////////////////////////////////
double alpha = 1.0;
double beta = 1.0;
double gama = 1.0;
double delta = 1.0;
double relydefect = 1.8; //1.8;
double coolFactor = -10;

///////////////////////////////////////////////////////////////////////////////////
//Number of simulations per backselect step
///////////////////////////////////////////////////////////////////////////////////
static int simNum=1000;
///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//Arrays to determine search sets for strategic and tactical analysis
///////////////////////////////////////////////////////////////////////////////////
bool policySet [25] = {0};
///////////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[]) {
	
	double TotalTime, SATime;
	time_t start, end;
	start = clock();	
    
    srand((unsigned)time(0)); //Setting the seed for the random number generator
    cout.setf(ios::fixed,ios::floatfield);
    cout.precision(12);
    
    ///////////////////////////////////////////////////////////////////////////////////
    //Block for declaring variables
    ///////////////////////////////////////////////////////////////////////////////////
    project x, s, sb, sn;
    double initattset[x.ATTN];
    bool searchattset[x.ATTN] = {0};
    double finalattset[x.ATTN];
    int attNumUndefined=0;
    double e, eb, en;
    
    double minE = 100000;
    double maxE = 0;
    
    minmax stat;
    randomNum rdm;
    
    double bore = 0.1;
    double emax = 0.0000001; //min energy to be reached before stopping SA
    int kmax = 10000; //max number of itrations for SA
    int run = 0;
    
    string scoring("");
    string policyVal("");
    string projectVal("");
    string mutation(""); 
    string stratVal("");
    string bfcVal("");
    
    bool worst = false;
    bool help = false;
    bool log = false;
    bool file = false;
    bool setPolicy = false;
    bool ERank = false;
    bool OutRuns = false;
    bool Extreme = false;
    bool LCout = false;
    bool LogBest = false;
    bool png = false;
    ///////////////////////////////////////////////////////////////////////////////////
    	
    //Parsing command line input
    commandLine(argc, argv, &bore, &emax, &kmax, &worst, &help, &log, &file, &setPolicy, &ERank, &x, &OutRuns, &LCout, &Extreme, &LogBest, &png, &run, &policyVal, &projectVal, &stratVal, &bfcVal);
    	
    if (bfcVal.empty()) bfcVal = "bfc";
    if (stratVal.empty()) stratVal = "none";
    
    if (Extreme) mutation = "extreme";
    else mutation = "normal";
    
    if (ERank) scoring = "energy";
    else scoring = "bore"; 
    
    ///////////////////////////////////////////////////////////////////////////////////
    //For command line options that cause termination of STAR
    ///////////////////////////////////////////////////////////////////////////////////
    if (help) {
        string helpPath(getenv("HOME"));
        helpPath += "/STAR/help.txt";
        ifstream helpCheck(helpPath.c_str());
        
        if (!helpCheck) {
            cout << "Unable to open the help file... exiting..." << endl;
            exit(1);
        }
        
        string outHelp("cat " + helpPath + "|less");
        system(outHelp.c_str());
        exit(1);
    }
    
    //if no input file specified
    if (!file) {
        cout << "Please specify a project and the location of its files using -f" << endl
                << "Refer to the help by using -h option" << endl;
        exit(1);
    }
    ///////////////////////////////////////////////////////////////////////////////////
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    //Debug block
    ///////////////////////////////////////////////////////////////////////////////////
//	outStats(x);
//
//	for (int i=0; i<25; i++) {
//			x.displayAtt(i);
//	}
//
//	for (int i=0; i<x.ATTN; i++) {
//		cout << x.displayAttName(i) << " " <<  x.attrangeNorm[0][i] << " " << x.attrangeNorm[1][i] << endl;
//	}

//    for (int i=0; i<x.ATTN; i++) {
//		cout << x.displayAttName(i) << " " <<  x.attributes[i] << endl;
//	}
    ///////////////////////////////////////////////////////////////////////////////////
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    //Copying original project and setting unset attributes and setting the search set
    ///////////////////////////////////////////////////////////////////////////////////
    //Saving the initial settings for the attributes
    for (int i=0; i<x.ATTN; i++) {
        initattset[i] = x.attributes[i];
        if (initattset[i] != 0) searchattset[i] = false;
        else searchattset[i] = true;
    }
    
    if (setPolicy) {
        for (int i=0; i<25; i++) {
            if (searchattset[i] == true) searchattset[i] = policySet[i];
        }
    }
    
    else {
        cout << "Please set the policy to be used";
        exit(1);
    }
    
    s=x; //copying the project
    
    //Setting the initial attributes.
    for (int i=0; i<25; i++) {
        if (s.attributes[i]==0) {
            s.setattnum(i, rdm.randomGenerateDouble(s.attrangeNorm[0][i], s.attrangeNorm[1][i]));
            attNumUndefined++; //determinning number of undefined attributes
        }
    }
    
    for (int i=25; i<x.ATTN; i++) {
        s.setattnum(i, rdm.randomGenerateDouble(s.attrangeNorm[0][i], s.attrangeNorm[1][i]));
    }
    ///////////////////////////////////////////////////////////////////////////////////
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    //File I/O Block
    ///////////////////////////////////////////////////////////////////////////////////
    
    time_t rawtime;
 	time ( &rawtime );

    char * chartime = ctime (&rawtime);
    chartime = strtok(chartime, "\n");
    
    char * temptime = strtok(chartime, " :");
    
    string runtime("");
    
    while (temptime!=NULL) {
    	runtime = runtime + "_" + temptime;
    	temptime = strtok(NULL, " :");
    }
    
	string runspec("");
    
    for (int i=1; i<argc; i++) {
        runspec += argv[i];
        runspec += "_";
    }
    
    int f = runspec.find_first_of("STAR");
    if (f != 0) runspec = "STAR" + runspec;
    
    runspec = "STAR_results/" + runspec + runtime;
           
    string htmp(getenv("HOME"));
    string hmkdir("");
    
    hmkdir += "mkdir -p " + htmp + "/STAR/" + runspec;
    system(hmkdir.c_str());
    
    string hlog(htmp + "/STAR/" + runspec + "/STAR.csv");
    string hlogbest(htmp + "/STAR/" + runspec + "/STARbest.csv");
    
    ofstream outfile(hlog.c_str(), ios::out);
    outfile.setf(ios::fixed,ios::floatfield);
    outfile.precision(12);
    
    if (!outfile) { cout << "Unable to open log file... exiting..." << endl; exit(1); }
    
    for (int i=0; i<x.ATTN; i++) {
        outfile << s.displayAttName(i) << ",";
    }
    outfile << "Energy\n";
    
    ofstream outbest;
    outbest.setf(ios::fixed,ios::floatfield);
    outbest.precision(12);
    
    if (LogBest) {
        outbest.close();
        outbest.open(hlogbest.c_str(), ios::out);
        if (!outbest) { cout << "Unable to open log file for best... exiting..." << endl; exit(1); }
        
        for (int i=0; i<x.ATTN; i++) {
            outbest << s.displayAttName(i) << ",";
        }
        outbest << "Energy\n";
    }
    else {
        outbest.close();
    }
    ///////////////////////////////////////////////////////////////////////////////////
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    //Block for setting and diplaying min/max for the model for the project in
    //question. These are used for normalization purposes.
    ///////////////////////////////////////////////////////////////////////////////////
    cocomoMax = stat.effortMax(x);
    cocomoMin = stat.effortMin(x);
    coqualmoMax = stat.defectMax(x);
    coqualmoMin =stat.defectMin(x);
    threatMax = stat.thrMax(x);
    threatMin = stat.thrMin(x);
    tdevMax = stat.monthsMax(x);
    tdevMin = stat.monthsMin(x);
        
    e = energyM(s);
    
    //Outputting weighting attributes
    if (log) {
	    cout << "Alpha = " << alpha << endl;
	    cout << "Beta  = " << beta << endl;
	    cout << "Gamma = " << gama << endl;
	    cout << "Delta = " << delta << endl;
	    cout << "Rely-Defects = " << relydefect << endl;
	    cout << "Cooling Factor = " << coolFactor << endl;
	    
	    
	    cout << "Cocomo Min: " << cocomoMin
	            << "\nCocomo Max: " << cocomoMax
	            << "\nCoqualmo Min: " << coqualmoMin
	            << "\nCoqualmo Max: " << coqualmoMax
	            << "\nThreat Min: " << threatMin
	            << "\nThreat Max: " << threatMax
	            << "\nTdev Min : " << tdevMin
	            << "\nTdev Max : " << tdevMax;
	    ///////////////////////////////////////////////////////////////////////////////////
	    	    
	    ///////////////////////////////////////////////////////////////////////////////////
	    //Finding best or near best solution for project using simulated annealing.
	    ///////////////////////////////////////////////////////////////////////////////////
	    
	    cout << "\nInitial Energy: " << e << endl;
    }
    
    sb = s;
    eb = e;
    
    double discreteAttEScore [12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}; //Discrete att energy scoring
    
    if (log) cout << "Energy threshold: " << emax << "\nMax iterations: " << kmax << "\nSimulation iterations: " << simNum << endl;
    
    time_t SAstart, SAend;
    SAstart = clock();
    	
    int recNum = SA(initattset, searchattset, &s, &sb, &sn, attNumUndefined, &e, &eb, &en, &minE, &maxE, log, Extreme, &outfile, &outbest, kmax, emax, discreteAttEScore, LogBest);
           
    SAend = clock();
    SATime = ((double)(SAend - SAstart)/CLOCKS_PER_SEC );  
           
    outfile.close();
    
    for (int i=0; i<x.ATTN; i++)
        finalattset[i] = sb.attributes[i];
    ///////////////////////////////////////////////////////////////////////////////////
    //class bore and continuous var 10 bins
    
    int numBest = 0;
    int numRest = 0;
    
    //Discrete Scoring
    int discreteAttBest [12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    int discreteAttRest [12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    int contAttBest [10][15] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    int contAttRest [10][15] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    
    
    ifstream infile(hlog.c_str(), ios::in);
    string descLog(htmp + "/STAR/" + runspec + "/STAR-discrete.csv");
    outfile.open(descLog.c_str(), ios::out);
    
    if (!ERank)	tenBinBore(&infile, &outfile, minE, maxE, worst, bore, &numBest, &numRest, discreteAttBest, discreteAttRest, contAttBest, contAttRest, recNum, x);
    
    outfile.close();
    
    //end dicretization
    
    //scoring of the attributes
    //Discrete Scoring
    double discreteAttScore [12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
	double contAttScore [10][15] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    
    if (!ERank)	score(discreteAttBest, discreteAttRest, discreteAttScore, contAttBest, contAttRest, contAttScore, numBest, numRest);
    //end scoring
    
    
    // Simulations
    
    string simLog(htmp + "/STAR/" + runspec + "/simlog.csv");
    outfile.open(simLog.c_str(), ios::out);
    
    if (!ERank)	BackSelSim(attNumUndefined, sb, x, searchattset, discreteAttScore, contAttScore, &outfile, rdm, OutRuns, LCout, runspec, log);
    else EBackSelSim(attNumUndefined, sb, x, searchattset, worst, discreteAttEScore, contAttScore, &outfile, rdm, OutRuns, LCout, runspec, log);
    outfile.close();
    
    end = clock();
    
    TotalTime = ((double)(end - start)/CLOCKS_PER_SEC );
    
    string finalout("cd " + htmp + "/STAR/");
    string graphPNG("./graphPNG " + runspec);
    string graph("./graph " + runspec);
    string snum, minEnergy, SANum, TTime, STime, srun, salpha, sbeta, sgamma, sdelta, srelydefect, scoolFactor,slog;
    
    snum = itos(simNum);   
    minEnergy = dtos(minE);
    SANum = itos(kmax);
    TTime = dtos(TotalTime);
    STime = dtos(SATime);
    srun = itos(run);
    salpha = dtos(alpha);
    sbeta = dtos(beta);
    sgamma = dtos(gama);
    sdelta = dtos(delta);
    srelydefect = dtos(relydefect);
    scoolFactor = dtos(coolFactor);
    if (log) slog = "1";
    else slog = "0";
    
    string policy("gawk -v out=" + runspec + " -v N=" + snum + " -v minEnergy=" + minEnergy + " -v scoring=" + scoring
    				+ " -v mutation=" + mutation + " -v SANum=" + SANum  + " -v TotalTime=" + TTime + " -v SATime=" + STime  + " -v policyVal=" + policyVal 
    				+ " -v projectVal=" + projectVal + " -v run=" + srun + " -v alpha=" + salpha + " -v beta=" + sbeta + " -v gamma=" + sgamma 
    				+ " -v delta=" + sdelta + " -v relydefect=" + srelydefect + " -v coolFactor=" + scoolFactor + " -v stratVal=" + stratVal
    				+ " -v bfcVal=" + bfcVal + " -v slog=" + slog + " -f policy.awk " + runspec + "/simlog.csv");
    string command("");
    
    command += finalout;
    if (png) command += "\n" + graphPNG;
    if (log) command += "\n" + graph;
    command += "\n" + policy;
    
    int sys = system(command.c_str()); 
    
    return 0;
}

double energy(project x) {
    double E = (x.effort()-cocomoMin)/(cocomoMax-cocomoMin);
    double D = (x.defects()-coqualmoMin)/(coqualmoMax-coqualmoMin);
    double T = (threatMax == threatMin) ? 0 : (x.threat()-threatMin)/(threatMax-threatMin);
    double M = (x.months()-tdevMin)/(tdevMax-tdevMin);
    
    double RD;
    
    if (relydefect != 0)
        RD = pow(relydefect, (x.getattnum(13)-3));
    else
        RD = 0;
    
    double EA = E*alpha;
    double DBRD = D*(beta+RD);
    double TG = T*gama;
    double MD = M*delta;
    
    double BRD = beta+RD;
    
    double Energy = sqrt(pow(EA, 2)+pow(DBRD, 2)+pow(TG, 2)+pow(MD, 2))/sqrt(pow(alpha, 2)+pow(BRD, 2)+pow(gama, 2)+pow(delta, 2)); 
    return Energy;
}

double energyM(project x) {
    double E = (x.effortMutate()-cocomoMin)/(cocomoMax-cocomoMin);
    double D = (x.defectsMutate()-coqualmoMin)/(coqualmoMax-coqualmoMin);
    double T = (threatMax == threatMin) ? 0 : (x.threatMutate()-threatMin)/(threatMax-threatMin);
    double M = (x.monthsMutate()-tdevMin)/(tdevMax-tdevMin);
    
    double RD;
    
    if (relydefect != 0)
        RD = pow(relydefect, (x.getattnum(13)-3));
    else
        RD = 0;
    
    double EA = E*alpha;
    double DBRD = D*(beta+RD);
    double TG = T*gama;
    double MD = M*delta;
    
    double BRD = beta+RD;
    
    double EnergyM = sqrt(pow(EA, 2)+pow(DBRD, 2)+pow(TG, 2)+pow(MD, 2))/sqrt(pow(alpha, 2)+pow(BRD, 2)+pow(gama, 2)+pow(delta, 2));
    return EnergyM;
}

double calcEnergy(project x, double eff, double def, double thr, double mon) {
    double E = (eff-cocomoMin)/(cocomoMax-cocomoMin);
    double D = (def-coqualmoMin)/(coqualmoMax-coqualmoMin);
    double T = (threatMax == threatMin) ? 0 : (thr-threatMin)/(threatMax-threatMin);
    double M = (mon-tdevMin)/(tdevMax-tdevMin);
    
    double RD;
    
    if (relydefect != 0)
        RD = pow(relydefect, (x.getattnum(13)-3));
    else
        RD = 0;
    
    double EA = E*alpha;
    double DBRD = D*(beta+RD);
    double TG = T*gama;
    double MD = M*delta;
    
    double BRD = beta+RD;
    
    double EnergyCalc = sqrt(pow(EA, 2)+pow(DBRD, 2)+pow(TG, 2)+pow(MD, 2))/sqrt(pow(alpha, 2)+pow(BRD, 2)+pow(gama, 2)+pow(delta, 2));
    return EnergyCalc;
}

double prob(double e, double en, double T) {
    return (double)exp((e-en)/T);
}

project neighbour(project s, double initattset[], int numtochange, bool Extreme) {
    
    randomNum rdm;
    int numdone=0;
    int ChangedAtt[50] = {0};
    int att;
    double rndRange = rdm.randomN();
    
    
    while (numdone<numtochange) {
        bool doneprevious = true;
        while (doneprevious == true) {
            
            att=rdm.randomGenerateInt(0, 24);            
            
            ChangedAtt[numdone] = att;
            doneprevious = false;
            for (int i=0; i<numdone; i++) {
                if (ChangedAtt[i] == att) {
                    doneprevious = true;
                    break;
                }
            }
        }
        if (initattset[att]==0) {
            if (Extreme) {
                if (rndRange < 0.05) {
                    s.setattnum(att, s.attrangeNorm[0][att]);
                }
                if (rndRange >= 0.05 && rndRange < 0.95) {
                    s.setattnum(att, rdm.randomGenerateDouble(s.attrangeNorm[0][att], s.attrangeNorm[1][att]));
                }
                if (rndRange >= 0.95) {
                    s.setattnum(att, s.attrangeNorm[1][att]);
                }
            }
            else
                s.setattnum(att, rdm.randomGenerateDouble(s.attrangeNorm[0][att], s.attrangeNorm[1][att]));
            numdone++;
        }        
    }
    
    for (att=25; att<s.ATTN; att++) {
        s.setattnum(att, rdm.randomGenerateDouble(s.attrangeNorm[0][att], s.attrangeNorm[1][att]));
    }
    return s;
}

double temp(int k, int kmax) {
    return (double)exp(coolFactor*k/kmax);
}

void outStats(project x) {
    cout << "\nCocomoII: " << x.effort() << endl
    << "Coqualmo: " << x.defects() << endl
    << "Threat: " << x.threat() << endl
    << "Tdev: " << x.months() << endl;
    
}

void partition( double a[], int left, int right, int& lp, int &rp) {
    int i = left + 1;
    int j = left + 1;
    double x = a[left];
    while (j <= right) {
        if (a[j] < x) {
            double temp = a[j];
            a[j] = a[i];
            a[i] = temp;
            i++;
        }
        j++;
    }
    a[left] = a[i-1];
    a[i-1] = x;
    lp = i - 2;
    rp = i;
}

void quicksort( double a[], int left, int right ) {
    if (left < right) {
        int lp, rp;
        partition( a, left, right, lp, rp );
        quicksort(a, left, lp);
        quicksort(a, rp, right);
    }
}

void sort( double a[], int n ) {
    quicksort(a, 0, n-1);
}

void commandLine(int argc, char* argv[], double* bore, double* emax, int* kmax, bool* worst, bool* help, bool* log, bool* file,  bool* setPolicy, bool* ERank, project* x, bool* OutRuns, bool* LCout, bool* Extreme, bool* LogBest, bool* png, int* run, string* policyVal, string* projectVal, string* stratVal, string* bfcVal) {
    
    
    for (int i=1; i<argc; i++) {
        string option(argv[i]);
        
        if (option=="-sim" || option=="-SIM") {
        	i++;
            simNum = atoi(argv[i]);
        }
        
        if (option=="-png" || option=="-PNG") {
        	*png = true;
        }
        
        if (option=="-lb" || option=="-LB") {
        	*LogBest = true;
        }
        
        if (option=="-ex" || option=="-EX")	{
            *Extreme = true;
        }
        
        if (option=="-al" || option=="-AL")	{
            i++;
            alpha = (double)atof(argv[i]);
        }
        
        if (option=="-be" || option=="-BE")	{
            i++;
            beta = (double)atof(argv[i]);
        }
        
        if (option=="-ga" || option=="-GA") {
            i++;
            gama = (double)atof(argv[i]);
        }
        
        if (option=="-de" || option=="-DE" ) {
            i++;
            delta = (double)atof(argv[i]);
        }
        
        if (option=="-rd" || option=="-RD" ) {
            i++;
            relydefect = (double)atof(argv[i]);
        }
        
        if (option=="-cf" || option=="-CF")	{
            i++;
            coolFactor = (double)atof(argv[i]);
        }
        
        if (option=="-lc" || option=="-LC") {
            *LCout = true;
        }
        
        if (option=="-or" || option=="-OR") {
            *OutRuns = true;
        }
        
        if (option=="-n" || option=="-N") {
            *worst = true;
        }
        
        if (option=="-h" || option=="-H") {
            *help = true;
        }
        
        if (option=="-l" || option=="-L") {
            *log = true;
        }
        
        if (option=="-b" || option=="-B") {
            i++;
            *bore = atof(argv[i]);
        }
        
        if (option=="-e" || option=="-E") {
            i++;
            *emax = atof(argv[i]);
        }
        
        if (option=="-er" || option=="-ER") {
            *ERank = true;
        }
        
        if (option=="-run" || option=="-RUN") {
            i++;
            *run = atoi(argv[i]);
        }
        
        if (option=="-k" || option=="-K") {
            i++;
            *kmax = atoi(argv[i]);
        }
        
        if (option=="-bf" || option=="-BF") {
        	alpha = 0.0;
			beta = 2.0;
			gama = 0.0;
			delta = 2.0;
			relydefect = 1.8;
			*bfcVal = option;
			bfcVal->erase(0,1);
        }
        
        if (option=="-fc" || option=="-FC") {
        	alpha = 2.0;
			beta = 0.0;
			gama = 0.0;
			delta = 2.0;
			relydefect = 0.0;
			*bfcVal = option;
			bfcVal->erase(0,1);
        }
        
        if (option=="-bc" || option=="-BC") {
        	alpha = 2.0;
			beta = 2.0;
			gama = 0.0;
			delta = 0.0;
			relydefect = 1.8;
			*bfcVal = option;
			bfcVal->erase(0,1);
        }
        
        if (option=="-pol" || option=="-POL") {
            *setPolicy = true;
            i++;
            string inPolicy(getenv("HOME"));
            inPolicy += "/STAR/policies/";
            inPolicy += argv[i];
            inPolicy += ".policy";
            
            *policyVal = argv[i];
            
            ifstream policy(inPolicy.c_str(), ios::in);
            if (!policy) {
                cout << "Unable to open policy file " << inPolicy << "... exiting..." << endl;
                exit(1);
            }
            
            string tmpAtt("");
            
            while (!policy.eof()) {
                policy >> tmpAtt;
                bool right = false;
                for (int f=0;f<25;f++) {
                    string ttatt(x->displayAttName(f));
                    if (tmpAtt==ttatt) {
                        right = true;
                        policySet[f] = 1;
                        break;
                    }
                }
                if (!right) {
                    if (tmpAtt.length() != 0) cout << "The attribute " << tmpAtt << " in " << inPolicy << " is not a valid attribute" << endl;
                }
            }
        }
        
        if (option=="-f" || option=="-F") {
            *file = true;
            i++;
            string inProject(getenv("HOME"));
            inProject += "/STAR/STAR_projects/";
            inProject += argv[i];
            
            *projectVal = argv[i];
            
            string attvalfn(inProject+".values");
            string attrangefn(inProject+".ranges");
            
            ifstream attvals(attvalfn.c_str(), ios::in);
            ifstream attranges(attrangefn.c_str(), ios::in);
            
            if (!attvals) {
                cout << "Unable to open values file for project " << inProject << "... exiting..." << endl;
                exit(1);
            }
            
            if (!attranges) {
                cout << "Unable to open ranges file for project " << inProject << "... exiting..." << endl;
                exit(1);
            }
            
            string tmpAtt("");
            
            while (!attranges.eof()) {
                attranges >> tmpAtt;
                bool right = false;
                for (int f=0;f<x->ATTN;f++) {
                    string ttatt(x->displayAttName(f));
                    if (tmpAtt==ttatt) {
                        right = true;
                        attranges >> x->attrangeNorm[0][f] >> x->attrangeNorm[1][f];
                    }
                }
                if (!right) {
                    double dump;
                    attranges >> dump >> dump;
                    if (tmpAtt.length() != 0) cout << "The attribute " << tmpAtt << " in " << inProject << ".ranges is not a valid attribute" << endl;
                }
            }
            
            tmpAtt.clear();
            
            while (!attvals.eof()) {
                attvals >> tmpAtt;
                bool right = false;
                for (int f=0;f<x->ATTN;f++) {
                    string ttatt(x->displayAttName(f));
                    if (tmpAtt==ttatt) {
                        right = true;
                        double tmpval;
                        attvals >> tmpval;
                        if (tmpval!=0) x->setattnum(f, tmpval);
                        x->attrangeNorm[0][f] = x->attrangeNorm[1][f] = tmpval;
                    }
                }
                if (!right) {
                    double dump;
                    attvals >> dump;
                    if (tmpAtt.length() != 0) cout << "The attribute " << tmpAtt << " in " << inProject << ".values is not a valid attribute" << endl;
                }
            }
        }
        
        if (option=="-st" || option=="-ST") {
            *file = true;
            i++;
            string inStrategy(getenv("HOME"));
            inStrategy += "/STAR/strategies/";
            inStrategy += argv[i];
            
            *stratVal = argv[i];
            
            string attvalfn(inStrategy+".strg");
            
            ifstream attvals(attvalfn.c_str(), ios::in);
            
            if (!attvals) {
                cout << "Unable to open definition file for strategy " << inStrategy << "... exiting..." << endl;
                exit(1);
            }
            
            string tmpAtt("");
                          
            while (!attvals.eof()) {
                attvals >> tmpAtt;
                bool right = false;
                for (int f=0;f<x->ATTN;f++) {
                    string ttatt(x->displayAttName(f));
                    if (tmpAtt==ttatt) {
                        right = true;
                        double tmpval;
                        attvals >> tmpval;
                        if (tmpAtt=="Ksloc") {
                        	x->attrangeNorm[0][f] = tmpval*x->attrangeNorm[0][f];
                        	x->attrangeNorm[1][f] = tmpval*x->attrangeNorm[1][f];
                        }
                        else if (tmpval!=0) {
                        	x->setattnum(f, tmpval);
                        	x->attrangeNorm[0][f] = x->attrangeNorm[1][f] = tmpval;
                        }
                    }
                }
                if (!right) {
                    double dump;
                    attvals >> dump;
                    if (tmpAtt.length() != 0) cout << "The attribute " << tmpAtt << " in " << inStrategy << ".strg is not a valid attribute" << endl;
                }
            }
        }
    }
}

int SA(double initattset[], bool searchattset[], project *s, project *sb, project *sn, int attNumUndefined, double *e, double *eb, double *en, double *minE, double *maxE, bool log, bool Extreme, ofstream* outfile, ofstream* outbest, int kmax, double emax, double discreteAttEScore [][25], bool LogBest) {
    randomNum rdm;
    int k = 0;
    int bla = 0;
    double discreteAttNum [12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    *e = energyM(*s);
    
    *sb = *s;
    *eb = *e;
    
    int bestNum = 0;
    
    while (k < kmax && *e > emax) {
        *sn = neighbour(*s, initattset, (int)ceil((double)attNumUndefined/2), Extreme);
        *en = energyM(*sn);
                
        for (int i=0; i<25; i++) {
            discreteAttEScore[(int)(roundX(sn->attributes[i])*2-1)][i]+=(*en*(1-temp(k, kmax)));
            discreteAttNum[(int)(roundX(sn->attributes[i])*2-1)][i]+=(1-temp(k, kmax));
        }
        
        if (*en < *eb) {
            *sb = *sn;
            *eb = *en;
            *s = *sn;
            *e = *en;
            
            if (*en < *minE)
                *minE = *en;
            if (*en > *maxE)
                *maxE = *en;

            bestNum++;
            for (int i=0; i<s->ATTN; i++) {
                *outfile << sn->attributes[i] << ",";
            }
            *outfile << *en << "\n";
            
            if (LogBest) {
                for (int i=0; i<s->ATTN; i++) {
                    *outbest << sn->attributes[i] << ",";
                }
                *outbest << *en << "\n";
            }
            
            k++;
        }
        else if (rdm.randomN() < prob(*e, *en, temp(k, kmax))) {
            bla++;
            *s = *sn;
            *e = *en;
            
            if (*en < *minE)
                *minE = *en;
            if (*en > *maxE)
                *maxE = *en;

            bestNum++;
            for (int i=0; i<s->ATTN; i++) {
                *outfile << sn->attributes[i] << ",";
            }
            *outfile << *en << "\n";

            
            k++;
        }
        else
        {
            
            bestNum++;
            for (int i=0; i<s->ATTN; i++) {
                *outfile << sn->attributes[i] << ",";
            }
            *outfile << *en << "\n";
        
            k++;
        }
            
    }
    
    for (int i=0; i<12; i++) {
        for (int j=0; j<25; j++) {
            if(discreteAttNum[i][j]!=0)	discreteAttEScore[i][j]/=discreteAttNum[i][j];
        }
    }
    
    if (log) {
	    cout << "Here is the final output for the unset values:" << endl;
	    for (int i=0; i<25; i++) {
	        if (searchattset[i]==true) {
	            sb->displayAtt(i);
	        }
	    }
	    for (int i=25; i<s->ATTN; i++) {
	        sb->displayAtt(i);
	    }
	    cout << "Final Energy: " << energy(*sb) << endl;
	    cout << "Max Energy: " << *maxE << endl << "Min Energy: " << *minE << endl << "Number of Iterations Executed: " << k << endl;
	    cout << "Non-Optimal Jumps: " << bla << endl;
    }
         
    return bestNum;
}

void tenBinBore(ifstream *infile, ofstream *outfile, double minE, double maxE, bool worst, double bore, int *numBest, int *numRest, int discreteAttBest[][25], int discreteAttRest[][25], int contAttBest[][15], int contAttRest[][15], int recNum, project x) {
    const double zero=0;
    const double one=1;
           
    string sbuff("");
    char cbuff [50];
    
    *infile >> sbuff;
    
    double * energies;
    energies = new double [recNum];
    double borderEnergy;
    double negBorderEnergy;
    
    int count=0;
    while(!infile->eof()) { //This loop is for getting the energies for evaluation using BORE 
        
        for (int i=0; i<x.ATTN; i++) {
            infile->getline(cbuff, 45, ',');
            sbuff.clear();
            sbuff.append(cbuff);
            if (sbuff=="") break;
        }
        
        infile->getline(cbuff, 45);
        sbuff.clear();
        sbuff.append(cbuff);
        if (sbuff=="") break;
        
        double dbuff = atof(sbuff.c_str());
        dbuff = (dbuff-minE)/(maxE-minE); //Normalising energy
        
        energies[count] = dbuff;
        
        count++;
    }
    
    sort(energies, recNum);
    
    int BestBorder = (int)floor(recNum*bore);
    int NegBestBorder = (int)recNum - (int)ceil(recNum*bore);
    
    borderEnergy = energies[BestBorder];
    negBorderEnergy = energies[NegBestBorder];
    
    delete [] energies;
    energies = NULL;
    
    infile->clear();
    infile->seekg(0, ios::beg);
    
    sbuff.clear();
    
    //Copying the first line to the Discrete output file
    *infile >> sbuff;
    *outfile << sbuff << "\n";
    
    while(!infile->eof()) { //This is the discretization and scoring loop
        
        int Att [x.ATTN] = {0};
        
        for (int i=0; i<25; i++) {
            infile->getline(cbuff, 45, ',');
            sbuff.clear();
            sbuff.append(cbuff);
            if (sbuff=="") break;
            
            double dbuff = atof(sbuff.c_str());
            dbuff = roundX(dbuff);
            
            *outfile << dbuff << ",";
            Att[i] = (int)(dbuff*2);
        }
        
        for (int i=25; i<x.ATTN; i++) {
            infile->getline(cbuff, 45, ',');
            sbuff.clear();
            sbuff.append(cbuff);
            if (sbuff=="") break;
            
            double dbuff = atof(sbuff.c_str());
            dbuff = (dbuff-x.attrangeNorm[0][i])/(x.attrangeNorm[1][i]-x.attrangeNorm[0][i]);
            dbuff = ceil(dbuff*10);
            
            *outfile << dbuff << ",";
            Att[i] = (int)dbuff;
        }
        
        infile->getline(cbuff, 45);
        sbuff.clear();
        sbuff.append(cbuff);
        if (sbuff=="") break;
        
        double dbuff = atof(sbuff.c_str());
        dbuff = (dbuff-minE)/(maxE-minE);
        
        if (worst) {
            if (dbuff>negBorderEnergy) {
                *outfile << "1\n";
                *numBest= (*numBest+1);
                for(int i=0; i<25; i++) discreteAttBest [Att[i]-1][i]++;
                for(int i=25; i<x.ATTN; i++) contAttBest [Att[i]-1][i-25]++;
            }
            else {
                *outfile << "0\n";
                *numRest= (*numRest+1);
                for(int i=0; i<25; i++) discreteAttRest [Att[i]-1][i]++;
                for(int i=25; i<x.ATTN; i++) contAttRest [Att[i]-1][i-25]++;
            }
        }
                
        else {
            if (dbuff<borderEnergy) {
                *outfile << one << "\n";
                *numBest= (*numBest+1);
                for(int i=0; i<25; i++) discreteAttBest [Att[i]-1][i]++;
                for(int i=25; i<x.ATTN; i++) contAttBest [Att[i]-1][i-25]++;
            }
            else {
                *outfile << zero << "\n";
                *numRest= (*numRest+1);
                for(int i=0; i<25; i++) discreteAttRest [Att[i]-1][i]++;
                for(int i=25; i<x.ATTN; i++) contAttRest [Att[i]-1][i-25]++;
            }
        }
    }
}

void score(int discreteAttBest[][25], int discreteAttRest[][25], double discreteAttScore[][25], int contAttBest[][15], int contAttRest[][15], double contAttScore[][15], int numBest, int numRest) {
    for(int i=0; i<25; i++) {
        for (int j=0; j<12; j++) {
            double LBest = ((double)discreteAttBest [j][i]/(double)numBest)*((double)numBest/(double)(numBest+numRest));
            double LRest = ((double)discreteAttRest [j][i]/(double)numRest)*((double)numRest/(double)(numBest+numRest));
            if ((LBest+LRest)==0) discreteAttScore [j][i] = 0;
            else discreteAttScore [j][i] = pow(LBest, 2)/(LBest+LRest);
        }
    }
    
   for(int i=0; i<15; i++) {
        for (int j=0; j<10; j++) {
            double LBest = ((double)contAttBest [j][i]/(double)numBest)*((double)numBest/(double)(numBest+numRest));
            double LRest = ((double)contAttRest [j][i]/(double)numRest)*((double)numRest/(double)(numBest+numRest));
            if ((LBest+LRest)==0) contAttScore [j][i] = 0;
            else contAttScore [j][i] = pow(LBest, 2)/(LBest+LRest);
        }
    }
}

void BackSelSim(int attNumUndefined, project sb, project x, bool searchattset[], double discreteAttScore [][25], double contAttScore [][15], ofstream *outfile, randomNum rdm, bool OutRuns, bool LCout, string runspec, bool log) {
    
    int thrownAtt[12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    
    if (log) cout << "Attribute,value,score,sumE,sumE^2,medE,spE,sumEffort,sumEffort^2,medEffort,spEffort,sumDefects,sumDefects^2,medDefects,spDefects,sumThreat,sumThreat^2,medThreat,spThreat,sumMonths,sumMonths^2,medMonths,spMonths\n";
    
    *outfile << "Attribute,value,score,sumE,sumE^2,medE,spE,sumEffort,sumEffort^2,medEffort,spEffort,sumDefects,sumDefects^2,medDefects,spDefects,sumThreat,sumThreat^2,medThreat,spThreat,sumMonths,sumMonths^2,medMonths,spMonths\n";
    
    int numPolicy = 0;
    
    for (int k=0; k<(attNumUndefined*12); k++) {
        
        double minScore = 100000;
        int minAtt;
        int minAttVal;
        
        for (int i=0; i<25; i++) {
	
            for (int j=(int)(roundX(x.attrangeNorm[0][i])*2); j<=(int)(roundX(x.attrangeNorm[1][i])*2); j++) {
            	
        		if (searchattset[i] == true && thrownAtt[j-1][i] == 0 && discreteAttScore [j-1][i] < minScore && discreteAttScore [j-1][i] != 0) {
                    minScore = discreteAttScore [j-1][i];
                    minAtt=i;
                    minAttVal=j-1;
                }
            }
        }
        
        thrownAtt[minAttVal][minAtt] ++;
        
//        if (discreteAttScore [minAttVal][minAtt] == 0) cout << x.displayAttName(minAtt) << "\t" << (double)(minAttVal+1)/2 << endl;
        
        if (discreteAttScore [minAttVal][minAtt] != 0 && thrownAtt[minAttVal][minAtt] == 1) {
            
            numPolicy++;
            ofstream timfile;
            timfile.setf(ios::fixed,ios::floatfield);
            timfile.precision(12);
            
            if (LCout) {
                //Tim Out
                /////////////////////////////////////////////////////
                char c[10];
                sprintf(c, "%i", numPolicy);
                string numc(c);
                
                string htmp(getenv("HOME"));                
                string timLog(htmp + "/STAR/" + runspec + "/LCcomp" + numc);
                timfile.open(timLog.c_str(), ios::app);
                ////////////////////////////////////////////////////
            }
                  
            double avgE = 0;
            double sdE = 0;
            double medianE = 0;
            double spreadE = 0;
            
            double * E;
            E = new double [simNum];
//            double E[simNum] = {0};
            
            double avgEffort = 0;
            double sdEffort = 0;
            double medianEffort = 0;
            double spreadEffort = 0;
            
            double * Effort;
            Effort = new double [simNum];
//            double Effort[simNum] = {0};
            
            double avgDefects = 0;
            double sdDefects = 0;
            double medianDefects = 0;
            double spreadDefects = 0;
            
            double * Defects;
            Defects = new double [simNum];
//            double Defects[simNum] = {0};
            
            double avgThreat = 0;
            double sdThreat = 0;
            double medianThreat = 0;
            double spreadThreat = 0;
            
            double * Threat;
            Threat = new double [simNum];
//            double Threat[simNum] = {0};
            
            double avgMonths = 0;
            double sdMonths = 0;
            double medianMonths = 0;
            double spreadMonths = 0;
            
            double * Months;
            Months = new double [simNum];
//            double Months[simNum] = {0};
            
            for (int simn=0; simn<simNum; simn++) {
                
                if (LCout) {
                    //Tim out
                    ////////////////////////////////////////////////////
                    if (simn == 0) {
                        timfile << x.displayAttName(3);
                        for (int i=4; i<25; i++)
                            timfile << "," << x.displayAttName(i);
                        for (int i=37; i<x.ATTN; i++)
                            timfile << "," << x.displayAttName(i);
                        timfile << ",Effort\n";
                    }
                    /////////////////////////////////////////////////////
                }
                
                project sim = sb; //Starting from the best SA case
                for (int i=0; i<25; i++) {
                    bool allThrown = true;
                    int numNotThrown = 0;
                    double notThrown [12] = {0};
                    
                    for (int j=(int)(roundX(x.attrangeNorm[0][i])*2); j<=(int)(roundX(x.attrangeNorm[1][i])*2); j++) {
                    	if(thrownAtt[j-1][i]==0) {
                        	allThrown = false;
                        	notThrown[numNotThrown]=(double)j/2;
                        	numNotThrown++;
                        }                        	
                    }                  
                
                    if(allThrown) sim.setattnum(i, roundX(rdm.randomGenerateDouble(x.attrangeNorm[0][i], x.attrangeNorm[1][i])));
                    
                    else sim.setattnum(i, notThrown[rdm.randomGenerateInt(0,numNotThrown-1)]);                    
                }
                
                for (int l=25; l<x.ATTN; l++) {
                    sim.setattnum(l, rdm.randomGenerateDouble(x.attrangeNorm[0][l], x.attrangeNorm[1][l]));
                }               
                
                double tmpEffort = sim.effortMutate();
                double tmpDefects = sim.defectsMutate();
                double tmpThreat = sim.threatMutate();
                double tmpMonths = sim.monthsMutate();
                double tmpE = calcEnergy(sim, tmpEffort, tmpDefects, tmpThreat, tmpMonths);
                
                if (LCout) {
                    //Tim Out
                    //////////////////////////////////////////////////////////
                    timfile << sim.getattnumvaleff(1);//getattnum(1);
                    for (int i=2; i<23; i++)
                        timfile << "," << sim.getattnumvaleff(i);//getattnum(i);
                    for (int i=37; i<x.ATTN; i++)
                        timfile << "," << sim.getattnum(i);
                    timfile << "," << sim.effort() << "\n";
                    //////////////////////////////////////////////////////////
                }
                
                avgE += tmpE;
                sdE += tmpE*tmpE;
                E[simn] = tmpE;
                
                avgEffort += tmpEffort;
                sdEffort += tmpEffort*tmpEffort;
                Effort[simn] = tmpEffort;
                
                avgDefects += tmpDefects;
                sdDefects += tmpDefects*tmpDefects;
                Defects[simn] = tmpDefects;
                
                avgThreat += tmpThreat;
                sdThreat += tmpThreat*tmpThreat;
                Threat[simn] = tmpThreat;
                
                avgMonths += tmpMonths;
                sdMonths += tmpMonths*tmpMonths;
                Months[simn] = tmpMonths;
            }
            
            sort(E, simNum);
            sort(Effort, simNum);            
            sort(Defects, simNum);
            sort(Threat, simNum);
            sort(Months, simNum);           
            
            if (OutRuns) {
                char c[10];
                sprintf(c, "%i", k);
                string numc(c);
                
                string htmp(getenv("HOME"));
                string runLog(htmp + "/STAR/" + runspec + "/run" + numc);
                ofstream runfile(runLog.c_str(), ios::out);
                runfile.setf(ios::fixed,ios::floatfield);
                runfile.precision(12);
                
                for (int i=0; i<simNum; i++) {
                    runfile << E[i] << "\t" << Effort[i] << "\t" << Defects[i] << "\t" << Threat[i] << "\t" << Months[i] << "\n";
                }
            }
            
//            avgE = avgE/simNum;
//            sdE = sqrt(fabs((sdE/simNum)-(avgE*avgE)));
            medianE = E[(int)(simNum/2)];
            spreadE = E[(int)(simNum*3/4)]-E[(int)(simNum/2)];
            
//            avgEffort = avgEffort/simNum;
//            sdEffort = sqrt(fabs((sdEffort/simNum)-(avgEffort*avgEffort)));
            medianEffort = Effort[(int)(simNum/2)];
            spreadEffort = Effort[(int)(simNum*3/4)]-Effort[(int)(simNum/2)];
            
//            avgDefects = avgDefects/simNum;
//            sdDefects = sqrt(fabs((sdDefects/simNum)-(avgDefects*avgDefects)));
            medianDefects = Defects[(int)(simNum/2)];
            spreadDefects = Defects[(int)(simNum*3/4)]-Defects[(int)(simNum/2)];
            
//            avgThreat = avgThreat/simNum;
//            sdThreat = sqrt(fabs((sdThreat/simNum)-(avgThreat*avgThreat)));
            medianThreat = Threat[(int)(simNum/2)];
            spreadThreat = Threat[(int)(simNum*3/4)]-Threat[(int)(simNum/2)];
            
//            avgMonths = avgMonths/simNum;
//            sdMonths = sqrt(fabs((sdMonths/simNum)-(avgMonths*avgMonths)));
            medianMonths = Months[(int)(simNum/2)];
            spreadMonths = Months[(int)(simNum*3/4)]-Months[(int)(simNum/2)];
            
            //Output of simulation results
            if (log) {
	            cout << x.displayAttName(minAtt) << ","
	            << (double)(minAttVal+1)/2 << "," << discreteAttScore [minAttVal][minAtt]	<< ","
	            << avgE << "," << sdE << "," << medianE << "," << spreadE << ","
	            << avgEffort << "," << sdEffort << "," << medianEffort << "," << spreadEffort << ","
	            << avgDefects << "," << sdDefects << "," << medianDefects << "," << spreadDefects << ","
	            << avgThreat << "," << sdThreat << "," << medianThreat << "," << spreadThreat << ","
	            << avgMonths << "," << sdMonths << "," << medianMonths << "," << spreadMonths << "\n";
            }
            *outfile << x.displayAttName(minAtt) << ","
            << (double)(minAttVal+1)/2 << "," << discreteAttScore [minAttVal][minAtt]	<< ","
            << avgE << "," << sdE << "," << medianE << "," << spreadE << ","
            << avgEffort << "," << sdEffort << "," << medianEffort << "," << spreadEffort << ","
            << avgDefects << "," << sdDefects << "," << medianDefects << "," << spreadDefects << ","
            << avgThreat << "," << sdThreat << "," << medianThreat << "," << spreadThreat << ","
            << avgMonths << "," << sdMonths << "," << medianMonths << "," << spreadMonths << "\n";
            
            delete [] E;
            E = NULL;
            
            delete [] Effort;
            Effort = NULL;
            
            delete [] Defects;
            Defects = NULL;
            
            delete [] Threat;
            Threat = NULL;
            
            delete [] Months;
            Months = NULL;
        }
    }
}

void EBackSelSim(int attNumUndefined, project sb, project x, bool searchattset[], bool worst, double discreteAttEScore [][25], double contAttScore [][15], ofstream *outfile, randomNum rdm, bool OutRuns, bool LCout, string runspec, bool log) {
    
    int thrownAtt[12][25] = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}};
    
    if (log) {
	    cout << "Energy Ranking:" << endl;
	    cout << "Attribute,value,score,sumE,sumE^2,medE,spE,sumEffort,sumEffort^2,medEffort,spEffort,sumDefects,sumDefects^2,medDefects,spDefects,sumThreat,sumThreat^2,medThreat,spThreat,sumMonths,sumMonths^2,medMonths,spMonths\n";
    }
    
    *outfile << "Attribute,value,score,sumE,sumE^2,medE,spE,sumEffort,sumEffort^2,medEffort,spEffort,sumDefects,sumDefects^2,medDefects,spDefects,sumThreat,sumThreat^2,medThreat,spThreat,sumMonths,sumMonths^2,medMonths,spMonths\n";
    
    int numPolicy = 0;
    
    for (int k=0; k<(attNumUndefined*12); k++) {
        
        double minScore = -1;
        int minAtt;
        int minAttVal;
        
        if (worst) {
            minScore = 100000000;
        }
        
        for (int i=0; i<25; i++) {
            for (int j=(int)roundX(x.attrangeNorm[0][i])*2; j<=(int)roundX(x.attrangeNorm[1][i])*2; j++) {
                if (!worst && searchattset[i] == true && thrownAtt[j-1][i] == 0 && discreteAttEScore [j-1][i] > minScore && discreteAttEScore [j-1][i] != 0) {
                    minScore = discreteAttEScore [j-1][i];
                    minAtt=i;
                    minAttVal=j-1;
                }
                else if (worst && searchattset[i] == true && thrownAtt[j-1][i] == 0 && discreteAttEScore [j-1][i] < minScore && discreteAttEScore [j-1][i] != 0) {
                    minScore = discreteAttEScore [j-1][i];
                    minAtt=i;
                    minAttVal=j-1;
                }
            }
        }
        
        thrownAtt[minAttVal][minAtt] ++;
        
//        if (discreteAttEScore [minAttVal][minAtt] == 0) cout << x.displayAttName(minAtt) << "\t" << (double)(minAttVal+1)/2 << endl;
        
        if (discreteAttEScore [minAttVal][minAtt] != 0 && thrownAtt[minAttVal][minAtt] == 1) {
            
            numPolicy++;
            ofstream timfile;
            timfile.setf(ios::fixed,ios::floatfield);
            timfile.precision(12);
            
            if (LCout) {
                //Tim Out
                /////////////////////////////////////////////////////
                char c[10];
                sprintf(c, "%i", numPolicy);
                string numc(c);
                
                string htmp(getenv("HOME"));                
                string timLog(htmp + "/STAR/" + runspec + "/LCcomp" + numc);
                timfile.open(timLog.c_str(), ios::app);
                ////////////////////////////////////////////////////
            }
            
            double avgE = 0;
            double sdE = 0;
            double medianE = 0;
            double spreadE = 0;
            
            double * E;
            E = new double [simNum];
//            double E[simNum] = {0};
            
            double avgEffort = 0;
            double sdEffort = 0;
            double medianEffort = 0;
            double spreadEffort = 0;
            
            double * Effort;
            Effort = new double [simNum];
//            double Effort[simNum] = {0};
            
            double avgDefects = 0;
            double sdDefects = 0;
            double medianDefects = 0;
            double spreadDefects = 0;
            
            double * Defects;
            Defects = new double [simNum];
//            double Defects[simNum] = {0};
            
            double avgThreat = 0;
            double sdThreat = 0;
            double medianThreat = 0;
            double spreadThreat = 0;
            
            double * Threat;
            Threat = new double [simNum];
//            double Threat[simNum] = {0};
            
            double avgMonths = 0;
            double sdMonths = 0;
            double medianMonths = 0;
            double spreadMonths = 0;
            
            double * Months;
            Months = new double [simNum];
//            double Months[simNum] = {0};
            
            for (int simn=0; simn<simNum; simn++) {
                
                if (LCout) {
                    //Tim out
                    ////////////////////////////////////////////////////
                    if (simn == 0) {
                        timfile << x.displayAttName(3);
                        for (int i=4; i<25; i++)
                            timfile << "," << x.displayAttName(i);
                        for (int i=37; i<x.ATTN; i++)
                            timfile << "," << x.displayAttName(i);
                        timfile << ",Effort\n";
                    }
                    /////////////////////////////////////////////////////
                }
                
                project sim = sb; //Starting from the best SA case
                for (int i=0; i<25; i++) {
                    bool allThrown = true;
                    int numNotThrown = 0;
                    double notThrown [12] = {0};
                    
                    for (int j=(int)(roundX(x.attrangeNorm[0][i])*2); j<=(int)(roundX(x.attrangeNorm[1][i])*2); j++) {
                    	if(thrownAtt[j-1][i]==0) {
                        	allThrown = false;
                        	notThrown[numNotThrown]=(double)j/2;
                        	numNotThrown++;
                        }                        	
                    }                  
                
                    if(allThrown) sim.setattnum(i, roundX(rdm.randomGenerateDouble(x.attrangeNorm[0][i], x.attrangeNorm[1][i])));
                    
                    else sim.setattnum(i, notThrown[rdm.randomGenerateInt(0,numNotThrown-1)]);                    
                }
                
                for (int l=25; l<x.ATTN; l++) {
                    sim.setattnum(l, rdm.randomGenerateDouble(x.attrangeNorm[0][l], x.attrangeNorm[1][l]));
                }
                
                double tmpEffort = sim.effortMutate();
                double tmpDefects = sim.defectsMutate();
                double tmpThreat = sim.threatMutate();
                double tmpMonths = sim.monthsMutate();
                
                double tmpE = calcEnergy(sim, tmpEffort, tmpDefects, tmpThreat, tmpMonths);
                
                if (LCout) {
                    //Tim Out
                    //////////////////////////////////////////////////////////
                    timfile << sim.getattnumvaleff(1);//getattnum(1);
                    for (int i=2; i<23; i++)
                        timfile << "," << sim.getattnumvaleff(i);//getattnum(i);
                    for (int i=37; i<x.ATTN; i++)
                        timfile << "," << sim.getattnum(i);
                    timfile << "," << sim.effort() << "\n";
                    //////////////////////////////////////////////////////////
                }
                
                avgE += tmpE;
                sdE += tmpE*tmpE;
                E[simn] = tmpE;
                
                avgEffort += tmpEffort;
                sdEffort += tmpEffort*tmpEffort;
                Effort[simn] = tmpEffort;
                
                avgDefects += tmpDefects;
                sdDefects += tmpDefects*tmpDefects;
                Defects[simn] = tmpDefects;
                
                avgThreat += tmpThreat;
                sdThreat += tmpThreat*tmpThreat;
                Threat[simn] = tmpThreat;
                
                avgMonths += tmpMonths;
                sdMonths += tmpMonths*tmpMonths;
                Months[simn] = tmpMonths;
            }
            
            sort(E, simNum);
            sort(Effort, simNum);            
            sort(Defects, simNum);
            sort(Threat, simNum);
            sort(Months, simNum);           
            
            if (OutRuns) {
                char c[10];
                sprintf(c, "%i", k);
                string numc(c);
                
                string htmp(getenv("HOME"));
                string runLog(htmp + "/STAR/" + runspec + "/run" + numc);
                ofstream runfile(runLog.c_str(), ios::out);
                runfile.setf(ios::fixed,ios::floatfield);
                runfile.precision(12);
                
                for (int i=0; i<simNum; i++) {
                    runfile << E[i] << "\t" << Effort[i] << "\t" << Defects[i] << "\t" << Threat[i] << "\t" << Months[i] << "\n";
                }
            }
            
//            avgE = avgE/simNum;
//            sdE = sqrt(fabs((sdE/simNum)-(avgE*avgE)));
            medianE = E[(int)(simNum/2)];
            spreadE = E[(int)(simNum*3/4)]-E[(int)(simNum/2)];
            
//            avgEffort = avgEffort/simNum;
//            sdEffort = sqrt(fabs((sdEffort/simNum)-(avgEffort*avgEffort)));
            medianEffort = Effort[(int)(simNum/2)];
            spreadEffort = Effort[(int)(simNum*3/4)]-Effort[(int)(simNum/2)];
            
//            avgDefects = avgDefects/simNum;
//            sdDefects = sqrt(fabs((sdDefects/simNum)-(avgDefects*avgDefects)));
            medianDefects = Defects[(int)(simNum/2)];
            spreadDefects = Defects[(int)(simNum*3/4)]-Defects[(int)(simNum/2)];
            
//            avgThreat = avgThreat/simNum;
//            sdThreat = sqrt(fabs((sdThreat/simNum)-(avgThreat*avgThreat)));
            medianThreat = Threat[(int)(simNum/2)];
            spreadThreat = Threat[(int)(simNum*3/4)]-Threat[(int)(simNum/2)];
            
//            avgMonths = avgMonths/simNum;
//            sdMonths = sqrt(fabs((sdMonths/simNum)-(avgMonths*avgMonths)));
            medianMonths = Months[(int)(simNum/2)];
            spreadMonths = Months[(int)(simNum*3/4)]-Months[(int)(simNum/2)];
            
            //Output of simulation results
            if (log) {
	            cout << x.displayAttName(minAtt) << ","
	            << (double)(minAttVal+1)/2 << "," << discreteAttEScore [minAttVal][minAtt]	<< ","
	            << avgE << "," << sdE << "," << medianE << "," << spreadE << ","
	            << avgEffort << "," << sdEffort << "," << medianEffort << "," << spreadEffort << ","
	            << avgDefects << "," << sdDefects << "," << medianDefects << "," << spreadDefects << ","
	            << avgThreat << "," << sdThreat << "," << medianThreat << "," << spreadThreat << ","
	            << avgMonths << "," << sdMonths << "," << medianMonths << "," << spreadMonths <<"\n";
            }
            
            *outfile << x.displayAttName(minAtt) << ","
            << (double)(minAttVal+1)/2 << "," << discreteAttEScore [minAttVal][minAtt]	<< ","
            << avgE << "," << sdE << "," << medianE << "," << spreadE << ","
            << avgEffort << "," << sdEffort << "," << medianEffort << "," << spreadEffort << ","
            << avgDefects << "," << sdDefects << "," << medianDefects << "," << spreadDefects << ","
            << avgThreat << "," << sdThreat << "," << medianThreat << "," << spreadThreat << ","
            << avgMonths << "," << sdMonths << "," << medianMonths << "," << spreadMonths <<"\n";
            
            delete [] E;
            E = NULL;
            
            delete [] Effort;
            Effort = NULL;
            
            delete [] Defects;
            Defects = NULL;
            
            delete [] Threat;
            Threat = NULL;
            
            delete [] Months;
            Months = NULL;
        }
    }
}

string itos(int i)	// convert int to string
{
	stringstream s;
	s << i;
	return s.str();
}

string dtos(double d)	// convert double to string
{
	stringstream s;
	s.setf(ios::fixed,ios::floatfield);
	s.precision(12);
	s << d;
	return s.str();
}

double roundX(double num)
{
	double decimal = num - (int)num;
	
	if (decimal < 0.25) num = (int)num;
	else if (decimal >= 0.25 && decimal < 0.75) num = (int)num + 0.5;
	else num = (int)num + 1;
	
	return num;
}
