/// <summary> /// Performs crossover to generate a new child. The crossover type is specifed in the /// Settings property. /// </summary> /// <param name="mate">The individual to crossover with.</param> /// <returns>A new child individual</returns> public IIndividual Crossover(IIndividual mate) { if (mate.GetType() != typeof(LanderIndividual)) { throw new ArgumentException("Mate must be a LanderIndividual"); } // Get the weights in a easier to use form. this.weights = this.neuralNet.GetAllWeights(); List<double> mateWeights = ((LanderIndividual)mate).neuralNet.GetAllWeights(); // Create the child weights with a copy of this individual's weights initially List<double> childWeights = new List<double>(this.weights); switch (this.settings.CrossoverAlgorithm) { case LanderIndividualSettings.CrossoverType.OnePoint: // Copy the mate's weights into the first section int crossoverPoint = this.RandomGenerator.Next(this.weights.Count); for (var i = 0; i < crossoverPoint; i++) { childWeights[i] = mateWeights[i]; } break; case LanderIndividualSettings.CrossoverType.TwoPoint: // Copy the mate's weights into the first section int firstPoint = this.RandomGenerator.Next(this.weights.Count); int secondPoint = this.RandomGenerator.Next(this.weights.Count); if (secondPoint < firstPoint) { int temp = firstPoint; firstPoint = secondPoint; secondPoint = temp; } for (var i = 0; i < firstPoint; i++) { childWeights[i] = mateWeights[i]; } for (var i = secondPoint; i < childWeights.Count; i++) { childWeights[i] = mateWeights[i]; } break; case LanderIndividualSettings.CrossoverType.Uniform: for (int i = 0; i < childWeights.Count; i++) { if (RandomGenerator.NextDouble() < 0.5) { childWeights[i] = mateWeights[i]; } } break; default: throw new ArgumentException("Lander individual crossover type not supported"); } // Create the new child LanderIndividual child = new LanderIndividual(this.RandomGenerator); child.Settings = this.Settings; child.neuralNet.SetAllWeights(childWeights); return child; }