Exemple #1
0
        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);
        }