Reputation: 1780
Has anyone seen convincing results from the .Net Genetic Algorithm Framework?
I am seeing poor randomization in the Traveling Salesman Problem demo provided with the Genetic Algorithm Framework. The following call generates the same gene shuffle order across the x 100 seed chromosome population:
chromosome.Genes.ShuffleFast();
If I single step through the code the gene order looks randomized hence I suspect there is a time/Rdn() bug in ShuffleFast() or else I am overlooking a setup step.
I have tried to work around the problem by preshuffling the chromosome gene sequences and this produced a minor change in the TSP results. However the console log of the run still shows the GAF discovering only 4 potential solutions across 400 population generations. This is at odds with GA YouTube videos showing genetic algorithm implementations homing in on a suggested solution with a lot of jitter. I cite this as a further indication that the GAF has a systemic internal problem with random number generation.
The Genetic Algorithm Framework is very well documented via the authors Blog, so I am trying to keep an open mind as the reason.
Steps to reproduce = Download GAF from nuget, compile & debug the default project with a breakpoint after the create chromosomes for-loop, inspect population.Solutions. Windows 7, VS2015, .Net 4.5 & 4.61. Debug or Release.
Upvotes: 6
Views: 723
Reputation: 384
Sorry for the late response to the question. The issue is indeed with the GAF. The Shuffle method uses a System.Random number generator and creates a new one each time the method is called. This causes issues due to seeding. I have fixed this (tonight) in the GAF and this will be in the next release. I suggest that the following code is used as a workaround.
var rnd = GAF.Threading.RandomProvider.GetThreadRandom ();
myList.ShuffleFast (rnd);
Each random number generator created using the above code creates a random number generator with a singe seed per thread. This can then be passed to the Shuffle() method as described by Matthew.
Upvotes: 3
Reputation: 20620
Looking at the code in a disassembler, there are two versions of ShuffleFast
defined as extension methods: one takes a Random
object as a parameter and the other creates a new one using the default constructor and uses that. They are otherwise identical, doing a standard Fisher–Yates shuffle.
So you need to construct your own Random
and then pass it in:
Random r = new Random();
...
chromosome.Genes.ShuffleFast(r);
otherChromosome.Genes.ShuffleFast(r);
...
This way you've got only one stream of random numbers, and that stream is seeded based on the current time whenever you run your program.
Upvotes: 3