Optimisation Practical
[Practical 10 of 11] - Part 1
Make DataHandler a Singleton:
Currently we can make as many DataHandler objects as we want. Actually it would be beneficial for us to
just have one, so we can load the data and access it from anywhere. There is a pattern to help us do this it is called
the singleton.
In this pattern we create a private static instance variable of type DataHandler called data.
data belongs to the class because it is static (remember practical 1) and it is private so it can only
be accessed from within the DataHandler class.
Next we set the constructor for the class to be private which effectively means that nothing can make an
instance of this class. To access the class we create a method, public static DataHandler getDataHandler.
This method belongs to the class (it is static) so can be called before an instance of the class exists.
It checks to see if an instance has been made in out static variable data, if not it creates one and
returns it, if there is one existing already it simply returns that one.
This means we can only ever have one object of type DataHandler so we can get the instance from anywhere and
know that it is consistent across all objects in our project.
Altering this will have caused errors to appear in the SpatialInteractionModel class, don't worry we will deal with
these in a little while.
Create Parameter:
Create a new class in your SIM package called Parameter. Add the imports, constructors and
getValue method as shown in Figure 3.
Now add the extends Gene code after the class declaration and select to implement all
abstract methods by clicking on the yellow light bulb in the left margin.
When you have selected to implement all abstract methods you will get a series of method declarations. Delete the auto-generated error messages and populate the methods as shown in Figure 4.
The key method here is the mutate method which is called by the genetic algorithm to mutate the genes as the
algorithm evolves towards a solution. The clone method creates a exact replica of the this object in a completely
separate reference. This is important to ensure that as one 'gene' mutates it does not affect any other 'genes' being used
elsewhere.
The equals method compares two objects to see if they area meaningfully equal. Read the code to see if you
understand how this is being accomplished. Why do you think we only consider a set number of decimal places?
Adjust Model:
We need to adjust our model class so that we can use it with the genetic algorithm and so that it will use the
DataHandler as a singleton. First we need to add the two imports:
import uk.ac.leeds.mass.optimisation.genetic.Chromosome;
import uk.ac.leeds.mass.statistics.gof.IGOF;
Delete the constructor that takes in a parameter and make the current private constructor public.
Add the line data = DataHandler.getDataHandler(); to the top of the calculate method.
We need to inherit the functionality of the genetic algorithm using the code extends Chromosome after the
class declaration. Figure 5 shows the Model class header as it should be after these changes.
When Chromosome has been inherited into Model you will be prompted to
implement all abstract methods.
The auto-generated methods will again be populated by code to raise an error link the ones shown in Figure 6. Delete these error lines.
Replace the auto-generated code with the code shown in Figure 7. The populateGenes populates the Genes in the
Chromosome class that we have inherited.
The calculateFitness method runs the model and uses the
IGOF object passed into the method to calculate the fitness statistic which is then returned. It is worth noting
that the instance level i and j variables need to be reset before each run of the model. If
this is not done the model will not run (because the index counters are already at their maximum values) and you will get
a result array full of 0.0s.
Create ModelMenuItemListener:
We are going to add a Menu structure to the GUI, so we will need a way to act on events raised. Create a new class
in the SIM package called ModelMenuItemListener. Populate it with the code as shown in
Figure 8.
The actionPerformed method is called when an action is performed on a menu item that an object created
from this class has been attached to. The ActionEvent parameter provides us with information about the
event. We use one of these pieces of information to decide on the action to take.
When you enter the line sim.setPane it will show as an error. This is to be expected as the method does
not exist yet, we will create that in a little while.