/// <summary> /// Метод для выполнения одноточечной инверсии особи /// </summary> /// <param name="population">Популяция, в которой находится родительская /// особь и в которую будет помещен потомок</param> /// <param name="unitNumber">Номер особи, над которой нужно выполнить инверсию /// (уникальный)</param> /// <param name="newGenerationNumber">Номер поколения, к которому относится потомок</param> private static void Inversion( ref AdditivePopulation population, int unitNumber, int newGenerationNumber) { // Признаки, у новой особи они будут такие же, // за исключением значений признаков - их поправим позже Dictionary <TId, IndividualAttribute> attributes = population[unitNumber].Attributes; // Генетический код родителя string parentChromo = population[unitNumber].GetChromo(); Random rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Точка инверсии // Такая формула обусловлена следующим: // - не должно получатся число, равное длине строки, потому что // нумерация символов zero-based и будет ошибка; int crossoverPointPosition = rnd.Next(parentChromo.Length - 1); // Разделим хромосому на части, первая из которых останется неизменной, // а вторая инвертируется string parentFirstPart = parentChromo.Substring(0, crossoverPointPosition); string parentSecondPart = parentChromo.Substring(crossoverPointPosition); // Инвертируем вторую часть хромосомы string newSecondPart = string.Empty; // Проверим каждый ген в этой части хромосомы char[] secondPart = parentSecondPart.ToCharArray(); foreach (char gene in secondPart) { // Выполним добавление гена к новой хромосоме, // попутно инвертировав его switch (gene) { case '1': newSecondPart += "0"; break; case '0': newSecondPart += "1"; break; } } // Составим хромосому потомка string сhildChromo = parentFirstPart + newSecondPart; // Получим и добавим в популяцию потомка AdditiveIndividual child = new AdditiveIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); child.UpdateAttributes(сhildChromo); population.Add(child.Number, child); }
/// <summary> /// Метод для преобразования модели в популяцию /// </summary> /// <param name="model">Исходная модель для преобразования</param> /// <param name="generationNumber">Номер поколения, который будет присвоен /// всем особям в создаваемой популяции</param> /// <returns></returns> private static AdditivePopulation ModelToPopulation(Model model, int generationNumber) { AdditivePopulation pop = new AdditivePopulation(); // 1. Сформируем словарь с параметрами особей. Все особи // данной популяции должны характеризоваться одинаковым // набором параметров, поэтому сформируем его заранее, а // потом будем передавать в качестве параметра конструктора // всем особям. Значения параметров будем затем назначать // вручную Dictionary <TId, IndividualAttribute> attributes = new Dictionary <TId, IndividualAttribute>(); foreach (Parameter param in model.Parameters.Values) { IndividualAttribute attribute = new IndividualAttribute( param.Id, param.MinValue, param.MaxValue, Program.ApplicationSettings.ValuesDecimalPlaces); attributes.Add(param.Id, attribute); } // 2. Добавим в популяцию особи - столько же, сколько // АКТИВНЫХ экспериментов в модели foreach (Experiment exp in model.Experiments.Values) { if (exp.IsActive) { AdditiveIndividual unit = new AdditiveIndividual( exp.Number, generationNumber, attributes); // Запишем значения оптимизируемых параметров эксперимента // в словарь признаков особи foreach (Parameter param in model.Parameters.Values) { unit.Attributes[param.Id].Value = exp.ParameterValues[param.Id]; // Рассчитаем генетический код этой особи unit.Attributes[param.Id].ResolveCodeFromValue(); } // Добавим особь в популяцию pop.Add(exp.Number, unit); } } return(pop); throw new NotImplementedException(); }
/// <summary> /// Метод для выполнения одноточечного скрещивания двух /// особей /// </summary> /// <param name="population">Популяция, в которой находятся две /// родительские особи и куда будут помещены два потомка</param> /// <param name="firstUnitNumber">Номер первого родителя в популяции (уникальный)</param> /// <param name="secondUnitNumber">Номер второго родителя в популяции (уникальный)</param> /// <param name="newGenerationNumber">Номер поколения, к которому относятся потомки</param> private static void CrossTwoUnits( ref AdditivePopulation population, int firstUnitNumber, int secondUnitNumber, int newGenerationNumber) { // Признаки, у новых двух особей они будут такие же, // за исключением значений признаков - их поправим позже Dictionary <TId, IndividualAttribute> attributes = population[firstUnitNumber].Attributes; // Генетические коды родителей string firstChromo = population[firstUnitNumber].GetChromo(); string secondChromo = population[secondUnitNumber].GetChromo(); // Небольшая проверка: длины кодов должны быть одинаковые int chromoLength = firstChromo.Length; if (chromoLength != secondChromo.Length) { throw new Exception("Chromosome lengths of two parents must be the same"); } Random rnd = new Random(DateTime.Now.Millisecond + DateTime.Now.Second); // Точка одноточечного скрещивания // Такая формула обусловлена следующим: // - не должно получатся число, равное длине строки, потому что // нумерация символов zero-based и будет ошибка; // - не должен получатся ноль, потому что тогда особи просто // обменяются кодами и ничего не выйдет int crossoverPointPosition = 1 + rnd.Next(chromoLength - 2); // Разделим хромосомы на части, из которых будут составлены // хромосомы потомков string firstParentFirstPart = firstChromo.Substring(0, crossoverPointPosition); string firstParentSecondPart = firstChromo.Substring(crossoverPointPosition); string secondParentFirstPart = secondChromo.Substring(0, crossoverPointPosition); string secondParentSecondPart = secondChromo.Substring(crossoverPointPosition); // Составим хромосомы потомков string firstChildChromo = firstParentFirstPart + secondParentSecondPart; string secondChildChromo = secondParentFirstPart + firstParentSecondPart; // Получим и добавим в популяцию первого потомка AdditiveIndividual firstChild = new AdditiveIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); firstChild.UpdateAttributes(firstChildChromo); population.Add(firstChild.Number, firstChild); // Получим и добавим в популяцию второго потомка AdditiveIndividual secondChild = new AdditiveIndividual( population.GetFreeUnitNumber(), newGenerationNumber, attributes); secondChild.UpdateAttributes(secondChildChromo); population.Add(secondChild.Number, secondChild); }