bpp-core  2.2.0
RescaledHmmLikelihood.cpp
Go to the documentation of this file.
1 //
2 // File: RescaledHmmLikelihood.cpp
3 // Created by: Julien Dutheil
4 // Created on: Fri Oct 26 11:57 2007
5 //
6 
7 /*
8 Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
9 
10 This software is a computer program whose purpose is to provide classes
11 for phylogenetic data analysis.
12 
13 This software is governed by the CeCILL license under French law and
14 abiding by the rules of distribution of free software. You can use,
15 modify and/ or redistribute the software under the terms of the CeCILL
16 license as circulated by CEA, CNRS and INRIA at the following URL
17 "http://www.cecill.info".
18 
19 As a counterpart to the access to the source code and rights to copy,
20 modify and redistribute granted by the license, users are provided only
21 with a limited warranty and the software's author, the holder of the
22 economic rights, and the successive licensors have only limited
23 liability.
24 
25 In this respect, the user's attention is drawn to the risks associated
26 with loading, using, modifying and/or developing or reproducing the
27 software by the user in light of its specific status of free software,
28 that may mean that it is complicated to manipulate, and that also
29 therefore means that it is reserved for developers and experienced
30 professionals having in-depth computer knowledge. Users are therefore
31 encouraged to load and test the software's suitability as regards their
32 requirements in conditions enabling the security of their systems and/or
33 data to be ensured and, more generally, to use and operate it in the
34 same conditions as regards security.
35 
36 The fact that you are presently reading this means that you have had
37 knowledge of the CeCILL license and that you accept its terms.
38 */
39 
40 #include "RescaledHmmLikelihood.h"
41 
42 #include "../../App/ApplicationTools.h"
43 
44 // from the STL:
45 #include <iostream>
46 #include <algorithm>
47 using namespace bpp;
48 using namespace std;
49 
51  HmmStateAlphabet* hiddenAlphabet,
52  HmmTransitionMatrix* transitionMatrix,
53  HmmEmissionProbabilities* emissionProbabilities,
54  const std::string& prefix) throw (Exception):
56  AbstractParametrizable(prefix),
57  hiddenAlphabet_(hiddenAlphabet),
58  transitionMatrix_(transitionMatrix),
59  emissionProbabilities_(emissionProbabilities),
60  likelihood_(),
61  dLikelihood_(),
62  d2Likelihood_(),
63  backLikelihood_(),
64  backLikelihoodUpToDate_(false),
65  scales_(),
66  dScales_(),
67  d2Scales_(),
68  logLik_(),
69  breakPoints_(),
70  nbStates_(),
71  nbSites_()
72 {
73  if (!hiddenAlphabet) throw Exception("RescaledHmmLikelihood: null pointer passed for HmmStateAlphabet.");
74  if (!transitionMatrix) throw Exception("RescaledHmmLikelihood: null pointer passed for HmmTransitionMatrix.");
75  if (!emissionProbabilities) throw Exception("RescaledHmmLikelihood: null pointer passed for HmmEmissionProbabilities.");
76  if (!hiddenAlphabet_->worksWith(transitionMatrix->getHmmStateAlphabet()))
77  throw Exception("RescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
78  if (!hiddenAlphabet_->worksWith(emissionProbabilities->getHmmStateAlphabet()))
79  throw Exception("RescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
80  nbStates_ = hiddenAlphabet_->getNumberOfStates();
81  nbSites_ = emissionProbabilities_->getNumberOfPositions();
82 
83  //Manage parameters:
84  addParameters_(hiddenAlphabet_->getParameters());
85  addParameters_(transitionMatrix_->getParameters());
86  addParameters_(emissionProbabilities_->getParameters());
87 
88  //Init arrays:
89  likelihood_.resize(nbSites_ * nbStates_);
90 
91  scales_.resize(nbSites_);
92 
93  //Compute:
94  computeForward_();
95 }
96 
98 {
99  bool alphabetChanged = hiddenAlphabet_->matchParametersValues(pl);
100  bool transitionsChanged = transitionMatrix_->matchParametersValues(pl);
101  bool emissionChanged = emissionProbabilities_->matchParametersValues(pl);
102  // these lines are necessary because the transitions and emissions can depend on the alphabet.
103  // we could use a StateChangeEvent, but this would result in computing some calculations twice in some cases
104  // (when both the alphabet and other parameter changed).
105  if (alphabetChanged && !transitionsChanged) transitionMatrix_->setParametersValues(transitionMatrix_->getParameters());
106  if (alphabetChanged && !emissionChanged) emissionProbabilities_->setParametersValues(emissionProbabilities_->getParameters());
107 
108  computeForward_();
109  backLikelihoodUpToDate_=false;
110 }
111 
112 /***************************************************************************************************************************/
113 
115 {
116  double x;
117  vector<double> tmp(nbStates_);
118  vector<double> lScales(nbSites_);
119  vector<double> trans(nbStates_ * nbStates_);
120 
121  //Transition probabilities:
122  for (size_t i = 0; i < nbStates_; i++)
123  {
124  size_t ii = i * nbStates_;
125  for (size_t j = 0; j < nbStates_; j++) {
126  trans[ii + j] = transitionMatrix_->Pij(j, i);
127  if (isnan(trans[ii + j]))
128  throw Exception("RescaledHmmLikelihood::computeForward_. NaN transition probability");
129  if (trans[ii + j] < 0)
130  throw Exception("RescaledHmmLikelihood::computeForward_. Negative transition probability: " + TextTools::toString(trans[ii + j]));
131  }
132  }
133 
134  //Initialisation:
135  scales_[0] = 0;
136  const vector<double>* emissions = &(*emissionProbabilities_)(0);
137  for (size_t j = 0; j < nbStates_; j++)
138  {
139  size_t jj = j * nbStates_;
140  x = 0;
141  for (size_t k = 0; k < nbStates_; k++)
142  {
143  x += trans[k + jj] * transitionMatrix_->getEquilibriumFrequencies()[k];
144  //cerr << j << "\t" << k << "\t" << trans[k + jj] << "\t" << transitionMatrix_->getEquilibriumFrequencies()[k] << "\t" << trans[k + jj] * transitionMatrix_->getEquilibriumFrequencies()[k] << "\t" << x << endl;
145  }
146  tmp[j] = (*emissions)[j] * x;
147  //cerr << "e[j]=" << (*emissions)[j] << "\t" << tmp[j] << endl;
148  scales_[0] += tmp[j];
149  }
150  for (size_t j = 0; j < nbStates_; j++)
151  {
152  likelihood_[j] = tmp[j] / scales_[0];
153  }
154  lScales[0] = log(scales_[0]);
155 
156  //Recursion:
157  size_t nextBrkPt = nbSites_; //next break point
158  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
159  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
160 
161  double a;
162  for (size_t i = 1; i < nbSites_; i++)
163  {
164  size_t ii = i * nbStates_;
165  size_t iip = (i - 1) * nbStates_;
166  scales_[i] = 0 ;
167  emissions = &(*emissionProbabilities_)(i);
168  if (i < nextBrkPt)
169  {
170  for (size_t j = 0; j < nbStates_; j++)
171  {
172  size_t jj = j * nbStates_;
173  x = 0;
174  for (size_t k = 0; k < nbStates_; k++)
175  {
176  a = trans[jj + k] * likelihood_[iip + k];
177  //if (a < 0)
178  //{
179  // (*ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": " << likelihood_[iip + k] << ", Pij = " << trans[jj + k]).endLine();
180  // a = 0;
181  //}
182  x += a;
183  }
184  tmp[j] = (*emissions)[j] * x;
185  if (tmp[j] < 0)
186  {
187  (*ApplicationTools::warning << "Negative probability at " << i << ", state " << j << ": " << (*emissions)[j] << "\t" << x).endLine();
188  tmp[j] = 0;
189  }
190  scales_[i] += tmp[j];
191  }
192  }
193  else //Reset markov chain:
194  {
195  for (size_t j = 0; j < nbStates_; j++)
196  {
197  size_t jj = j * nbStates_;
198  x = 0;
199  for (size_t k = 0; k < nbStates_; k++)
200  {
201  a = trans[jj + k] * transitionMatrix_->getEquilibriumFrequencies()[k];
202  //if (a < 0)
203  //{
204  // (*ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": ,Pij = " << trans[jj + k]).endLine();
205  // a = 0;
206  //}
207  x += a;
208  }
209  tmp[j] = (*emissions)[j] * x;
210  //if (tmp[j] < 0)
211  //{
212  // (*ApplicationTools::warning << "Negative emission probability at " << i << ", state " << j << ": " << (*emissions)[j]).endLine();
213  // tmp[j] = 0;
214  //}
215  scales_[i] += tmp[j];
216  }
217  bpIt++;
218  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
219  else nextBrkPt = nbSites_;
220  }
221 
222  for (size_t j = 0; j < nbStates_; j++)
223  {
224  if (scales_[i] > 0) likelihood_[ii + j] = tmp[j] / scales_[i];
225  else likelihood_[ii + j] = 0;
226  }
227  lScales[i] = log(scales_[i]);
228  }
229  greater<double> cmp;
230  sort(lScales.begin(), lScales.end(), cmp);
231  logLik_ = 0;
232  for (size_t i = 0; i < nbSites_; ++i)
233  {
234  logLik_ += lScales[i];
235  }
236 }
237 
238 /***************************************************************************************************************************/
239 
241 {
242  if (backLikelihood_.size()==0)
243  {
244  backLikelihood_.resize(nbSites_);
245  for (size_t i=0;i<nbSites_;i++)
246  backLikelihood_[i].resize(nbStates_);
247  }
248 
249  double x;
250 
251  //Transition probabilities:
252  vector<double> trans(nbStates_ * nbStates_);
253  for (size_t i = 0; i < nbStates_; i++)
254  {
255  size_t ii = i * nbStates_;
256  for (size_t j = 0; j < nbStates_; j++)
257  trans[ii + j] = transitionMatrix_->Pij(i, j);
258  }
259 
260 
261  //Initialisation:
262  const vector<double>* emissions = 0;
263  size_t nextBrkPt = 0; //next break point
264  vector<size_t>::const_reverse_iterator bpIt = breakPoints_.rbegin();
265  if (bpIt != breakPoints_.rend()) nextBrkPt = *bpIt;
266 
267  for (size_t j = 0; j < nbStates_; j++)
268  {
269  x = 0;
270  backLikelihood_[nbSites_ - 1][j] = 1.;
271  }
272 
273  //Recursion:
274  for (size_t i = nbSites_ - 1; i > 0; i--)
275  {
276  emissions = &(*emissionProbabilities_)(i);
277  if (i > nextBrkPt)
278  {
279  for (size_t j = 0; j < nbStates_; j++)
280  {
281  x = 0;
282  size_t jj = j * nbStates_;
283  for (size_t k = 0; k < nbStates_; k++)
284  {
285  x += (*emissions)[k] * trans[jj + k] * backLikelihood_[i][k];
286  }
287  backLikelihood_[i-1][j] = x / scales_[i];
288  }
289  }
290  else //Reset markov chain
291  {
292  for (size_t j = 0; j < nbStates_; j++)
293  {
294  backLikelihood_[i-1][j] = 1.;
295  }
296  bpIt++;
297  if (bpIt != breakPoints_.rend()) nextBrkPt = *bpIt;
298  else nextBrkPt = 0;
299  }
300  }
301 
302  backLikelihoodUpToDate_=true;
303 }
304 
305 /***************************************************************************************************************************/
306 
308 {
309  Vdouble probs=getHiddenStatesPosteriorProbabilitiesForASite(site);
310  double x=0;
311  for (size_t i=0;i<nbStates_;i++)
312  x+=probs[i]*(*emissionProbabilities_)(site,i);
313 
314  return x;
315 }
316 
318 {
319  std::vector< std::vector<double> > vv;
320  getHiddenStatesPosteriorProbabilities(vv);
321 
322  Vdouble ret(nbSites_);
323  for (size_t i=0;i<nbSites_;i++)
324  {
325  ret[i]=0;
326  for (size_t j=0;j<nbStates_;j++)
327  ret[i]+=vv[i][j]*(*emissionProbabilities_)(i,j);
328  }
329 
330  return ret;
331 }
332 
333 /***************************************************************************************************************************/
334 
336 {
337  if (!backLikelihoodUpToDate_)
338  computeBackward_();
339 
340  Vdouble probs(nbStates_);
341 
342  for (size_t j = 0; j < nbStates_; j++)
343  {
344  probs[j] = likelihood_[site * nbStates_ + j] * backLikelihood_[site][j];
345  }
346 
347  return probs;
348 }
349 
350 
351 void RescaledHmmLikelihood::getHiddenStatesPosteriorProbabilities(std::vector< std::vector<double> >& probs, bool append) const throw (Exception)
352 {
353  size_t offset = append ? probs.size() : 0;
354  probs.resize(offset + nbSites_);
355  for (size_t i = 0; i < nbSites_; i++)
356  {
357  probs[offset + i].resize(nbStates_);
358  }
359 
360  if (!backLikelihoodUpToDate_)
361  computeBackward_();
362 
363  for (size_t i = 0; i < nbSites_; i++)
364  {
365  size_t ii = i * nbStates_;
366  for (size_t j = 0; j < nbStates_; j++)
367  {
368  probs[offset + i][j] = likelihood_[ii + j] * backLikelihood_[i][j];
369  }
370  }
371 }
372 
373 /***************************************************************************************************************************/
374 
376 {
377  //Init arrays:
378  if (dLikelihood_.size()==0){
379  dLikelihood_.resize(nbSites_);
380  for (size_t i=0;i<nbSites_;i++)
381  dLikelihood_[i].resize(nbStates_);
382  }
383  if (dScales_.size()==0)
384  dScales_.resize(nbSites_);
385 
386  double x;
387  vector<double> tmp(nbStates_), dTmp(nbStates_);
388  vector<double> dLScales(nbSites_);
389 
390  //Transition probabilities:
391  const ColMatrix<double> trans(transitionMatrix_->getPij());
392 
393  //Initialisation:
394  dScales_[0] = 0;
395  const vector<double>* emissions = &(*emissionProbabilities_)(0);
396  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
397 
398  for (size_t j = 0; j < nbStates_; j++)
399  {
400  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
401  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
402 
403  dScales_[0] += dTmp[j];
404  }
405 
406  dLScales[0]=dScales_[0]/scales_[0];
407 
408 
409  for (size_t j = 0; j < nbStates_; j++)
410  dLikelihood_[0][j] = (dTmp[j] * scales_[0] - tmp[j] * dScales_[0]) / pow(scales_[0],2);
411 
412  //Recursion:
413 
414  size_t nextBrkPt = nbSites_; //next break point
415  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
416  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
417 
418  for (size_t i = 1; i < nbSites_; i++)
419  {
420  size_t iip = (i - 1) * nbStates_;
421 
422  dScales_[i] = 0 ;
423 
424  emissions = &(*emissionProbabilities_)(i);
425  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
426 
427  if (i < nextBrkPt)
428  {
429  for (size_t j = 0; j < nbStates_; j++)
430  {
431  x = 0;
432  for (size_t k = 0; k < nbStates_; k++)
433  x += trans(k,j) * likelihood_[iip + k];
434 
435  tmp[j] = (*emissions)[j] * x;
436  dTmp[j] = (*dEmissions)[j] * x + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i-1]);
437 
438  dScales_[i] += dTmp[j];
439  }
440  }
441  else //Reset markov chain:
442  {
443  for (size_t j = 0; j < nbStates_; j++)
444  {
445  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
446  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
447 
448  dScales_[i] += dTmp[j];
449  }
450 
451  bpIt++;
452  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
453  else nextBrkPt = nbSites_;
454  }
455 
456  dLScales[i]=dScales_[i]/scales_[i];
457 
458  for (size_t j = 0; j < nbStates_; j++)
459  dLikelihood_[i][j] = (dTmp[j] * scales_[i] - tmp[j] * dScales_[i]) / pow(scales_[i],2);
460  }
461 
462  greater<double> cmp;
463  sort(dLScales.begin(), dLScales.end(), cmp);
464  dLogLik_ = 0;
465  for (size_t i = 0; i < nbSites_; ++i)
466  {
467  dLogLik_ += dLScales[i];
468  }
469 }
470 
471 /***************************************************************************************************************************/
472 
473 
475 {
476  //Init arrays:
477  if (d2Likelihood_.size()==0){
478  d2Likelihood_.resize(nbSites_);
479  for (size_t i=0;i<nbSites_;i++)
480  d2Likelihood_[i].resize(nbStates_);
481  }
482  if (d2Scales_.size()==0)
483  d2Scales_.resize(nbSites_);
484 
485  double x;
486  vector<double> tmp(nbStates_), dTmp(nbStates_), d2Tmp(nbStates_);
487  vector<double> d2LScales(nbSites_);
488 
489  //Transition probabilities:
490  const ColMatrix<double> trans(transitionMatrix_->getPij());
491 
492  //Initialisation:
493  d2Scales_[0] = 0;
494  const vector<double>* emissions = &(*emissionProbabilities_)(0);
495  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
496  const vector<double>* d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(0);
497 
498  for (size_t j = 0; j < nbStates_; j++)
499  {
500  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
501  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
502  d2Tmp[j] = (*d2Emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
503 
504  d2Scales_[0] += d2Tmp[j];
505  }
506 
507  d2LScales[0]=d2Scales_[0]/scales_[0]-pow(dScales_[0]/scales_[0],2);
508 
509  for (size_t j = 0; j < nbStates_; j++)
510  d2Likelihood_[0][j] = d2Tmp[j] / scales_[0] - (d2Scales_[0] * tmp[j] + 2 * dScales_[0] * dTmp[j]) / pow(scales_[0],2)
511  + 2 * pow(dScales_[0],2) * tmp[j] / pow(scales_[0],3);
512 
513  //Recursion:
514 
515  size_t nextBrkPt = nbSites_; //next break point
516  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
517  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
518 
519  for (size_t i = 1; i < nbSites_; i++)
520  {
521  dScales_[i] = 0 ;
522 
523  emissions = &(*emissionProbabilities_)(i);
524  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
525  d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(i);
526 
527  if (i < nextBrkPt)
528  {
529  size_t iip = (i - 1) * nbStates_;
530 
531  for (size_t j = 0; j < nbStates_; j++)
532  {
533  x = 0;
534  for (size_t k = 0; k < nbStates_; k++)
535  x += trans(k,j) * likelihood_[iip + k];
536 
537  tmp[j] = (*emissions)[j] * x;
538  dTmp[j] = (*dEmissions)[j] * x + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i-1]);
539  d2Tmp[j] = (*d2Emissions)[j] * x + 2 * (*dEmissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i-1])
540  + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * d2Likelihood_[i-1]);
541 
542  d2Scales_[i] += d2Tmp[j];
543  }
544  }
545  else //Reset markov chain:
546  {
547  for (size_t j = 0; j < nbStates_; j++)
548  {
549  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
550  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
551  d2Tmp[j] = (*d2Emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
552 
553  d2Scales_[i] += d2Tmp[j];
554  }
555 
556  bpIt++;
557  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
558  else nextBrkPt = nbSites_;
559  }
560 
561  d2LScales[i]=d2Scales_[i]/scales_[i]-pow(dScales_[i]/scales_[i],2);
562 
563  for (size_t j = 0; j < nbStates_; j++)
564  d2Likelihood_[i][j] = d2Tmp[j] / scales_[i] - (d2Scales_[i] * tmp[j] + 2 * dScales_[i] * dTmp[j]) / pow(scales_[i],2)
565  + 2 * pow(dScales_[i],2) * tmp[j] / pow(scales_[i],3);
566  }
567 
568  greater<double> cmp;
569  sort(d2LScales.begin(), d2LScales.end(), cmp);
570  dLogLik_ = 0;
571  for (size_t i = 0; i < nbSites_; ++i)
572  {
573  d2LogLik_ += d2LScales[i];
574  }
575 }
576 
577 /***************************************************************************************************************************/
Hidden states alphabet.
This class allows to perform a correspondence analysis.
void fireParameterChanged(const ParameterList &pl)
Notify the class when one or several parameters have changed.
A partial implementation of the Parametrizable interface.
static T sum(const std::vector< T > &v1)
Definition: VectorTools.h:614
Vdouble getHiddenStatesPosteriorProbabilitiesForASite(size_t site) const
Interface for computing emission probabilities in a Hidden Markov Model.
STL namespace.
static std::string toString(T t)
General template method to convert to a string.
Definition: TextTools.h:189
The parameter list object.
Definition: ParameterList.h:61
RescaledHmmLikelihood(HmmStateAlphabet *hiddenAlphabet, HmmTransitionMatrix *transitionMatrix, HmmEmissionProbabilities *emissionProbabilities, const std::string &prefix)
Build a new RescaledHmmLikelihood object.
void getHiddenStatesPosteriorProbabilities(std::vector< std::vector< double > > &probs, bool append=false) const
Matrix storage by column.
Definition: Matrix.h:232
std::vector< double > Vdouble
Definition: VectorTools.h:67
Vdouble getLikelihoodForEachSite() const
Get the likelihood for each site.
Exception base class.
Definition: Exceptions.h:57
static OutputStream * warning
The output stream where warnings have to be displayed.
double getLikelihoodForASite(size_t site) const
Get the likelihood for a site.
Describe the transition probabilities between hidden states of a Hidden Markov Model.