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);
            }
        }
        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);
        }