#include "computeJumps.h"
	//runComputation: Use Suchard equations to compute expectation - good only for {0,1}
	void runComputation(const MDOUBLE Lambda1, const MDOUBLE Lambda2);


//runComputation: Use suchard equations to compute expectation - good only for {0,1}
void simulateJumps::runComputation(const MDOUBLE Lambda1, const MDOUBLE Lambda2)
{
	computeJumps computeJumpsObj(Lambda1,Lambda2);
	
	//MDOUBLE prob01 = 0.0039;
	//MDOUBLE prob02 = 0.9961;
	//MDOUBLE branchLength = 0.1;
	//MDOUBLE	gainExp = computeJumpsObj.gainExp(branchLength,prob01,prob02);
	//LOGnOUT(4,<< "gainExp with branchLength="<<branchLength<<" prob01="<<prob01<<" prob02="<<prob02<<" -> "<< gainExp <<endl);

}



Command line:
"D:\My Documents\TAU.BU\HGT\gainLossCode\gainLoss\test\params.txt"
-s "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\seqsABC.txt"  -dl
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName_noGaps.55.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.55.ph" -dl -di
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName_noGaps.55.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.55.ph" -dl -di -xh
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName_noGaps.55.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.55.ph"
-s "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\seqsABC.txt" -t "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\treeABC.ph" -bg -ct
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName_noGaps.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.ph" -bn -ct -v 6 -e 0.05 -dl
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_fullName.ph"
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -l "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_release\log.txt" -o "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_release\gainLoss.res" -y "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_release\gainLossOrig.res"
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -l "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_debug\log.txt" -o "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_debug\gainLoss.res" -y "D:\My Documents\TAU.BU\HGT\COG_BBL_prints_debug\gainLossOrig.res"
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -l "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.randSeedsAndBBL_Run06\log.txt" -o "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.randSeedsAndBBL_Run06\gainLoss.res" -y "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.randSeedsAndBBL_Run06\gainLossOrig.res"
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -l "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.Baysian_Run01\log.txt" -o "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.Baysian_Run01\gainLoss.res" -y "D:\My Documents\TAU.BU\HGT\COG_gamma_mlAndAlphaBBL.Baysian_Run01\gainLossOrig.res"
-s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -l "D:\My Documents\TAU.BU\HGT\COG_BBL_Model_sep\log.txt" -o "D:\My Documents\TAU.BU\HGT\COG_BBL_Model_sep\gainLoss.res" -y "D:\My Documents\TAU.BU\HGT\COG_BBL_Model_sep\gainLossOrig.res"
-s "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\seqsABC.txt" -t "D:\My Documents\pupkoSVN\programs\gainLoss\test\treeABC.ph"  

-s "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\seqsABC.txt" -t "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\treeABC.ph" -o "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\output.txt"
-n -s "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.fa" -t  "D:\My Documents\TAU.BU\HGT\seqs_COG_abrrev.ph" -o "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\outputALL.txt" 
-s "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\seqsABC.txt" -t "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\test\treeABC.ph" -d -n

Command line: rate4site
-s "D:\My Documents\Temp\seqs.fa" -t "D:\My Documents\Temp\tree.ph" -o "D:\My Documents\Temp\r4s.out" -Mj
-s "D:\My Documents\TAU.BU\DrugResistance\apv\CoMapLatest\Sequences\apv.coded.partial.fa" -t "D:\My Documents\TAU.BU\DrugResistance\apv\CoMapLatest\Phylogeny\apv.coded.tree"  -o "D:\My Documents\pupkoSVN\trunk\programs\gainLoss\R4S\r4s.out" -Mj

