Скачиваний:
0
Добавлен:
26.10.2025
Размер:
177.04 Кб
Скачать

МИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ, СВЯЗИ И МАССОВЫХ КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ.ПРОФ.М.А.БОНЧ-БРУЕВИЧА»

(СПбГУТ)

Факультет: «Институт магистратуры»

Кафедра: «Систем автоматизации и робототехники»

Направление подготовки:

Автоматизация технологических процессов и производств

Направленность (профиль):

Интеллектуальные технологии в автоматизации

ЛАБОРАТОРНАЯ РАБОТА № 3

по дисциплине:

Методы и модели искусственного интеллекта в управлении техническими системами

на тему:

Программная реализация и экспериментальное исследование генетического алгоритма

Вариант: 10

Выполнили студенты группы:

дата, подпись

Фамилия И. О.

Принял к.т.н., доцент

Верхова Г.В.

дата, подпись

Фамилия И. О.

Цель работы: приобретение навыков разработки, программной реализации на C# генетических алгоритмов, а также решение их помощью задач нелинейного математического программирования.

Задание: Использую созданные в ходе выполнения предыдущей лабораторной работы алгоритмические структуры, создать генетический алгоритм, выполнить его настройку и протестировать его на решении тестовой фитнес функции. Операторы селекции выбираются согласно своему варианту.

По результатам исследований разработанного генетического алгоритма необходимо заполнить таблицы.

Ход работы

1. Оператор селекции

1.1. Блок-схема оператора селекции

Рис.1 ­— Блок-схема оператора селекции (турнирный отбор)

1.2. Исходный код программной реализации оператора селекции

namespace EvolutionaryAlgorithmTemplate

{

public class Population

{

public List<Individual> Individuals { get; private set; }

public Population()

{

Individuals = new List<Individual>();

}

// Создаёт новую особь и добавляет её в популяцию

public void NewIndividual(List<double> values, double xmin, double xmax)

{

Individual ind = new Individual(values, xmin, xmax);

Individuals.Add(ind);

}

// Создаёт новую случайную особь с заданной размерностью и диапазоном рабочих параметров

public void NewRandomIndividual(int dimension, double xmin, double xmax, Random rnd)

{

List<double> values = new List<double>();

for (int i = 0; i < dimension; i++)

{

double val = xmin + rnd.NextDouble() * (xmax - xmin);

values.Add(val);

}

NewIndividual(values, xmin, xmax);

}

// Выбирает пару родителей методом турнирного отбора

// Каждый турнир состоит из 2 особей, выбранных из 70% лучших (элита),

// и с вероятностью 0.9 выбирается лучшая из них.

public (Individual, Individual) SelectPair(Random rnd)

{

if (Individuals.Count < 2)

throw new InvalidOperationException("Недостаточно особей для селекции.");

Individual parent1 = TournamentSelection(rnd, 0.9);

Individual parent2 = TournamentSelection(rnd, 0.9);

while (parent1 == parent2 && Individuals.Count > 1)

{

parent2 = TournamentSelection(rnd, 0.9);

}

return (parent1, parent2);

}

// Метод турнирного отбора: из элитного подмножества (70% лучших) случайно выбираются 2 особи.

// С вероятностью selectionProbability (0.9) возвращается лучшая, иначе – другая.

private Individual TournamentSelection(Random rnd, double selectionProbability)

{

// Сортируем особей по возрастанию фитнеса (минимизация)

List<Individual> sorted = Individuals.OrderBy(ind => ind.FitnessValue).ToList();

int eligibleCount = (int)Math.Ceiling(0.7 * sorted.Count);

if (eligibleCount < 2)

eligibleCount = sorted.Count;

// Выбираем случайным образом 2 индекса из элитного подмножества

int idx1 = rnd.Next(eligibleCount);

int idx2 = rnd.Next(eligibleCount);

while (idx2 == idx1 && eligibleCount > 1)

{

idx2 = rnd.Next(eligibleCount);

}

Individual candidate1 = sorted[idx1];

Individual candidate2 = sorted[idx2];

// Определяем лучшую особь (с меньшим значением фитнеса)

Individual bestCandidate = candidate1.FitnessValue <= candidate2.FitnessValue ? candidate1 : candidate2;

Individual otherCandidate = bestCandidate == candidate1 ? candidate2 : candidate1;

// С вероятностью selectionProbability выбираем лучшую, иначе – другую

return rnd.NextDouble() < selectionProbability ? bestCandidate : otherCandidate;

}

// Выполняет кроссинговер BLX‑a‑b двух родителей для создания двух потомков

public List<Individual> Crossingover(Individual parent1, Individual parent2, double a, double b, double xmin, double xmax, Random rnd)

{

var (childChrom1, childChrom2) = Chromosome.BLXabCrossover(parent1.Chromosome, parent2.Chromosome, a, b, xmin, xmax, rnd);

Individual child1 = new Individual(childChrom1);

Individual child2 = new Individual(childChrom2);

return new List<Individual> { child1, child2 };

}

// Очищает популяцию

public void Clean()

{

Individuals.Clear();

}

}

}

