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.

Making DataHandler a Singleton
Figure 2

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.

Making the Parameter class
Figure 3

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?

Populating the abstract methods in Parameter
Figure 4

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.

Extending Chromosome into Model
Figure 5

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.

Implementing abstract methods
Figure 6

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.

Populating the abstract methods
Figure 7

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.

Creating the Listener
Figure 8

Continue to part 2