bpp-phyl3  3.0.0
MutationProcess.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 #include <Bpp/Text/TextTools.h>
7 
8 #include "MutationProcess.h"
9 
10 using namespace bpp;
11 using namespace std;
12 
13 /******************************************************************************/
14 
15 size_t AbstractMutationProcess::mutate(size_t state) const
16 {
18  for (size_t j = 0; j < size_; j++)
19  {
20  if (alea < repartition_[state][j])
21  return j;
22  }
23  throw Exception("AbstractMutationProcess::mutate. Repartition function is incomplete for state " + TextTools::toString(state));
24 }
25 
26 /******************************************************************************/
27 
28 size_t AbstractMutationProcess::mutate(size_t state, unsigned int n) const
29 {
30  size_t s = state;
31  for (unsigned int k = 0; k < n; k++)
32  {
34  for (size_t j = 1; j < size_ + 1; j++)
35  {
36  if (alea < repartition_[s][j])
37  {
38  s = j;
39  break;
40  }
41  }
42  }
43  return s;
44 }
45 
46 /******************************************************************************/
47 
49 {
50  return RandomTools::randExponential(-1. / model_->Qij(state, state));
51 }
52 
53 /******************************************************************************/
54 
55 size_t AbstractMutationProcess::evolve(size_t initialState, double time) const
56 {
57  double t = 0;
58  size_t currentState = initialState;
59  t += getTimeBeforeNextMutationEvent(currentState);
60  while (t < time)
61  {
62  currentState = mutate(currentState);
63  t += getTimeBeforeNextMutationEvent(currentState);
64  }
65  return currentState;
66 }
67 
68 /******************************************************************************/
69 
70 MutationPath AbstractMutationProcess::detailedEvolve(size_t initialState, double time) const
71 {
72  MutationPath mp(model_->getAlphabet(), initialState, time);
73  double t = 0;
74  size_t currentState = initialState;
75 
76  t += getTimeBeforeNextMutationEvent(currentState);
77  while (t < time)
78  {
79  currentState = mutate(currentState);
80  mp.addEvent(currentState, t);
81  t += getTimeBeforeNextMutationEvent(currentState);
82  }
83 
84  return mp;
85 }
86 
87 /******************************************************************************/
88 
89 MutationPath AbstractMutationProcess::detailedEvolve(size_t initialState, size_t finalState, double time) const
90 {
91  size_t maxIterNum = 1000; // max nb of tries
92  MutationPath mp(model_->getAlphabet(), initialState, time);
93 
94  for (size_t i = 0; i < maxIterNum; ++i)
95  {
96  mp.clear();
97 
98  double t = 0;
99 
100  // if the father's state is not the same as the son's state -> use the correction corresponding to equation (11) in the paper
101  if (initialState != finalState)
102  { // sample timeTillChange conditional on it being smaller than time
104  double waitingTimeParam = model_->Qij(initialState, initialState); // get the parameter for the exponential distribution to draw the waiting time
105  double tmp = u * (1.0 - exp(time * waitingTimeParam));
106  t = log(1.0 - tmp) / waitingTimeParam;
107  }
108  else
109  {
110  t = getTimeBeforeNextMutationEvent(initialState); // draw the time until a transition from exponential distribution with the rate of leaving fatherState
111  }
112 
113  size_t currentState = initialState;
114  while (t < time) // a jump occurred but not passed the whole time
115  {
116  currentState = mutate(currentState);
117  mp.addEvent(currentState, t); // add the current state and time to branch history
118  t += getTimeBeforeNextMutationEvent(currentState); // draw the time until a transition from exponential distribution with the rate of leaving currentState from initial state curState based on the relative transition rates distribution
119  }
120  // // the last jump passed the length of the branch -> finish the simulation and check if it's successful (i.e, mapping is finished at the son's state)
121  if (currentState != finalState) // if the simulation failed, try again
122  {
123  continue;
124  }
125  else
126  return mp;
127  }
128 
129  // Emergency case when none simul reached finalState
130  mp.addEvent(finalState, time);
131  return mp;
132 }
133 
134 
135 /******************************************************************************/
136 
138  shared_ptr<const SubstitutionModelInterface> model) :
140 {
141  size_ = model->getNumberOfStates();
143  // Each element contains the probabilities concerning each character in the alphabet.
144 
145  // We will now initiate each of these probability vector.
146  RowMatrix<double> Q = model->generator();
147  for (size_t i = 0; i < size_; i++)
148  {
149  repartition_[i] = Vdouble(size_, 0);
150  if (abs(Q(i, i)) > NumConstants::TINY())
151  {
152  double cum = 0;
153  double sum_Q = 0;
154  for (size_t j = 0; j < size_; j++)
155  {
156  if (j != i)
157  sum_Q += Q(i, j);
158  }
159 
160  for (size_t j = 0; j < size_; j++)
161  {
162  if (j != i)
163  {
164  cum += model->Qij(i, j) / sum_Q;
165  repartition_[i][j] = cum;
166  }
167  else
168  repartition_[i][j] = -1;
169  // Forbidden value: does not correspond to a change.
170  }
171  }
172  }
173 
174  // Note that I use cumulative probabilities in repartition_ (hence the name).
175  // These cumulative probabilities are useful for the 'mutate(...)' function.
176 }
177 
179 
180 /******************************************************************************/
181 
182 size_t SimpleMutationProcess::evolve(size_t initialState, double time) const
183 {
184  // Compute all cumulative pijt:
185  Vdouble pijt(size_);
186  pijt[0] = model_->Pij_t(initialState, 0, time);
187  for (size_t i = 1; i < size_; i++)
188  {
189  pijt[i] = pijt[i - 1] + model_->Pij_t(initialState, i, time);
190  }
192  for (size_t i = 0; i < size_; i++)
193  {
194  if (rand < pijt[i])
195  return i;
196  }
197  throw Exception("SimpleSimulationProcess::evolve(intialState, time): error all pijt do not sum to one (total sum = " + TextTools::toString(pijt[size_ - 1]) + ").");
198 }
199 
200 /******************************************************************************/
201 
204 {
205  size_ = alphabetSize;
207  // Each element contains the probabilities concerning each character in the alphabet.
208 
209  // We will now initiate each of these probability vector.
210  for (size_t i = 0; i < size_; i++)
211  {
212  repartition_[i] = Vdouble(size_);
213  for (size_t j = 0; j < size_; j++)
214  {
215  repartition_[i][j] = static_cast<double>(j + 1) / static_cast<double>(size_);
216  }
217  }
218  // Note that I use cumulative probabilities in repartition_ (hence the name).
219  // These cumulative probabilities are useful for the 'mutate(...)' function.
220 }
221 
223 
224 /******************************************************************************/
Partial implementation of the MutationProcess interface.
size_t size_
The number of states allowed for the character to mutate.
size_t evolve(size_t initialState, double time) const
Simulation a character evolution during a specified time according to the given substitution model an...
std::shared_ptr< const SubstitutionModelInterface > model_
The substitution model to use:
size_t mutate(size_t state) const
Mutate a character in state i.
VVdouble repartition_
The repartition function for states probabilities.
double getTimeBeforeNextMutationEvent(size_t state) const
Get the time before next mutation event.
MutationPath detailedEvolve(size_t initialState, double time) const
Simulation a character evolution during a specified time according to the given substitution model an...
This class is used by MutationProcess to store detailed results of simulations.
void addEvent(size_t state, double time)
Add a new mutation event.
static double TINY()
static double giveRandomNumberBetweenZeroAndEntry(double entry)
static double randExponential(double mean)
SelfMutationProcess(size_t alphabetSize)
size_t evolve(size_t initialState, double time) const
Method redefinition for better performance.
SimpleMutationProcess(std::shared_ptr< const SubstitutionModelInterface > model)
Build a new SimpleMutationProcess object.
std::string toString(T t)
Defines the basic types of data flow nodes.
double log(const ExtendedFloat &ef)
std::vector< double > Vdouble
ExtendedFloat exp(const ExtendedFloat &ef)
std::vector< Vdouble > VVdouble
ExtendedFloat abs(const ExtendedFloat &ef)