/********************************************************************************************
*********************************************************************************************/
//void gainLoss::optimizationsManyStartsNoVec(const MDOUBLE epsilonOptimization, const int numIterations){
//	stochasticProcess* bestSp = _sp->clone();
//	tree bestTr = _tr;
//	cout<<"_tr at: "<<&_tr<<endl;
//	cout<<"_sp at: "<<_sp<<endl;
//	cout<<"bestTr at: "<<&bestTr<<endl;
//	cout<<"bestSp at: "<<bestSp<<endl;
//	MDOUBLE bestL = VERYSMALL;
//	int bestModel = 0;
//
//	for(int i=0; i<gainLossOptions::_numberOfRandPointsInOptimization; ++i){
//		LOGnOUT(4,<<"-------startOptimization "<<i<<endl);
//		gainLossOptimizer glOpt(_tr,_sp,_sc,epsilonOptimization,numIterations,epsilonOptimization,numIterations,epsilonOptimization,numIterations);
//		glOpt.getBestL();
//		if(glOpt.getBestL()>bestL){
//			bestModel = i;
//			bestTr = glOpt.getOptTree();
//			bestSp = _sp;
//		}
//		LOGnOUT(4,<<"-------L= "<<glOpt.getBestL()<<endl);
//	}
//	_sp = bestSp;
//	_tr = bestTr;
//	cout<<"_tr at: "<<&_tr<<endl;
//	cout<<"_sp at: "<<_sp<<endl;
//}


// converting Q into doubleRep format
// printing the input Q matrix
//cout<<"Q[0][0]="<<convert(_Q[0][0])<<" ";
//cout<<"Q[0][1]="<<convert(_Q[0][1])<<" ";
//cout<<"Q[1][0]="<<convert(_Q[1][0])<<" ";
//cout<<"Q[1][1]="<<convert(_Q[1][1])<<" "<<endl;

//debug: print matrix for 2x2
//cout<<"M[0][0]="<<convert(Pt[0][0])<<" ";
//cout<<"M[0][1]="<<convert(Pt[0][1])<<" ";
//cout<<"M[1][0]="<<convert(Pt[1][0])<<" ";
//cout<<"M[1][1]="<<convert(Pt[1][1])<<" "<<endl;

//DEBUG - reverse m1 and m2 
//static_cast<gainLossModelNonReversible*>((*_sp).getPijAccelerator()->getReplacementModel())->setMu1(bestM2);
//static_cast<gainLossModelNonReversible*>((*_sp).getPijAccelerator()->getReplacementModel())->setMu2(bestM1);
//res = likelihoodComputation::getTreeLikelihoodAllPosAlphTheSame(_tr,_sc,*_sp,NULL,_isReverible);


/********************************************************************************************
run
*********************************************************************************************/
void gainLoss::run(){
	MDOUBLE res = likelihoodComputation::getTreeLikelihoodAllPosAlphTheSame(_tr,_sc,*_sp,0,_isReverible);
	cout<<"The Tree Likelihood AllPosAlphTheSame  is "<<res<<endl;	
	optimizeParameters();
	printPij_t();	
}

/********************************************************************************************
initialize
*********************************************************************************************/
void gainLoss::initialize(int argc, char* argv[]) {
	string inputTree; 
	_rootAt = "";
	_isReverible = false;
	for (int ix = 0; ix < argc; ix++) {
		char *pchar=argv[ix];
		switch (pchar[0]) {
		case '-':
			switch (pchar[1]) {
			case 'h':
				cout <<"USAGE:	"<<argv[0]<<" [-options] "<<endl <<endl;
				cout <<"+----------------------------------------------+"<<endl;
				cout <<"|-t    input treeFile                          |"<<endl;
				cout <<"|-s    input seqsFile (must be same names as treeFile!|"<<endl;
				cout <<"|-l    logFile				                   |"<<endl;
				cout <<"|-o    output file					           |"<<endl;
				cout <<"|-r    root at (input the name of the node)    |"<<endl;
				cout <<"|-n    The replacement model is non reversible  |"<<endl;
				cout <<"|----------------------------------------------|"<<endl;
				cout <<"|-h or -? or -H     help                       |"<<endl;
				cout <<"|capital and lowercase letters are ok          |"<<endl;
				cout <<"+----------------------------------------------+"<<endl;
			cout<<endl;	cerr<<" please press 0 to exit "; int d; cin>>d;exit (0);
			case 'l':
				_logFile=argv[++ix];
				break;
			case 'o':
				_outPutFile=argv[++ix];
				break;
			case 'r':
				_rootAt=argv[++ix];
				break;
			case 's':
				_seqsFile=argv[++ix];
				break;
			case 't':
				inputTree=argv[++ix];
				break;
			case 'n':
				_isReverible=false;
				break;
			}
		}
	}
	tree t(inputTree);
	_tr = t;
	if (!(_rootAt =="")){
		tree::nodeP myroot = _tr.findNodeByName(_rootAt); //returns NULL if not found
		if (myroot){
			_tr.rootAt(myroot);
			cout<<"tree rooted at "<<myroot->name()<<endl;
			cout<<"sons of root are "<<_tr.getRoot()->getSon(0)->name()<<" , "<<_tr.getRoot()->getSon(1)->name()<<" , "<<_tr.getRoot()->getSon(2)->name()<<endl;
			return;
		}
	}
	cout<<"default rooting used, root name is "<<_tr.getRoot()->name()<<endl;
	cout<<"sons of root are "<<_tr.getRoot()->getSon(0)->name()<<" , "<<_tr.getRoot()->getSon(1)->name()<<endl;
}

