Functions

From Bio++ Wiki
Jump to: navigation, search

The Bio++ NumCalc module allows you to easily handle functions in an object-oriented way. It include support for parameter constraints, numerical derivatives and function optimization (minimum finding). This articles presents an overview of the existing classes. Detailed functionalities can be found in the API documentation.

Parameters

Parameters are the most simple objects in the function set. A parameter is an instance of the Parameter class, which has basically three features:

  • A name
  • A value (floating)
  • An optional pointer toward a constraint object.

Constraints are instances of the Constraint interface. There is a full hierarchy of those. A Constraint object simply tells whether a value is correct or not (isCorrect(double value) method). If a constraint is attached to a parameter and an incorrect value is specified using the setValue(double) method, then a ConstraintException is raised.

Parameter lists

ParameterList objects are simple Parameter containers. They provide name access (see getParameter(string name)), but also several tools to merge and update distinct parameter lists. A ParameterList own the stored parameters, which are copied when needed. Parameters are however stored as pointers, so that the copy will preserve the original type of parameters: it is possible to define your own parameter class by extending Parameter, and still be able to store them in a ParameterList without any loss.


Objects with parameters

Several objects in Bio++ have parameters (functions of course, but also probability distributions, and more generally, any kind of model). An object with parameters implements the Parametrizable interface. The Parametrizable interface has functions similar to the ParameterList object, as it allows name access and parameter updates. As a consequence, many Parametrizable objects will simply maintain a ParameterList, and retrieve values when needed. The AbstractParametrizable class provides a simple implementation of the Parametrizable interface based on this principle, so that the user has very few remaining functions to implement: in most cases, this will basically consist in declaring the supported parameters in the constructor of the derived class. This abstract class capture any parameter modification by firing an event, that can be caught on the derived class (see Implementing a Parametrizable class). Parametrizable objects also add support for namespaces. As there can be conflicts between parameter names in some complicated cases, this can turn useful (for instance to distinguish between the alpha shape parameter of a gamma law and an alpha parameter in a substitution model).

Function objects

Function object are Parametrizable objects. They basically add two methods:

  1. setParameters(ParameterList) will update the inner parameter list with the values in the given list,
  2. double getValue() will return the function value for the current parameter values.

The distinction between these two steps is for computational efficiency: for complicated functions, the setParameters method will only perform the required recomputations depending on the modified parameter values. Several call on getValue() while parameters did not change will therefore be very fast. For convenience, a double f(ParameterList) function is provided, which simply calls setParameters and getValue() consecutively.

The Derivable FirstOrder and DerivableSecondOrder interfaces inherit from the Function interface, and add support for derivatives.

Here is an example of function implementation: <source lang="cpp"> using namespace bpp;

class MyFunction:

 public virtual Function,
 public AbstractParametrizable

{

 private:
   double fval_;
 public:
   MyFunction() : AbstractParametrizable(""), fval_(0) {
     //We declare parameters here:
     addParameter_(Parameter("x", 0));
     addParameter_(Parameter("y", 0));
   }
   MyFunction* clone() const { return new MyFunction(*this); }
 public:
   void setParameters(const ParameterList& pl) 
       throw (ParameterNotFoundException, ConstraintException, Exception)
   {
     matchParametersValues(pl);
   }
   double getValue() const throw (Exception) { return fval_; }
   void fireParameterChanged(const ParameterList& pl) {
     double x = getParameterValue("x");
     double y = getParameterValue("y");
     fval_ = sqrt((x-5)*(x-5) + (y+2)*(y+2));
   }

}; </source> Parameters supported by the function are declared in the constructor using the addParameter_ protected function. The matchParametersValues function from the AbstractParametrizable class updates the parameters with the ones passed as argument of the setParameters method, which will call fireParameterChanged if some parameter value have changed. The actual fucntion claculation are in fireParameterChanged, so that they are only performed when need. [Note that the function could be further optimized by testing if only one of the two parameters actually changed, by only recalculating one square value...]

How to find the minimum of a function: Optimizers

Optimizer objects implement methods for finding the minimum of a Function object. Several methods are available, and the detailed use can be slightly different. The global scheme however is to

  1. build a new optimizer object,
  2. set the function to optimize,
  3. set the parameters that have to be searched through, together with their initial values (init(ParameterList)),
  4. launch the optimization (optimize())

The end of the optimization process is determined using an OptimizationStopCondition object which has to be set and can be changed. Most optimizers provide a default one though. Optimizer objects also support detailed logging. The values that parameters take over the optimization process, together with any error that happens can be caught (see setProfiler and setMessageHandler methods). Optimizer objects also generate events, which can be used to finely tune the full process. Finally, Bio++ optimizers can deal with parameter constraints. The easiest way is to use the AutoParameter functionality (see setConstraintPolicy). Another possibility is to use a ReparametrizationFunctionWrapper, which will automatically transform the parameter space to remove constraints.

We can take the example of the previous section to find the minimum of the function: <source lang="cpp"> Function* f = new MyFunction; Optimizer* optimizer = new SimpleMultiDimensions(f); optimizer->init(f->getParameters()); //Here we optimizer all parameters, and start with the default values. optimizer->optimize(); optimizer->getParameters().printParameters(cout); //Outputs result to the standard output. </source>

By default, the optimizer outputs a lot of text, including for instance all the parameter values that were reached during optimization. This can be easily switch off or redirected to files, for instance by calling <source lang="cpp"> optimizer->setProfiler(0); optimizer->setMessageHandler(0); </source>