bpp-core  2.2.0
LogsumHmmLikelihood.cpp
Go to the documentation of this file.
1 //
2 // File: LogsumHmmLikelihood.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 "LogsumHmmLikelihood.h"
41 
42 // from the STL:
43 #include <iostream>
44 #include <algorithm>
45 using namespace bpp;
46 using namespace std;
47 
49  HmmStateAlphabet* hiddenAlphabet,
50  HmmTransitionMatrix* transitionMatrix,
51  HmmEmissionProbabilities* emissionProbabilities,
52  const std::string& prefix) throw (Exception):
54  AbstractParametrizable(prefix),
55  hiddenAlphabet_(hiddenAlphabet),
56  transitionMatrix_(transitionMatrix),
57  emissionProbabilities_(emissionProbabilities),
58  logLikelihood_(),
59  partialLogLikelihoods_(),
60  logLik_(),
61  dLogLikelihood_(),
62  partialDLogLikelihoods_(),
63  d2LogLikelihood_(),
64  partialD2LogLikelihoods_(),
65  backLogLikelihood_(),
66  backLogLikelihoodUpToDate_(false),
67  breakPoints_(),
68  nbStates_(),
69  nbSites_()
70 {
71  if (!hiddenAlphabet) throw Exception("LogsumHmmLikelihood: null pointer passed for HmmStateAlphabet.");
72  if (!transitionMatrix) throw Exception("LogsumHmmLikelihood: null pointer passed for HmmTransitionMatrix.");
73  if (!emissionProbabilities) throw Exception("LogsumHmmLikelihood: null pointer passed for HmmEmissionProbabilities.");
74  if (!hiddenAlphabet_->worksWith(transitionMatrix->getHmmStateAlphabet()))
75  throw Exception("LogsumHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
76  if (!hiddenAlphabet_->worksWith(emissionProbabilities->getHmmStateAlphabet()))
77  throw Exception("LogsumHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
78  nbStates_ = hiddenAlphabet_->getNumberOfStates();
79  nbSites_ = emissionProbabilities_->getNumberOfPositions();
80 
81  //Manage parameters:
82  addParameters_(hiddenAlphabet_->getParameters());
83  addParameters_(transitionMatrix_->getParameters());
84  addParameters_(emissionProbabilities_->getParameters());
85 
86  //Init arrays:
87  logLikelihood_.resize(nbSites_ * nbStates_);
88 
89  //Compute:
90  computeForward_();
91 }
92 
94 {
95  dVariable_="";
96  d2Variable_="";
97 
98  bool alphabetChanged = hiddenAlphabet_->matchParametersValues(pl);
99  bool transitionsChanged = transitionMatrix_->matchParametersValues(pl);
100  bool emissionChanged = emissionProbabilities_->matchParametersValues(pl);
101  // these lines are necessary because the transitions and emissions can depend on the alphabet.
102  // we could use a StateChangeEvent, but this would result in computing some calculations twice in some cases
103  // (when both the alphabet and other parameter changed).
104  if (alphabetChanged && !transitionsChanged) transitionMatrix_->setParametersValues(transitionMatrix_->getParameters());
105  if (alphabetChanged && !emissionChanged) emissionProbabilities_->setParametersValues(emissionProbabilities_->getParameters());
106 
107  computeForward_();
108  backLogLikelihoodUpToDate_=false;
109 }
110 
111 /***************************************************************************************************************************/
112 
114 {
115  double x, a;
116  vector<double> logTrans(nbStates_ * nbStates_);
117 
118  //Transition probabilities:
119  for (size_t i = 0; i < nbStates_; i++)
120  {
121  size_t ii = i * nbStates_;
122  for (size_t j = 0; j < nbStates_; j++)
123  logTrans[ii + j] = log(transitionMatrix_->Pij(j, i));
124  }
125 
126  //Initialisation:
127  const vector<double>* emissions = &(*emissionProbabilities_)(0);
128 
129  for (size_t j = 0; j < nbStates_; j++)
130  {
131  size_t jj = j * nbStates_;
132  x = logTrans[jj] + log(transitionMatrix_->getEquilibriumFrequencies()[0]);
133 
134  for (size_t k = 1; k < nbStates_; k++)
135  {
136  a = logTrans[k + jj] + log(transitionMatrix_->getEquilibriumFrequencies()[k]);
137  x = NumTools::logsum(x, a);
138  }
139  logLikelihood_[j] = log((*emissions)[j]) + x;
140  }
141 
142  //Recursion:
143  size_t nextBrkPt = nbSites_; //next break point
144  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
145  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
146  partialLogLikelihoods_.clear();
147 
148  for (size_t i = 1; i < nbSites_; i++)
149  {
150  size_t ii = i * nbStates_;
151  size_t iip = (i - 1) * nbStates_;
152  emissions = &(*emissionProbabilities_)(i);
153  if (i < nextBrkPt)
154  {
155  for (size_t j = 0; j < nbStates_; j++)
156  {
157  size_t jj = j * nbStates_;
158  x = logTrans[jj] + logLikelihood_[iip];
159  for (size_t k = 1; k < nbStates_; k++)
160  {
161  a = logTrans[jj + k] + logLikelihood_[iip + k];
162  x = NumTools::logsum(x, a);
163  }
164  logLikelihood_[ii + j] = log((*emissions)[j]) + x;
165  }
166  }
167  else //Reset markov chain:
168  {
169  //Termination of previous segment:
170  double tmpLog = logLikelihood_[(i - 1) * nbStates_];
171  for (size_t k = 1; k < nbStates_; k++)
172  tmpLog = NumTools::logsum(tmpLog, logLikelihood_[(i - 1) * nbStates_ + k]);
173  partialLogLikelihoods_.push_back(tmpLog);
174 
175  for (size_t j = 0; j < nbStates_; j++)
176  {
177  size_t jj = j * nbStates_;
178  x = logTrans[jj] + log(transitionMatrix_->getEquilibriumFrequencies()[0]);
179  for (size_t k = 1; k < nbStates_; k++)
180  {
181  a = logTrans[jj + k] + log(transitionMatrix_->getEquilibriumFrequencies()[k]);
182  x = NumTools::logsum(x, a);
183  }
184  logLikelihood_[ii + j] = log((*emissions)[j]) + x;
185  }
186  bpIt++;
187  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
188  else nextBrkPt = nbSites_;
189  }
190  }
191 
192  //Termination:
193  double tmpLog = logLikelihood_[(nbSites_ - 1) * nbStates_];
194  for (size_t k = 1; k < nbStates_; k++)
195  tmpLog = NumTools::logsum(tmpLog, logLikelihood_[(nbSites_ - 1) * nbStates_ + k]);
196  partialLogLikelihoods_.push_back(tmpLog);
197 
198  //Compute likelihood:
199  logLik_ = 0;
200  vector<double> copy = partialLogLikelihoods_; //We need to keep the original order for posterior decoding.
201  sort(copy.begin(), copy.end());
202  for (size_t i = copy.size(); i > 0; --i)
203  logLik_ += copy[i - 1];
204 }
205 
206 /***************************************************************************************************************************/
207 
209 {
210  if (backLogLikelihood_.size()==0)
211  {
212  backLogLikelihood_.resize(nbSites_);
213  for (size_t i=0;i<nbSites_;i++)
214  backLogLikelihood_[i].resize(nbStates_);
215  }
216 
217  double x;
218 
219  //Transition probabilities:
220  vector<double> logTrans(nbStates_ * nbStates_);
221  for (size_t i = 0; i < nbStates_; i++)
222  {
223  size_t ii = i * nbStates_;
224  for (size_t j = 0; j < nbStates_; j++)
225  logTrans[ii + j] = log(transitionMatrix_->Pij(i, j));
226  }
227 
228 
229  //Initialisation:
230  const vector<double>* emissions = 0;
231  size_t nextBrkPt = 0; //next break point
232  vector<size_t>::const_reverse_iterator bpIt = breakPoints_.rbegin();
233  if (bpIt != breakPoints_.rend()) nextBrkPt = *bpIt;
234 
235  for (size_t k = 0; k < nbStates_; k++)
236  {
237  backLogLikelihood_[nbSites_ - 1][k] = 0.;
238  }
239 
240  //Recursion:
241  for (size_t i = nbSites_ - 1; i > 0; i--)
242  {
243  emissions = &(*emissionProbabilities_)(i);
244  if (i > nextBrkPt)
245  {
246  for (size_t j = 0; j < nbStates_; j++)
247  {
248  size_t jj = j * nbStates_;
249  x = log((*emissions)[0]) + logTrans[jj] + backLogLikelihood_[i][0];
250  for (size_t k = 1; k < nbStates_; k++)
251  {
252  x = NumTools::logsum(x, log((*emissions)[k]) + logTrans[jj + k] + backLogLikelihood_[i][k]);
253  }
254  backLogLikelihood_[i - 1][j] = x;
255  }
256  }
257  else //Reset markov chain
258  {
259  for (unsigned int j = 0; j < nbStates_; j++)
260  {
261  backLogLikelihood_[i - 1][j] = 0.;
262  }
263  bpIt++;
264  if (bpIt != breakPoints_.rend()) nextBrkPt = *bpIt;
265  else nextBrkPt = 0;
266  }
267  }
268 
269  backLogLikelihoodUpToDate_=true;
270 }
271 
272 
273 /***************************************************************************************************************************/
274 
276 {
277  Vdouble probs=getHiddenStatesPosteriorProbabilitiesForASite(site);
278  double x=0;
279  for (size_t i=0;i<nbStates_;i++)
280  x+=probs[i]*(*emissionProbabilities_)(site,i);
281 
282  return x;
283 }
284 
286 {
287  std::vector< std::vector<double> > vv;
288  getHiddenStatesPosteriorProbabilities(vv);
289 
290  Vdouble ret(nbSites_);
291  for (size_t i=0;i<nbSites_;i++)
292  {
293  ret[i]=0;
294  for (size_t j=0;j<nbStates_;j++)
295  ret[i]+=vv[i][j]*(*emissionProbabilities_)(i,j);
296  }
297 
298  return ret;
299 }
300 
301 
302 /***************************************************************************************************************************/
303 
305 {
306  if (!backLogLikelihoodUpToDate_)
307  computeBackward_();
308 
309  Vdouble probs(nbStates_);
310 
311  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
312  vector<double>::const_iterator logLikIt = partialLogLikelihoods_.begin();
313  while (bpIt != breakPoints_.end())
314  {
315  if (site>=(*bpIt))
316  logLikIt++;
317  else
318  break;
319  bpIt++;
320  }
321 
322  for (size_t j = 0; j < nbStates_; j++)
323  {
324  probs[j] = exp(logLikelihood_[site * nbStates_ + j] + backLogLikelihood_[site][j] - *logLikIt);
325  }
326 
327  return probs;
328 }
329 
330 void LogsumHmmLikelihood::getHiddenStatesPosteriorProbabilities(std::vector< std::vector<double> >& probs, bool append) const throw (Exception)
331 {
332  size_t offset = append ? probs.size() : 0;
333  probs.resize(offset + nbSites_);
334  for (size_t i = 0; i < nbSites_; i++)
335  {
336  probs[offset + i].resize(nbStates_);
337  }
338 
339  if (!backLogLikelihoodUpToDate_)
340  computeBackward_();
341 
342  size_t nextBrkPt = nbSites_; //next break point
343  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
344  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
345 
346  vector<double>::const_iterator logLikIt = partialLogLikelihoods_.begin();
347  for (size_t i = 0; i < nbSites_; i++)
348  {
349  if (i == nextBrkPt) {
350  logLikIt++;
351  bpIt++;
352  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
353  else nextBrkPt = nbSites_;
354  }
355 
356  size_t ii = i * nbStates_;
357  for (size_t j = 0; j < nbStates_; j++)
358  {
359  probs[offset + i][j] = exp(logLikelihood_[ii + j] + backLogLikelihood_[i][j] - *logLikIt);
360  }
361  }
362 }
363 
364 /***************************************************************************************************************************/
365 
367 {
368  //Init arrays:
369  if (dLogLikelihood_.size()==0){
370  dLogLikelihood_.resize(nbSites_);
371  for (size_t i=0;i<nbSites_;i++)
372  dLogLikelihood_[i].resize(nbStates_);
373  }
374 
375  partialDLogLikelihoods_.clear();
376 
377  double x;
378 
379  vector<double> num(nbStates_);
380 
381  //Transition probabilities:
382  const ColMatrix<double> trans(transitionMatrix_->getPij());
383 
384  //Initialisation:
385  const vector<double>* emissions = &(*emissionProbabilities_)(0);
386  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
387 
388  for (size_t j = 0; j < nbStates_; j++)
389  dLogLikelihood_[0][j] = (*dEmissions)[j] / (*emissions)[j];
390 
391  //Recursion:
392  size_t nextBrkPt = nbSites_; //next break point
393  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
394  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
395  partialDLogLikelihoods_.clear();
396 
397  for (size_t i = 1; i < nbSites_; i++)
398  {
399  size_t iip = (i - 1) * nbStates_;
400 
401  emissions = &(*emissionProbabilities_)(i);
402  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
403 
404  if (i < nextBrkPt)
405  {
406  for (size_t j = 0; j < nbStates_; j++)
407  {
408  x=(*dEmissions)[j]/(*emissions)[j];
409 
410  for (size_t k = 0; k < nbStates_; k++)
411  {
412  for (size_t kp = 0; kp < nbStates_; kp++)
413  num[kp]=logLikelihood_[iip+kp]-logLikelihood_[iip+k];
414 
415  x+=dLogLikelihood_[i-1][k]*trans(k,j)/VectorTools::sumExp(num,trans.getCol(j));
416  }
417 
418  dLogLikelihood_[i][j] = x;
419  }
420  }
421  else //Reset markov chain:
422  {
423  //Termination of previous segment
424  x = 0;
425  for (size_t k = 0; k < nbStates_; k++)
426  {
427  for (size_t kp = 0; kp < nbStates_; kp++)
428  num[kp]=logLikelihood_[iip+kp]-logLikelihood_[iip+k];
429 
430  x += dLogLikelihood_[i-1][k] / VectorTools::sumExp(num);
431  }
432 
433  partialDLogLikelihoods_.push_back(x);
434 
435  for (size_t j = 0; j < nbStates_; j++)
436  dLogLikelihood_[i][j] = (*dEmissions)[j] / (*emissions)[j];
437 
438  bpIt++;
439  if (bpIt != breakPoints_.end())
440  nextBrkPt = *bpIt;
441  else
442  nextBrkPt = nbSites_;
443  }
444  }
445 
446  //Termination:
447  x=0;
448  for (size_t k = 0; k < nbStates_; k++)
449  {
450  for (size_t kp = 0; kp < nbStates_; kp++)
451  num[kp]=logLikelihood_[nbStates_*(nbSites_-1)+kp]-logLikelihood_[nbStates_*(nbSites_-1)+k];
452 
453  x += dLogLikelihood_[nbSites_-1][k] / VectorTools::sumExp(num);
454  }
455 
456  partialDLogLikelihoods_.push_back(x);
457 
458  //Compute dLogLikelihood
459 
460  dLogLik_ = 0;
461  vector<double> copy = partialDLogLikelihoods_; //We need to keep the original order for posterior decoding.
462  sort(copy.begin(), copy.end());
463  for (size_t i = copy.size(); i > 0; --i)
464  dLogLik_ += copy[i - 1];
465 }
466 
467 /***************************************************************************************************************************/
468 
470 {
471  // Make sure that Dlikelihoods are correctly computed
472  getFirstOrderDerivative(d2Variable_);
473 
474  //Init arrays:
475  if (d2LogLikelihood_.size()==0){
476  d2LogLikelihood_.resize(nbSites_);
477  for (size_t i=0;i<nbSites_;i++)
478  d2LogLikelihood_[i].resize(nbStates_);
479  }
480 
481  partialD2LogLikelihoods_.clear();
482 
483  double x, z, snum;
484 
485  vector<double> num(nbStates_);
486 
487  //Transition probabilities:
488  const ColMatrix<double> trans(transitionMatrix_->getPij());
489 
490  //Initialisation:
491  const vector<double>* emissions = &(*emissionProbabilities_)(0);
492  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
493  const vector<double>* d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(0);
494 
495  for (size_t j = 0; j < nbStates_; j++)
496  d2LogLikelihood_[0][j] = (*d2Emissions)[j] / (*emissions)[j] - pow((*dEmissions)[j] / (*emissions)[j],2);
497 
498  //Recursion:
499  size_t nextBrkPt = nbSites_; //next break point
500  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
501  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
502  partialDLogLikelihoods_.clear();
503 
504  for (size_t i = 1; i < nbSites_; i++)
505  {
506  size_t iip = (i - 1) * nbStates_;
507 
508  emissions = &(*emissionProbabilities_)(i);
509  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
510  d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(i);
511 
512  if (i < nextBrkPt)
513  {
514  for (size_t j = 0; j < nbStates_; j++)
515  {
516  x=(*d2Emissions)[j] / (*emissions)[j] - pow((*dEmissions)[j] / (*emissions)[j],2);
517 
518  for (size_t k = 0; k < nbStates_; k++)
519  {
520  for (size_t kp = 0; kp < nbStates_; kp++)
521  num[kp]=logLikelihood_[iip+kp]-logLikelihood_[iip+k];
522  snum=VectorTools::sumExp(num,trans.getCol(j));
523 
524 
525  z=d2LogLikelihood_[i-1][k]+pow(dLogLikelihood_[i-1][k],2)
526  - dLogLikelihood_[i-1][k] * VectorTools::sumExp(num, trans.getCol(j) * dLogLikelihood_[i-1])/snum;
527 
528  x += z * trans(k,j) / snum;
529  }
530 
531  d2LogLikelihood_[i][j] = x;
532  }
533  }
534  else //Reset markov chain:
535  {
536  x=0;
537 
538  //Termination of previous segment:
539  for (size_t k = 1; k < nbStates_; k++)
540  {
541  for (size_t kp = 0; kp < nbStates_; kp++)
542  num[kp]=logLikelihood_[iip+kp]-logLikelihood_[iip+k];
543 
544  snum=VectorTools::sumExp(num);
545 
546  x += (d2LogLikelihood_[i-1][k]+pow(dLogLikelihood_[i-1][k],2)
547  - dLogLikelihood_[i-1][k] * VectorTools::sumExp(num, dLogLikelihood_[i-1])/snum)/snum;
548  }
549 
550  partialD2LogLikelihoods_.push_back(x);
551 
552  for (size_t j = 0; j < nbStates_; j++)
553  d2LogLikelihood_[i][j] = (*d2Emissions)[j] / (*emissions)[j] - pow((*dEmissions)[j] / (*emissions)[j],2);
554 
555 
556  bpIt++;
557  if (bpIt != breakPoints_.end()) nextBrkPt = *bpIt;
558  else nextBrkPt = nbSites_;
559  }
560  }
561 
562  //Termination:
563  x=0;
564  for (size_t k = 0; k < nbStates_; k++)
565  {
566  for (size_t kp = 0; kp < nbStates_; kp++)
567  num[kp]=logLikelihood_[nbStates_*(nbSites_-1)+kp]-logLikelihood_[nbStates_*(nbSites_-1)+k];
568 
569  snum=VectorTools::sumExp(num);
570 
571  x += (d2LogLikelihood_[nbSites_-1][k]+pow(dLogLikelihood_[nbSites_-1][k],2)
572  - dLogLikelihood_[nbSites_-1][k] * VectorTools::sumExp(num, dLogLikelihood_[nbSites_-1])/snum)/snum;
573  }
574 
575  partialD2LogLikelihoods_.push_back(x);
576 
577  //Compute dLogLikelihood
578 
579  d2LogLik_ = 0;
580  vector<double> copy = partialD2LogLikelihoods_; //We need to keep the original order for posterior decoding.
581  sort(copy.begin(), copy.end());
582  for (size_t i = copy.size(); i > 0; --i)
583  d2LogLik_ += copy[i - 1];
584 }
Hidden states alphabet.
static T sumExp(const std::vector< T > &v1)
Definition: VectorTools.h:719
This class allows to perform a correspondence analysis.
double getLikelihoodForASite(size_t site) const
Get the likelihood for a site.
A partial implementation of the Parametrizable interface.
Interface for computing emission probabilities in a Hidden Markov Model.
STL namespace.
static T logsum(T lnx, T lny)
Compute the logarithm of a sum from the sum of logarithms.
Definition: NumTools.h:131
Vdouble getLikelihoodForEachSite() const
Get the likelihood for each site.
virtual void fireParameterChanged(const ParameterList &pl)
Notify the class when one or several parameters have changed.
The parameter list object.
Definition: ParameterList.h:61
LogsumHmmLikelihood(HmmStateAlphabet *hiddenAlphabet, HmmTransitionMatrix *transitionMatrix, HmmEmissionProbabilities *emissionProbabilities, const std::string &prefix)
Build a new LogsumHmmLikelihood object.
Matrix storage by column.
Definition: Matrix.h:232
std::vector< double > Vdouble
Definition: VectorTools.h:67
Exception base class.
Definition: Exceptions.h:57
void getHiddenStatesPosteriorProbabilities(std::vector< std::vector< double > > &probs, bool append=false) const
Vdouble getHiddenStatesPosteriorProbabilitiesForASite(size_t site) const
Describe the transition probabilities between hidden states of a Hidden Markov Model.