Difference between revisions of "Observables"

From SUMOwiki
Jump to navigationJump to search
 
(6 intermediate revisions by one other user not shown)
Line 8: Line 8:
 
* A complete generation has been built for the genetic model builder
 
* A complete generation has been built for the genetic model builder
  
The observables are currently split into two groups, observables on a model, and observables on a batch (or generation) of models.  
+
The observables are currently split into two groups, observables on a '''model''', and observables on a '''batch''' (or generation) of models.  
 +
 
 
Examples of the first kind are:
 
Examples of the first kind are:
 
* Weights, flags and percentage for rational models
 
* Weights, flags and percentage for rational models
Line 16: Line 17:
 
* Spread (= largest/average/smallest value) of model parameters for a generation
 
* Spread (= largest/average/smallest value) of model parameters for a generation
 
* Distribution of different model types in a generation when using the heterogeneous model interface
 
* Distribution of different model types in a generation when using the heterogeneous model interface
 +
  
 
To accommodate this framework, a few key components have been implemented:
 
To accommodate this framework, a few key components have been implemented:
 
* The <code>getObservables()</code> member function that each model interface should implement. This method returns a cell array of Observable objects.
 
* The <code>getObservables()</code> member function that each model interface should implement. This method returns a cell array of Observable objects.
 
* The <code>getBatchObservables()</code> member function of <code>BatchInterface</code> (superclass of <code>GeneticInterface</code>). This method return a cell array of observable objects on a Batch/Generation of models.
 
* The <code>getBatchObservables()</code> member function of <code>BatchInterface</code> (superclass of <code>GeneticInterface</code>). This method return a cell array of observable objects on a Batch/Generation of models.
* The methods <code>registerObserver()</code> and <code>observe()</code> of the <code>AdaptiveModelBuilder</code> base class.
+
* The methods <code>registerObserver()</code> and <code>observe()</code> of the <code>ModelBuilder</code> base class.
  
 
The sequel will elaborate on all different classes and components.
 
The sequel will elaborate on all different classes and components.
Line 26: Line 28:
 
== Observable ==
 
== Observable ==
  
The Observable class is just an `abstract' base class corresponding to `a thing that can be observed'. It has following methods:
+
The <code>Observable</code> class is just an `abstract' base class corresponding to `a thing that can be observed'. It has following methods:
* Observable( (string) name, (string) description ). The constructor (doh)
+
* <code>Observable( (string) name, (string) description )</code>. The constructor (doh)
* (string) getName( void ) { return name; }
+
* <code>(string) getName( void ) { return name; }</code>
* (string) getDescription( void ) { return description; }
+
* <code>(string) getDescription( void ) { return description; }</code>
* (struct) getColumns( void )
+
* <code>(struct) getColumns( void )</code>
* (vector) process( (void*) object )
+
* <code>(vector) process( (void*) object )</code>
 +
 
  
getColumns() returns names and descriptions for the outputs of this observable. For example, suppose we work in input dimension 3: An Observable that extracts the weight parameters out of a polynomial model, returns names [weight1, weight2, weight3] and suitable descriptions.
+
<code>getColumns()</code> returns names and descriptions for the outputs of this observable. For example, suppose we work in input dimension 3: An Observable that extracts the weight parameters out of a rational model, returns names [weight1, weight2, weight3] and suitable descriptions.
The return type of getColumns() is a struct array with 2 fields, `name' and `description'.
+
The return type of <code>getColumns()</code> is a struct array with 2 fields, '<code>name</code>' and '<code>description</code>'.
  
process() processes the object (e.g. a model) out of which something has to be extracted (e.g. the weights) and returns the extracted values. It is mandatory the length of the double vector returned matches the number of columns returned by getColumns(). If it is impossible to extract the data from the model, process() SHOULD return an empty vector []
+
<code>process()</code> processes the object (e.g. a model) out of which something has to be extracted (e.g. the weights) and returns the extracted values. It is mandatory the length of the double vector returned matches the number of columns returned by <code>getColumns()</code>. If it is impossible to extract the data from the model, <code>process()</code> SHOULD return an empty vector []
  
 
Things will become clearer as you read on!
 
Things will become clearer as you read on!
Line 42: Line 45:
 
