private void SwapGenes(Chromosome childToMutate) { CrossoverData data = CreateCrossoverData(childToMutate.Genes.Count); for (int i = 0; i < Interval; i++) { Gene g1 = childToMutate.Genes[data.Points[0] + i]; Gene g2 = childToMutate.Genes[data.Points[1] + i]; childToMutate.Genes[data.Points[0] + i] = g2; childToMutate.Genes[data.Points[1] + i] = g1; } }
//handles the crossover procedure, taking into account the crossover probability. uses random selection? roulette wheel selection? protected void Process() { int num1 = 100; int num2 = 0; this._evaluations = 0; if (this._replacementMethodS == ReplacementMethod.DeleteLast) { this._newPopulation.Solutions.Clear(); this._newPopulation.Solutions.AddRange((IEnumerable <Chromosome>) this._currentPopulation.Solutions); } else { List <Chromosome> elites = this._currentPopulation.GetElites(); num2 = Enumerable.Count <Chromosome>((IEnumerable <Chromosome>)elites); if (elites != null && num2 > 0) { this._newPopulation.Solutions.AddRange((IEnumerable <Chromosome>)elites); } } this._currentPopulationSize = this._currentPopulation.Solutions.Count; this._numberOfChildrenToGenerate = this._currentPopulationSize - num2; while (this._numberOfChildrenToGenerate > 0) { --num1; if (num1 <= 0) { break; } Chromosome c1 = (Chromosome)null; Chromosome c2 = (Chromosome)null; List <Chromosome> list = this._currentPopulation.SelectParents(); Chromosome p1 = list[0]; Chromosome p2 = list[1]; CrossoverData crossoverData = this.CreateCrossoverData(p1.Genes.Count, this.CrossoverShape); CrossoverData crossoverResult = this.PerformCrossover(p1, p2, this.CrossoverProbability, this.CrossoverShape, crossoverData, out c1, out c2); if (this.OnCrossoverComplete != null) { this.OnCrossoverComplete((object)this, new CrossoverEventArgs(crossoverResult)); } if (this.AddChild(c1)) { --this._numberOfChildrenToGenerate; } if (this._numberOfChildrenToGenerate > 0 && this.AddChild(c2)) { --this._numberOfChildrenToGenerate; } } }
internal CrossoverData CreateCrossoverData(int chromosomeLength) { var result = new CrossoverData(); int point1; int point2; do { point2 = RandomProvider.GetThreadRandom().Next(1, chromosomeLength / Interval) * Interval; point1 = RandomProvider.GetThreadRandom().Next(1, chromosomeLength / Interval) * Interval; } while (point2 == point1); result.Points.Add(System.Math.Min(point2, point1)); result.Points.Add(System.Math.Max(point2, point1)); return(result); }
internal CrossoverData CreateCrossoverData(int chromosomeLength, CrossoverType crossoverType) { var result = new CrossoverData(); //this is like double point except that the values are all taken from one parent //first the centre section of the parent selection is taken to the child //the remaining values of the same parent are passed to the child in the order in //which they appear in the second parent. If the second parent does not include the value //an exception is thrown. //these can bring back the same number, this is ok as the values will be both inclusive //so if crossoverPoint1 and crossoverPoint2 are the same, one gene will form the center section. switch (crossoverType) { case CrossoverType.SinglePoint: //0 is invalid, range for single point is 1 to [length] result.Points.Add(RandomProvider.GetThreadRandom().Next(1, chromosomeLength / Index) * Index); break; case CrossoverType.DoublePoint: case CrossoverType.DoublePointOrdered: //0 is invalid, range for double needs to leave room for right segment and is 1 to [length] int point1; int point2; do { point2 = RandomProvider.GetThreadRandom().Next(1, chromosomeLength / Index) * Index; point1 = RandomProvider.GetThreadRandom().Next(1, chromosomeLength / Index) * Index; } while (point2 == point1); result.Points.Add(System.Math.Min(point2, point1)); result.Points.Add(System.Math.Max(point2, point1)); break; } return(result); }
internal CrossoverData PerformCrossover(Chromosome p1, Chromosome p2, double crossoverProbability, Crossover2DShape crossoverShape, CrossoverData crossoverData, out Chromosome c1, out Chromosome c2) { CrossoverData crossoverData1 = new CrossoverData(); int count1 = p1.Genes.Count; if (count1 != p2.Genes.Count) { throw new ArgumentException("Parent chromosomes are not the same length."); } if (crossoverData == null) { throw new ArgumentException("The CrossoverData parameter is null."); } List <Gene> source1 = ListClone(p1.Genes); // new List<Gene>(); List <Gene> source2 = ListClone(p2.Genes); // new List<Gene>(); if (RandomProvider.GetThreadRandom().NextDouble() <= crossoverProbability) { //iterate all the replacement points foreach (int point in crossoverData.Points) { var tmpG = source1[point].DeepClone(); source1[point] = source2[point].DeepClone(); source2[point] = tmpG; } //APIClass.CountNeighbours(source1); //APIClass.CountNeighbours(source2); } if (source1.Count != count1 || source1.Count != count1) { throw new ChromosomeCorruptException("Chromosome is corrupt!"); } c1 = new Chromosome((IEnumerable <Gene>)source1); c2 = new Chromosome((IEnumerable <Gene>)source2); return(crossoverData1); }
/// <summary> /// Crossover data represents the points (int) where the crossover will be performed, in this case, we want to switch several points between parents /// </summary> /// <param name="chromosomeLength"></param> /// <param name="crossoverShape"></param> /// <returns></returns> internal CrossoverData CreateCrossoverData(int chromosomeLength, Crossover2DShape crossoverShape) { CrossoverData crossoverData = new CrossoverData(); switch (crossoverShape) { case Crossover2DShape.TwoByTwoSquare: { int rx, ry; //do //{ rx = RandomProvider.GetThreadRandom().Next(0, MAP_WIDTH - 1 - 2); ry = RandomProvider.GetThreadRandom().Next(0, MAP_HEIGHT - 1 - 2); //} //while (rx > 30 || ry > 30); for (int yOffset = 0; yOffset < 2; yOffset++) { for (int xOffset = 0; xOffset < 2; xOffset++) { crossoverData.Points.Add((MAP_HEIGHT * (ry + yOffset) + (rx + xOffset))); } } } break; case Crossover2DShape.ThreeByThreeSquare: { int rx, ry; //do //{ rx = RandomProvider.GetThreadRandom().Next(0, MAP_WIDTH - 1 - 3); ry = RandomProvider.GetThreadRandom().Next(0, MAP_HEIGHT - 1 - 3); //} //while (rx > 29 || ry > 29); for (int yOffset = 0; yOffset < 3; yOffset++) { for (int xOffset = 0; xOffset < 3; xOffset++) { crossoverData.Points.Add((MAP_HEIGHT * (ry + yOffset) + (rx + xOffset))); } } } break; case Crossover2DShape.FourByFourSquare: { int rx, ry; //do //{ rx = RandomProvider.GetThreadRandom().Next(0, MAP_WIDTH - 1 - 4); ry = RandomProvider.GetThreadRandom().Next(0, MAP_HEIGHT - 1 - 4); //} //while (rx > 28 || ry > 28); for (int yOffset = 0; yOffset < 4; yOffset++) { for (int xOffset = 0; xOffset < 4; xOffset++) { crossoverData.Points.Add((MAP_HEIGHT * (ry + yOffset) + (rx + xOffset))); } } } break; case Crossover2DShape.FourByFourCircle: { int rx, ry; do { rx = RandomProvider.GetThreadRandom().Next(0, MAP_WIDTH - 1); ry = RandomProvider.GetThreadRandom().Next(1, MAP_HEIGHT - 1); }while (rx > 28 || ry > 28); for (int yOffset = 0; yOffset < 4; yOffset++) { for (int xOffset = 0; xOffset < 4; xOffset++) { if ((yOffset == 0 && xOffset == 0) || (yOffset == 0 && xOffset == 3) || (yOffset == 3 && xOffset == 0) || (yOffset == 3 && xOffset == 3)) { continue; } else { crossoverData.Points.Add((MAP_HEIGHT * (ry + yOffset) + (rx + xOffset))); } } } } break; case Crossover2DShape.Triangle: //size?? break; case Crossover2DShape.Dispersion: break; default: { int rx, ry; //do //{ rx = RandomProvider.GetThreadRandom().Next(0, MAP_WIDTH - 1 - 4); ry = RandomProvider.GetThreadRandom().Next(0, MAP_HEIGHT - 1 - 4); //} //while (rx > 28 || ry > 28); for (int yOffset = 0; yOffset < 4; yOffset++) { for (int xOffset = 0; xOffset < 4; xOffset++) { crossoverData.Points.Add((MAP_HEIGHT * (ry + yOffset) + (rx + xOffset))); } } } break; } return(crossoverData); }
internal CrossoverData PerformCrossover(Chromosome p1, Chromosome p2, double crossoverProbability, CrossoverType crossoverType, CrossoverData crossoverData, out Chromosome c1, out Chromosome c2) { var result = new CrossoverData(); var chromosomeLength = p1.Genes.Count; if (chromosomeLength != p2.Genes.Count) { throw new ArgumentException("Parent chromosomes are not the same length."); } if (crossoverData == null) { throw new ArgumentException("The CrossoverData parameter is null."); } List <Gene> cg1 = new List <Gene>(); List <Gene> cg2 = new List <Gene>(); //check probability by generating a random number between zero and one and if //this number is less than or equal to the given crossover probability //then crossover takes place." var rd = RandomProvider.GetThreadRandom().NextDouble(); if (rd <= crossoverProbability) { switch (crossoverType) { case CrossoverType.SinglePoint: { if (crossoverData.Points == null || crossoverData.Points.Count < 1) { throw new ArgumentException( "The CrossoverData.Points property is either null or is missing the required crossover points."); } var crossoverPoint1 = crossoverData.Points[0]; result.Points.Add(crossoverPoint1); //create the two children cg1.AddRangeCloned(p1.Genes.Take(crossoverPoint1).ToList()); //cg1.AddRange(p2.Genes.Skip(crossoverPoint1).Take(chromosomeLength - crossoverPoint1)); cg1.AddRangeCloned(p2.Genes.Skip(crossoverPoint1).Take(chromosomeLength - crossoverPoint1)); cg2.AddRangeCloned(p2.Genes.Take(crossoverPoint1).ToList()); cg2.AddRangeCloned(p1.Genes.Skip(crossoverPoint1).Take(chromosomeLength - crossoverPoint1)); break; } case CrossoverType.DoublePoint: { if (crossoverData.Points == null || crossoverData.Points.Count < 2) { throw new ArgumentException( "The CrossoverData.Points property is either null or is missing the required crossover points."); } var firstPoint = crossoverData.Points[0]; var secondPoint = crossoverData.Points[1]; result.Points.Add(firstPoint); result.Points.Add(secondPoint); //first child //first part of Parent 1 cg1.AddRangeCloned(p1.Genes.Take(firstPoint).ToList()); //middle part pf Parent 2 cg1.AddRangeCloned(p2.Genes.Skip(firstPoint).Take(secondPoint - firstPoint)); //last part of Parent 1 cg1.AddRangeCloned(p1.Genes.Skip(secondPoint).Take(chromosomeLength - secondPoint)); //second child //first part of Parent 2 cg2.AddRangeCloned(p2.Genes.Take(firstPoint).ToList()); //middle part pf Parent 1 cg2.AddRangeCloned(p1.Genes.Skip(firstPoint).Take(secondPoint - firstPoint)); //last part of Parent 2 cg2.AddRangeCloned(p2.Genes.Skip(secondPoint).Take(chromosomeLength - secondPoint)); break; } case CrossoverType.DoublePointOrdered: { if (crossoverData.Points == null || crossoverData.Points.Count < 2) { throw new ArgumentException( "The CrossoverData.Points property is either null or is missing the required crossover points."); } //this is like double point except that the values are all taken from one parent //first the centre section of the parent selection is taken to the child //the remaining values of the same parent are passed to the child in the order in //which they appear in the second parent. If the second parent does not include the value //an exception is thrown. //these can bring back the same number, this is ok as the values will be both inclusive //so if crossoverPoint1 and crossoverPoint2 are the same, one gene will form the center section. var firstPoint = crossoverData.Points[0]; var secondPoint = crossoverData.Points[1]; result.Points.Add(firstPoint); result.Points.Add(secondPoint); //pass the middle part of Parent 1 to child 1 cg1.AddRangeCloned(p1.Genes.Skip(firstPoint).Take(secondPoint - firstPoint)); //+1 make this exclusive e.g. 4-6 include 3 genes. //pass the middle part of Parent 2 to child 2 cg2.AddRangeCloned(p2.Genes.Skip(firstPoint).Take(secondPoint - firstPoint)); //create hash sets for parent1 and child1 var p1Hash = new HashSet <object>(); var cg1Hash = new HashSet <object>(); //populate the parent hash set with object values (not the gene itself) foreach (var gene in p1.Genes) { p1Hash.Add(gene.ObjectValue); } //populate the child hash set with object values (not the gene itself) //at this point only the center section of P1 will be in C1 foreach (var gene in cg1) { cg1Hash.Add(gene.ObjectValue); } //run through the P2 adding to C1 those that exist in P1 but not yet in C1 //add them in the order found in P2. This has to be done by value as the first parent //is used but the order id determined by the second parent. Can't use Guid as the second //parent has a different set of genes guids. foreach (var gene in p2.Genes) { //if we have the value in P1 and it is not already in C1, then add it. bool existsInP1 = p1Hash.Contains(gene.ObjectValue); bool existsInCg1 = cg1Hash.Contains(gene.ObjectValue); if (existsInP1 && !existsInCg1) { cg1.AddCloned(gene); } } var p2Hash = new HashSet <object>(); var cg2Hash = new HashSet <object>(); foreach (var gene in p2.Genes) { p2Hash.Add(gene.ObjectValue); } foreach (var gene in cg2) { cg2Hash.Add(gene.ObjectValue); } //run through the P1 adding to C2 those that exist in P2 but not yet in C2 //add them in the order found in P1. This has to be done by value as the first parent //is used but the order id determined by the second parent. Can't use Guid as the second //parent has a different set of genes (guids) foreach (var gene in p1.Genes) { //if we have the value in P1 and it is not already in C1, then add it. bool existsInP2 = p2Hash.Contains(gene.ObjectValue); bool existsInCg2 = cg2Hash.Contains(gene.ObjectValue); if (existsInP2 && !existsInCg2) { cg2.AddCloned(gene); } } //if at this point we do not have a complete child, raise an exception if (cg1.Count != p1.Count || cg2.Count != p2.Count) { throw new CrossoverTypeIncompatibleException("The parent Chromosomes were not suitable for Ordered Crossover as they do not contain the same set of values. Consider using a different crossover type, or ensure all solutions are build with the same set of values."); } break; } } } else { //crossover probaility dictates that these pass through to the next generation untouched (except for an ID change. //get the existing parent genes and treat them as the new children cg1.AddRangeCloned(p1.Genes); cg2.AddRangeCloned(p2.Genes); } if (cg1.Count != chromosomeLength || cg1.Count != chromosomeLength) { throw new ChromosomeCorruptException("Chromosome is corrupt!"); } c1 = new Chromosome(cg1); c2 = new Chromosome(cg2); return(result); }