Katzlab dd76ab1d12 Added PTL2 Scripts
These are PTL2 files from Auden 2/9
2023-02-14 11:20:52 -05:00

263 lines
9.4 KiB
C++

#include "optGammaMixtureLS.h"
#include "likelihoodComputation.h"
#include "numRec.h"
//#include "optimizer.h"
//#include "NRconjugateGradient.h"
#include <fstream>
#include <algorithm>
#include <ctime>
using namespace std;
using namespace likelihoodComputation;
optGammaMixtureLS::optGammaMixtureLS(stochasticProcess* pSp, const sequenceContainer& sc, const tree& inTree, MDOUBLE upperBoundAlpha/*=15.0*/, MDOUBLE upperBoundBeta/*=15.0*/,unObservableData* unObservableData_p)
{
_pSc = &sc;
_pTree = &inTree;
_pSp = pSp;
_upperBoundAlpha = upperBoundAlpha;
_upperBoundBeta = upperBoundBeta;
_unObservableData_p = unObservableData_p;
}
optGammaMixtureLS::~optGammaMixtureLS()
{
}
MDOUBLE optGammaMixtureLS::optimizeParam(const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights, optAlg optType)
{
mixtureDistribution * pMixture = static_cast<mixtureDistribution*>(_pSp->distr());
return optimizeParam(pMixture, maxIterations, tol, pWeights, optType);
}
MDOUBLE optGammaMixtureLS::optimizeParam(mixtureDistribution * pMixture, const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights, optAlg optType)
{
switch (optType)
{
case ONE_DIM:
return optimizeParamOneDim(pMixture, maxIterations, tol, pWeights);
break;
//case POWELL:
// return optimizeParamPowell(pMixture, maxIterations, tol, pWeights, pOutF);
// break;
//case CONJUGATE_DERIVATIVES:
// return optimizeParamConjugateDeriv(pMixture, maxIterations, tol, pWeights, pOutF);
// break;
default:
errorMsg::reportError("unknown optimization algorithm in optGammaMixtureLS::optimizeParam()");
return -1;
}
}
//this function finds the best mixture param using a line search maximization. Each time only one parameter is optimized using the regular brent algorithm.
//CAN BE USED FOR 2 COMPONENTS ONLY (the maximization on components probabilities maximize only P1, the prob of the first component, while the prob of the second is set to 1-P1)
// ...Note: if more than 2 components, all the others are scaled by P1
//total there are 5 parameters to optimize: alpha1, beta1, alpha2, beta2, and P1
MDOUBLE optGammaMixtureLS::optimizeParamOneDim(mixtureDistribution * pMixture, const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights)
{
MDOUBLE lowerBound = 0.0;
MDOUBLE newL = VERYSMALL; //newL is the LL after a single param optimization.
//MDOUBLE curL = VERYSMALL; //the current LL.
MDOUBLE curL = likelihoodComputation::getTreeLikelihoodAllPosAlphTheSame(*_pTree,*_pSc,*_pSp,pWeights,_unObservableData_p); //the current LL.
MDOUBLE prevIterL = VERYSMALL; //The LL of the previous iteration. the loop quit if the increase in LL between iterations is smaller than tol
MDOUBLE bestA=0, bestB=0, bestW = 0;
for (int it = 0; it < maxIterations; ++it)
{
//prevIterL = newL;
prevIterL = curL;
for (int comp = 0; comp < pMixture->getComponentsNum(); ++comp)
{
//optimize alpha
MDOUBLE oldAlpha = pMixture->getAlpha(comp);
newL = -brent(lowerBound,oldAlpha, _upperBoundAlpha, C_evalAlphaMixture(*_pTree,*_pSc,_pSp,comp,pWeights,_unObservableData_p), tol, &bestA);
if (newL < curL)
{
//the Likelihood wend down
pMixture->setAlpha(oldAlpha, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
LOG(5, <<"likelihood went down in optGammaMixtureLS::optimizeParam()"<<endl<<"old L= "<<curL<<" newL = "<<newL<<endl);
}
else
{
pMixture->setAlpha(bestA, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
curL = newL;
LOG(7, <<"iteration: "<<it<<" Optimize alpha comp"<<comp<<" new Likelihood = "<<curL<<endl);
}
//optimize beta
MDOUBLE oldBeta = pMixture->getBeta(comp);
newL = -brent(lowerBound,oldBeta,_upperBoundBeta, C_evalBetaMixture(*_pTree,*_pSc,_pSp,comp,pWeights,_unObservableData_p), tol, &bestB);
if (newL < curL)
{
//the Likelihood wend down
pMixture->setBeta(oldBeta, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
LOG(5, <<"likelihood went down in optGammaMixtureLS::optimizeParam()"<<endl<<"old L= "<<curL<<" newL = "<<newL<<endl);
}
else
{
pMixture->setBeta(bestB, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
curL = newL;
LOG(7, <<"iteration: "<<it<<" Optimize beta comp"<<comp<<" new Likelihood = "<<curL<<endl);
}
//optimize components probability.
if (pMixture->getComponentsNum() == 1)
continue;
MDOUBLE upperBound = 0.0;
MDOUBLE lowerBound = 1.0;
MDOUBLE oldWeight = pMixture->getComponentWeight(comp);
newL = -brent(lowerBound, oldWeight, upperBound, C_evalProbMixture(*_pTree,*_pSc, _pSp, comp, pWeights), tol, &bestW);
if (newL < curL)
{
//the Likelihood wend down
pMixture->setComponentWeight(oldWeight, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
LOG(5, <<"likelihood went down in optGammaMixtureLS::optimizeParam()"<<endl<<"old L= "<<curL<<" newL = "<<newL<<endl);
}
else
{
pMixture->setComponentWeight(bestW, comp);
if(_unObservableData_p){
_unObservableData_p->setLforMissingData(*_pTree,_pSp);
}
curL = newL;
LOG(7, <<"iteration: "<<it<<" Optimize Prob"<<" new Likelihood = "<<curL<<endl);
}
}
pMixture->normalizeProbabilities(); // why again ???
printIter(pMixture, it, curL);
if (curL < prevIterL + tol){
//if(_unObservableData_p){
// _unObservableData_p->setLforMissingData(*_pTree,_pSp);
//}
return max(curL,prevIterL); // not to reduce likelihood
}
}
return curL;
}
/*
//this function uses a line search maximization. The difference is that it does not use the naive method (optimize each parameter seperatly untill convergence)
//but uses Powel's quadratically convergent method (Numerical Recipes pp 420).
//CAN BE USED FOR 2 COMPONENTS ONLY (the maximization on components probabilities maximize only P1, the prob of the first component, while the prob of the second is set to 1-P1)
//total there are 5 parameters to optimize: alpha1, beta1, alpha2, beta2, and P1
MDOUBLE optGammaMixtureLS::optimizeParamPowell(mixtureDistribution* pMixture, const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights, ofstream* pOutF)
{
if (pMixture->getComponentsNum() == 1)
return optimizeParam1CompPowel(pMixture, maxIterations, tol, pWeights, pOutF);
else return optimizeParamManyCompPowel(pMixture, maxIterations, tol, pWeights, pOutF);
}
MDOUBLE optGammaMixtureLS::optimizeParam1CompPowel(mixtureDistribution * pMixture, const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights, ofstream* pOutF)
{
tree tree1(*_pTree);
sequenceContainer sc1(*_pSc);
C_evalGammaMixture optPowell(&tree1, &sc1, _pSp, NULL);
optimizer<C_evalGammaMixture> opt(optPowell);
Vdouble param(2);
param[0] = pMixture->getAlpha(0);
param[1] = pMixture->getBeta(0);
MDOUBLE res = opt.findmin(param);
return res;
}
MDOUBLE optGammaMixtureLS::optimizeParamManyCompPowel(mixtureDistribution * pMixture, const int maxIterations, const MDOUBLE tol, const Vdouble * pWeights, ofstream* pOutF)
{
tree tree1(*_pTree);
sequenceContainer sc1(*_pSc);
Vdouble param(pMixture->getComponentsNum() * 3 - 1);
int paramNum = 0;
for (int comp = 0; comp < pMixture->getComponentsNum(); ++comp)
{
param[paramNum++] = pMixture->getAlpha(comp);
param[paramNum++] = pMixture->getBeta(comp);
param[paramNum++] = pMixture->getComponentWeight(comp);
}
C_evalGammaMixture optPowell(&tree1, &sc1, _pSp, NULL);
optimizer<C_evalGammaMixture> opt(optPowell);
MDOUBLE res = opt.findmin(param);
cerr <<"optimized Powell result = "<< res<<endl;
return res;
}
*/
/*
MDOUBLE optGammaMixtureLS::optimizeParamConjugateDeriv(
mixtureDistribution * pMixture, const int maxIterations,
const MDOUBLE tol, const Vdouble * pWeights, ofstream* pOutF)
{
tree tree1(*_pTree);
sequenceContainer sc1(*_pSc);
Vdouble param(pMixture->getComponentsNum() * 3);
int paramNum = 0;
int comp;
for (comp = 0; comp < pMixture->getComponentsNum(); ++comp)
{
param[paramNum++] = pMixture->getAlpha(comp);
param[paramNum++] = pMixture->getBeta(comp);
param[paramNum++] = pMixture->getComponentWeight(comp);
}
C_evalGammaMixture func(&tree1, &sc1, _pSp, pWeights);
NRconjugateGradient<C_evalGammaMixture> opt;
if (pOutF != NULL)
{
*pOutF <<endl<<endl<<"starting NRconjugateGradient optimization..."<<endl;
printIter(pMixture, 0, 0.0, pOutF);
}
MDOUBLE res = opt.findmin(param, &func, tol);
paramNum = 0;
for (comp = 0; comp < pMixture->getComponentsNum(); ++comp)
{
pMixture->setAlpha(param[paramNum++], comp);
pMixture->setBeta(param[paramNum++], comp);
pMixture->setComponentWeight(param[paramNum++], comp);
}
pMixture->normalizeProbabilities();
if (pOutF != NULL)
{
*pOutF <<endl<<endl<<"after NRconjugateGradient optimization"<<endl;
printIter(pMixture, 0, res, pOutF);
}
cerr <<"optimized Conjugate Deriv result = "<< res<<endl;
return res;
}
*/
void optGammaMixtureLS::printIter(const mixtureDistribution * pMixture, const int it, const MDOUBLE curL)
{
LOG(4,<< "iter " << it <<": cur likelihood= " << curL <<endl);
for (int k = 0; k < pMixture->getComponentsNum(); ++k)
{
LOG(4, << "comp="<<k<<" Alp/Beta= "<<pMixture->getAlpha(k)/pMixture->getBeta(k)<<" alpha= "<<pMixture->getAlpha(k) << " beta= " <<pMixture->getBeta(k)<<" Prob= "<<pMixture->getComponentProb(k)<<endl);
}
}