Refactor for conveniance

Points from previous post

There will be a Go conference in Paris on the 10th of October 2014 (The European Go Conference).

It’s up to the discretion of the developer if they want to convert the number to log, and if they do, they can just do it within the fitness function they define. For those times, I have added an extra attribute to the individual struct ([]chromoVal) that can be used to store the floating point representation of the chromosome or any other fitness calculation needs.

 

 

Refactoring for usability

I have also restructured, refactored and commented the whole framework for ease of use and scalability. This included adding an additional population struct parameter ‘roulSelectCount’ that allows the user to change the number of low fitness individuals replaced with their higher fitness counter parts during the roulette wheel selection process.

 

This was accompanied with a change a change to the roulette selection method.

 

This adds the complexity of having to define this parameter during initialisation.

Additionally, I removed the need to do sum up the populations fitness within the fitness functions. The summed population fitness is used within the roulette selection process. Before we had this line (line 20) that incremented a population fitness counter.

 

 

This was stored in a population field and used within the relative fitness calculation

 

 

This method was a little more efficient computation wise since we incremented the counter while calculating the fitness but it required the user to remember to always remember to include that line of code during each optimisation function calculation. So we opted to implement an additional method whose sole job is to return the summed fitness of the current population.

 

Now we no longer need the ‘totalPopFit’ field in the population struct and the framework is abit more user friendly but a little more processor intensive.

To confirm that the relative fitness calculation is still correct. I lowered the population size to 4 individuals and manually made sure that when the relative fitness of every individual within a population  is summed up, it equal to 1.

 

 

With all these changes, I removed the mate and calcfitness methods and used one single method called evolve to carry out one iteration of optimisation on a population.

 

When more selection and crossover methods are implemented. I will also have to make generic assignable functions for the selection and crossover methods (Just like I did for the fitness function).

After double checking that the changes in code structure did not impact behaviour by testing out both DeJong’s Function and the simple fitness function. I proceeded.

How to use the Go rand method

Analysis of the mutation problem in Go mentioned in the previous post.

The mutation genetic operation is called by the uniform crossover method in this framework.

 

We multiply the mutationRate by two because we are working on two individuals at a time, and then only select one of them depending on a 50% chance.

 

We then call the mutation function that randomly picks a gene within the chromosome to mutate (and in the case of decimal encoding, randomly pick a new value between 0-9).

As can be seen, we are heavily relying on the Go random function.

Yet, this is the behaviour we get over several generations (approximately 4-8 generations at a time).

 

It seems like the rand values do not change for several generations as the rand method picks the same values over several iterations.

Okay, so let’s simplify the output code so that we only get the run number and the mutation value when the mutation operation is called.

Updated code:

 

Results:

 

 

As can be seen, We are generating the same exact number for different functions over several generation (5 in this case). So let’s try to reseed the rand function.

 

 

And the results:

 

 

It took 3 trials to create the problem this time, but it still is occurring. So let’s see what the inter-web has to say about this. According to stack overflow  , I should seed the rand function at the start of the main function. I was already reseeding in the initialisation method for the population but still, let’s move all reseeding to the top of main function.

 

 

Voila!! It worked, but it only worked because I reseeded only once, In the main function. So there you go guys, the secret to random behaviour in the rand function is to seed only once at the start of the main function. The key thing is to call it only once, I moved that call to the first line evaluated in the framework and the behaviour is still the same. Problem solved!

 

Investigating the NaN problem

I initially thought that the NaN message that came up previously weas due to the -0 number being stored in the float64 variable. So I first created a check and some if statements that took care of the negative zero statement and printed out a message.

 

So it shouldn’t, bring up a NaN message then? Well it still does:

 

I assume that since this only appears during the running of the algorithm and disappears after a generation is calculated (as seen in the population print out after ‘completed’ in the screen grab). The number may be stored under a different representation by the compiler during run time and so appears as NaN when printed.

Additionally I made the chromo2float() function more flexible since it now allows the user to choose if the first bit it evaluates deals with the sign (+/-) of the chromosome.

 

This also required an addition of the chromoSign attribute to the population struct:

 

 

A flexible initialisation

I also added the ability of the GA to automatically calculate the chromosome length when given the number of dimensions of the target solution, how many bits (genes) will represent each float and whether the search space includes signed numbers. Also did additional checks on other variables such as roulette selection count.

 

 

Now the initialisation of the GA can be called like this:

 

Lines 16-18 are now used to automatically calculate the chromosome length.

 

Issue with the Rosenbrock function

Now all I have to do is implement all the fitness functions, but I have been running into a strange problem with the rosenbrock function:

 

 

I have implemented it but there must be an error in there somewhere since it does not properly converge to a solution of 0.

 

The above completed list is ordered by fitness from left top being the fittest to bottom right being the un-fittest. We now the true solution converges at 0 yet the above screen cap shows that the program seems to think that the solution that aren’t 0 have a higher fitness than the solutions that are 0. The fitness can be seen in the first element of every individual object {}. This problem requires more investigation, then I can implement other fitness functions.

I am currently on number 4 on the to-do list from last week’s post.

 

Talk with Prof. Emma H.

I had the chance to discuss my project with Prof. Emma H. and she suggested that if I manage to complete the total implementation of it this week. Then it may be possible for me to do a direct comparison between the HFC model and more traditional multi-population island models then right a paper on it for publication in this year’s evolutionary algorithms journal. Which has a submission deadline of next Friday or the following Friday if it is extended.

 

 

 

 

Comments   

0 #1 Jon Kerridge 2014-03-11 13:46
What a lot of work done and achieved.

If you can, go for Emma's paper!
Then return to the parallel stuff

You need a poster for 9th April
Stress GO parallel HFC
Flexible Architecture and novelty thereof
sell yourself
Quote

Add comment


Security code
Refresh