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
9using namespace bpp;
10using namespace std;
11
12ProcessComputationTree::ProcessComputationTree(
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
306void 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:49
static const NodeEvent mixtureEvent
Definition: PhyloNode.h:50
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_
Defines the basic types of data flow nodes.
std::vector< unsigned int > Vuint