/// <summary> /// Initializes a new instance of the <see cref="GAF.Operators.CrossoverEventArgs"/> class. /// </summary> /// <param name="crossoverResult">Crossover result.</param> /// <param name="parent1">Parent1.</param> /// <param name="parent2">Parent2.</param> /// <param name="child1">Child1.</param> /// <param name="child2">Child2.</param> public CrossoverEventArgs(CrossoverData crossoverResult, Chromosome parent1, Chromosome parent2, Chromosome child1, Chromosome child2) { _crossoverResult = crossoverResult; _parent1 = parent1; _parent2 = parent2; _child1 = child1; _child2 = child2; }
/// <summary> /// Performs a crossover. /// </summary> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> /// <param name="crossoverData">Crossover data.</param> /// <param name="c1">C1.</param> /// <param name="c2">C2.</param> protected void PerformCrossover(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out Chromosome c1, out Chromosome c2) { var chromosomeLength = p1.Genes.Count; if (chromosomeLength != p2.Genes.Count) { throw new ArgumentException("Parent chromosomes are not the same length."); } List <Gene> cg1 = null; //new List<Gene> (); List <Gene> cg2 = null; //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 <= this.CrossoverProbability) { switch (this.CrossoverType) { case CrossoverType.SinglePoint: { PerformCrossoverSinglePoint(p1, p2, crossoverData, out cg1, out cg2); break; } case CrossoverType.DoublePoint: { PerformCrossoverDoublePoint(p1, p2, crossoverData, out cg1, out cg2); break; } case CrossoverType.DoublePointOrdered: { PerformCrossoverDoublePointOrdered(p1, p2, crossoverData, out cg1, out cg2); break; } } } else { cg1 = new List <Gene> (); cg2 = new List <Gene> (); //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 || cg2.Count != chromosomeLength) { throw new ChromosomeCorruptException("Chromosome is corrupt!"); } c1 = new Chromosome(cg1); c2 = new Chromosome(cg2); }
internal CrossoverData CreateCrossoverData(int chromosomeLength, CrossoverType crossoverType) { var result = new CrossoverData(chromosomeLength); //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)); 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); point1 = RandomProvider.GetThreadRandom().Next(1, chromosomeLength); } while (point2 == point1); result.Points.Add(System.Math.Min(point2, point1)); result.Points.Add(System.Math.Max(point2, point1)); break; } return(result); }
/// <summary> /// Abstract Method /// </summary> protected abstract void PerformCrossoverDoublePointOrdered(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out List <Gene> cg1, out List <Gene> cg2);
/// <summary> /// Abstract Method /// </summary> protected abstract void PerformCrossoverSinglePoint(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out List <Gene> cg1, out List <Gene> cg2);
internal void PerformCrossover(Chromosome p1, Chromosome p2, double crossoverProbability, CrossoverType crossoverType, CrossoverData crossoverData, out Chromosome c1, out Chromosome c2) { this.CrossoverProbability = crossoverProbability; this.CrossoverType = crossoverType; this.PerformCrossover(p1, p2, crossoverData, out c1, out c2); }
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); }
/// <summary> /// Performs a single point crossover. /// </summary> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> /// <param name="crossoverData">Crossover data.</param> /// <param name="cg1">Cg1.</param> /// <param name="cg2">Cg2.</param> protected override void PerformCrossoverSinglePoint(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out List <Gene> cg1, out List <Gene> cg2) { 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."); } cg1 = new List <Gene> (); cg2 = new List <Gene> (); var crossoverPoint1 = crossoverData.Points [0]; var chromosomeLength = crossoverData.ChromosomeLength; //create the two children cg1.AddRangeCloned(p1.Genes.Take(crossoverPoint1).ToList()); 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)); }
/// <summary> /// Performs a double point ordered crossover. /// </summary> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> /// <param name="crossoverData">Crossover data.</param> /// <param name="cg1">Cg1.</param> /// <param name="cg2">Cg2.</param> protected override void PerformCrossoverDoublePointOrdered(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out List <Gene> cg1, out List <Gene> cg2) { 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]; cg1 = new List <Gene> (); cg2 = new List <Gene> (); //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."); } }
/// <summary> /// Performs a double point crossover. /// </summary> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> /// <param name="crossoverData">Crossover data.</param> /// <param name="cg1">Cg1.</param> /// <param name="cg2">Cg2.</param> protected override void PerformCrossoverDoublePoint(Chromosome p1, Chromosome p2, CrossoverData crossoverData, out List <Gene> cg1, out List <Gene> cg2) { 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]; var chromosomeLength = crossoverData.ChromosomeLength; cg1 = new List <Gene> (); cg2 = new List <Gene> (); //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)); }