bpp-phyl3  3.0.0
ProcessComputationTree.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 <numeric>
6 
8 
9 using namespace bpp;
10 using namespace std;
11 
13  shared_ptr<const SubstitutionProcessInterface> process) :
14  BaseTree(process->getModelScenario() ? 0 :
15  (process->getParametrizablePhyloTree() ? process->getParametrizablePhyloTree()->getGraph() : 0)),
16  process_(process)
17 {
18  shared_ptr<const ParametrizablePhyloTree> ptree = process->getParametrizablePhyloTree();
19  if (!ptree)
20  throw Exception("ProcessComputationTree::ProcessComputationTree: missing tree.");
21 
22  // if no model scenario, copy the basic tree
23  auto scenario = process->getModelScenario();
24 
25  if (!scenario)
26  {
27  auto itN = ptree->allNodesIterator();
28  for (itN->start(); !itN->end(); itN->next())
29  {
30  auto index = ptree->getNodeIndex(*(*itN));
31  auto nnode = make_shared<ProcessComputationNode>(*(*(*itN)), index);
32  nnode->setProperty("event", NodeEvent::speciationEvent);
33  associateNode(nnode, ptree->getNodeGraphid(*(*itN)));
34  setNodeIndex(nnode, index);
35  }
36 
37  auto itE = ptree->allEdgesIterator();
38  for (itE->start(); !itE->end(); itE->next())
39  {
40  auto index = ptree->getEdgeIndex(*(*itE));
41  auto model = process->getModelForNode(index);
42  size_t nmodel = process->getModelNumberForNode(index);
43  auto nedge = make_shared<ProcessComputationEdge>(model, nmodel, index);
44  associateEdge(nedge, ptree->getEdgeGraphid(*(*itE)));
45  setEdgeIndex(nedge, index);
46  }
47 
48  return;
49  }
50 
51  // Map of the mrca of the MixedTransitionModel split in several paths
52  map<shared_ptr<MixedTransitionModelInterface>, uint> mMrca;
53 
54  auto vMod = scenario->getModels();
55  map<shared_ptr<MixedTransitionModelInterface>, vector<shared_ptr<PhyloNode>>> mnodes;
56 
57  auto vNodes = ptree->getAllNodes();
58 
59  auto root = ptree->getRoot();
60 
61  // first the nodes that carry the models
62  for (const auto& node:vNodes)
63  {
64  if (node == root)
65  continue;
66 
67  const auto medge = process_->getModelForNode(ptree->getNodeIndex(node));
68  shared_ptr<MixedTransitionModelInterface> mok(0);
69  for (const auto& mod:vMod)
70  {
71  if (mod.get() == medge.get())
72  {
73  mok = mod;
74  break;
75  }
76  }
77  if (mok == 0)
78  continue;
79 
80  if (mnodes.find(mok) == mnodes.end())
81  mnodes[mok] = vector<shared_ptr<PhyloNode>>();
82  mnodes[mok].push_back(node);
83  }
84 
85  // then the mrca
86 
87  for (const auto& mnode:mnodes)
88  {
89  auto nrca = ptree->MRCA(mnode.second);
90  mMrca[mnode.first] = ptree->getNodeIndex(nrca);
91  }
92 
93  // Then construction of the tree
94 
95  auto nroot = make_shared<ProcessComputationNode>(*root, ptree->getRootIndex());
96  createNode(nroot);
97  addNodeIndex(nroot);
98  buildFollowingScenario_(nroot, *scenario, mMrca);
99 
100  rootAt(nroot);
101 }
102 
103 
105  shared_ptr<ProcessComputationNode> father,
106  const ModelScenario& scenario,
107  map<shared_ptr<MixedTransitionModelInterface>,
108  uint>& mMrca)
109 {
110  auto spInd = father->getSpeciesIndex();
111 
112  size_t nbpath = scenario.getNumberOfModelPaths();
113 
114  auto ptree = process_->getParametrizablePhyloTree();
115 
116  shared_ptr<MixedTransitionModelInterface> mrca(0); // One MixedModel which is
117  // "split" at father node
118 
119  for (const auto& mod:mMrca)
120  {
121  if (mod.second == spInd)
122  {
123  mrca = mod.first;
124  mMrca.erase(mod.first);
125  break;
126  }
127  }
128 
129 
130  if (mrca == 0) // it is a speciation node
131  {
132  // set the event
133  father->setProperty("event", NodeEvent::speciationEvent);
134 
135  // and then look at the branches
136  auto vbrInd = ptree->getBranches(spInd);
137 
138  for (const auto& brInd:vbrInd)
139  {
140  auto sonInd = ptree->getSon(brInd);
141  auto son = ptree->getNode(sonInd);
142 
143  auto modSon = process_->getModelForNode(sonInd);
144  size_t nmodel = process_->getModelNumberForNode(sonInd);
145 
146  auto sonnode = make_shared<ProcessComputationNode>(*son, sonInd);
147  createNode(sonnode);
148  addNodeIndex(sonnode);
149 
150  // Check if model is a mixture
151  auto mixMod = dynamic_pointer_cast<const MixedTransitionModelInterface>(modSon);
152 
153  if (!mixMod) // No mixture, then a branch with a full model
154  {
155  auto nedge = make_shared<ProcessComputationEdge>(modSon, nmodel, sonInd);
156  link(father, sonnode, nedge);
157  addEdgeIndex(nedge);
158  buildFollowingScenario_(sonnode, scenario, mMrca);
159  continue;
160  }
161 
162  // If it is a mixture model, check its decomposition in the modelpaths
163 
164  map<Vuint, vector<shared_ptr<ModelPath>>> vMP;
165 
166  auto v0 = Vuint(); // ie model not seen in the model path
167  for (size_t i = 0; i < nbpath; i++)
168  {
169  auto smp = make_shared<ModelPath>(*scenario.getModelPath(i));
170  if (!smp->hasModel(mixMod))
171  {
172  if (vMP.find(Vuint()) == vMP.end())
173  vMP[v0] = vector<shared_ptr<ModelPath>>(1, smp);
174  else
175  vMP[v0].push_back(smp);
176  continue;
177  }
178 
179  const Vuint np(smp->getPathNode(mixMod));
180  if (vMP.find(np) == vMP.end())
181  vMP[np] = vector<shared_ptr<ModelPath>>(1, smp);
182  else
183  vMP[np].push_back(smp);
184  }
185 
186  if (vMP.size() > 1) // mixture on edges, build a mixture node
187  {
188  sonnode->setProperty("event", NodeEvent::mixtureEvent);
189 
190  auto vedge = make_shared<ProcessComputationEdge>(nullptr, 0, sonInd, true);
191  link(father, sonnode, vedge);
192  addEdgeIndex(vedge);
193 
194  // and then below sonnode
195  for (auto vmp:vMP)
196  {
197  // edge for proportion
198  auto ssonnode = make_shared<ProcessComputationNode>(*son, sonInd);
199  createNode(ssonnode);
200  addNodeIndex(ssonnode);
201  ssonnode->setProperty("event", NodeEvent::speciationEvent);
202  auto ssedge = make_shared<ProcessComputationEdge>(mixMod, nmodel, sonInd, true, vmp.first);
203  link(sonnode, ssonnode, ssedge);
204  addEdgeIndex(ssedge);
205 
206  // edge for transition
207  auto s3onnode = make_shared<ProcessComputationNode>(*son, sonInd);
208  createNode(s3onnode);
209  addNodeIndex(s3onnode);
210  auto s3edge = make_shared<ProcessComputationEdge>(mixMod, nmodel, sonInd, false, vmp.first);
211  link(ssonnode, s3onnode, s3edge);
212  addEdgeIndex(s3edge);
213 
214  if (vmp.second.size() > 1)
215  {
216  ModelScenario scen(vmp.second);
217  buildFollowingScenario_(s3onnode, scen, mMrca);
218  }
219  else
220  buildFollowingPath_(s3onnode, *vmp.second[0]);
221  }
222  }
223  else // all modelpaths agree on this path, no mixture here
224  // (probably done before)
225  {
226  auto beg = vMP.begin();
227  auto nedge = make_shared<ProcessComputationEdge>(mixMod, nmodel, sonInd, false, beg->first);
228  link(father, sonnode, nedge);
229  addEdgeIndex(nedge);
230 
231  if (beg->second.size() == 1) // only one path
232  buildFollowingPath_(sonnode, *beg->second[0]);
233  else
234  buildFollowingScenario_(sonnode, scenario, mMrca);
235  }
236  }
237  }
238  else // it is a mixture node
239  {
240  // build the node
241  father->setProperty("event", NodeEvent::mixtureEvent);
242 
243  // Check decomposition in the modelpaths
244  map<Vuint, vector<shared_ptr<ModelPath>>> vMP;
245 
246  auto v0 = Vuint(); // ie model not seen in the model path
247  for (size_t i = 0; i < nbpath; i++)
248  {
249  auto smp = make_shared<ModelPath>(*scenario.getModelPath(i));
250  if (!smp->hasModel(mrca))
251  {
252  if (vMP.find(Vuint()) == vMP.end())
253  vMP[v0] = vector<shared_ptr<ModelPath>>(1, smp);
254  else
255  vMP[v0].push_back(smp);
256  continue;
257  }
258 
259  const Vuint np(smp->getPathNode(mrca));
260  if (vMP.find(np) == vMP.end())
261  vMP[np] = vector<shared_ptr<ModelPath>>(1, smp);
262  else
263  vMP[np].push_back(smp);
264  }
265 
266  size_t nmodel = 0; // number model of the model split at this mrca node
267  bool modok(false);
268 
269  auto modNbs = process_->getModelNumbers();
270  for (auto nb: modNbs)
271  {
272  if (process_->getModel(nb) == mrca)
273  {
274  nmodel = nb;
275  modok = true;
276  }
277  }
278 
279  if (!modok)
280  throw Exception("ProcessComputationTree::ProcessComputationTree : unknown model for process : " + mrca->getName());
281 
282 
283  auto node = ptree->getNode(spInd);
284 
285  for (auto vmp:vMP)
286  {
287  auto sonnode = make_shared<ProcessComputationNode>(*node, spInd);
288  createNode(sonnode);
289  addNodeIndex(sonnode);
290 
291  auto sedge = make_shared<ProcessComputationEdge>(mrca, nmodel, spInd, true, vmp.first);
292  link(father, sonnode, sedge);
293  addEdgeIndex(sedge);
294 
295  if (vmp.second.size() > 1)
296  {
297  ModelScenario scen(vmp.second);
298  buildFollowingScenario_(sonnode, scen, mMrca);
299  }
300  else
301  buildFollowingPath_(sonnode, *vmp.second[0]);
302  }
303  }
304 }
305 
306 void ProcessComputationTree::buildFollowingPath_(shared_ptr<ProcessComputationNode> father, const ModelPath& path)
307 {
308  father->setProperty("event", NodeEvent::speciationEvent);
309 
310  auto nodeIndex = father->getSpeciesIndex();
311 
312  auto ptree = process_->getParametrizablePhyloTree();
313 
314  // and look at the branches
315 
316  auto vbrInd = ptree->getBranches(nodeIndex);
317 
318  for (const auto brInd:vbrInd)
319  {
320  // create the son
321  auto sonInd = ptree->getSon(brInd);
322  auto son = ptree->getNode(sonInd);
323 
324  auto sonnode = make_shared<ProcessComputationNode>(*son, sonInd);
325  createNode(sonnode);
326  addNodeIndex(sonnode);
327 
328 
329  // then the edge
330  auto modSon = process_->getModelForNode(sonInd);
331  auto nmodel = process_->getModelNumberForNode(sonInd);
332 
333  shared_ptr<ProcessComputationEdge> nedge;
334  auto mixmod = dynamic_pointer_cast<const MixedTransitionModelInterface>(modSon);
335 
336  if (mixmod && path.hasModel(mixmod))
337  nedge = make_shared<ProcessComputationEdge>(modSon, nmodel, sonInd, false, (const Vuint&)path.getPathNode(mixmod));
338  else
339  nedge = make_shared<ProcessComputationEdge>(modSon, nmodel, sonInd);
340 
341  link(father, sonnode, nedge);
342  addEdgeIndex(nedge);
343 
344  buildFollowingPath_(sonnode, path);
345  }
346 }
EdgeIndex addEdgeIndex(const Eref edgeObject)
NodeIndex addNodeIndex(const Nref nodeObject)
virtual void link(std::shared_ptr< N > nodeObjectA, std::shared_ptr< N > nodeObjectB, std::shared_ptr< E > edgeObject=00)=0
virtual NodeIndex setNodeIndex(const std::shared_ptr< N > nodeObject, NodeIndex index)=0
virtual void associateNode(std::shared_ptr< N > nodeObject, NodeGraphid node)=0
virtual EdgeIndex setEdgeIndex(const std::shared_ptr< E > edgeObject, EdgeIndex index)=0
virtual void associateEdge(std::shared_ptr< E > edgeObject, EdgeGraphid edge)=0
virtual void createNode(std::shared_ptr< N > newNodeObject)=0
void rootAt(const std::shared_ptr< N > root)
Organization of submodels in mixed substitution models in a path. See class ModelScenario for a thoro...
Definition: ModelPath.h:22
const PathNode & getPathNode(std::shared_ptr< MixedTransitionModelInterface > mMod) const
gets the pathnode associated with a model
Definition: ModelPath.h:251
bool hasModel(std::shared_ptr< MixedTransitionModelInterface > mMod) const
checks if there is a pathnode associated with a model
Definition: ModelPath.h:235
Organization of submodels in mixed substitution models as paths.
Definition: ModelScenario.h:81
std::shared_ptr< ModelPath > getModelPath(size_t i)
size_t getNumberOfModelPaths() const
static const NodeEvent speciationEvent
Definition: PhyloNode.h:45
static const NodeEvent mixtureEvent
Definition: PhyloNode.h:46
void buildFollowingScenario_(std::shared_ptr< ProcessComputationNode > father, const ModelScenario &scenario, std::map< std::shared_ptr< MixedTransitionModelInterface >, uint > &mMrca)
void buildFollowingPath_(std::shared_ptr< ProcessComputationNode > father, const ModelPath &path)
Build rest of the tree under given father (event on father will be set in this method)
std::shared_ptr< const SubstitutionProcessInterface > process_
ProcessComputationTree(std::shared_ptr< const SubstitutionProcessInterface > process)
construction of a ProcessComputationTree from a SubstitutionProcess
Defines the basic types of data flow nodes.
std::vector< unsigned int > Vuint