bpp-core3  3.0.0
LowMemoryRescaledHmmLikelihood.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
6 
7 // from the STL:
8 #include <iostream>
9 #include <algorithm>
10 using namespace bpp;
11 using namespace std;
12 
14  std::shared_ptr<HmmStateAlphabet> hiddenAlphabet,
15  std::shared_ptr<HmmTransitionMatrix> transitionMatrix,
16  std::shared_ptr<HmmEmissionProbabilities> emissionProbabilities,
17  const std::string& prefix,
18  size_t maxSize) :
20  AbstractParametrizable(prefix),
21  hiddenAlphabet_(hiddenAlphabet),
22  transitionMatrix_(transitionMatrix),
23  emissionProbabilities_(emissionProbabilities),
24  likelihood1_(),
25  likelihood2_(),
26  logLik_(),
27  maxSize_(maxSize),
28  breakPoints_(),
29  nbStates_(),
30  nbSites_()
31 {
32  if (!hiddenAlphabet)
33  throw Exception("LowMemoryRescaledHmmLikelihood: null pointer passed for HmmStateAlphabet.");
34  if (!transitionMatrix)
35  throw Exception("LowMemoryRescaledHmmLikelihood: null pointer passed for HmmTransitionMatrix.");
36  if (!emissionProbabilities)
37  throw Exception("LowMemoryRescaledHmmLikelihood: null pointer passed for HmmEmissionProbabilities.");
38  if (!hiddenAlphabet_->worksWith(transitionMatrix->hmmStateAlphabet()))
39  throw Exception("LowMemoryRescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
40  if (!hiddenAlphabet_->worksWith(emissionProbabilities->hmmStateAlphabet()))
41  throw Exception("LowMemoryRescaledHmmLikelihood: HmmTransitionMatrix and HmmEmissionProbabilities should point toward the same HmmStateAlphabet object.");
42  nbStates_ = hiddenAlphabet_->getNumberOfStates();
43  nbSites_ = emissionProbabilities_->getNumberOfPositions();
44 
45  // Manage parameters:
46  addParameters_(hiddenAlphabet_->getParameters());
47  addParameters_(transitionMatrix_->getParameters());
48  addParameters_(emissionProbabilities_->getParameters());
49 
50  // Init arrays:
51  likelihood1_.resize(nbStates_);
52  likelihood2_.resize(nbStates_);
53 
54  // Compute:
56 }
57 
58 void LowMemoryRescaledHmmLikelihood::setNamespace(const std::string& nameSpace)
59 {
61 
62  hiddenAlphabet_->setNamespace(nameSpace);
63  transitionMatrix_->setNamespace(nameSpace);
64  emissionProbabilities_->setNamespace(nameSpace);
65 }
66 
68 {
69  bool alphabetChanged = hiddenAlphabet_->matchParametersValues(pl);
70  bool transitionsChanged = transitionMatrix_->matchParametersValues(pl);
71  bool emissionChanged = emissionProbabilities_->matchParametersValues(pl);
72  // these lines are necessary because the transitions and emissions can depend on the alphabet.
73  // we could use a StateChangeEvent, but this would result in computing some calculations twice in some cases
74  // (when both the alphabet and other parameter changed).
75  if (alphabetChanged && !transitionsChanged)
76  transitionMatrix_->setParametersValues(transitionMatrix_->getParameters());
77  if (alphabetChanged && !emissionChanged)
78  emissionProbabilities_->setParametersValues(emissionProbabilities_->getParameters());
79 
81 }
82 
83 /***************************************************************************************************************************/
84 
86 {
87  double x;
88  vector<double> tmp(nbStates_);
89  vector<double> lScales(min(maxSize_, nbSites_));
90  vector<double> trans(nbStates_ * nbStates_);
91 
92  // Transition probabilities:
93  for (size_t i = 0; i < nbStates_; i++)
94  {
95  size_t ii = i * nbStates_;
96  for (size_t j = 0; j < nbStates_; j++)
97  {
98  trans[ii + j] = transitionMatrix_->Pij(j, i);
99  }
100  }
101 
102  // Initialisation:
103  double scale = 0;
104  const vector<double>* emissions = &(*emissionProbabilities_)(0);
105  for (size_t j = 0; j < nbStates_; j++)
106  {
107  size_t jj = j * nbStates_;
108  x = 0;
109  for (size_t k = 0; k < nbStates_; k++)
110  {
111  x += trans[k + jj] * transitionMatrix_->getEquilibriumFrequencies()[k];
112  }
113  tmp[j] = (*emissions)[j] * x;
114  scale += tmp[j];
115  }
116  for (size_t j = 0; j < nbStates_; j++)
117  {
118  likelihood1_[j] = tmp[j] / scale;
119  }
120  lScales[0] = log(scale);
121 
122  vector<double>* previousLikelihood = &likelihood2_, * currentLikelihood = &likelihood1_, * tmpLikelihood;
123 
124  // Recursion:
125  size_t nextBrkPt = nbSites_; // next break point
126  vector<size_t>::const_iterator bpIt = breakPoints_.begin();
127  if (bpIt != breakPoints_.end())
128  nextBrkPt = *bpIt;
129 
130  double a;
131  logLik_ = 0;
132  size_t offset = 0;
133  greater<double> cmp;
134  for (size_t i = 1; i < nbSites_; i++)
135  {
136  // Swap pointers:
137  tmpLikelihood = previousLikelihood;
138  previousLikelihood = currentLikelihood;
139  currentLikelihood = tmpLikelihood;
140 
141  scale = 0;
142  emissions = &(*emissionProbabilities_)(i);
143  if (i < nextBrkPt)
144  {
145  for (size_t j = 0; j < nbStates_; j++)
146  {
147  size_t jj = j * nbStates_;
148  x = 0;
149  for (size_t k = 0; k < nbStates_; k++)
150  {
151  a = trans[jj + k] * (*previousLikelihood)[k];
152  if (a < 0)
153  {
154  // *ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": " << _likelihood[i-1][k] << ", Pij = " << _hiddenModel->Pij(k, j) << endl;
155  a = 0;
156  }
157  x += a;
158  }
159  tmp[j] = (*emissions)[j] * x;
160  if (tmp[j] < 0)
161  {
162  // *ApplicationTools::warning << "Negative emission probability at " << i << ", state " << j << ": " << _emissions[i][j] << endl;
163  tmp[j] = 0;
164  }
165  scale += tmp[j];
166  }
167  }
168  else // Reset markov chain:
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] * transitionMatrix_->getEquilibriumFrequencies()[k];
177  if (a < 0)
178  {
179  // *ApplicationTools::warning << "Negative value for likelihood at " << i << ", state " << j << ": " << _likelihood[i-1][k] << ", Pij = " << _hiddenModel->Pij(k, j) << endl;
180  a = 0;
181  }
182  x += a;
183  }
184  tmp[j] = (*emissions)[j] * x;
185  if (tmp[j] < 0)
186  {
187  // *ApplicationTools::warning << "Negative emission probability at " << i << ", state " << j << ": " << _emissions[i][j] << endl;
188  tmp[j] = 0;
189  }
190  scale += tmp[j];
191  }
192  bpIt++;
193  if (bpIt != breakPoints_.end())
194  nextBrkPt = *bpIt;
195  else
196  nextBrkPt = nbSites_;
197  }
198 
199  for (size_t j = 0; j < nbStates_; j++)
200  {
201  if (scale > 0)
202  (*currentLikelihood)[j] = tmp[j] / scale;
203  else
204  (*currentLikelihood)[j] = 0;
205  }
206  lScales[i - offset] = log(scale);
207 
208  if (i - offset == maxSize_ - 1)
209  {
210  // We make partial calculations and reset the arrays:
211  double partialLogLik = 0;
212  sort(lScales.begin(), lScales.end(), cmp);
213  for (size_t j = 0; j < maxSize_; ++j)
214  {
215  partialLogLik += lScales[j];
216  }
217  logLik_ += partialLogLik;
218  offset += maxSize_;
219  }
220  }
221  sort(lScales.begin(), lScales.begin() + static_cast<ptrdiff_t>(nbSites_ - offset), cmp);
222  double partialLogLik = 0;
223  for (size_t i = 0; i < nbSites_ - offset; ++i)
224  {
225  partialLogLik += lScales[i];
226  }
227  logLik_ += partialLogLik;
228 }
229 
230 /***************************************************************************************************************************/
std::shared_ptr< HmmTransitionMatrix > transitionMatrix_
std::shared_ptr< HmmEmissionProbabilities > emissionProbabilities_
void setNamespace(const std::string &nameSpace) override
Set the namespace for the parameter names.
A partial implementation of the Parametrizable interface.
void setNamespace(const std::string &prefix) override
Set the namespace for the parameter names.
STL namespace.
The parameter list object.
Definition: ParameterList.h:27
std::shared_ptr< HmmStateAlphabet > hiddenAlphabet_
The alphabet describing the hidden states.
void fireParameterChanged(const ParameterList &pl) override
Notify the class when one or several parameters have changed.
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::vector< double > likelihood1_
The likelihood array.
LowMemoryRescaledHmmLikelihood(std::shared_ptr< HmmStateAlphabet > hiddenAlphabet, std::shared_ptr< HmmTransitionMatrix > transitionMatrix, std::shared_ptr< HmmEmissionProbabilities > emissionProbabilities, const std::string &prefix, size_t maxSize=1000000)
Build a new LowMemoryRescaledHmmLikelihood object.
virtual void addParameters_(const ParameterList &parameters)