/// <summary> /// Mutates each element of a <see cref="ListEntityBase"/> if it meets a certain /// probability. /// </summary> /// <param name="entity"><see cref="ListEntityBase"/> to be mutated.</param> /// <returns>True if a mutation occurred; otherwise, false.</returns> /// <exception cref="ArgumentNullException"><paramref name="entity"/> is null.</exception> protected override bool GenerateMutation(GeneticEntity entity) { if (entity is null) { throw new ArgumentNullException(nameof(entity)); } ListEntityBase listEntity = (ListEntityBase)entity; if (RandomNumberService.Instance.GetDouble() <= this.MutationRate) { int firstPosition = RandomNumberService.Instance.GetRandomValue(listEntity.Length - 1); int secondPosition; do { secondPosition = RandomNumberService.Instance.GetRandomValue(listEntity.Length - 1); } while (secondPosition == firstPosition); object?firstValue = listEntity.GetValue(firstPosition); listEntity.SetValue(firstPosition, listEntity.GetValue(secondPosition)); listEntity.SetValue(secondPosition, firstValue); return(true); } return(false); }
/// <summary> /// Mutates each bit of a <see cref="ListEntityBase"/> if it meets a certain /// probability. /// </summary> /// <param name="entity"><see cref="ListEntityBase"/> to be mutated.</param> /// <returns>True if a mutation occurred; otherwise, false.</returns> /// <exception cref="ArgumentNullException"><paramref name="entity"/> is null.</exception> protected override bool GenerateMutation(GeneticEntity entity) { if (entity is null) { throw new ArgumentNullException(nameof(entity)); } ListEntityBase listEntity = (ListEntityBase)entity; if (RandomNumberService.Instance.GetDouble() <= this.MutationRate) { int firstPosition = RandomNumberService.Instance.GetRandomValue(listEntity.Length); int secondPosition; do { secondPosition = RandomNumberService.Instance.GetRandomValue(listEntity.Length); } while (secondPosition == firstPosition); if (firstPosition < secondPosition) { object?currentMovingValue = listEntity.GetValue(firstPosition); for (int i = firstPosition + 1; i <= secondPosition; i++) { object?savedValue = listEntity.GetValue(i); listEntity.SetValue(i, currentMovingValue); currentMovingValue = savedValue; } listEntity.SetValue(firstPosition, currentMovingValue); } else { object?currentMovingValue = listEntity.GetValue(firstPosition); for (int i = firstPosition - 1; i >= secondPosition; i--) { object?savedValue = listEntity.GetValue(i); listEntity.SetValue(i, currentMovingValue); currentMovingValue = savedValue; } listEntity.SetValue(firstPosition, currentMovingValue); } return(true); } return(false); }
/// <summary> /// Replaces the elements in <paramref name="entity"/>, starting at <paramref name="targetCrossoverLocus"/>, /// with the elements located in <paramref name="sourceElements"/> starting at <paramref name="sourceCrossoverLocus"/>. /// </summary> /// <param name="entity"><see cref="ListEntityBase"/> whose bits are to be replaced.</param> /// <param name="sourceElements">List of elements to replace with.</param> /// <param name="targetCrossoverLocus">Element position at which to begin replacement.</param> /// <param name="sourceCrossoverLocus">Element position of the source elements to begin copying from.</param> private static void ReplaceBits(ListEntityBase entity, List <object?> sourceElements, int targetCrossoverLocus, int sourceCrossoverLocus) { entity.Length = targetCrossoverLocus + sourceElements.Count - sourceCrossoverLocus; for (int sourceBitIndex = sourceCrossoverLocus, targetBitIndex = targetCrossoverLocus; sourceBitIndex < sourceElements.Count; sourceBitIndex++, targetBitIndex++) { entity.SetValue(targetBitIndex, sourceElements[sourceBitIndex]); } }
/// <summary> /// When overriden in a derived class, generates a crossover based on the parent entities. /// </summary> /// <param name="parents">The <see cref="GeneticEntity"/> objects to be operated upon.</param> /// <returns> /// Collection of the <see cref="GeneticEntity"/> objects resulting from the crossover. /// </returns> protected override IEnumerable <GeneticEntity> GenerateCrossover(IList <GeneticEntity> parents) { if (parents == null) { throw new ArgumentNullException(nameof(parents)); } ListEntityBase listEntity1 = (ListEntityBase)parents[0]; ListEntityBase listEntity2 = (ListEntityBase)parents[1]; int entity1Length = listEntity1.Length; int entity2Length = listEntity2.Length; int crossoverLocus = RandomNumberService.Instance.GetRandomValue(Math.Min(entity1Length, entity2Length)); IList <GeneticEntity> crossoverOffspring = new List <GeneticEntity>(); int maxLength = Math.Max(entity1Length, entity2Length); // Normalize the lists into a common length if (entity1Length != entity2Length) { listEntity1.Length = maxLength; listEntity2.Length = maxLength; } // swap the elements of the lists starting at the crossover locus for (int i = crossoverLocus; i < maxLength; i++) { object?tempGeneValue = listEntity1.GetValue(i); listEntity1.SetValue(i, listEntity2.GetValue(i)); listEntity2.SetValue(i, tempGeneValue); } // Set the length based on their swapped length listEntity1.Length = entity2Length; listEntity2.Length = entity1Length; crossoverOffspring.Add(listEntity1); crossoverOffspring.Add(listEntity2); return(crossoverOffspring); }
/// <summary> /// Executes a single-point crossover between two list-based entities. /// </summary> /// <param name="parents">The <see cref="GeneticEntity"/> objects to be operated upon.</param> /// <returns> /// Collection of the list-based entities resulting from the crossover. /// </returns> protected override IEnumerable <GeneticEntity> GenerateCrossover(IList <GeneticEntity> parents) { if (parents == null) { throw new ArgumentNullException(nameof(parents)); } ListEntityBase listEntity1 = (ListEntityBase)parents[0]; ListEntityBase listEntity2 = (ListEntityBase)parents[1]; int entity1Length = listEntity1.Length; int entity2Length = listEntity2.Length; List <int> crossoverLoci = new List <int>(); int minLength = Math.Min(entity1Length, entity2Length); // Generate the set of crossover points. for (int i = 0; i < this.CrossoverPointCount; i++) { int crossoverLocus; do { crossoverLocus = RandomNumberService.Instance.GetRandomValue(minLength); } while (crossoverLoci.Contains(crossoverLocus)); crossoverLoci.Add(crossoverLocus); } crossoverLoci.Sort(); IList <GeneticEntity> crossoverOffspring = new List <GeneticEntity>(); // If the number of crossover points is odd and the lengths of the entities are not the // same, the crossover will cause the lengths of the entities to be swapped. bool entityLengthsAreSwapped = (this.CrossoverPointCount % 2 != 0 && entity1Length != entity2Length); int maxLength = Math.Max(entity1Length, entity2Length); if (entityLengthsAreSwapped) { // Normalize the lists into a common length if (entity1Length != entity2Length) { listEntity1.Length = maxLength; listEntity2.Length = maxLength; } } ListEntityBase originalEntity1 = (ListEntityBase)listEntity1.Clone(); ListEntityBase originalEntity2 = (ListEntityBase)listEntity2.Clone(); ListEntityBase entity1Source = listEntity1; ListEntityBase entity2Source = listEntity2; for (int i = crossoverLoci[0]; i < maxLength; i++) { // If this is a crossover point, swap the source entities if (crossoverLoci.Contains(i)) { if (listEntity1 == entity1Source) { entity1Source = listEntity2; entity2Source = listEntity1; } else { entity1Source = listEntity1; entity2Source = listEntity2; } } object?entity1SourceVal = null; object?entity2SourceVal = null; if (i < listEntity1.Length) { entity1SourceVal = this.GetEntityValue(i, listEntity1, entity1Source, originalEntity1, originalEntity2); } if (i < listEntity2.Length) { entity2SourceVal = this.GetEntityValue(i, listEntity2, entity2Source, originalEntity2, originalEntity1); } if (entity1SourceVal != null) { listEntity1.SetValue(i, entity1SourceVal); } if (entity2SourceVal != null) { listEntity2.SetValue(i, entity2SourceVal); } } if (entityLengthsAreSwapped) { // Set the length based on their swapped length listEntity1.Length = entity2Length; listEntity2.Length = entity1Length; } crossoverOffspring.Add(listEntity1); crossoverOffspring.Add(listEntity2); return(crossoverOffspring); }