1.3. Исходный код юнит-теста оператора селекции

namespace EvolutionaryAlgorithmTemplate.Tests

{

public class PopulationTournamentSelectionTests

{

private class FakeRandom : Random

{

private Queue<int> intValues;

private Queue<double> doubleValues;

public FakeRandom(Queue<int> intValues, Queue<double> doubleValues)

{

this.intValues = intValues;

this.doubleValues = doubleValues;

}

// Переопределяем Next(int maxValue) для возврата предопределённых значений

public override int Next(int maxValue)

{

// Игнорируем maxValue, так как значения уже подготовлены для элитного подмножества

return intValues.Dequeue();

}

// Переопределяем NextDouble() для возврата предопределённых значений

public override double NextDouble()

{

return doubleValues.Dequeue();

}

}

[Fact]

public void SelectPair_ShouldReturnTournamentSelectedParents()

{

Population pop = new Population();

double xmin = -5.0, xmax = 5.0;

/* Создаем 5 особей с известными значениями генов.

Фитнес-функция (трехгорбый верблюд) достигает глобального минимума в (0,0).

Таким образом, после сортировки по возрастанию фитнеса особь с (0,0) будет лучшей.*/

pop.NewIndividual(new List<double> { 0.0, 0.0 }, xmin, xmax); // Особь A, фитнес = 0.0 (лучший)

pop.NewIndividual(new List<double> { 1.0, 0.0 }, xmin, xmax); // Особь B, фитнес = 1.11667

pop.NewIndividual(new List<double> { 2.0, 0.0 }, xmin, xmax); // Особь C, фитнес = 1.86667

pop.NewIndividual(new List<double> { 3.0, 0.0 }, xmin, xmax); // Особь D, фитнес значительно выше

pop.NewIndividual(new List<double> { 4.0, 0.0 }, xmin, xmax); // Особь E, фитнес очень высокий

/* После сортировки по фитнесу (OrderBy(ind => ind.FitnessValue)) элитное подмножество (70% от 5, округляем вверх) содержит 4 особи:

элита[0] = A, элита[1] = B, элита[2] = C, элита[3] = D

Для первого турнира:

rnd.Next(eligibleCount) вернет 1 candidate1 = элита[1] (особь B)

rnd.Next(eligibleCount) вернет 3 candidate2 = элита[3] (особь D)

Из них лучшей является особь B (так как её фитнес ниже).

rnd.NextDouble() вернет 0.5 (< 0.9)выбираем лучшую, то есть особь B

Для второго турнира:

rnd.Next(eligibleCount) вернет 0 candidate1 = элита[0] (особь A)

rnd.Next(eligibleCount) вернет 2 candidate2 = элита[2] (особь C)

Лучшей является особь A.

rnd.NextDouble() вернет 0.8 (< 0.9)выбираем лучшую, то есть особь A

Ожидаемая пара: (B, A)*/

Queue<int> intQueue = new Queue<int>(new List<int> { 1, 3, 0, 2 });

Queue<double> doubleQueue = new Queue<double>(new List<double> { 0.5, 0.8 });

FakeRandom fakeRandom = new FakeRandom(intQueue, doubleQueue);

// выбор пары методом турнирного отбора

var (parent1, parent2) = pop.SelectPair(fakeRandom);

// Проверяем, что родитель 1 – особь B с генами [1.0, 0.0]

Assert.Equal(1.0, parent1.Chromosome.Gens[0].Value, 5);

Assert.Equal(0.0, parent1.Chromosome.Gens[1].Value, 5);

// Проверяем, что родитель 2 – особь A с генами [0.0, 0.0]

Assert.Equal(0.0, parent2.Chromosome.Gens[0].Value, 5);

Assert.Equal(0.0, parent2.Chromosome.Gens[1].Value, 5);

}

}

}

