private static void CalcUnitsFitness( ref Model initModel, ref AdditivePopulation population, string externalAppPath) { // У нас есть модель. Рассчитаем для нее с помощью внешней // программы значения критериев оптимальности и Ф.О. #if DUMMY // Запустим внешнюю программу и дождемся, пока она отработает if (!AdditiveSolver.UseDummyExternalApplication(initModel, externalAppPath)) { throw new Exception("Can not calculate fitness values using external program"); } #else // Файл для обмена данными между opt и расчетной программой string dataFilePath = System.IO.Path.GetDirectoryName(externalAppPath) + "\\_ga_temp_file.xml"; // Запустим внешнюю программу и дождемся, пока она отработает if (!AdditiveSolver.UseExternalApplication( initModel, externalAppPath, dataFilePath)) { throw new Exception("Can not calculate fitness values using external program"); } // Раз программа отработала, прочтем результаты из файла initModel = modelProvider.Load(dataFilePath); // Удалим файл с данными if (System.IO.File.Exists(dataFilePath)) { System.IO.File.Delete(dataFilePath); } #endif // Применим решатель для аддитивного критерия, чтобы получить его значения. // Они послужат нам эквивалентом функции приспособленности AdditiveCriterionSolver solver = new AdditiveCriterionSolver(); IntegralCriterionMethodResult result = solver.FindDecision(initModel); // Из результатов аддитивного критерия выдерем его значения foreach (TId expId in result.SortedPoints) { int unitNumber = initModel.Experiments[expId].Number; population[unitNumber].FitnessValue = result.AdditionalData[expId]; } // Применим Ф.О. к модели initModel.ApplyFunctionalConstraints(); // Пометим на удаление в популяции особи, соответсвующие экспериментам, // ставшим неактивными после применения Ф.О. foreach (Experiment exp in initModel.Experiments.Values) { if (!exp.IsActive) { population.MarkForRemoval(exp.Number); } } // И удалим помеченные population.RemoveMarked(); }
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); }