/********************************************************************************************
startingBranchLengthsAndAlpha
*********************************************************************************************/
void gainLoss::startingBranchLengthsAndAlpha(){
	int maxBBLIterations = 5;
	int maxTotalAlphaBBLIterations = 3;
	MDOUBLE epsilonForBBL= 0.1;
	MDOUBLE epsilonForAlpha= 0.1;
	MDOUBLE upperBoundAlpha = 5.0;
	MDOUBLE intitalAlpha = upperBoundAlpha * 0.3;
	
	bestAlphaAndBBL bbl1(_tr, _sc, *_sp, NULL, intitalAlpha, upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
}

/********************************************************************************************
optimizeBranchLengths
*********************************************************************************************/
void gainLoss::optimizeBranchLengths(MDOUBLE epsilonOptimization){
	time_t ltime1;
	time( &ltime1 );
	LOGnOUT(LOGLEVEL,<<" #################### get Starting Branch Lengths #################### "<<endl);
	int maxBBLIterations = 5;
	int maxTotalAlphaBBLIterations = 2;
	MDOUBLE epsilonForBBL= epsilonOptimization;
	MDOUBLE epsilonForAlpha= epsilonOptimization;
	MDOUBLE upperBoundAlpha = 10.0;
	MDOUBLE intitalAlpha = static_cast<gammaDistribution*>((*_sp).distr())->getAlpha();
	
	if (gainLossOptions::_rateEstimationMethod == gainLossOptions::mlRate) {
		if (gainLossOptions::_optimizeBranchLengths == gainLossOptions::noBBL) {
			return;
		} else if (gainLossOptions::_optimizeBranchLengths == gainLossOptions::mlBBLUniform) {
			bblEM bblEM1(_tr, _sc, *_sp, NULL, maxBBLIterations , epsilonForBBL, epsilonForBBL);
		} else {
			// Here we want to optimize branch lengths with a gamma model,
			// but sp is with a inhomogeneous model. Hence, we have to create a local
			// copy of a gamma stochastic process.
			if (gainLossOptions::_userInputAlpha != 0) intitalAlpha = gainLossOptions::_userInputAlpha;
			gammaDistribution localDist(intitalAlpha,gainLossOptions::_numberOfRateCategories);
			stochasticProcess localSP(&localDist,_sp->getPijAccelerator());
			if (gainLossOptions::_userInputAlpha == 0) {
				// in this case we have to optimize both the alpha and the branch lengths
				bestAlphaAndBBL bbl1(_tr, _sc, localSP, NULL, intitalAlpha, upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
			} else {
				// in this case we know the alpa, and we want to just optimize branch lengths with this alpha
				bestAlphaAndBBL bbl(_tr, _sc, localSP, NULL, intitalAlpha, upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
			}
		}
	} else { // method for inference is Bayesian
		if (gainLossOptions::_optimizeBranchLengths == gainLossOptions::noBBL) {
			//FIND BEST ALPHA, AND RETURN WITHOUT CHANING THE TREE
			if (gainLossOptions::_userInputAlpha == 0){
				bestAlphaFixedTree bbl2(_tr, _sc, *_sp, NULL, upperBoundAlpha, epsilonForAlpha);
			} else {// in this case we just want to set the alpha to the right one
				static_cast<gammaDistribution*>(_sp->distr())->setAlpha(gainLossOptions::_userInputAlpha);
			}
		} else if (gainLossOptions::_optimizeBranchLengths == gainLossOptions::mlBBLUniform) {
			//FIND TREE WITHOUT ALPHA with an homogenoues model. Update
			uniDistribution lUni;
			const pijAccelerator* lpijAcc = _sp->getPijAccelerator();// note this is just a copy of the pointer.
			stochasticProcess lsp(&lUni,lpijAcc);
			bestAlphaAndBBL bbl(_tr, _sc, lsp, NULL, intitalAlpha,  upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
			//THEN FIND ALPHA WITHOUT OPT TREE
			if (gainLossOptions::_userInputAlpha == 0){
				bestAlphaFixedTree bbl3(_tr,_sc,*_sp, NULL, upperBoundAlpha, epsilonForAlpha);
			} else {
				static_cast<gammaDistribution*>(_sp->distr())->setAlpha(gainLossOptions::_userInputAlpha);
			}
		} else {
			//ML OPT WITH GAMMA
			if (gainLossOptions::_userInputAlpha == 0){
				bestAlphaAndBBL bbl1(_tr, _sc, *_sp, NULL, intitalAlpha, upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
			} else {// alpha is known
				static_cast<gammaDistribution*>(_sp->distr())->setAlpha(gainLossOptions::_userInputAlpha);
				bestAlphaAndBBL bbl1(_tr, _sc, *_sp, NULL, intitalAlpha, upperBoundAlpha, epsilonForAlpha, epsilonForBBL, maxBBLIterations, maxTotalAlphaBBLIterations);
			}
		}
	}
	LOGnOUT(LOGLEVEL,<<" #################### After Branch Lengths And Alpha #################### "<<endl);
	time_t ltime2;
	time( &ltime2 );
	int t = static_cast<long>(ltime2 - ltime1);
	//timingsF<<"time for alpha and branch lengths optimization = "<<t<<endl;	
}

/********************************************************************************************
bestAlphaFixedTree
*********************************************************************************************/
//MDOUBLE*  optimizeGainLossModel::startingBestAlphaFixedTree(tree& tr,sequenceContainer& sc,stochasticProcess& sp){
//	MDOUBLE epsilonForAlpha= 0.01;
//	MDOUBLE upperBoundAlpha = upperValueOfParam;
//	MDOUBLE intitalAlpha = upperBoundAlpha * 0.3;
//	Vdouble* weights = 0;
//
//	bestAlphaFixedTree bAlpha(tr,sc,sp,weights,upperBoundAlpha,epsilonForAlpha);
//	
//	MDOUBLE bestAlphaAndL[] = {bAlpha.getBestAlpha(), bAlpha.getBestL()};
//	return bestAlphaAndL;	//cause a warning "returning address of local variable or temporary"
//
//}


	//MDOUBLE currM1 = talRandom::giveRandomNumberBetweenTwoPoints(lowerValueOfParam, upperValueOfParam); 
	//MDOUBLE currM2 = talRandom::giveRandomNumberBetweenTwoPoints(lowerValueOfParam, upperValueOfParam); 
	//MDOUBLE currAlpha = talRandom::giveRandomNumberBetweenTwoPoints(lowerValueOfParam, upperValueOfParam);	


/********************************************************************************************
*********************************************************************************************/
void printTreeStatesAsBPValues(ostream &out, Vint &states, tree &tr, 
							   VVVdouble *probs,bool printGains) {
								   printTreeStatesAsBPValues(out,states, tr.getRoot(), probs);
								   out<<"["<<states[(tr.getRoot())->id()]<<"];";
								   //out<<"["<<(tr.getRoot())->name()<<"];";
							   }
void printTreeStatesAsBPValues(ostream &out, Vint &states, const tree::nodeP &myNode, 
							   VVVdouble *probs,bool printGains)  {
	if (myNode->isLeaf()) {
		out << myNode->name()<< ":"<<myNode->dis2father();
		return;
	} else {
		out <<"(";
		for (int i=0;i<myNode->getNumberOfSons();++i) {
			if (i>0) out <<",";
			printTreeStatesAsBPValues(out,states,myNode->getSon(i),probs);
		}
		out <<")";
		if (myNode->isRoot()==false) {
			//out<<states[myNode->id()]<<"--";
			//out<<myNode->name();
			out.precision(3);
			if (probs){
				if (printGains)
					out<<(*probs)[myNode->id()][0][1]; 
				else //print losses
					out<<(*probs)[myNode->id()][1][0]; 
			}
			out << "["<<myNode->name()<<"]"; 
			out<<":"<<myNode->dis2father();
		}
	}
}

/********************************************************************************************
*********************************************************************************************/
void computeEB_EXP_siteSpecificGL_zero(Vdouble & GainLossV,
								  Vdouble & stdV,
								  Vdouble & lowerBoundV,
								  Vdouble & upperBoundV,
								  VVdouble & posteriorsV,
								  const sequenceContainer& sc,
								  const vector<vector<stochasticProcess*> >& spVVec,
								  const tree& tr,
								  const distribution * gainDist,
								  const distribution * lossDist,
								  const distribution * distPrim,
								  const MDOUBLE alphaConf)
{
	LOG(5,<<"Calculating posterior and expectation of posterior values for all sites Under 'Zero' assignment for non-computed value"<<endl);
	
	vector<vector<stochasticProcess*> > spVVecZero;
	spVVecZero.resize(gainDist->categories());
	for (int gainCategor=0; gainCategor<gainDist->categories(); gainCategor++){
		spVVecZero[gainCategor].resize(lossDist->categories());
		for (int lossCategor=0; lossCategor<lossDist->categories(); lossCategor++){		
			spVVecZero[gainCategor][lossCategor] = spVVec[gainCategor][lossCategor]->clone();
			if(distPrim == gainDist){
				static_cast<gainLossModelNonReversible*>((*spVVecZero[gainCategor][lossCategor]).getPijAccelerator()->getReplacementModel())->setMu2(0.0) ;
			}
			else{
				static_cast<gainLossModel*>((*spVVecZero[gainCategor][lossCategor]).getPijAccelerator()->getReplacementModel())->setMu1(0.0,gainLossOptions::_isReversible) ;
			}

		}
	}	
	
	int seqLen = sc.seqLen();
	GainLossV.resize(seqLen);
	stdV.resize(seqLen);
	lowerBoundV.resize(seqLen);
	upperBoundV.resize(seqLen);	
	int numOfSPs = gainDist->categories()*lossDist->categories();
	resizeMatrix(posteriorsV,seqLen,numOfSPs);
	//computePijGam cpg;
	//cpg._V.resize(numOfSPs);
	//for (int i=0; i < numOfSPs; ++i) {
	//	int gainIndex =fromIndex2gainIndex(i,gainDist->categories(),lossDist->categories());
	//	int lossIndex =fromIndex2lossIndex(i,gainDist->categories(),lossDist->categories());
	//	cpg._V[i].fillPij(tr,*spVVec[gainIndex][lossIndex]);
	//}
	for (int pos=0; pos < sc.seqLen(); ++pos) {
		computeEB_EXP_siteSpecificGL(pos, sc, spVVecZero, tr, gainDist,lossDist,distPrim,posteriorsV[pos],	//cpg
			GainLossV[pos], stdV[pos], lowerBoundV[pos], upperBoundV[pos], alphaConf);
	}
}