ФГБОУ ВО НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
«МОСКОВСКИЙ ЭНЕРГЕТИЧЕСКИЙ ИНСТИТУТ»
Кафедра управления и интеллектуальных технологий
Отчёт по лабораторной работе №2
«Изучение основ применения генетических алгоритмов»
По дисциплине «Нейро-нечеткие технологии в задачах управления»
Цель работы – изучение основ работы с генетическими алгоритмами.
В работе рассматривается решение задачи поиска максимума функции на заданном интервале с применением генетических алгоритмов.
Выполнение
1. Анализ функции и построение ее графика
Рис.1. График функции
2. Формулировка задачи поиска оптимального значения функции на отрезке [0;15] с точностью до целых значений в терминах генетического алгоритма.
Необходимо решить задачу поиска максимального значения с помощью генетического алгоритма. Решение задачи состоит в следующих шагах:
Инициализация. Создаем начальную популяцию представляя элементы в виде двоичного кода.
Оценка приспособленности. Вычисление функции приспособленности для каждой особи.
Проверка условий остановки генетического алгоритма. Например: достижение определенной точности оптимизации функции, ограничение по времени выполнения или числу итераций.
Селекция: Выбор родителей для создания следующего поколения с учетом их значений функции приспособленности. Выбор происходит по методу рулетки, в котором вероятность выбрать более приспособленную хромосому пропорциональна значению ее приспособленности.
Скрещивание и мутация: Применение генетических операторов скрещивания по одной точке, чтобы создать потомство для следующего поколения на основе выбранных хромосом.
Формирование новой популяции: Создание новой популяции особей, полученных в результате скрещивания или мутации, вероятность которой равна 0,1.
Выбор лучшей особи: Выбор наилучшей особи в новой популяции, соответствующей наибольшему значению функции приспособленности.
3. Разработка и листинг программы для нахождения оптимального решения.
Код программы на Python:
import random
import matplotlib.pyplot as plt
import numpy as np
import math
# Кодировать значение в виде двоичной строки заданной битовой длины (по умолчанию - 6)
def encode(value, min_value, max_value, bit_length=None):
if bit_length is None:
bit_length = 6
normalized_value = (value - min_value) / (max_value - min_value + 1) * (2 ** bit_length)
binary_representation = bin(int(normalized_value))[2:]
return binary_representation.zfill(bit_length)
# Декодирование
def decode(binary_string, min_value, max_value):
string_length = len(binary_string)
decoded_value = (max_value - min_value + 1) * int(binary_string, 2) / (2 ** string_length) + min_value
return decoded_value
# Задание функции
@np.vectorize
def fitness_function(x):
return math.sqrt(abs(x + 2))
# Селекция рулеткой
def roulette_wheel_selection(population, fitness_values):
total_fitness = np.sum(fitness_values)
probability_distribution = np.cumsum([score / total_fitness for score in fitness_values])
selected_parents = [
population[np.searchsorted(probability_distribution, random.random())]
for _ in range(len(population) // 2)
]
return selected_parents
# Ранговый метод
def rank_based_selection(population, fitness_values):
sorted_indices = np.argsort(fitness_values)
selected_parents = [population[i] for i in sorted_indices[len(population) // 2:]]
return selected_parents
SELECTION_METHODS = {
"rank-based": rank_based_selection,
"roulette": roulette_wheel_selection
}
# Скрещивание
def crossover(parent_pool, crossover_points=None):
if crossover_points is None:
crossover_points = 1
parent1, parent2 = random.sample(parent_pool, 2)
crossover_positions = sorted(random.sample(range(len(parent_pool) - 1), crossover_points))
for position in crossover_positions:
offspring1 = parent1[:position] + parent2[position:]
offspring2 = parent2[:position] + parent1[position:]
parent1, parent2 = offspring1, offspring2
return offspring1, offspring2
# Мутация
def mutate(individual, position):
if individual[position] == '1':
return individual[:position] + '0' + individual[position + 1:]
return individual[:position] + '1' + individual[position + 1:]
def genetic_algorithm(
population_size,
generations_count,
min_value,
max_value,
objective_function,
selection_method=None,
mutation_probability=0.01,
crossover_points_count=None,
encoding_length=None,
show_graph=False,
verbose_output=False
):
# Инициализация популяции
population = [
encode(random.uniform(min_value, max_value), min_value, max_value, encoding_length)
for _ in range(population_size)
]
# Итерация по поколениям
if verbose_output:
print("Generation\tPopulation")
for current_generation in range(1, generations_count + 1):
# Оценка каждой особи
decoded_population = [decode(individual, min_value, max_value) for individual in population]
fitness_scores = objective_function(decoded_population)
# Выбор родителей
selection_function = SELECTION_METHODS.get(selection_method, SELECTION_METHODS["rank-based"])
parent_selection = selection_function(population, fitness_scores)
# Создание следующего поколения
next_generation = []
for _ in range(population_size // 2):
offspring1, offspring2 = crossover(parent_selection, crossover_points_count)
for gene_index in range(len(offspring1)):
random_value = random.random()
if random_value < mutation_probability:
if random_value % 2:
offspring1 = mutate(offspring1, gene_index)
else:
offspring2 = mutate(offspring2, gene_index)
next_generation.extend([offspring1, offspring2])
population = next_generation
if verbose_output:
print(current_generation, population, sep="\t" * 3)
# Нахождение лучшего значения
best_solution = max(population, key=lambda individual: objective_function(decode(individual, min_value, max_value)))
solution_value = decode(best_solution, min_value, max_value)
print(f"Best solution: {best_solution} ({solution_value})")
if show_graph:
x_values = np.array(range(-max_value, max_value))
plt.plot(x_values, fitness_function(x_values))
plt.grid()
plt.show()
if __name__ == '__main__':
genetic_algorithm(
population_size=6,
generations_count=4,
objective_function=fitness_function,
selection_method="roulette",
min_value=0,
max_value=15,
crossover_points_count=1,
encoding_length=4,
verbose_output=True,
mutation_probability=0.1
)
4. Запуск программы и анализ результатов ее работы.
Результат работы программы
Таблица 1 Результат работы одного запуска классического алгоритма
generation |
population |
1 |
'1101', '1101', '1001', '1101', '1101', '1000' |
2 |
'1101', '1101', '1101', '1101', '0101', '1101' |
3 |
'1101', '1101', '1100', '1101', '1101', '1101' |
4 |
'1101', '1101', '1101', '1101', '1101', '1101' |
best candidate is 1101 (13.0) |
|
Таблица 2 Результат работы классического алгоритма
№ запуска |
Результат |
1 |
best candidate is 1101 (13.0) |
2 |
best candidate is 1011 (11.0) |
3 |
best candidate is 1110 (14.0) |
Анализ результатов
Полученное решение не является оптимальным, но все же довольно близко к нему. Более того, результаты могут немного разниться от запуска к запуску.
5. Модифицировали программу (скрещивание по 2 точкам, ранговый метод)
if __name__ == '__main__':
genetic_algorithm(
population_size=6,
generations_count=4,
objective_function=fitness_function,
selection_method="rank",
min_value=0,
max_value=15,
crossover_points_count=2,
encoding_length=4,
verbose_output=True,
mutation_probability=0.1
)
6. Запуск программы и анализ результатов ее работы.
Результат работы программы
Таблица 3 Результат работы одного запуска модифицированного алгоритма
generation |
population |
1 |
'0011', '1111', '0011', '1111', '0011', '0101' |
2 |
'0111', '1101', '1011', '1111', '1111', '0111' |
3 |
'1101', '1111', '1101', '1111', '1011', '1101' |
4 |
'1101', '1111', '1101', '1111', '1011', '1101' |
best candidate is 1111 (15.0) |
|
Таблица 4 Результат работы модифицированного алгоритма
-
№ запуска
Результат работы программы
1
best candidate is 1111 (15.0)
2
best candidate is 1111 (15.0)
3
best candidate is 1111 (14.0)
Анализ результатов
После усовершенствования классического генетического алгоритма получили более устойчивый результат, который к тому же оказался более близким к максимуму на данном отрезке.
Вывод: В рамках данной работы был изучен генетический алгоритм (ГА). Мы разработали две программы, которые решают задачу поиска максимального значения заданной целевой функции с использованием различных методов ГА. Модифицированный метод продемонстрировал более высокую эффективность по сравнению с классическим подходом. Для повышения точности решения можно изменять параметры алгоритма, например увеличить длину кодирующих битов, изменить метод отбора особей или снизить вероятность мутации. Повторный запуск программы также может улучшить результаты из-за зависимости от случайных факторов. ГА является стохастическим методом, поэтому его результаты не всегда стабильны, так как в процессе решения задачи присутствует элемент случайности, проявляющийся в выборе родителей для скрещивания и вероятности мутации потомков.
Москва
2025
