/// <summary> /// Метод для выполнения одноточечной инверсии особи /// </summary> /// <param name="population">Популяция, в которой находится родительская /// особь и в которую будет помещен потомок</param> /// <param name="unitNumber">Номер особи, над которой нужно выполнить инверсию /// (уникальный)</param> /// <param name="newGenerationNumber">Номер поколения, к которому относится потомок</param> private static void Inversion( ref Population <NsgaIndividual> population, int unitNumber, int newGenerationNumber) { // Признаки, у новой особи они будут такие же, // за исключением значений признаков - их поправим позже Dictionary <TId, IndividualAttribute> attributes = population[unitNumber].Attributes; // Генетический код родителя string parentChromo = population[unitNumber].GetChromo(); Random rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Точка инверсии // Такая формула обусловлена следующим: // - не должно получатся число, равное длине строки, потому что // нумерация символов zero-based и будет ошибка; int crossoverPointPosition = rnd.Next(parentChromo.Length - 1); // Разделим хромосому на части, первая из которых останется неизменной, // а вторая инвертируется string parentFirstPart = parentChromo.Substring(0, crossoverPointPosition); string parentSecondPart = parentChromo.Substring(crossoverPointPosition); // Инвертируем вторую часть хромосомы string newSecondPart = string.Empty; // Проверим каждый ген в этой части хромосомы char[] secondPart = parentSecondPart.ToCharArray(); foreach (char gene in secondPart) { // Выполним добавление гена к новой хромосоме, // попутно инвертировав его switch (gene) { case '1': newSecondPart += "0"; break; case '0': newSecondPart += "1"; break; } } // Составим хромосому потомка string сhildChromo = parentFirstPart + newSecondPart; // Получим и добавим в популяцию потомка var child = new NsgaIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); child.UpdateAttributes(сhildChromo); population.Add(child.Number, child); // Удалим из популяции исходную особь population.Remove(unitNumber); }
/// <summary> /// Метод для выполнения одноточечного скрещивания двух /// особей /// </summary> /// <param name="population">Популяция, в которой находятся две /// родительские особи и куда будут помещены два потомка</param> /// <param name="firstUnitNumber">Номер первого родителя в популяции (уникальный)</param> /// <param name="secondUnitNumber">Номер второго родителя в популяции (уникальный)</param> /// <param name="newGenerationNumber">Номер поколения, к которому относятся потомки</param> private static void CrossTwoUnits( ref Population <NsgaIndividual> population, int firstUnitNumber, int secondUnitNumber, int newGenerationNumber) { // Признаки, у новых двух особей они будут такие же, // за исключением значений признаков - их поправим позже var attributes = population[firstUnitNumber].Attributes; // Генетические коды родителей string firstChromo = population[firstUnitNumber].GetChromo(); string secondChromo = population[secondUnitNumber].GetChromo(); // Небольшая проверка: длины кодов должны быть одинаковые int chromoLength = firstChromo.Length; if (chromoLength != secondChromo.Length) { throw new Exception("Chromosome lengths of two parents must be the same"); } var rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Точка одноточечного скрещивания // Такая формула обусловлена следующим: // - не должно получатся число, равное длине строки, потому что // нумерация символов zero-based и будет ошибка; // - не должен получатся ноль, потому что тогда особи просто // обменяются кодами и ничего не выйдет int crossoverPointPosition = 1 + rnd.Next(chromoLength - 2); // Разделим хромосомы на части, из которых будут составлены // хромосомы потомков string firstParentFirstPart = firstChromo.Substring(0, crossoverPointPosition); string firstParentSecondPart = firstChromo.Substring(crossoverPointPosition); string secondParentFirstPart = secondChromo.Substring(0, crossoverPointPosition); string secondParentSecondPart = secondChromo.Substring(crossoverPointPosition); // Составим хромосомы потомков string firstChildChromo = firstParentFirstPart + secondParentSecondPart; string secondChildChromo = secondParentFirstPart + firstParentSecondPart; // Получим и добавим в популяцию первого потомка var firstChild = new NsgaIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); firstChild.UpdateAttributes(firstChildChromo); population.Add(firstChild.Number, firstChild); // Получим и добавим в популяцию второго потомка var secondChild = new NsgaIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); secondChild.UpdateAttributes(secondChildChromo); population.Add(secondChild.Number, secondChild); // Удалим из популяции родителей population.Remove(firstUnitNumber); population.Remove(secondUnitNumber); }