1.4. Результаты выполнения юнит-теста оператора селекции

Рис.2 ­— Результаты выполнения юнит-теста оператора селекции (турнирный отбор)

2. Генетический алгоритм

2.1. Блок-схема генетического алгоритма

Рис.3 ­— Блок-схема генетического алгоритма

2.2. Исходный код генетического алгоритма

namespace EvolutionaryAlgorithmApp

{

class Program

{

static void Main(string[] args)

{

// Параметры задачи

int dimension = 2; // Число рабочих параметров (генов)

double xmin = -5.0; // Нижняя граница допустимых значений

double xmax = 5.0; // Верхняя граница допустимых значений

int populationSize = 5000; // Число особей в популяции

// Параметры мутации

double Pmin = 0.005; // Минимальная вероятность мутации

double Pmax = 0.1; // Максимальная вероятность мутации

double mutationProbability = 0.1; // Средняя вероятность мутации (Pmax - Pmin) / 2

// Параметры оператора кроссинговера BLX‑a‑b

double crossoverA = 0.3;

double crossoverB = 0.7;

// Параметры остановки ГА

double fitnessThreshold = 0.001; // Если лучшая фитнес-функция меньше порога, останавливаем

int maxGenerations = 100; // Максимальное число поколений для одного запуска

int numberOfRuns = 10; // Число запусков ГА для статистики

List<int> generationCounts = new List<int>();

List<double> runTimes = new List<double>();

List<double> bestFitnessValues = new List<double>();

// Проведение нескольких запусков ГА

for (int run = 0; run < numberOfRuns; run++)

{

EvolutionManager manager = new EvolutionManager(dimension, xmin, xmax, mutationProbability, crossoverA, crossoverB);

manager.InitPopulation(populationSize);

int generationCount = 0;

Stopwatch stopwatch = Stopwatch.StartNew();

double bestFitness = double.MaxValue;

// Эволюционный цикл: создаём новое поколение до достижения порога или maxGenerations

while (generationCount < maxGenerations)

{

bestFitness = GetBestFitness(manager.Populations[manager.Populations.Count - 1]);

if (bestFitness < fitnessThreshold)

break;

manager.CreateNewGeneration();

generationCount++;

}

stopwatch.Stop();

runTimes.Add(stopwatch.Elapsed.TotalSeconds);

generationCounts.Add(generationCount);

bestFitnessValues.Add(bestFitness);

}

// Вычисление статистических показателей

double overallBestFitness = double.MaxValue;

int minGenerations = int.MaxValue;

int maxGenerationsCount = int.MinValue;

double totalGenerations = 0;

double totalTime = 0;

double minTime = double.MaxValue;

double maxTime = double.MinValue;

foreach (var genCount in generationCounts)

{

totalGenerations += genCount;

if (genCount < minGenerations) minGenerations = genCount;

if (genCount > maxGenerationsCount) maxGenerationsCount = genCount;

}

foreach (var time in runTimes)

{

totalTime += time;

if (time < minTime) minTime = time;

if (time > maxTime) maxTime = time;

}

foreach (var fit in bestFitnessValues)

{

if (fit < overallBestFitness) overallBestFitness = fit;

}

double avgGenerations = totalGenerations / numberOfRuns;

double avgTime = totalTime / numberOfRuns;

// Вывод статистики в консоль

Console.WriteLine("Результаты работы генетического алгоритма:");

Console.WriteLine($"Наилучшее значение фитнес-функции: {overallBestFitness:F6}");

Console.WriteLine($"Среднее число поколений: {avgGenerations:F2}");

Console.WriteLine($"Минимальное число поколений: {minGenerations}");

Console.WriteLine($"Максимальное число поколений: {maxGenerationsCount}");

Console.WriteLine($"Среднее время работы ГА (сек): {avgTime:F6}");

Console.WriteLine($"Минимальное время работы ГА (сек): {minTime:F6}");

Console.WriteLine($"Максимальное время работы ГА (сек): {maxTime:F6}");

Console.WriteLine("\nНажмите Enter для завершения...");

Console.ReadLine();

}

// Вспомогательный метод для получения лучшего значения фитнес-функции в популяции

static double GetBestFitness(Population pop)

{

double best = double.MaxValue;

foreach (var ind in pop.Individuals)

{

if (ind.FitnessValue < best)

best = ind.FitnessValue;

}

return best;

}

}

}

Соседние файлы в предмете Методы и модели искусственного интеллекта в управлении техническими системами