bpp-phyl3  3.0.0
SubstitutionModelSet.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 <Bpp/Utils/MapTools.h>
6 
7 #include "../../Model/MixedTransitionModel.h"
8 #include "SubstitutionModelSet.h"
9 
10 using namespace bpp;
11 using namespace std;
12 
15  alphabet_ (set.alphabet_),
16  nbStates_ (set.nbStates_),
17  modelSet_(set.modelSet_.size()),
18  rootFrequencies_(set.stationarity_ ? nullptr : set.rootFrequencies_->clone()),
19  nodeToModel_ (set.nodeToModel_),
20  modelToNodes_ (set.modelToNodes_),
21  modelParameters_ (set.modelParameters_),
22  stationarity_ (set.stationarity_)
23 {
24  // Duplicate all model objects:
25  for (size_t i = 0; i < set.modelSet_.size(); ++i)
26  {
27  modelSet_[i].reset(set.modelSet_[i]->clone());
28  }
29 }
30 
32 {
34  alphabet_ = set.alphabet_;
35  nbStates_ = set.nbStates_;
40  if (set.stationarity_)
41  rootFrequencies_ = nullptr;
42  else
43  rootFrequencies_.reset(set.rootFrequencies_->clone());
44 
45  // Duplicate all model objects:
46  modelSet_.resize(set.modelSet_.size());
47  for (size_t i = 0; i < set.modelSet_.size(); ++i)
48  {
49  modelSet_[i].reset(set.modelSet_[i]->clone());
50  }
51  return *this;
52 }
53 
55 {
57  nbStates_ = 0;
58  modelSet_.clear();
59  rootFrequencies_.reset();
60  nodeToModel_.clear();
61  modelParameters_.clear();
62  stationarity_ = true;
63 }
64 
65 void SubstitutionModelSet::setRootFrequencies(shared_ptr<FrequencySetInterface> rootFreqs)
66 {
67  if (rootFreqs)
68  {
69  stationarity_ = false;
70  rootFrequencies_ = rootFreqs;
71  addParameters_(rootFrequencies_->getParameters());
72  }
73 }
74 
75 std::vector<int> SubstitutionModelSet::getNodesWithParameter(const std::string& name) const
76 {
77  if (!(hasParameter(name)))
78  throw ParameterNotFoundException("SubstitutionModelSet::getNodesWithParameter.", name);
79 
80  vector<string> nalias = getAlias(name);
81  size_t p = name.rfind("_");
82  vector<int> inode = getNodesWithModel(TextTools::to<size_t>(name.substr(p + 1, string::npos)) - 1);
83 
84  for (size_t i = 0; i < nalias.size(); i++)
85  {
86  p = nalias[i].rfind("_");
87  size_t pos = TextTools::to<size_t>(nalias[i].substr(p + 1, string::npos));
88  if (pos > 0)
89  {
90  vector<int> ni = getNodesWithModel(pos - 1);
91  inode.insert(inode.end(), ni.begin(), ni.end());
92  }
93  }
94 
95  return inode;
96 }
97 
98 void SubstitutionModelSet::addModel(shared_ptr<TransitionModelInterface> model, const std::vector<int>& nodesId) // , const vector<string>& newParams)
99 {
100  if (model->alphabet().getAlphabetType() != alphabet_->getAlphabetType())
101  throw Exception("SubstitutionModelSet::addModel. A Substitution Model cannot be added to a Model Set if it does not have the same alphabet.");
102  if (modelSet_.size() > 0 && model->getNumberOfStates() != nbStates_)
103  throw Exception("SubstitutionModelSet::addModel. A Substitution Model cannot be added to a Model Set if it does not have the same number of states.");
104  if (modelSet_.size() == 0)
106  modelSet_.push_back(model);
107  size_t thisModelIndex = modelSet_.size() - 1;
108 
109  // Associate this model to specified nodes:
110  for (size_t i = 0; i < nodesId.size(); i++)
111  {
112  nodeToModel_[nodesId[i]] = thisModelIndex;
113  modelToNodes_[thisModelIndex].push_back(nodesId[i]);
114  }
115 
116  // Associate parameters:
117  string pname;
118 
119  vector<string> nplm = model->getParameters().getParameterNames();
120 
121  modelParameters_.push_back(model->getParameters());
122 
123  for (size_t i = 0; i < nplm.size(); i++)
124  {
125  pname = nplm[i];
126  Parameter* p = new Parameter(model->getParameters().parameter(pname)); // We work with namespaces here, so model->parameter(pname) does not work.
127  p->setName(pname + "_" + TextTools::toString(thisModelIndex + 1));
128  addParameter_(p);
129  }
130 }
131 
133 {
134  // reset nodeToModel_
135  nodeToModel_.clear();
136  // reset modelToNodes_
137  modelToNodes_.clear();
138 }
139 
140 void SubstitutionModelSet::setNodeToModel(size_t modelIndex, int nodeId)
141 {
142  if (modelIndex > modelSet_.size() - 1)
143  throw Exception("SubstitutionModelSet::setNodesToModel. There is no Substitution Model of index " + TextTools::toString(modelIndex));
144 
145  nodeToModel_[nodeId] = modelIndex;
146  modelToNodes_[modelIndex].push_back(nodeId);
147 }
148 
149 void SubstitutionModelSet::replaceModel(size_t modelIndex, shared_ptr<TransitionModelInterface> model)
150 {
151  modelSet_[modelIndex] = model;
152 
153  // Erase all parameter references to this model
154 
156 
157  for (size_t i = pl.size(); i > 0; i--)
158  {
159  string pn = pl[i - 1].getName();
160 
161  size_t pu = pn.rfind("_");
162  int nm = TextTools::toInt(pn.substr(pu + 1, string::npos));
163 
164  if (nm == (int)modelIndex + 1)
165  {
166  vector<string> alpn = getAlias(pn);
167  for (unsigned j = 0; j < alpn.size(); j++)
168  {
169  try
170  {
171  unaliasParameters(alpn[j], pn);
172  }
173  catch (Exception& e)
174  {
175  continue;
176  }
177  }
178  deleteParameter_(pn);
179  }
180  }
181 
182  // Associate new parameters
183  string pname;
184 
185  vector<string> nplm = model->getParameters().getParameterNames();
186 
187  for (size_t i = 0; i < nplm.size(); i++)
188  {
189  pname = nplm[i];
190  Parameter* p = new Parameter(model->getParameters().parameter(pname)); // We work with namespaces here, so model->parameter(pname) does not work.
191  p->setName(pname + "_" + TextTools::toString(modelIndex + 1));
192  addParameter_(p);
193  }
194 
195  // update modelParameters_
196 
197  modelParameters_[modelIndex].reset();
198  modelParameters_[modelIndex] = *model->getParameters().clone();
199 }
200 
201 void SubstitutionModelSet::listModelNames(std::ostream& out) const
202 {
203  for (size_t i = 0; i < modelSet_.size(); i++)
204  {
205  out << "Model " << i + 1 << ": " << modelSet_[i]->getName() << "\t attached to nodes ";
206  for (size_t j = 0; j < modelToNodes_[i].size(); j++)
207  {
208  out << modelToNodes_[i][j];
209  }
210  out << endl;
211  }
212 }
213 
215 {
216  // Update root frequencies:
218 
219  // Then we update all models in the set:
220  for (size_t i = 0; i < modelParameters_.size(); i++)
221  {
222  for (size_t np = 0; np < modelParameters_[i].size(); np++)
223  {
224  modelParameters_[i][np].setValue(getParameterValue(modelParameters_[i][np].getName() + "_" + TextTools::toString(i + 1)));
225  }
226  modelSet_[i]->matchParametersValues(modelParameters_[i]);
227  }
228 }
229 
231 {
232  vector<size_t> index = MapTools::getValues(nodeToModel_);
233  for (size_t i = 0; i < modelSet_.size(); i++)
234  {
235  if (!VectorTools::contains(index, i))
236  {
237  if (throwEx)
238  throw Exception("SubstitutionModelSet::checkOrphanModels(). Model '" + TextTools::toString(i + 1) + "' is associated to no node.");
239  return false;
240  }
241  }
242  return true;
243 }
244 
245 bool SubstitutionModelSet::checkOrphanNodes(const Tree& tree, bool throwEx) const
246 {
247  vector<int> ids = tree.getNodesId();
248  int rootId = tree.getRootId();
249  for (size_t i = 0; i < ids.size(); i++)
250  {
251  if (ids[i] != rootId && nodeToModel_.find(ids[i]) == nodeToModel_.end())
252  {
253  if (throwEx)
254  throw Exception("SubstitutionModelSet::checkOrphanNodes(). Node '" + TextTools::toString(ids[i]) + "' in tree has no model associated.");
255  return false;
256  }
257  }
258  return true;
259 }
260 
261 bool SubstitutionModelSet::checkUnknownNodes(const Tree& tree, bool throwEx) const
262 {
263  vector<int> ids = tree.getNodesId();
264  int id;
265  int rootId = tree.getRootId();
266  for (size_t i = 0; i < modelToNodes_.size(); i++)
267  {
268  for (size_t j = 0; j < modelToNodes_[i].size(); j++)
269  {
270  id = modelToNodes_[i][j];
271  if (id == rootId || !VectorTools::contains(ids, id))
272  {
273  if (throwEx)
274  throw Exception("SubstitutionModelSet::checkUnknownNodes(). Node '" + TextTools::toString(id) + "' is not found in tree or is the root node.");
275  return false;
276  }
277  }
278  }
279  return true;
280 }
281 
283 {
284  for (size_t i = 0; i < getNumberOfModels(); ++i)
285  {
286  if ((dynamic_cast<const MixedTransitionModelInterface*>(getModel(i).get()) != nullptr) && (modelToNodes_[i].size() > 1))
287  return true;
288  }
289  return false;
290 }
void addParameters_(const ParameterList &parameters)
virtual std::vector< std::string > getAlias(const std::string &name) const
void unaliasParameters(const std::string &p1, const std::string &p2)
void deleteParameter_(size_t index)
void addParameter_(Parameter *parameter)
AbstractParameterAliasable & operator=(const AbstractParameterAliasable &ap)
bool hasParameter(const std::string &name) const override
double getParameterValue(const std::string &name) const override
virtual std::string getAlphabetType() const=0
virtual size_t getNumberOfStates() const =0
Get the number of states.
virtual const Alphabet & alphabet() const =0
static std::vector< T > getValues(const std::map< Key, T, Cmp > &myMap)
Interface for Transition models, defined as a mixture of "simple" transition models.
size_t size() const
virtual std::vector< std::string > getParameterNames() const
ParameterList * clone() const
virtual const Parameter & parameter(const std::string &name) const
virtual void setName(const std::string &name)
virtual const ParameterList & getParameters() const=0
Substitution models manager for non-homogeneous / non-reversible models of evolution.
virtual void fireParameterChanged(const ParameterList &parameters)
void setNodeToModel(size_t modelIndex, int nodeId)
Sets an assignment of a given model index to a given onde id.
SubstitutionModelSet(std::shared_ptr< const Alphabet > alpha)
Create a model set according to the specified alphabet. Stationarity is assumed.
const TransitionModelInterface & model(size_t i) const
std::shared_ptr< FrequencySetInterface > rootFrequencies_
Root frequencies.
std::vector< int > getNodesWithParameter(const std::string &name) const
const std::vector< int > & getNodesWithModel(size_t i) const
Get a list of nodes id for which the given model is associated.
bool checkOrphanModels(bool throwEx) const
std::shared_ptr< const TransitionModelInterface > getModel(size_t i) const
Get one model from the set knowing its index.
std::shared_ptr< const Alphabet > alphabet_
A pointer toward the common alphabet to all models in the set.
bool checkOrphanNodes(const Tree &tree, bool throwEx) const
void setRootFrequencies(std::shared_ptr< FrequencySetInterface > rootFreqs)
Sets a given FrequencySet for root frequencies.
std::map< int, size_t > nodeToModel_
Contains for each node in a tree the index of the corresponding model in modelSet_.
void addModel(std::shared_ptr< TransitionModelInterface > model, const std::vector< int > &nodesId)
Add a new model to the set, and set relationships with nodes and params.
void listModelNames(std::ostream &out=std::cout) const
void resetModelToNodeIds()
Reset model indices to node ids assignment.
SubstitutionModelSet & operator=(const SubstitutionModelSet &set)
std::map< size_t, std::vector< int > > modelToNodes_
ParameterList getNodeParameters() const
Get the parameters corresponding attached to the nodes of the tree.
bool checkUnknownNodes(const Tree &tree, bool throwEx) const
void replaceModel(size_t modelIndex, std::shared_ptr< TransitionModelInterface > model)
Replace a model in the set, and all corresponding parameters. The replaced model deleted.
std::vector< std::shared_ptr< TransitionModelInterface > > modelSet_
Contains all models used in this tree.
std::vector< ParameterList > modelParameters_
Parameters for each model in the set.
void clear()
Resets all the information contained in this object.
Interface for phylogenetic tree objects.
Definition: Tree.h:115
virtual std::vector< int > getNodesId() const =0
virtual int getRootId() const =0
static bool contains(const std::vector< T > &vec, T el)
int toInt(const std::string &s, char scientificNotation='e')
std::string toString(T t)
Defines the basic types of data flow nodes.