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); } }
/// <summary> /// Метод для поиска решения с помощью генетического алгоритма /// </summary> /// <param name="model">Оптимизационная модель, эксперименты из которой /// выступят в качестве начальной популяции</param> /// <param name="gaParams">Параметры генетического алгоритма</param> /// <param name="table">Таблица для отображения процесса поиска решения. /// Если null, то процесс поиска решения не отображается</param> public static AdditiveMethodResult FindDecision(Model model, AdditiveParams gaParams, DataGridView table) { bool showProcess = (table != null); int currentGeneration = 0; // 1. Получим начальную популяцию из модели AdditivePopulation population = AdditiveSolver.ModelToPopulation(model, currentGeneration); // Рассчитаем значения функции приспособленности AdditiveSolver.CalcUnitsFitness( ref model, ref population, gaParams.ExternalAppPath); // Если надо, подготовим таблицу к выводу процесса и // выведем начальную популяцию (без разделителя) if (showProcess) { AdditiveDataGridFiller.PrepareProcessDataGrid(table); AdditiveDataGridFiller.AddPopulationToDataGrid(table, population, false); } // 2. Пока не достигнуто нужное количество поколений while (currentGeneration < gaParams.MaxGenerationsNumber) { // Увеличим счетчик поколений currentGeneration++; // 3. Отбор population = AdditiveSelection.TournamentSelection(population, gaParams.SelectionLimit); // 4. Скрещивание population = AdditiveCrossover.OnePointCrossover(population, currentGeneration); // 5. Мутация population = AdditiveMutation.PerformMutation(population, gaParams.MutationProbability); // 6. Расчет приспособленности // Модель обновится, метод CalcUnitsFitness рассчитает // для популяции значения функции приспособленности, а для // модели - значения критериев и Ф.О. model = AdditiveSolver.PopulationToModel(model, population); AdditiveSolver.CalcUnitsFitness( ref model, ref population, gaParams.ExternalAppPath); // Если надо, то выведем на экран информацию (с разделителем) if (showProcess) { AdditiveDataGridFiller.AddPopulationToDataGrid(table, population, true); } } // Подготовим результат на основе конечной популяции AdditiveMethodResult result = AdditiveSolver.PrepareResult(population); // Вернем результат return(result); }