private void Process(GeneType geneType) { var solutions = _population.Solutions; double totalFitness = 0.0; double maximumFitness = 0.0; double minimumFitness = 1.0; var fitnessList = new List <double> (_populationSize); double totalHammingDistance = 0.0; double totalFitnessDistance = 0.0; int [] diversityGraph = new int [BucketCount]; //loop through each solution for (var sIndex = 0; sIndex < _populationSize; sIndex++) { var solution = solutions [sIndex]; #region Storing Data for Later //store the values for using later on with Average and StddDev var currentFitness = solution.Fitness; totalFitness += currentFitness; fitnessList.Add(currentFitness); #endregion #region Max and Min if (currentFitness < minimumFitness) { minimumFitness = currentFitness; } if (currentFitness > maximumFitness) { maximumFitness = currentFitness; } #endregion #region Hamming Distance //TODO: Check that this is correct. //We safely compare to ourselves as this will produce a 0 result. //compare the current solution with all others. Note that we only need //to compare each once hence the shortened 'innerIndex' loop for (var innerIndex = sIndex; innerIndex < _populationSize; innerIndex++) { // hamming only applies to binary chromosome if (geneType == GeneType.Binary) { //calculate hamming distance var string1 = solutions [sIndex].ToBinaryString(); var string2 = solutions [innerIndex].ToBinaryString(); //TODO: Look at converting the binary to an integer and using the bitwise function (See below) for (var index = 0; index < _chromosomeLength; index++) { if (string1 [index] != string2 [index]) { totalHammingDistance++; } } //our gene is actually strored as a double. //we also need to make sure we dont cause errors if a non binary chromosome is used; //e.g. Here is an example in C comparing two integers /* * def hamming2(x,y): * """Calculate the Hamming distance between two bit strings""" * assert len(x) == len(y) * count,z = 0,x^y * while z: * count += 1 * z &= z-1 # magic! * return count */ //end of hamming distance } //fitness distance (diversity via fitness var fitness1 = solutions [sIndex].Fitness; var fitness2 = solutions [innerIndex].Fitness; totalFitnessDistance += System.Math.Abs(fitness1 - fitness2); } //Debug.Print ("Total Hamming Distance: {0}", new [] { totalHammingDistance.ToString() }); //Debug.Print ("Total Fitness Distance: {0}", new [] { totalFitnessDistance.ToString () }); #endregion #region Diversity Graph var bucket = (int)System.Math.Floor(currentFitness / (1.0 / BucketCount)); //if fitness ends up being 1.0 we could end up with a bucket of 16 which would fail if (bucket == BucketCount) { bucket--; } diversityGraph [bucket]++; /* * Each bucket will contain the number of solutions from the total number of solutions * in the population. */ #endregion } #region Hamming Distance // sampleSize is given by = N(N-1)/2 and is the number of chromosome comparisons // totalHammingDistance refers to the number of bits that are different when comparing // all chromosomes with each other e.g. N(N-1)/2 // average hammiing distance starts at approximatelly: chromosomeLength/2 // and ends up at 0 when the GA is converged var sampleSize = (_populationSize * (_populationSize - 1)) / 2.0; AverageHammingDistance = (totalHammingDistance / sampleSize); AverageFitnessDistance = totalFitnessDistance / sampleSize; //if (AverageHammingDistance < 0) // throw new ApplicationException ("Hamming Distance is negative."); //if (AverageFitnessDistance < 0) // throw new ApplicationException ("Fitness Distance is negative."); #endregion #region Duplicates double percentageDuplicates = 0.0; var count = _population.GetDuplicates(); if (count > 0) { percentageDuplicates = ((double)count / _populationSize) * 100; } this.Duplicates = (int)System.Math.Round(percentageDuplicates); #endregion #region Upper Quartile Count var uqCount = 0; for (var bucket = BucketCount - UpperQuartileBucketCount; bucket < BucketCount; bucket++) { uqCount += _diversityGraph [bucket]; } this.UpperQuartileCount = (int)(((double)uqCount / _populationSize) * 100); #endregion #region Scale the Distribution Graph for (int index = 0; index < diversityGraph.Length; index++) { var bucketPercentage = ((double)diversityGraph [index] / _populationSize) * 100; var bucketPercentageScaled = bucketPercentage * _diversityGraphScale; diversityGraph [index] = (int)(bucketPercentageScaled <= 100 ? bucketPercentageScaled : 100); } this.DiversityGraph = diversityGraph; #endregion #region Average Fitness if (!Math.AboutEqual(totalFitness, 0.0) && _populationSize != 0) { this.AverageFitness = totalFitness / _populationSize; } #endregion #region Standard Deviation this.StandardDeviation = CalculateStdDev(fitnessList); #endregion #region Max/Min this.MaximumFitness = maximumFitness; this.MinimumFitness = minimumFitness; #endregion this.C9Fitness = GAF.Math.ReRange(GetConsecutiveNines(maximumFitness), 0, 10, 0, 1); //TODO: Determine how is this derived? //average hamming distance is per population, and ranges from chromosomeLenth/2 //(good estimate of initial hamming distance, see Louis & Rawlins, Predicting Convergence Time for Genetic Algorithms) //and 0 (fully converged). //e.g. with a chromsome length of 22 the range would be 22 - 0 the following rescales to 1 - 0;) var diversity = (AverageHammingDistance / (_chromosomeLength / 2)); if (diversity > 100) { diversity = 100; } this.Diversity = diversity; var diversityF = AverageFitnessDistance / 0.5; if (diversityF > 100) { diversityF = 100; } this.DiversityF = diversityF; if (geneType == GeneType.Binary) { this.Convergence = 1 - diversity; this.DiversityGraph = diversityGraph; } else { this.Convergence = 0; this.Diversity = 0; } this.ConvergenceF = 1 - diversityF; }