public static AdditivePopulation OnePointCrossover( AdditivePopulation initPop, int newGenerationNumber) { // Для начала проверим валидность данных // Если в популяции ноль особей, то ошибка if (initPop.Count < 1) { throw new ArgumentException("Can not perform crossover on a population with 0 units in it"); } // Если номер нового (следующего) поколения меньше или равен // номеру текущего, то ошибка if (newGenerationNumber <= initPop.GetMaxGenerationNumber()) { throw new Exception("New generation number is lesser than current"); } // Все в порядке, можно проводить скрещивание // Генератор случайных чисел Random rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Для создания пар сформируем стек. // 1. Заполним его случайным образом (в случ. // порядке) всеми имеющимися особями. // 2. Будем доставать по две и скрещивать их между собой. // 3. Если осталось 0 особей, то конец. // 4. Если осталась 1 особь, то инверсия и goto п. 3. Stack <int> unitsStack = new Stack <int>(); int maxUnitNumber = initPop.GetMaxUnitNumber(); while (unitsStack.Count < initPop.Count) { // Выберем из популяции случайную особь int rndNumber = -1; while (!IsValidRandomUnit(rndNumber, unitsStack, initPop)) { // "+ 1" из-за особенностей реализации метода // Random.Next(Int32, Int32). Если не будет "+ 1", // то maxUnitNumber не выпадет никогда rndNumber = rnd.Next(0, maxUnitNumber + 1); } // Номер подходящий, добавим его в стек unitsStack.Push(rndNumber); } // Теперь стек заполнен номерами имеющихся особей в // случайном порядке // Будем доставать оттуда по две, пока там не останется // 0 или 1 особь, и скрещивать while (unitsStack.Count >= 2) { int firstParent = unitsStack.Pop(); int secondParent = unitsStack.Pop(); AdditiveCrossover.CrossTwoUnits( ref initPop, firstParent, secondParent, newGenerationNumber); } // Если осталось 0 особей, то всё готово, вернем // популяцию if (unitsStack.Count == 0) { return(initPop); } else { // Иначе же осталась 1 особь и мы должны выполнить инверсию AdditiveCrossover.Inversion( ref initPop, unitsStack.Pop(), newGenerationNumber); return(initPop); } }
public static AdditivePopulation TournamentSelection( AdditivePopulation initPop, int selectionLimit) { // Сначала проверим: если надо отобрать больше, чем есть, // то выбросим ошибку if (selectionLimit > initPop.Count) { throw new ArgumentException("Number of units to be selected is greater than number of units in population"); } // Если надо отобрать столько же, сколько есть, просто // вернем входную популяцию if (selectionLimit == initPop.Count) { return(initPop); } // Список номеров отобранных особей List <int> selectedUnitNumbers = new List <int>(); // Рандомайзер для выбора случайных особей Random rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Флагом того, что пора прекртатить итерации отбора, // будет служить совпадение количества отобранных // особей (в списке, объявленном выше) и переданного // в качестве аргумента требуемого количества int maxUnitNumber = initPop.GetMaxUnitNumber(); while (selectedUnitNumbers.Count != selectionLimit) { // В этом цикле будет проходить разбиение на пары // и выбор лучшей особи из пары // Список пары отобранных для турнира особей List <int> selectedPair = new List <int>(); // Проверим: если среди неотобранных особей осталось всего две, // то составим из них пару и не будем морочить себе голову // случайностями if ((initPop.Count - selectedUnitNumbers.Count) == 2) { foreach (AdditiveIndividual unit in initPop) { if (IsValidPairUnit(unit.Number, selectedPair, selectedUnitNumbers, initPop)) { selectedPair.Add(unit.Number); } } } // Флагом остановки выбора случайной особи в пару // будет служить наличие двух отобранных особей while (selectedPair.Count != 2) { // Будем выбирать случайное число в диапазоне // от 0 до значения счетчика особей в популяции // до тех пор, пока не наткнемся на особь, которую // можно отобрать в турнирную пару int rndNumber = -1; while (!IsValidPairUnit(rndNumber, selectedPair, selectedUnitNumbers, initPop)) { // "+ 1" из-за особенностей реализации метода // Random.Next(Int32, Int32). Если не будет "+ 1", // то maxUnitNumber не выпадет никогда rndNumber = rnd.Next(0, maxUnitNumber + 1); } // Когда найден подходящий номер, добавим его в пару selectedPair.Add(rndNumber); } // Выберем из пары наиболее приспособленную особь // (ту, у которой значение функции приспособленности // лучше - то есть меньше, потому что мы работаем с // аддитивным критерием) if (opt.Helpers.Comparer.IsFirstValueBetter( initPop[selectedPair[0]].FitnessValue, initPop[selectedPair[1]].FitnessValue, opt.DataModel.CriterionType.Minimizing)) { // Первая особь лучше второй selectedUnitNumbers.Add(selectedPair[0]); } else { // Вторая особь лучше первой selectedUnitNumbers.Add(selectedPair[1]); } } // Пометим на удаление все особи, кроме отобранных во время турнира foreach (AdditiveIndividual unit in initPop) { if (!selectedUnitNumbers.Contains(unit.Number)) { initPop.MarkForRemoval(unit.Number); } } // Удалим помеченные особи initPop.RemoveMarked(); // Вернем результат return(initPop); }