bpp-core3  3.0.0
RescaledHmmLikelihood.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #include "../../App/ApplicationTools.h"
7 
8 // from the STL:
9 #include <iostream>
10 #include <algorithm>
11 using namespace bpp;
12 using namespace std;
13 
15  std::shared_ptr<HmmStateAlphabet> hiddenAlphabet,
16  std::shared_ptr<HmmTransitionMatrix> transitionMatrix,
17  std::shared_ptr<HmmEmissionProbabilities> emissionProbabilities,
18  const std::string& prefix) :
20  AbstractParametrizable(prefix),
21  hiddenAlphabet_(hiddenAlphabet),
22  transitionMatrix_(transitionMatrix),
23  emissionProbabilities_(emissionProbabilities),
24  likelihood_(),
25  dLikelihood_(),
26  d2Likelihood_(),
27  backLikelihood_(),
28  backLikelihoodUpToDate_(false),
29  scales_(),
30  dScales_(),
31  d2Scales_(),
32  logLik_(),
33  breakPoints_(),
34  nbStates_(),
35  nbSites_()
36 {
37  if (!hiddenAlphabet)
38  throw Exception("RescaledHmmLikelihood: null pointer passed for HmmStateAlphabet.");
39  if (!transitionMatrix)
40  throw Exception("RescaledHmmLikelihood: null pointer passed for HmmTransitionMatrix.");
41  if (!emissionProbabilities)
42  throw Exception("RescaledHmmLikelihood: null pointer passed for HmmEmissionProbabilities.");
43  if (!hiddenAlphabet_->worksWith(transitionMatrix->hmmStateAlphabet()))
44  throw Exception("RescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
45  if (!hiddenAlphabet_->worksWith(emissionProbabilities->hmmStateAlphabet()))
46  throw Exception("RescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
47  nbStates_ = hiddenAlphabet_->getNumberOfStates();
48  nbSites_ = emissionProbabilities_->getNumberOfPositions();
49 
50  // Manage parameters:
51  addParameters_(hiddenAlphabet_->getParameters());
52  addParameters_(transitionMatrix_->getParameters());
53  addParameters_(emissionProbabilities_->getParameters());
54 
55  // Init arrays:
56  likelihood_.resize(nbSites_ * nbStates_);
57 
58  scales_.resize(nbSites_);
59 
60  // Compute:
62 }
63 
64 void RescaledHmmLikelihood::setNamespace(const std::string& nameSpace)
65 {
67 
68  hiddenAlphabet_->setNamespace(nameSpace);
69  transitionMatrix_->setNamespace(nameSpace);
70  emissionProbabilities_->setNamespace(nameSpace);
71 }
72 
74 {
75  bool alphabetChanged = hiddenAlphabet_->matchParametersValues(pl);
76  bool transitionsChanged = transitionMatrix_->matchParametersValues(pl);
77  bool emissionChanged = emissionProbabilities_->matchParametersValues(pl);
78  // these lines are necessary because the transitions and emissions can depend on the alphabet.
79  // we could use a StateChangeEvent, but this would result in computing some calculations twice in some cases
80  // (when both the alphabet and other parameter changed).
81  if (alphabetChanged && !transitionsChanged)
82  transitionMatrix_->setParametersValues(transitionMatrix_->getParameters());
83  if (alphabetChanged && !emissionChanged)
84  emissionProbabilities_->setParametersValues(emissionProbabilities_->getParameters());
85 
88 }
89 
90 /***************************************************************************************************************************/
91 
93 {
94  double x;
95  vector<double> tmp(nbStates_);
96  vector<double> lScales(nbSites_);
97  vector<double> trans(nbStates_ * nbStates_);
98 
99  // Transition probabilities:
100  for (size_t i = 0; i < nbStates_; i++)
101  {
102  size_t ii = i * nbStates_;
103  for (size_t j = 0; j < nbStates_; j++)
104  {
105  trans[ii + j] = transitionMatrix_->Pij(j, i);
106  if (std::isnan(trans[ii + j]))
107  throw Exception("RescaledHmmLikelihood::computeForward_. NaN transition probability");
108  if (trans[ii + j] < 0)
109  throw Exception("RescaledHmmLikelihood::computeForward_. Negative transition probability: " + TextTools::toString(trans[ii + j]));
110  }
111  }
112 
113  // Initialisation:
114  scales_[0] = 0;
115  const vector<double>* emissions = &(*emissionProbabilities_)(0);
116  for (size_t j = 0; j < nbStates_; j++)
117  {
118  size_t jj = j * nbStates_;
119  x = 0;
120  for (size_t k = 0; k < nbStates_; k++)
121  {
122  x += trans[k + jj] * transitionMatrix_->getEquilibriumFrequencies()[k];
123  // cerr << j << "\t" << k << "\t" << trans[k + jj] << "\t" << transitionMatrix_->getEquilibriumFrequencies()[k] << "\t" << trans[k + jj] * transitionMatrix_->getEquilibriumFrequencies()[k] << "\t" << x << endl;
124  }
125  tmp[j] = (*emissions)[j] * x;
126  // cerr << "e[j]=" << (*emissions)[j] << "\t" << tmp[j] << endl;
127  scales_[0] += tmp[j];
128  }
129  for (size_t j = 0; j < nbStates_; j++)
130  {
131  likelihood_[j] = tmp[j] / scales_[0];
132  }
133  lScales[0] = log(scales_[0]);
134 
135  // Recursion:
136  size_t nextBrkPt = nbSites_; // next break point
137  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
138  if (bpIt != breakPoints_.end())
139  nextBrkPt = *bpIt;
140 
141  double a;
142  for (size_t i = 1; i < nbSites_; i++)
143  {
144  size_t ii = i * nbStates_;
145  size_t iip = (i - 1) * nbStates_;
146  scales_[i] = 0;
147  emissions = &(*emissionProbabilities_)(i);
148  if (i < nextBrkPt)
149  {
150  for (size_t j = 0; j < nbStates_; j++)
151  {
152  size_t jj = j * nbStates_;
153  x = 0;
154  for (size_t k = 0; k < nbStates_; k++)
155  {
156  a = trans[jj + k] * likelihood_[iip + k];
157  // if (a < 0)
158  // {
159  // (*ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": " << likelihood_[iip + k] << ", Pij = " << trans[jj + k]).endLine();
160  // a = 0;
161  // }
162  x += a;
163  }
164  tmp[j] = (*emissions)[j] * x;
165  if (tmp[j] < 0)
166  {
167  (*ApplicationTools::warning << "Negative probability at " << i << ", state " << j << ": " << (*emissions)[j] << "\t" << x).endLine();
168  tmp[j] = 0;
169  }
170  scales_[i] += tmp[j];
171  }
172  }
173  else // Reset markov chain:
174  {
175  for (size_t j = 0; j < nbStates_; j++)
176  {
177  size_t jj = j * nbStates_;
178  x = 0;
179  for (size_t k = 0; k < nbStates_; k++)
180  {
181  a = trans[jj + k] * transitionMatrix_->getEquilibriumFrequencies()[k];
182  // if (a < 0)
183  // {
184  // (*ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": ,Pij = " << trans[jj + k]).endLine();
185  // a = 0;
186  // }
187  x += a;
188  }
189  tmp[j] = (*emissions)[j] * x;
190  // if (tmp[j] < 0)
191  // {
192  // (*ApplicationTools::warning << "Negative emission probability at " << i << ", state " << j << ": " << (*emissions)[j]).endLine();
193  // tmp[j] = 0;
194  // }
195  scales_[i] += tmp[j];
196  }
197  bpIt++;
198  if (bpIt != breakPoints_.end())
199  nextBrkPt = *bpIt;
200  else
201  nextBrkPt = nbSites_;
202  }
203 
204  for (size_t j = 0; j < nbStates_; j++)
205  {
206  if (scales_[i] > 0)
207  likelihood_[ii + j] = tmp[j] / scales_[i];
208  else
209  likelihood_[ii + j] = 0;
210  }
211  lScales[i] = log(scales_[i]);
212  }
213  greater<double> cmp;
214  sort(lScales.begin(), lScales.end(), cmp);
215  logLik_ = 0;
216  for (size_t i = 0; i < nbSites_; ++i)
217  {
218  logLik_ += lScales[i];
219  }
220 }
221 
222 /***************************************************************************************************************************/
223 
225 {
226  if (backLikelihood_.size() == 0)
227  {
228  backLikelihood_.resize(nbSites_);
229  for (size_t i = 0; i < nbSites_; i++)
230  {
231  backLikelihood_[i].resize(nbStates_);
232  }
233  }
234 
235  double x;
236 
237  // Transition probabilities:
238  vector<double> trans(nbStates_ * nbStates_);
239  for (size_t i = 0; i < nbStates_; i++)
240  {
241  size_t ii = i * nbStates_;
242  for (size_t j = 0; j < nbStates_; j++)
243  {
244  trans[ii + j] = transitionMatrix_->Pij(i, j);
245  }
246  }
247 
248 
249  // Initialisation:
250  const vector<double>* emissions = 0;
251  size_t nextBrkPt = 0; // next break point
252  vector<size_t>::const_reverse_iterator bpIt = breakPoints_.rbegin();
253  if (bpIt != breakPoints_.rend())
254  nextBrkPt = *bpIt;
255 
256  for (size_t j = 0; j < nbStates_; j++)
257  {
258  x = 0;
259  backLikelihood_[nbSites_ - 1][j] = 1.;
260  }
261 
262  // Recursion:
263  for (size_t i = nbSites_ - 1; i > 0; i--)
264  {
265  emissions = &(*emissionProbabilities_)(i);
266  if (i > nextBrkPt)
267  {
268  for (size_t j = 0; j < nbStates_; j++)
269  {
270  x = 0;
271  size_t jj = j * nbStates_;
272  for (size_t k = 0; k < nbStates_; k++)
273  {
274  x += (*emissions)[k] * trans[jj + k] * backLikelihood_[i][k];
275  }
276  backLikelihood_[i - 1][j] = x / scales_[i];
277  }
278  }
279  else // Reset markov chain
280  {
281  for (size_t j = 0; j < nbStates_; j++)
282  {
283  backLikelihood_[i - 1][j] = 1.;
284  }
285  bpIt++;
286  if (bpIt != breakPoints_.rend())
287  nextBrkPt = *bpIt;
288  else
289  nextBrkPt = 0;
290  }
291  }
292 
294 }
295 
296 /***************************************************************************************************************************/
297 
299 {
301  double x = 0;
302  for (size_t i = 0; i < nbStates_; i++)
303  {
304  x += probs[i] * (*emissionProbabilities_)(site, i);
305  }
306 
307  return x;
308 }
309 
311 {
312  std::vector< std::vector<double>> vv;
314 
315  Vdouble ret(nbSites_);
316  for (size_t i = 0; i < nbSites_; i++)
317  {
318  ret[i] = 0;
319  for (size_t j = 0; j < nbStates_; j++)
320  {
321  ret[i] += vv[i][j] * (*emissionProbabilities_)(i, j);
322  }
323  }
324 
325  return ret;
326 }
327 
328 /***************************************************************************************************************************/
329 
331 {
334 
335  Vdouble probs(nbStates_);
336 
337  for (size_t j = 0; j < nbStates_; j++)
338  {
339  probs[j] = likelihood_[site * nbStates_ + j] * backLikelihood_[site][j];
340  }
341 
342  return probs;
343 }
344 
345 
346 void RescaledHmmLikelihood::getHiddenStatesPosteriorProbabilities(std::vector< std::vector<double>>& probs, bool append) const
347 {
348  size_t offset = append ? probs.size() : 0;
349  probs.resize(offset + nbSites_);
350  for (size_t i = 0; i < nbSites_; i++)
351  {
352  probs[offset + i].resize(nbStates_);
353  }
354 
357 
358  for (size_t i = 0; i < nbSites_; i++)
359  {
360  size_t ii = i * nbStates_;
361  for (size_t j = 0; j < nbStates_; j++)
362  {
363  probs[offset + i][j] = likelihood_[ii + j] * backLikelihood_[i][j];
364  }
365  }
366 }
367 
368 /***************************************************************************************************************************/
369 
371 {
372  // Init arrays:
373  if (dLikelihood_.size() == 0)
374  {
375  dLikelihood_.resize(nbSites_);
376  for (size_t i = 0; i < nbSites_; i++)
377  {
378  dLikelihood_[i].resize(nbStates_);
379  }
380  }
381  if (dScales_.size() == 0)
382  dScales_.resize(nbSites_);
383 
384  double x;
385  vector<double> tmp(nbStates_), dTmp(nbStates_);
386  vector<double> dLScales(nbSites_);
387 
388  // Transition probabilities:
389  const ColMatrix<double> trans(transitionMatrix_->getPij());
390 
391  // Initialisation:
392  dScales_[0] = 0;
393  const vector<double>* emissions = &(*emissionProbabilities_)(0);
394  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
395 
396  for (size_t j = 0; j < nbStates_; j++)
397  {
398  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
399  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
400 
401  dScales_[0] += dTmp[j];
402  }
403 
404  dLScales[0] = dScales_[0] / scales_[0];
405 
406 
407  for (size_t j = 0; j < nbStates_; j++)
408  {
409  dLikelihood_[0][j] = (dTmp[j] * scales_[0] - tmp[j] * dScales_[0]) / pow(scales_[0], 2);
410  }
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())
417  nextBrkPt = *bpIt;
418 
419  for (size_t i = 1; i < nbSites_; i++)
420  {
421  size_t iip = (i - 1) * nbStates_;
422 
423  dScales_[i] = 0;
424 
425  emissions = &(*emissionProbabilities_)(i);
426  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
427 
428  if (i < nextBrkPt)
429  {
430  for (size_t j = 0; j < nbStates_; j++)
431  {
432  x = 0;
433  for (size_t k = 0; k < nbStates_; k++)
434  {
435  x += trans(k, j) * likelihood_[iip + k];
436  }
437 
438  tmp[j] = (*emissions)[j] * x;
439  dTmp[j] = (*dEmissions)[j] * x + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i - 1]);
440 
441  dScales_[i] += dTmp[j];
442  }
443  }
444  else // Reset markov chain:
445  {
446  for (size_t j = 0; j < nbStates_; j++)
447  {
448  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
449  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
450 
451  dScales_[i] += dTmp[j];
452  }
453 
454  bpIt++;
455  if (bpIt != breakPoints_.end())
456  nextBrkPt = *bpIt;
457  else
458  nextBrkPt = nbSites_;
459  }
460 
461  dLScales[i] = dScales_[i] / scales_[i];
462 
463  for (size_t j = 0; j < nbStates_; j++)
464  {
465  dLikelihood_[i][j] = (dTmp[j] * scales_[i] - tmp[j] * dScales_[i]) / pow(scales_[i], 2);
466  }
467  }
468 
469  greater<double> cmp;
470  sort(dLScales.begin(), dLScales.end(), cmp);
471  dLogLik_ = 0;
472  for (size_t i = 0; i < nbSites_; ++i)
473  {
474  dLogLik_ += dLScales[i];
475  }
476 }
477 
479 {
480  return dScales_[site] / scales_[site];
481 }
482 
483 /***************************************************************************************************************************/
484 
485 
487 {
488  // Init arrays:
489  if (d2Likelihood_.size() == 0)
490  {
491  d2Likelihood_.resize(nbSites_);
492  for (size_t i = 0; i < nbSites_; i++)
493  {
494  d2Likelihood_[i].resize(nbStates_);
495  }
496  }
497  if (d2Scales_.size() == 0)
498  d2Scales_.resize(nbSites_);
499 
500  double x;
501  vector<double> tmp(nbStates_), dTmp(nbStates_), d2Tmp(nbStates_);
502  vector<double> d2LScales(nbSites_);
503 
504  // Transition probabilities:
505  const ColMatrix<double> trans(transitionMatrix_->getPij());
506 
507  // Initialisation:
508  d2Scales_[0] = 0;
509  const vector<double>* emissions = &(*emissionProbabilities_)(0);
510  const vector<double>* dEmissions = &emissionProbabilities_->getDEmissionProbabilities(0);
511  const vector<double>* d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(0);
512 
513  for (size_t j = 0; j < nbStates_; j++)
514  {
515  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
516  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
517  d2Tmp[j] = (*d2Emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
518 
519  d2Scales_[0] += d2Tmp[j];
520  }
521 
522  d2LScales[0] = d2Scales_[0] / scales_[0] - pow(dScales_[0] / scales_[0], 2);
523 
524  for (size_t j = 0; j < nbStates_; j++)
525  {
526  d2Likelihood_[0][j] = d2Tmp[j] / scales_[0] - (d2Scales_[0] * tmp[j] + 2 * dScales_[0] * dTmp[j]) / pow(scales_[0], 2)
527  + 2 * pow(dScales_[0], 2) * tmp[j] / pow(scales_[0], 3);
528  }
529 
530  // Recursion:
531 
532  size_t nextBrkPt = nbSites_; // next break point
533  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
534  if (bpIt != breakPoints_.end())
535  nextBrkPt = *bpIt;
536 
537  for (size_t i = 1; i < nbSites_; i++)
538  {
539  dScales_[i] = 0;
540 
541  emissions = &(*emissionProbabilities_)(i);
542  dEmissions = &emissionProbabilities_->getDEmissionProbabilities(i);
543  d2Emissions = &emissionProbabilities_->getD2EmissionProbabilities(i);
544 
545  if (i < nextBrkPt)
546  {
547  size_t iip = (i - 1) * nbStates_;
548 
549  for (size_t j = 0; j < nbStates_; j++)
550  {
551  x = 0;
552  for (size_t k = 0; k < nbStates_; k++)
553  {
554  x += trans(k, j) * likelihood_[iip + k];
555  }
556 
557  tmp[j] = (*emissions)[j] * x;
558  dTmp[j] = (*dEmissions)[j] * x + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i - 1]);
559  d2Tmp[j] = (*d2Emissions)[j] * x + 2 * (*dEmissions)[j] * VectorTools::sum(trans.getCol(j) * dLikelihood_[i - 1])
560  + (*emissions)[j] * VectorTools::sum(trans.getCol(j) * d2Likelihood_[i - 1]);
561 
562  d2Scales_[i] += d2Tmp[j];
563  }
564  }
565  else // Reset markov chain:
566  {
567  for (size_t j = 0; j < nbStates_; j++)
568  {
569  tmp[j] = (*emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
570  dTmp[j] = (*dEmissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
571  d2Tmp[j] = (*d2Emissions)[j] * transitionMatrix_->getEquilibriumFrequencies()[j];
572 
573  d2Scales_[i] += d2Tmp[j];
574  }
575 
576  bpIt++;
577  if (bpIt != breakPoints_.end())
578  nextBrkPt = *bpIt;
579  else
580  nextBrkPt = nbSites_;
581  }
582 
583  d2LScales[i] = d2Scales_[i] / scales_[i] - pow(dScales_[i] / scales_[i], 2);
584 
585  for (size_t j = 0; j < nbStates_; j++)
586  {
587  d2Likelihood_[i][j] = d2Tmp[j] / scales_[i] - (d2Scales_[i] * tmp[j] + 2 * dScales_[i] * dTmp[j]) / pow(scales_[i], 2)
588  + 2 * pow(dScales_[i], 2) * tmp[j] / pow(scales_[i], 3);
589  }
590  }
591 
592  greater<double> cmp;
593  sort(d2LScales.begin(), d2LScales.end(), cmp);
594  dLogLik_ = 0;
595  for (size_t i = 0; i < nbSites_; ++i)
596  {
597  d2LogLik_ += d2LScales[i];
598  }
599 }
600 
601 /***************************************************************************************************************************/
602 
604 {
605  return d2Scales_[site] / scales_[site] - pow(dScales_[site] / scales_[site], 2);
606 }
std::vector< size_t > breakPoints_
std::vector< double > likelihood_
The likelihood arrays.
std::vector< double > dScales_
double getLikelihoodForASite(size_t site) const override
Get the likelihood for a site, and its derivatives.
A partial implementation of the Parametrizable interface.
void setNamespace(const std::string &prefix) override
Set the namespace for the parameter names.
static T sum(const std::vector< T > &v1)
Definition: VectorTools.h:587
STL namespace.
void setNamespace(const std::string &nameSpace) override
Set the namespace for the parameter names.
void getHiddenStatesPosteriorProbabilities(std::vector< std::vector< double >> &probs, bool append=false) const override
std::vector< std::vector< double > > backLikelihood_
backward likelihood
The parameter list object.
Definition: ParameterList.h:27
std::shared_ptr< HmmEmissionProbabilities > emissionProbabilities_
RescaledHmmLikelihood(std::shared_ptr< HmmStateAlphabet > hiddenAlphabet, std::shared_ptr< HmmTransitionMatrix > transitionMatrix, std::shared_ptr< HmmEmissionProbabilities > emissionProbabilities, const std::string &prefix)
Build a new RescaledHmmLikelihood object.
std::vector< double > d2Scales_
static std::shared_ptr< OutputStream > warning
The output stream where warnings have to be displayed.
Matrix storage by column.
Definition: Matrix.h:200
Vdouble getLikelihoodForEachSite() const override
Get the likelihood for each site.
void fireParameterChanged(const ParameterList &pl) override
Notify the class when one or several parameters have changed.
std::vector< double > Vdouble
Definition: VectorTools.h:34
std::vector< double > scales_
scales for likelihood computing
std::vector< std::vector< double > > d2Likelihood_
partial impmementation of Hmm Likelihoods.
Exception base class. Overload exception constructor (to control the exceptions mechanism). Destructor is already virtual (from std::exception)
Definition: Exceptions.h:20
std::shared_ptr< HmmStateAlphabet > hiddenAlphabet_
The alphabet describing the hidden states.
std::shared_ptr< HmmTransitionMatrix > transitionMatrix_
double getDLogLikelihoodForASite(size_t site) const override
std::string toString(T t)
General template method to convert to a string.
Definition: TextTools.h:115
Vdouble getHiddenStatesPosteriorProbabilitiesForASite(size_t site) const override
virtual void addParameters_(const ParameterList &parameters)
double getD2LogLikelihoodForASite(size_t site) const override
std::vector< std::vector< double > > dLikelihood_
derivatec of forward likelihood