bpp-core3  3.0.0
LogsumHmmLikelihood.cpp
Go to the documentation of this file.
1 //
2 // File: LogsumHmmLikelihood.cpp
3 // Authors:
4 // Julien Dutheil
5 // Created: 2007-10-26 11:57:00
6 //
7 
8 /*
9  Copyright or © or Copr. Bio++ Development Team, (November 16, 2004)
10 
11  This software is a computer program whose purpose is to provide classes
12  for phylogenetic data analysis.
13 
14  This software is governed by the CeCILL license under French law and
15  abiding by the rules of distribution of free software. You can use,
16  modify and/ or redistribute the software under the terms of the CeCILL
17  license as circulated by CEA, CNRS and INRIA at the following URL
18  "http://www.cecill.info".
19 
20  As a counterpart to the access to the source code and rights to copy,
21  modify and redistribute granted by the license, users are provided only
22  with a limited warranty and the software's author, the holder of the
23  economic rights, and the successive licensors have only limited
24  liability.
25 
26  In this respect, the user's attention is drawn to the risks associated
27  with loading, using, modifying and/or developing or reproducing the
28  software by the user in light of its specific status of free software,
29  that may mean that it is complicated to manipulate, and that also
30  therefore means that it is reserved for developers and experienced
31  professionals having in-depth computer knowledge. Users are therefore
32  encouraged to load and test the software's suitability as regards their
33  requirements in conditions enabling the security of their systems and/or
34  data to be ensured and, more generally, to use and operate it in the
35  same conditions as regards security.
36 
37  The fact that you are presently reading this means that you have had
38  knowledge of the CeCILL license and that you accept its terms.
39 */
40 
41 
42 #include "LogsumHmmLikelihood.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  bool ownsPointers,
55  const std::string& prefix) :
57  AbstractParametrizable(prefix),
58  hiddenAlphabet_(hiddenAlphabet),
59  transitionMatrix_(transitionMatrix),
60  emissionProbabilities_(emissionProbabilities),
61  ownsPointers_(ownsPointers),
62  logLikelihood_(),
63  partialLogLikelihoods_(),
64  logLik_(),
65  dLogLikelihood_(),
66  partialDLogLikelihoods_(),
67  d2LogLikelihood_(),
68  partialD2LogLikelihoods_(),
69  backLogLikelihood_(),
70  backLogLikelihoodUpToDate_(false),
71  breakPoints_(),
72  nbStates_(),
73  nbSites_()
74 {
75  if (!hiddenAlphabet)
76  throw Exception("LogsumHmmLikelihood: null pointer passed for HmmStateAlphabet.");
77  if (!transitionMatrix)
78  throw Exception("LogsumHmmLikelihood: null pointer passed for HmmTransitionMatrix.");
79  if (!emissionProbabilities)
80  throw Exception("LogsumHmmLikelihood: null pointer passed for HmmEmissionProbabilities.");
81 
83  throw Exception("LogsumHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
85  throw Exception("LogsumHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
88 
89  // Manage parameters:
93 
94  // Init arrays:
96 
97  // Compute:
99 }
100 
101 void LogsumHmmLikelihood::setNamespace(const std::string& nameSpace)
102 {
104 
105  hiddenAlphabet_->setNamespace(nameSpace);
106  transitionMatrix_->setNamespace(nameSpace);
108 }
109 
111 {
112  dVariable_ = "";
113  d2Variable_ = "";
114 
115  bool alphabetChanged = hiddenAlphabet_->matchParametersValues(pl);
116  bool transitionsChanged = transitionMatrix_->matchParametersValues(pl);
117  bool emissionChanged = emissionProbabilities_->matchParametersValues(pl);
118  // these lines are necessary because the transitions and emissions can depend on the alphabet.
119  // we could use a StateChangeEvent, but this would result in computing some calculations twice in some cases
120  // (when both the alphabet and other parameter changed).
121  if (alphabetChanged && !transitionsChanged)
123  if (alphabetChanged && !emissionChanged)
125 
128 }
129 
131 {
132  computeForward_();
133 }
134 
135 /***************************************************************************************************************************/
136 
138 {
139  double x, a;
140  vector<double> logTrans(nbStates_ * nbStates_);
141 
142  // Transition probabilities:
143  for (size_t i = 0; i < nbStates_; i++)
144  {
145  size_t ii = i * nbStates_;
146  for (size_t j = 0; j < nbStates_; j++)
147  {
148  logTrans[ii + j] = log(transitionMatrix_->Pij(j, i));
149  }
150  }
151 
152  // Initialisation:
153  const vector<double>* emissions = &(*emissionProbabilities_)(0);
154 
155  for (size_t j = 0; j < nbStates_; j++)
156  {
157  size_t jj = j * nbStates_;
158  x = logTrans[jj] + log(transitionMatrix_->getEquilibriumFrequencies()[0]);
159 
160  for (size_t k = 1; k < nbStates_; k++)
161  {
162  a = logTrans[k + jj] + log(transitionMatrix_->getEquilibriumFrequencies()[k]);
163  x = NumTools::logsum(x, a);
164  }
165 
166  logLikelihood_[j] = log((*emissions)[j]) + x;
167  }
168 
169  // Recursion:
170  size_t nextBrkPt = nbSites_; // next break point
171  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
172  if (bpIt != breakPoints_.end())
173  nextBrkPt = *bpIt;
174  partialLogLikelihoods_.clear();
175 
176  for (size_t i = 1; i < nbSites_; i++)
177  {
178  size_t ii = i * nbStates_;
179  size_t iip = (i - 1) * nbStates_;
180  emissions = &(*emissionProbabilities_)(i);
181  if (i < nextBrkPt)
182  {
183  for (size_t j = 0; j < nbStates_; j++)
184  {
185  size_t jj = j * nbStates_;
186  x = logTrans[jj] + logLikelihood_[iip];
187  for (size_t k = 1; k < nbStates_; k++)
188  {
189  a = logTrans[jj + k] + logLikelihood_[iip + k];
190  x = NumTools::logsum(x, a);
191  }
192  logLikelihood_[ii + j] = log((*emissions)[j]) + x;
193  }
194  }
195  else // Reset markov chain:
196  {
197  // Termination of previous segment:
198  double tmpLog = logLikelihood_[(i - 1) * nbStates_];
199  for (size_t k = 1; k < nbStates_; k++)
200  {
201  tmpLog = NumTools::logsum(tmpLog, logLikelihood_[(i - 1) * nbStates_ + k]);
202  }
203  partialLogLikelihoods_.push_back(tmpLog);
204 
205  for (size_t j = 0; j < nbStates_; j++)
206  {
207  size_t jj = j * nbStates_;
208  x = logTrans[jj] + log(transitionMatrix_->getEquilibriumFrequencies()[0]);
209  for (size_t k = 1; k < nbStates_; k++)
210  {
211  a = logTrans[jj + k] + log(transitionMatrix_->getEquilibriumFrequencies()[k]);
212  x = NumTools::logsum(x, a);
213  }
214  logLikelihood_[ii + j] = log((*emissions)[j]) + x;
215  }
216  bpIt++;
217  if (bpIt != breakPoints_.end())
218  nextBrkPt = *bpIt;
219  else
220  nextBrkPt = nbSites_;
221  }
222  }
223 
224  // Termination:
225  double tmpLog = logLikelihood_[(nbSites_ - 1) * nbStates_];
226  for (size_t k = 1; k < nbStates_; k++)
227  {
228  tmpLog = NumTools::logsum(tmpLog, logLikelihood_[(nbSites_ - 1) * nbStates_ + k]);
229  }
230  partialLogLikelihoods_.push_back(tmpLog);
231 
232  // Compute likelihood:
233  logLik_ = 0;
234  vector<double> copy = partialLogLikelihoods_; // We need to keep the original order for posterior decoding.
235  sort(copy.begin(), copy.end());
236  for (size_t i = copy.size(); i > 0; --i)
237  {
238  logLik_ += copy[i - 1];
239  }
240 }
241 
242 /***************************************************************************************************************************/
243 
245 {
246  if (backLogLikelihood_.size() == 0)
247  {
249  for (size_t i = 0; i < nbSites_; i++)
250  {
251  backLogLikelihood_[i].resize(nbStates_);
252  }
253  }
254 
255  double x;
256 
257  // Transition probabilities:
258  vector<double> logTrans(nbStates_ * nbStates_);
259  for (size_t i = 0; i < nbStates_; i++)
260  {
261  size_t ii = i * nbStates_;
262  for (size_t j = 0; j < nbStates_; j++)
263  {
264  logTrans[ii + j] = log(transitionMatrix_->Pij(i, j));
265  }
266  }
267 
268 
269  // Initialisation:
270  const vector<double>* emissions = 0;
271  size_t nextBrkPt = 0; // next break point
272  vector<size_t>::const_reverse_iterator bpIt = breakPoints_.rbegin();
273  if (bpIt != breakPoints_.rend())
274  nextBrkPt = *bpIt;
275 
276  for (size_t k = 0; k < nbStates_; k++)
277  {
278  backLogLikelihood_[nbSites_ - 1][k] = 0.;
279  }
280 
281  // Recursion:
282  for (size_t i = nbSites_ - 1; i > 0; i--)
283  {
284  emissions = &(*emissionProbabilities_)(i);
285  if (i > nextBrkPt)
286  {
287  for (size_t j = 0; j < nbStates_; j++)
288  {
289  size_t jj = j * nbStates_;
290  x = log((*emissions)[0]) + logTrans[jj] + backLogLikelihood_[i][0];
291  for (size_t k = 1; k < nbStates_; k++)
292  {
293  x = NumTools::logsum(x, log((*emissions)[k]) + logTrans[jj + k] + backLogLikelihood_[i][k]);
294  }
295  backLogLikelihood_[i - 1][j] = x;
296  }
297  }
298  else // Reset markov chain
299  {
300  for (unsigned int j = 0; j < nbStates_; j++)
301  {
302  backLogLikelihood_[i - 1][j] = 0.;
303  }
304  bpIt++;
305  if (bpIt != breakPoints_.rend())
306  nextBrkPt = *bpIt;
307  else
308  nextBrkPt = 0;
309  }
310  }
311 
313 }
314 
315 
316 /***************************************************************************************************************************/
317 
319 {
321  double x = 0;
322  for (size_t i = 0; i < nbStates_; i++)
323  {
324  x += probs[i] * (*emissionProbabilities_)(site, i);
325  }
326 
327  return x;
328 }
329 
331 {
332  std::vector< std::vector<double> > vv;
334 
335  Vdouble ret(nbSites_);
336  for (size_t i = 0; i < nbSites_; i++)
337  {
338  ret[i] = 0;
339  for (size_t j = 0; j < nbStates_; j++)
340  {
341  ret[i] += vv[i][j] * (*emissionProbabilities_)(i, j);
342  }
343  }
344 
345  return ret;
346 }
347 
348 
349 /***************************************************************************************************************************/
350 
352 {
355 
356  Vdouble probs(nbStates_);
357 
358  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
359  vector<double>::const_iterator logLikIt = partialLogLikelihoods_.begin();
360  while (bpIt != breakPoints_.end())
361  {
362  if (site >= (*bpIt))
363  logLikIt++;
364  else
365  break;
366  bpIt++;
367  }
368 
369  for (size_t j = 0; j < nbStates_; j++)
370  {
371  probs[j] = exp(logLikelihood_[site * nbStates_ + j] + backLogLikelihood_[site][j] - *logLikIt);
372  }
373 
374  return probs;
375 }
376 
377 void LogsumHmmLikelihood::getHiddenStatesPosteriorProbabilities(std::vector< std::vector<double> >& probs, bool append) const
378 {
379  size_t offset = append ? probs.size() : 0;
380  probs.resize(offset + nbSites_);
381  for (size_t i = 0; i < nbSites_; i++)
382  {
383  probs[offset + i].resize(nbStates_);
384  }
385 
388 
389  size_t nextBrkPt = nbSites_; // next break point
390  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
391  if (bpIt != breakPoints_.end())
392  nextBrkPt = *bpIt;
393 
394  vector<double>::const_iterator logLikIt = partialLogLikelihoods_.begin();
395  for (size_t i = 0; i < nbSites_; i++)
396  {
397  if (i == nextBrkPt)
398  {
399  logLikIt++;
400  bpIt++;
401  if (bpIt != breakPoints_.end())
402  nextBrkPt = *bpIt;
403  else
404  nextBrkPt = nbSites_;
405  }
406 
407  size_t ii = i * nbStates_;
408  for (size_t j = 0; j < nbStates_; j++)
409  {
410  probs[offset + i][j] = exp(logLikelihood_[ii + j] + backLogLikelihood_[i][j] - *logLikIt);
411  }
412  }
413 }
414 
415 /***************************************************************************************************************************/
416 
418 {
419  // Init arrays:
420  if (dLogLikelihood_.size() == 0)
421  {
422  dLogLikelihood_.resize(nbSites_);
423  for (size_t i = 0; i < nbSites_; i++)
424  {
425  dLogLikelihood_[i].resize(nbStates_);
426  }
427  }
428 
429  partialDLogLikelihoods_.clear();
430 
431  vector<double> num(nbStates_), num2(nbStates_);
432 
433  // Transition probabilities:
435 
436  // Initialisation:
437  const vector<double>* emissions = &(*emissionProbabilities_)(0);
438  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
439 
440  for (size_t j = 0; j < nbStates_; j++)
441  {
442  dLogLikelihood_[0][j] = (*dEmissions)[j] / (*emissions)[j];
443  }
444 
445  // Recursion:
446  size_t nextBrkPt = nbSites_; // next break point
447  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
448  if (bpIt != breakPoints_.end())
449  nextBrkPt = *bpIt;
450  partialDLogLikelihoods_.clear();
451 
452  for (size_t i = 1; i < nbSites_; i++)
453  {
454  size_t iip = (i - 1) * nbStates_;
455 
456  emissions = &(*emissionProbabilities_)(i);
458 
459  for (size_t kp = 0; kp < nbStates_; kp++)
460  {
461  num[kp] = logLikelihood_[iip + kp];
462  }
463 
464  num -= num[VectorTools::whichMax(num)];
465 
466  if (i < nextBrkPt)
467  {
468  for (size_t j = 0; j < nbStates_; j++)
469  {
470  num2 = dLogLikelihood_[i - 1] * trans.getCol(j);
471 
472  dLogLikelihood_[i][j] = (*dEmissions)[j] / (*emissions)[j] + VectorTools::sumExp(num, num2) / VectorTools::sumExp(num, trans.getCol(j));
473  }
474  }
475  else // Reset markov chain:
476  {
477  // Termination of previous segment
478 
480 
481  for (size_t j = 0; j < nbStates_; j++)
482  {
483  dLogLikelihood_[i][j] = (*dEmissions)[j] / (*emissions)[j];
484  }
485 
486  bpIt++;
487  if (bpIt != breakPoints_.end())
488  nextBrkPt = *bpIt;
489  else
490  nextBrkPt = nbSites_;
491  }
492  }
493 
494  // Termination:
495  for (size_t kp = 0; kp < nbStates_; kp++)
496  {
497  num[kp] = logLikelihood_[nbStates_ * (nbSites_ - 1) + kp];
498  }
499 
500  num -= num[VectorTools::whichMax(num)];
501 
503 
504  // Compute dLogLikelihood
505 
506  dLogLik_ = 0;
507  vector<double> copy = partialDLogLikelihoods_; // We need to keep the original order for posterior decoding.
508  sort(copy.begin(), copy.end());
509  for (size_t i = copy.size(); i > 0; --i)
510  {
511  dLogLik_ += copy[i - 1];
512  }
513 }
514 
516 {
517  return partialDLogLikelihoods_[site];
518 }
519 
520 /***************************************************************************************************************************/
521 
523 {
524  // Make sure that Dlikelihoods are correctly computed
526 
527  // Init arrays:
528  if (d2LogLikelihood_.size() == 0)
529  {
530  d2LogLikelihood_.resize(nbSites_);
531  for (size_t i = 0; i < nbSites_; i++)
532  {
533  d2LogLikelihood_[i].resize(nbStates_);
534  }
535  }
536 
537  partialD2LogLikelihoods_.clear();
538 
539  vector<double> num(nbStates_), num2(nbStates_), num3(nbStates_);
540 
541  // Transition probabilities:
543 
544  // Initialisation:
545  const vector<double>* emissions = &(*emissionProbabilities_)(0);
546  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
547  const vector<double>* d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(0);
548 
549  for (size_t j = 0; j < nbStates_; j++)
550  {
551  d2LogLikelihood_[0][j] = (*d2Emissions)[j] / (*emissions)[j] - pow((*dEmissions)[j] / (*emissions)[j], 2);
552  }
553 
554  // Recursion:
555  size_t nextBrkPt = nbSites_; // next break point
556  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
557  if (bpIt != breakPoints_.end())
558  nextBrkPt = *bpIt;
559  partialDLogLikelihoods_.clear();
560 
561  for (size_t i = 1; i < nbSites_; i++)
562  {
563  size_t iip = (i - 1) * nbStates_;
564 
565  emissions = &(*emissionProbabilities_)(i);
568 
569  for (size_t kp = 0; kp < nbStates_; kp++)
570  {
571  num[kp] = logLikelihood_[iip + kp];
572  }
573 
574  num -= num[VectorTools::whichMax(num)];
575 
576  if (i < nextBrkPt)
577  {
578  for (size_t j = 0; j < nbStates_; j++)
579  {
580  double den = VectorTools::sumExp(num, trans.getCol(j));
581 
582  num2 = dLogLikelihood_[i - 1] * trans.getCol(j);
583 
584  num3 = (dLogLikelihood_[i - 1] * dLogLikelihood_[i - 1] + d2LogLikelihood_[i - 1]) * trans.getCol(j);
585 
586  d2LogLikelihood_[i][j] = VectorTools::sumExp(num, num3) / den - pow(VectorTools::sumExp(num, num2) / den, 2);
587  }
588  }
589  else // Reset markov chain:
590  {
591  // Termination of previous segment:
592 
593  double den = VectorTools::sumExp(num);
594 
595  num2 = dLogLikelihood_[i - 1] * dLogLikelihood_[i - 1] + d2LogLikelihood_[i - 1];
596 
597  partialD2LogLikelihoods_.push_back(VectorTools::sumExp(num, num2) / den - pow(VectorTools::sumExp(num, dLogLikelihood_[i - 1]) / den, 2));
598 
599  for (size_t j = 0; j < nbStates_; j++)
600  {
601  d2LogLikelihood_[i][j] = (*d2Emissions)[j] / (*emissions)[j] - pow((*dEmissions)[j] / (*emissions)[j], 2);
602  }
603 
604 
605  bpIt++;
606  if (bpIt != breakPoints_.end())
607  nextBrkPt = *bpIt;
608  else
609  nextBrkPt = nbSites_;
610  }
611  }
612 
613  // Termination:
614  for (size_t kp = 0; kp < nbStates_; kp++)
615  {
616  num[kp] = logLikelihood_[nbStates_ * (nbSites_ - 1) + kp];
617  }
618 
619  num -= num[VectorTools::whichMax(num)];
620 
621  double den = VectorTools::sumExp(num);
622 
624 
625  partialD2LogLikelihoods_.push_back(VectorTools::sumExp(num, num2) / den - pow(VectorTools::sumExp(num, dLogLikelihood_[nbSites_ - 1]) / den, 2));
626 
627 
628  // Compute d2LogLikelihood
629 
630  d2LogLik_ = 0;
631  vector<double> copy = partialD2LogLikelihoods_; // We need to keep the original order for posterior decoding.
632  sort(copy.begin(), copy.end());
633  for (size_t i = copy.size(); i > 0; --i)
634  {
635  d2LogLik_ += copy[i - 1];
636  }
637 }
638 
640 {
641  return partialD2LogLikelihoods_[site];
642 }
double getFirstOrderDerivative(const std::string &variable) const
Get the derivative of the function at the current point.
A partial implementation of the Parametrizable interface.
void setNamespace(const std::string &prefix)
Set the namespace for the parameter names.
virtual void addParameters_(const ParameterList &parameters)
Matrix storage by column.
Definition: Matrix.h:239
const std::vector< Scalar > & getCol(size_t i) const
Definition: Matrix.h:304
Exception base class. Overload exception constructor (to control the exceptions mechanism)....
Definition: Exceptions.h:59
Interface for computing emission probabilities in a Hidden Markov Model.
virtual size_t getNumberOfPositions() const =0
virtual const std::vector< double > & getDEmissionProbabilities(size_t pos) const
virtual const HmmStateAlphabet * getHmmStateAlphabet() const =0
virtual const std::vector< double > & getD2EmissionProbabilities(size_t pos) const
Hidden states alphabet.
virtual size_t getNumberOfStates() const =0
virtual bool worksWith(const HmmStateAlphabet *stateAlphabet) const =0
Tell if this instance can work with the instance of alphabet given as input.
Describe the transition probabilities between hidden states of a Hidden Markov Model.
virtual const Matrix< double > & getPij() const =0
Get all transition probabilities as a matrix.
virtual const std::vector< double > & getEquilibriumFrequencies() const =0
virtual const HmmStateAlphabet * getHmmStateAlphabet() const =0
virtual double Pij(size_t i, size_t j) const =0
Get the transition probability between two states.
HmmStateAlphabet * hiddenAlphabet_
The alphabet describing the hidden states.
double getLikelihoodForASite(size_t site) const
Get the likelihood for a site, and its derivatives.
std::vector< size_t > breakPoints_
std::vector< double > partialD2LogLikelihoods_
Vdouble getLikelihoodForEachSite() const
Get the likelihood for each site.
std::vector< double > partialDLogLikelihoods_
double getDLogLikelihoodForASite(size_t site) const
void setNamespace(const std::string &nameSpace)
Set the namespace for the parameter names.
void getHiddenStatesPosteriorProbabilities(std::vector< std::vector< double > > &probs, bool append=false) const
void fireParameterChanged(const ParameterList &pl)
Notify the class when one or several parameters have changed.
HmmEmissionProbabilities * emissionProbabilities_
std::vector< std::vector< double > > backLogLikelihood_
backward logLikelihood
std::vector< double > partialLogLikelihoods_
std::vector< std::vector< double > > d2LogLikelihood_
LogsumHmmLikelihood(HmmStateAlphabet *hiddenAlphabet, HmmTransitionMatrix *transitionMatrix, HmmEmissionProbabilities *emissionProbabilities, bool ownsPointers_=true, const std::string &prefix="")
Build a new LogsumHmmLikelihood object.
HmmTransitionMatrix * transitionMatrix_
Vdouble getHiddenStatesPosteriorProbabilitiesForASite(size_t site) const
std::vector< double > logLikelihood_
The likelihood array.
std::vector< std::vector< double > > dLogLikelihood_
The DLogLikelihood arrays.
double getD2LogLikelihoodForASite(size_t site) const
static T logsum(T lnx, T lny)
Compute the logarithm of a sum from the sum of logarithms.
Definition: NumTools.h:132
The parameter list object.
Definition: ParameterList.h:65
virtual bool matchParametersValues(const ParameterList &parameters)=0
Update the parameters from parameters.
virtual const ParameterList & getParameters() const =0
Get all parameters available.
virtual void setParametersValues(const ParameterList &parameters)=0
Update the parameters from parameters.
virtual void setNamespace(const std::string &prefix)=0
Set the namespace for the parameter names.
static T sumExp(const std::vector< T > &v1)
Definition: VectorTools.h:748
static size_t whichMax(const std::vector< T > &v)
Template function to get the index of the maximum value of a std::vector.
Definition: VectorTools.h:1172
std::vector< double > Vdouble
Definition: VectorTools.h:70