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 Gene
s 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.