bpp-phyl3 3.0.0
OptimizationTools.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: The Bio++ Development Group
2//
3// SPDX-License-Identifier: CECILL-2.1
4
13
14#include "../Io/Newick.h"
15#include "../PseudoNewtonOptimizer.h"
16#include "../Tree/NNISearchable.h"
18#include "OptimizationTools.h"
20
21// From bpp-seq:
22#include <Bpp/Seq/Io/Fasta.h>
23
24using namespace bpp;
25using namespace std;
26
27/******************************************************************************/
28
29LegacyOptimizationTools::LegacyOptimizationTools() {}
30
32
33/******************************************************************************/
34
36 std::shared_ptr<TreeLikelihoodInterface> tl) :
37 tl_(tl),
38 brLen_(),
39 lambda_()
40{
41 // We work only on the branch lengths:
42 brLen_ = tl->getBranchLengthsParameters();
43 if (brLen_.hasParameter("RootPosition"))
44 brLen_.deleteParameter("RootPosition");
45 lambda_.addParameter(Parameter("scale factor", 0));
46}
47
49
51{
52 if (lambda.size() != 1)
53 throw Exception("LegacyOptimizationTools::ScaleFunction::f(). This is a one parameter function!");
54 lambda_.setParametersValues(lambda);
55}
56
58{
59 // Scale the tree:
60 ParameterList brLen = brLen_;
61 double s = exp(lambda_[0].getValue());
62 for (unsigned int i = 0; i < brLen.size(); i++)
63 {
64 try
65 {
66 brLen[i].setValue(brLen[i].getValue() * s);
67 }
68 catch (ConstraintException& cex)
69 {
70 // Do nothing. Branch value is already at bound...
71 }
72 }
73 return tl_->f(brLen);
74}
75
76/******************************************************************************/
77
79 std::shared_ptr<TreeLikelihoodInterface> tl,
80 double tolerance,
81 unsigned int tlEvalMax,
82 std::shared_ptr<OutputStream> messageHandler,
83 std::shared_ptr<OutputStream> profiler,
84 unsigned int verbose)
85{
86 auto sf = make_shared<ScaleFunction>(tl);
87 BrentOneDimension bod(sf);
88 bod.setMessageHandler(messageHandler);
89 bod.setProfiler(profiler);
90 ParameterList singleParameter;
91 singleParameter.addParameter(Parameter("scale factor", 0));
92 bod.setInitialInterval(-0.5, 0.5);
93 bod.init(singleParameter);
94 auto PS = make_shared<ParametersStopCondition>(&bod, tolerance);
95 bod.setStopCondition(PS);
96 bod.setMaximumNumberOfEvaluations(tlEvalMax);
97 bod.optimize();
99 if (verbose > 0)
100 ApplicationTools::displayResult("Tree scaled by", exp(sf->getParameters()[0].getValue()));
101 return bod.getNumberOfEvaluations();
102}
103
104/******************************************************************************/
105
107 std::shared_ptr<DiscreteRatesAcrossSitesTreeLikelihoodInterface> tl,
108 const ParameterList& parameters,
109 std::shared_ptr<OptimizationListener> listener,
110 unsigned int nstep,
111 double tolerance,
112 unsigned int tlEvalMax,
113 std::shared_ptr<OutputStream> messageHandler,
114 std::shared_ptr<OutputStream> profiler,
115 bool reparametrization,
116 unsigned int verbose,
117 const string& optMethodDeriv,
118 const string& optMethodModel)
119{
120 shared_ptr<SecondOrderDerivable> f = tl;
121 ParameterList pl = parameters;
122
123 // Shall we reparametrize the function to remove constraints?
124 if (reparametrization)
125 {
126 f = make_shared<ReparametrizationDerivableSecondOrderWrapper>(f, parameters);
127
128 // Reset parameters to remove constraints:
129 pl = f->getParameters().createSubList(parameters.getParameterNames());
130 }
131
132 // ///////////////
133 // Build optimizer:
134
135 // Branch lengths
136
137 auto desc = make_unique<MetaOptimizerInfos>();
138 unique_ptr<MetaOptimizer> poptimizer;
139 shared_ptr<AbstractNumericalDerivative> fnum(new ThreePointsNumericalDerivative(f));
140
141 if (optMethodDeriv == OPTIMIZATION_GRADIENT)
142 desc->addOptimizer("Branch length parameters", make_shared<ConjugateGradientMultiDimensions>(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
143 else if (optMethodDeriv == OPTIMIZATION_NEWTON)
144 desc->addOptimizer("Branch length parameters", make_shared<PseudoNewtonOptimizer>(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
145 else if (optMethodDeriv == OPTIMIZATION_BFGS)
146 desc->addOptimizer("Branch length parameters", make_shared<BfgsMultiDimensions>(f), tl->getBranchLengthsParameters().getParameterNames(), 2, MetaOptimizerInfos::IT_TYPE_FULL);
147 else
148 throw Exception("LegacyOptimizationTools::optimizeNumericalParameters. Unknown optimization method: " + optMethodDeriv);
149
150 // Other parameters
151
152 if (optMethodModel == OPTIMIZATION_BRENT)
153 {
154 ParameterList plsm = parameters.getCommonParametersWith(tl->getSubstitutionModelParameters());
155 desc->addOptimizer("Substitution model parameter", make_shared<SimpleMultiDimensions>(f), plsm.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
156
157
158 ParameterList plrd = parameters.getCommonParametersWith(tl->getRateDistributionParameters());
159 desc->addOptimizer("Rate distribution parameter", make_shared<SimpleMultiDimensions>(f), plrd.getParameterNames(), 0, MetaOptimizerInfos::IT_TYPE_STEP);
160 poptimizer.reset(new MetaOptimizer(f, std::move(desc), nstep));
161 }
162 else if (optMethodModel == OPTIMIZATION_BFGS)
163 {
164 vector<string> vNameDer;
165
166 ParameterList plsm = parameters.getCommonParametersWith(tl->getSubstitutionModelParameters());
167 vNameDer = plsm.getParameterNames();
168
169 ParameterList plrd = parameters.getCommonParametersWith(tl->getRateDistributionParameters());
170
171 vector<string> vNameDer2 = plrd.getParameterNames();
172
173 vNameDer.insert(vNameDer.begin(), vNameDer2.begin(), vNameDer2.end());
174 fnum->setParametersToDerivate(vNameDer);
175
176 desc->addOptimizer("Rate & model distribution parameters", make_shared<BfgsMultiDimensions>(fnum), vNameDer, 1, MetaOptimizerInfos::IT_TYPE_FULL);
177 poptimizer.reset(new MetaOptimizer(fnum, std::move(desc), nstep));
178 }
179 else
180 throw Exception("LegacyOptimizationTools::optimizeNumericalParameters. Unknown optimization method: " + optMethodModel);
181
182 poptimizer->setVerbose(verbose);
183 poptimizer->setProfiler(profiler);
184 poptimizer->setMessageHandler(messageHandler);
185 poptimizer->setMaximumNumberOfEvaluations(tlEvalMax);
186 poptimizer->getStopCondition()->setTolerance(tolerance);
187
188 // Optimize TreeLikelihood function:
189 poptimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
190 auto nanListener = make_shared<NaNListener>(poptimizer.get(), tl.get());
191 poptimizer->addOptimizationListener(nanListener);
192 if (listener)
193 poptimizer->addOptimizationListener(listener);
194 poptimizer->init(pl);
195 poptimizer->optimize();
196
197 if (verbose > 0)
199
200 // We're done.
201 unsigned int nb = poptimizer->getNumberOfEvaluations();
202 return nb;
203}
204
205
206/******************************************************************************/
207
209 std::shared_ptr<DiscreteRatesAcrossSitesTreeLikelihoodInterface> tl,
210 const ParameterList& parameters,
211 std::shared_ptr<OptimizationListener> listener,
212 double tolerance,
213 unsigned int tlEvalMax,
214 std::shared_ptr<OutputStream> messageHandler,
215 std::shared_ptr<OutputStream> profiler,
216 bool reparametrization,
217 bool useClock,
218 unsigned int verbose,
219 const std::string& optMethodDeriv)
220{
221 shared_ptr<SecondOrderDerivable> f = tl;
222 shared_ptr<GlobalClockTreeLikelihoodFunctionWrapper> fclock;
223
224 ParameterList pl = parameters;
225 // Shall we use a molecular clock constraint on branch lengths?
226 if (useClock)
227 {
229 f = fclock;
230 if (verbose > 0)
231 ApplicationTools::displayResult("Log-likelihood after adding clock", -(tl->getLogLikelihood()));
232
233 // Reset parameters to use new branch lengths. WARNING! 'old' branch parameters do not exist anymore and have been replaced by heights
234 pl = fclock->getParameters().getCommonParametersWith(parameters);
235 pl.addParameters(fclock->getHeightParameters());
236 }
237 // Shall we reparametrize the function to remove constraints?
238 if (reparametrization)
239 {
240 f = make_shared<ReparametrizationDerivableSecondOrderWrapper>(f, pl);
241
242 // Reset parameters to remove constraints:
243 pl = f->getParameters().createSubList(pl.getParameterNames());
244 }
245
246 shared_ptr<AbstractNumericalDerivative> fnum;
247
248 // Build optimizer:
249 unique_ptr<OptimizerInterface> optimizer;
250 if (optMethodDeriv == OPTIMIZATION_GRADIENT)
251 {
252 fnum.reset(new TwoPointsNumericalDerivative(dynamic_pointer_cast<FirstOrderDerivable>(f)));
253 fnum->setInterval(0.0000001);
254 optimizer.reset(new ConjugateGradientMultiDimensions(fnum));
255 }
256 else if (optMethodDeriv == OPTIMIZATION_NEWTON)
257 {
258 fnum.reset(new ThreePointsNumericalDerivative(f));
259 fnum->setInterval(0.0001);
260 optimizer.reset(new PseudoNewtonOptimizer(fnum));
261 }
262 else if (optMethodDeriv == OPTIMIZATION_BFGS)
263 {
264 fnum.reset(new TwoPointsNumericalDerivative(dynamic_pointer_cast<FirstOrderDerivable>(f)));
265 fnum->setInterval(0.0001);
266 optimizer.reset(new BfgsMultiDimensions(fnum));
267 }
268 else
269 throw Exception("LegacyOptimizationTools::optimizeNumericalParameters2. Unknown optimization method: " + optMethodDeriv);
270
271 // Numerical derivatives:
272 ParameterList tmp = tl->getNonDerivableParameters();
273
274 if (useClock)
275 tmp.addParameters(fclock->getHeightParameters());
276 fnum->setParametersToDerivate(tmp.getParameterNames());
277 optimizer->setVerbose(verbose);
278 optimizer->setProfiler(profiler);
279 optimizer->setMessageHandler(messageHandler);
280 optimizer->setMaximumNumberOfEvaluations(tlEvalMax);
281 optimizer->getStopCondition()->setTolerance(tolerance);
282
283 // Optimize TreeLikelihood function:
284 optimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
285 auto nanListener = make_shared<NaNListener>(optimizer.get(), tl.get());
286 optimizer->addOptimizationListener(nanListener);
287 if (listener)
288 optimizer->addOptimizationListener(listener);
289 optimizer->init(pl);
290 optimizer->optimize();
291
292 if (verbose > 0)
294
295 // We're done.
296 return optimizer->getNumberOfEvaluations();
297}
298
299
300/******************************************************************************/
301
303 std::shared_ptr<DiscreteRatesAcrossSitesTreeLikelihoodInterface> tl,
304 const ParameterList& parameters,
305 std::shared_ptr<OptimizationListener> listener,
306 double tolerance,
307 unsigned int tlEvalMax,
308 std::shared_ptr<OutputStream> messageHandler,
309 std::shared_ptr<OutputStream> profiler,
310 unsigned int verbose,
311 const string& optMethodDeriv)
312{
313 // Build optimizer:
314 unique_ptr<OptimizerInterface> optimizer;
315 if (optMethodDeriv == OPTIMIZATION_GRADIENT)
316 {
317 tl->enableFirstOrderDerivatives(true);
318 tl->enableSecondOrderDerivatives(false);
319 optimizer.reset(new ConjugateGradientMultiDimensions(tl));
320 }
321 else if (optMethodDeriv == OPTIMIZATION_NEWTON)
322 {
323 tl->enableFirstOrderDerivatives(true);
324 tl->enableSecondOrderDerivatives(true);
325 optimizer.reset(new PseudoNewtonOptimizer(tl));
326 }
327 else if (optMethodDeriv == OPTIMIZATION_BFGS)
328 {
329 tl->enableFirstOrderDerivatives(true);
330 tl->enableSecondOrderDerivatives(false);
331 optimizer.reset(new BfgsMultiDimensions(tl));
332 }
333 else
334 throw Exception("LegacyOptimizationTools::optimizeBranchLengthsParameters. Unknown optimization method: " + optMethodDeriv);
335 optimizer->setVerbose(verbose);
336 optimizer->setProfiler(profiler);
337 optimizer->setMessageHandler(messageHandler);
338 optimizer->setMaximumNumberOfEvaluations(tlEvalMax);
339 optimizer->getStopCondition()->setTolerance(tolerance);
340
341 // Optimize TreeLikelihood function:
342 ParameterList pl = parameters.getCommonParametersWith(tl->getBranchLengthsParameters());
343 optimizer->setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO);
344 if (listener)
345 optimizer->addOptimizationListener(listener);
346 optimizer->init(pl);
347 optimizer->optimize();
348 if (verbose > 0)
350
351 // We're done.
352 unsigned int n = optimizer->getNumberOfEvaluations();
353 return n;
354}
355
356/******************************************************************************/
357
359{
360 optimizeCounter_++;
361 if (optimizeCounter_ == optimizeNumerical_)
362 {
363 auto likelihood = dynamic_pointer_cast<DiscreteRatesAcrossSitesTreeLikelihoodInterface>(topoSearch_->getSearchableObject());
364 parameters_.matchParametersValues(likelihood->getParameters());
365 LegacyOptimizationTools::optimizeNumericalParameters(likelihood, parameters_, 0, nStep_, tolerance_, 1000000, messenger_, profiler_, reparametrization_, verbose_, optMethod_);
366 optimizeCounter_ = 0;
367 }
368}
369
370/******************************************************************************/
371
373{
374 optimizeCounter_++;
375 if (optimizeCounter_ == optimizeNumerical_)
376 {
377 auto likelihood = dynamic_pointer_cast<DiscreteRatesAcrossSitesTreeLikelihoodInterface>(topoSearch_->getSearchableObject());
378 parameters_.matchParametersValues(likelihood->getParameters());
379 LegacyOptimizationTools::optimizeNumericalParameters2(likelihood, parameters_, 0, tolerance_, 1000000, messenger_, profiler_, reparametrization_, false, verbose_, optMethod_);
380 optimizeCounter_ = 0;
381 }
382}
383
384// ******************************************************************************/
385
386shared_ptr<NNIHomogeneousTreeLikelihood> LegacyOptimizationTools::optimizeTreeNNI(
387 std::shared_ptr<NNIHomogeneousTreeLikelihood> tl,
388 const ParameterList& parameters,
389 bool optimizeNumFirst,
390 double tolBefore,
391 double tolDuring,
392 unsigned int tlEvalMax,
393 unsigned int numStep,
394 std::shared_ptr<OutputStream> messageHandler,
395 std::shared_ptr<OutputStream> profiler,
396 bool reparametrization,
397 unsigned int verbose,
398 const string& optMethodDeriv,
399 unsigned int nStep,
400 const string& nniMethod)
401{
402 // Roughly optimize parameter
403 if (optimizeNumFirst)
404 {
405 LegacyOptimizationTools::optimizeNumericalParameters(tl, parameters, NULL, nStep, tolBefore, 1000000, messageHandler, profiler, reparametrization, verbose, optMethodDeriv);
406 }
407 // Begin topo search:
408 auto topoSearch = make_shared<NNITopologySearch>(tl, nniMethod, verbose > 2 ? verbose - 2 : 0);
409 auto topoListener = make_shared<NNITopologyListener>(topoSearch, parameters, tolDuring, messageHandler, profiler, verbose, optMethodDeriv, nStep, reparametrization);
410 topoListener->setNumericalOptimizationCounter(numStep);
411 topoSearch->addTopologyListener(topoListener);
412 topoSearch->search();
413 return dynamic_pointer_cast<NNIHomogeneousTreeLikelihood>(topoSearch->getSearchableObject());
414}
415
416/******************************************************************************/
417
418shared_ptr<NNIHomogeneousTreeLikelihood> LegacyOptimizationTools::optimizeTreeNNI2(
419 std::shared_ptr<NNIHomogeneousTreeLikelihood> tl,
420 const ParameterList& parameters,
421 bool optimizeNumFirst,
422 double tolBefore,
423 double tolDuring,
424 unsigned int tlEvalMax,
425 unsigned int numStep,
426 std::shared_ptr<OutputStream> messageHandler,
427 std::shared_ptr<OutputStream> profiler,
428 bool reparametrization,
429 unsigned int verbose,
430 const string& optMethodDeriv,
431 const string& nniMethod)
432{
433 // Roughly optimize parameter
434 if (optimizeNumFirst)
435 {
436 LegacyOptimizationTools::optimizeNumericalParameters2(tl, parameters, nullptr, tolBefore, 1000000, messageHandler, profiler, reparametrization, false, verbose, optMethodDeriv);
437 }
438 // Begin topo search:
439 auto topoSearch = make_shared<NNITopologySearch>(tl, nniMethod, verbose > 2 ? verbose - 2 : 0);
440 auto topoListener = make_shared<NNITopologyListener2>(topoSearch, parameters, tolDuring, messageHandler, profiler, verbose, optMethodDeriv, reparametrization);
441 topoListener->setNumericalOptimizationCounter(numStep);
442 topoSearch->addTopologyListener(topoListener);
443 topoSearch->search();
444 return dynamic_pointer_cast<NNIHomogeneousTreeLikelihood>(topoSearch->getSearchableObject());
445}
446
447/******************************************************************************/
448
449shared_ptr<DRTreeParsimonyScore> LegacyOptimizationTools::optimizeTreeNNI(
450 std::shared_ptr<DRTreeParsimonyScore> tp,
451 unsigned int verbose)
452{
453 auto topo = dynamic_pointer_cast<NNISearchable>(tp);
454 NNITopologySearch topoSearch(topo, NNITopologySearch::PHYML, verbose);
455 topoSearch.search();
456 return dynamic_pointer_cast<DRTreeParsimonyScore>(topoSearch.getSearchableObject());
457}
unsigned int getNumberOfEvaluations() const override
void setProfiler(std::shared_ptr< OutputStream > profiler) override
void init(const ParameterList &params) override
void setMessageHandler(std::shared_ptr< OutputStream > mh) override
void setStopCondition(std::shared_ptr< OptimizationStopCondition > stopCondition) override
void setMaximumNumberOfEvaluations(unsigned int max) override
static void displayMessage(const std::string &text)
static void displayTaskDone()
static void displayResult(const std::string &text, const T &result)
static std::string CONSTRAINTS_AUTO
void setInitialInterval(double inf, double sup)
void setParameters(const ParameterList &lambda)
ScaleFunction(std::shared_ptr< TreeLikelihoodInterface > tl)
static std::shared_ptr< NNIHomogeneousTreeLikelihood > optimizeTreeNNI2(std::shared_ptr< NNIHomogeneousTreeLikelihood > tl, const ParameterList &parameters, bool optimizeNumFirst=true, double tolBefore=100, double tolDuring=100, unsigned int tlEvalMax=1000000, unsigned int numStep=1, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, bool reparametrization=false, unsigned int verbose=1, const std::string &optMethod=OptimizationTools::OPTIMIZATION_NEWTON, const std::string &nniMethod=NNITopologySearch::PHYML)
Optimize all parameters from a TreeLikelihood object, including tree topology using Nearest Neighbor ...
static unsigned int optimizeNumericalParameters2(std::shared_ptr< DiscreteRatesAcrossSitesTreeLikelihoodInterface > tl, const ParameterList &parameters, std::shared_ptr< OptimizationListener > listener=nullptr, double tolerance=0.000001, unsigned int tlEvalMax=1000000, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, bool reparametrization=false, bool useClock=false, unsigned int verbose=1, const std::string &optMethodDeriv=OPTIMIZATION_NEWTON)
Optimize numerical parameters (branch length, substitution model & rate distribution) of a TreeLikeli...
static unsigned int optimizeTreeScale(std::shared_ptr< TreeLikelihoodInterface > tl, double tolerance=0.000001, unsigned int tlEvalMax=1000000, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, unsigned int verbose=1)
Optimize the scale of a TreeLikelihood.
static std::shared_ptr< NNIHomogeneousTreeLikelihood > optimizeTreeNNI(std::shared_ptr< NNIHomogeneousTreeLikelihood > tl, const ParameterList &parameters, bool optimizeNumFirst=true, double tolBefore=100, double tolDuring=100, unsigned int tlEvalMax=1000000, unsigned int numStep=1, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, bool reparametrization=false, unsigned int verbose=1, const std::string &optMethod=OptimizationTools::OPTIMIZATION_NEWTON, unsigned int nStep=1, const std::string &nniMethod=NNITopologySearch::PHYML)
Optimize all parameters from a TreeLikelihood object, including tree topology using Nearest Neighbor ...
static unsigned int optimizeNumericalParameters(std::shared_ptr< DiscreteRatesAcrossSitesTreeLikelihoodInterface > tl, const ParameterList &parameters, std::shared_ptr< OptimizationListener > listener=nullptr, unsigned int nstep=1, double tolerance=0.000001, unsigned int tlEvalMax=1000000, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, bool reparametrization=false, unsigned int verbose=1, const std::string &optMethodDeriv=OPTIMIZATION_NEWTON, const std::string &optMethodModel=OPTIMIZATION_BRENT)
Optimize numerical parameters (branch length, substitution model & rate distribution) of a TreeLikeli...
static unsigned int optimizeBranchLengthsParameters(std::shared_ptr< DiscreteRatesAcrossSitesTreeLikelihoodInterface > tl, const ParameterList &parameters, std::shared_ptr< OptimizationListener > listener=nullptr, double tolerance=0.000001, unsigned int tlEvalMax=1000000, std::shared_ptr< OutputStream > messageHandler=ApplicationTools::message, std::shared_ptr< OutputStream > profiler=ApplicationTools::message, unsigned int verbose=1, const std::string &optMethodDeriv=OPTIMIZATION_NEWTON)
Optimize branch lengths parameters of a TreeLikelihood function.
static std::string IT_TYPE_STEP
static std::string IT_TYPE_FULL
void topologyChangeSuccessful(const TopologyChangeEvent &event)
Tell that a topology change is definitive.
void topologyChangeSuccessful(const TopologyChangeEvent &event)
Tell that a topology change is definitive.
NNI topology search method.
static const std::string PHYML
std::shared_ptr< NNISearchable > getSearchableObject()
void search()
Performs the search.
static std::string OPTIMIZATION_NEWTON
static std::string OPTIMIZATION_BFGS
static std::string OPTIMIZATION_BRENT
static std::string OPTIMIZATION_GRADIENT
virtual bool hasParameter(const std::string &name) const
virtual void addParameters(const ParameterList &params)
size_t size() const
virtual ParameterList getCommonParametersWith(const ParameterList &params) const
virtual std::vector< std::string > getParameterNames() const
virtual void addParameter(const Parameter &param)
virtual void deleteParameter(const std::string &name)
virtual void reset()
virtual ParameterList createSubList(const std::vector< std::string > &names) const
This Optimizer implements Newton's algorithm for finding a minimum of a function. This is in fact a m...
Class for notifying new toplogy change events.
Defines the basic types of data flow nodes.
ExtendedFloat exp(const ExtendedFloat &ef)