
Introduction to events
EpochX has an event handling mechanism which provides a way of listening for life cycle events such as the start of a crossover operation or the end of a generation. This is a powerful tool for interacting with the framework while it runs. The two most common uses of the life cycle listeners are for generating output at regular intervals and for modifying the run parameters dynamically.
All life events are handled by an instance of the Life
class.
Infact, we can refer to it as the instance of the Life
class, since
it implements the singleton pattern and so there is only ever one Life
object. You can obtain a reference to this instance from anywhere with a call to
the static method Life.get()
. The Life
class has a series of addXxxListener
methods
for adding listeners for different classes of event. The following is a list of the
standard addXxxListener
methods.
addCrossoverListener(CrossoverListener)
addElitismListener(ElitismListener)
addGenerationListener(GenerationListener)
addInitialisationListener(InitialisationListener)
addMutationListener(MutationListener)
addPoolSelectionListener(PoolSelectionListener)
addReproductionListener(ReproductionListener)
addRunListener(RunListener)
Each of these methods takes a listener instance. As is often the case with the listener pattern,
it would be typical to use an anonymous class that implements the listener interface. As such, an
XxxAdapter
abstract class exists for each XxxListener
that implements
that interface providing empty methods for each of the events. This makes it much more convenient
to extend XxxAdapter
, overriding only those methods for the events you are interested
in. For example, the following code might be used to listen for crossover end events.
Life.get().addCrossoverListener(new CrossoverAdapter(){ public void onCrossoverEnd() { // ...code to be executed at the end of each crossover. } });
Config events
In addition to the above classes of event, there is also one other type of event; the
config event. Listeners for the config event can be added in the same way, with the
addConfigListener(ConfigListener)
method. ConfigListener
only defines one
method - onConfigure
. This event is caused to fire at the following times:
- At the start of a series of runs.
- At the start of each run.
- At the start of initialisation and each generation.
- When manually fired.
When using the built-in components and operators provided with EpochX, there is probably no need to use config events at all. Their use will happen in the background. But, if you find yourself implementing a new operator, you might want to consider using them. A detailed description of how to go about this will be covered in a later tutorial, but it is worth describing the concept here. All built-in components and operators that require parameters have two forms of construction. They can either be constructed with the parameter values themselves, or with a reference to a model. In the latter case, they obtain the parameter values they need from the model and refresh the parameter values they are using upon every config event. As already mentioned in the Models chapter, this allows models to dynamically change their values and have the new value used from the next config event.
Although not usually necessary, it is possible to force operators to update their parameter values from
the model more frequently than at each generation by firing the config event manually. This can be done
with the following statement: Life.get().fireConfigureEvent();
Strong and weak listeners
In truth, the addXxxListener
methods above are only half the story, because for each one that takes
just an XxxListener
, there is another version which also takes a boolean value. The boolean
is an indicator for whether a strong reference should be maintained to the listener as it is stored in the Life
object. If the value is false
then only a weak reference will be maintained. Most users should
simply use the standard addXxxListener
method, which will use a strong reference by default. In
some extreme cases it may be possible to introduce a memory leak when adding listeners and not removing them
once finished, by using a weak reference they will automatically be removed when possible. This is something
that should simply be ignored by most users, it is mentioned here mainly for completeness.
Next: Statistics
Previous: Algorithm