== SimpleObservable ==
 
== SimpleObservable ==
  
Most Observables are quite simple, e.g. they just extract a field from a model object. Therefore, we have the SimpleObservable class, it has following methods:
+
Most Observables are quite simple, e.g. they just extract a field from a model object. Therefore, we have the <code>SimpleObservable</code> class, it has following methods:
* SimpleObservable( name, description, classtype, functor [, numColumns] ). If numColumns unspecified, use 1.
+
* <code>SimpleObservable( name, description, classtype, functor [, numColumns] )</code>. If <code>numColumns</code> unspecified, use 1.
* (struct) getColumns( void )
+
* <code>(struct) getColumns( void )</code>
* (vector) process( (void*) object )
+
* <code>(vector) process( (void*) object )</code>
  
process() checks whether the object passed is of type `classtype'. If not, it returns []. Else, it returns `feval( functor, object )'.
+
<code>process()</code> checks whether the object passed is of type '<code>classtype</code>'. If not, it returns []. Else, it returns '<code>feval( functor, object )</code>'.
  
getColumns() returns a struct array with names [name_1, ..., name_`numColumns'] and suitable descriptions.
+
<code>getColumns()</code> returns a struct array with names [name_1, ..., name_`numColumns'] and suitable descriptions.
  
As an example, following extract of PolynomialInterface::getObservables() constructs an Observable which processes only PolynomialModels, and has as a functor an implicit function which extract the config.parameters.weights field.
+
As an example, following extract of <code>RationalInterface::getObservables()</code> constructs an Observable which processes only RationalModels, and has as a functor an implicit function which extract the <code>config.parameters.weights</code> field.
  
 
<code>
 
<code>
Line 62: Line 65:
 
</code>
 
</code>
  
== AdaptiveModelBuilder ==
+
== ModelBuilder ==
  
 
The Adaptive Model Builder provides two methods:
 
The Adaptive Model Builder provides two methods:
* (AMB) registerObserver( (AMB) self, (string) tag, (string) x_name, (string) description, (Observable cell array) observables );
+
* <code>(ModelBuilder) registerObserver( (ModelBuilder) self, (string) tag, (string) x_name, (string) description, (Observable cell array) observables );</code>
* (AMB) observe( (AMB) self, (string) tag, (double) x_value, (void*) object );
+
* <code>(ModelBuilder) observe( (ModelBuilderself, (string) tag, (double) x_value, (void*) object );</code>
where AMB is short for AdaptiveModelBuilder...
 
  
 
The constructor of a xxxModelBuilder can register a new timestamp (tag) at which it wants to do profiling in the future. Example tags are:
 
The constructor of a xxxModelBuilder can register a new timestamp (tag) at which it wants to do profiling in the future. Example tags are:
* best (AdaptiveModelBuilder) -> The model parameters for each new best model
+
* best (ModelBuilder) -> The model parameters for each new best model
 
* iteration (SequentialModelBuilder) -> The model parameters for each model built
 
* iteration (SequentialModelBuilder) -> The model parameters for each model built
 
* batch (BatchModelBuilder) -> Model parameters of the best model in each batch
 
* batch (BatchModelBuilder) -> Model parameters of the best model in each batch
Line 77: Line 79:
 
`x_name' is a string name for the x-axis of the plot. `description' is a description of the plot. The last parameter of <code>registerObserver()</code> is a list of [[Observables]].
 
`x_name' is a string name for the x-axis of the plot. `description' is a description of the plot. The last parameter of <code>registerObserver()</code> is a list of [[Observables]].
  
<code>observe()</code> is called each time a new row has to be added to the profiler or when the last row has to be updated (the AMB keeps track of the last x_value's passed). A call to <code>observe()</code> makes the AMB browse through its registered `tag's looking for all matches. For each match, and each Observable, the Observable is called on the `object' parameter, and (if the observable returns data) its corresponding profiler gets updated.
+
<code>observe()</code> is called each time a new row has to be added to the profiler or when the last row has to be updated (the ModelBuilder keeps track of the last x_value's passed). A call to <code>observe()</code> makes the ModelBuilder browse through its registered `tag's looking for all matches. For each match, and each Observable, the Observable is called on the `object' parameter, and (if the observable returns data) its corresponding profiler gets updated.

Latest revision as of 09:03, 17 March 2014

General

This page explains the observables framework. It is designed to profile certain model parameter properties at certain timestamps during the adaptive modeling process.

Example timestamps are:

  • A new best model has been constructed
  • A new model has been constructed for the sequential model builder
  • A complete generation has been built for the genetic model builder

The observables are currently split into two groups, observables on a model, and observables on a batch (or generation) of models.

Examples of the first kind are:

  • Weights, flags and percentage for rational models
  • Kernel parameter (= spread) for a RBFNN model

Examples of the second kind are:

  • Model parameters of the best model in a generation
  • Spread (= largest/average/smallest value) of model parameters for a generation
  • Distribution of different model types in a generation when using the heterogeneous model interface


To accommodate this framework, a few key components have been implemented:

  • The getObservables() member function that each model interface should implement. This method returns a cell array of Observable objects.
  • The getBatchObservables() member function of BatchInterface (superclass of GeneticInterface). This method return a cell array of observable objects on a Batch/Generation of models.
  • The methods registerObserver() and observe() of the ModelBuilder base class.

The sequel will elaborate on all different classes and components.

Observable

The Observable class is just an `abstract' base class corresponding to `a thing that can be observed'. It has following methods:

  • Observable( (string) name, (string) description ). The constructor (doh)
  • (string) getName( void ) { return name; }
  • (string) getDescription( void ) { return description; }
  • (struct) getColumns( void )
  • (vector) process( (void*) object )


getColumns() returns names and descriptions for the outputs of this observable. For example, suppose we work in input dimension 3: An Observable that extracts the weight parameters out of a rational model, returns names [weight1, weight2, weight3] and suitable descriptions. The return type of getColumns() is a struct array with 2 fields, 'name' and 'description'.

process() processes the object (e.g. a model) out of which something has to be extracted (e.g. the weights) and returns the extracted values. It is mandatory the length of the double vector returned matches the number of columns returned by getColumns(). If it is impossible to extract the data from the model, process() SHOULD return an empty vector []

Things will become clearer as you read on!

SimpleObservable

Most Observables are quite simple, e.g. they just extract a field from a model object. Therefore, we have the SimpleObservable class, it has following methods:

  • SimpleObservable( name, description, classtype, functor [, numColumns] ). If numColumns unspecified, use 1.
  • (struct) getColumns( void )
  • (vector) process( (void*) object )

process() checks whether the object passed is of type 'classtype'. If not, it returns []. Else, it returns 'feval( functor, object )'.

getColumns() returns a struct array with names [name_1, ..., name_`numColumns'] and suitable descriptions.

As an example, following extract of RationalInterface::getObservables() constructs an Observable which processes only RationalModels, and has as a functor an implicit function which extract the config.parameters.weights field.

SimpleObservable(

 'weight', ...
 'The weight for a variable of a polynomial interpolant', ...
 'PolynomialModel', ...
 @(x) extractField( x, 'config.parameters.weights' ), ...
 s.dimension );

ModelBuilder

The Adaptive Model Builder provides two methods:

  • (ModelBuilder) registerObserver( (ModelBuilder) self, (string) tag, (string) x_name, (string) description, (Observable cell array) observables );
  • (ModelBuilder) observe( (ModelBuilderself, (string) tag, (double) x_value, (void*) object );

The constructor of a xxxModelBuilder can register a new timestamp (tag) at which it wants to do profiling in the future. Example tags are:

  • best (ModelBuilder) -> The model parameters for each new best model
  • iteration (SequentialModelBuilder) -> The model parameters for each model built
  • batch (BatchModelBuilder) -> Model parameters of the best model in each batch
  • ...

`x_name' is a string name for the x-axis of the plot. `description' is a description of the plot. The last parameter of registerObserver() is a list of Observables.

observe() is called each time a new row has to be added to the profiler or when the last row has to be updated (the ModelBuilder keeps track of the last x_value's passed). A call to observe() makes the ModelBuilder browse through its registered `tag's looking for all matches. For each match, and each Observable, the Observable is called on the `object' parameter, and (if the observable returns data) its corresponding profiler gets updated.