Вопрос или проблема
Задача: создать программу для симуляции генетического алгоритма на Python. Для использования обмена битами в качестве мутации оператор селекции должен масштабировать приспособленность, создать 3D график, использовать гладкую поверхность на графике. X: [-15, -2], Y: [-15, -2]
, формула приспособленности = 0.5*(X-3)(Y-5)(Y-1)*sin(Y)cos(2X)
.
Проблема: возвращается ошибка в строке 127, в функции обновления
x_points.append(x[entity[i][0]])
~~~~~~~~~^^^
IndexError: недопустимый индекс для скалярной переменной.
Я не могу понять, где была допущена ошибка. Без функции масштабирования приспособленности симуляция работает без сбоев.
import random
import matplotlib.pyplot as plt
import numpy as np
Q = 20 # Количество поколений
MAX_ENT = 100 # размер популяции
MAX_CH = 20 # количество детей в одном цикле воспроизводства
N = 15 # длина хромосомы
minFitAim = 500 # минимальный желаемый результат
maxFitAim = 1500 # максимальный желаемый результат
razmer = 100
def f(x, y):
return 0.5 * (x - 3) * (y - 5) * (y - 1) * np.sin(y) * np.cos(2 * x)
def fitness(inp): # inp - входной список из нолей и единиц
z = 0.0
x1 = x[inp[0]]
y1 = y[inp[1]]
z = f(x1, y1)
return z
def update(event):
# Начальное поколение
entity = [[random.randint(0, razmer - 1) for j in range(N)] for i in range(MAX_ENT)]
print(entity)
# Инициализация точек для графика
x_points = []
y_points = []
z_points = []
for i in range(MAX_ENT):
x_points.append(x[entity[i][0]])
y_points.append(y[entity[i][1]])
z_points.append(f(x_points[i], y_points[i]))
scatter = ax.scatter(x_points, y_points, z_points, c="r", marker="o")
for q in range(Q):
ax.set_title("Поколение: " + str(q))
fit = [0 for _ in range(MAX_ENT)] # fitness для каждого организма
tmp_fit = [0 for _ in range(MAX_ENT + 2 * MAX_CH)] # фитнес всех организмов вместе с потомками
for i in range(MAX_ENT):
fit[i] = fitness(entity[i])
print('fit=", max(fit))
# Воспроизводство
fl_parent = np.full(MAX_ENT, True) # до цикла воспроизводства всe могут быть родителями
child1 = [0 for _ in range(N)]
child2 = [0 for _ in range(N)]
k = 0
while k < MAX_CH: # цикл воспроизводства по 2 потомка
m1 = random.randint(0, MAX_ENT - 1) # первый кандидат родитель
m2 = random.randint(0, MAX_ENT - 1) # второй кандидат родитель
if m1 == m2:
continue # должны быть разные
if not (fl_parent[m1] & fl_parent[m2]):
continue # кто-то уже имел потомка
# построение 2-х потомков от m1 и m2
l1 = random.randint(0, N - 1) # точка обмена хромосом
child1[:l1] = entity[m1][:l1] + entity[m2][l1:] # первый потомок
child2[:l1] = entity[m2][:l1] + entity[m1][l1:] # второй потомок
ch1 = child1[:]
ch2 = child2[:]
# добавка к массиву организмов двух потомков
entity.append(ch1)
entity.append(ch2)
fl_parent[m1] = False
fl_parent[m2] = False
k += 1
#Мутация
p_vm = 0.1 # Вероятность победы менее приспособленного
p_m = 0.2 # Вероятность мутации гена
mut_entity = [0 for _ in range(N)] # мутант
for j in range(MAX_ENT + 2 * MAX_CH): # цикл по всем организмом вместе с потомками
mut_entity = entity[j]
for k in range(N): # цикл по всем битам каждого организма
if random.random() < p_m: # Мутация обменом для мутанта
mut_entity[k] = entity[j][(N - 1) - k]
mut_entity[(N - 1) - k] = entity[j][k]
f1 = fitness(entity[j]) # приспособленность организма
f2 = fitness(mut_entity) # приспособленность мутанта
if f1 > f2:
if random.random() < p_vm:
entity[j] = mut_entity[:] # останется менее приспособленный
else:
entity[j] = mut_entity[:] # остается более приспособленный
# ЕСТЕСТВЕННЫЙ ОТБОР
tmp_entity = []
for j in range(MAX_ENT + 2 * MAX_CH):
tmp_fit[j] = fitness(entity[j]) # новое значение фитнеса
print("tmp_fit=", tmp_fit)
min_fitness = min(tmp_fit) # минимальный фитнес в поколении
max_fitness = max(tmp_fit) # максимальный фитнес в поколении
a = (minFitAim - maxFitAim) / (min_fitness - max_fitness) # коэффициент для малого индивидуума
b = minFitAim - a * min_fitness # коэффициент для большего
for j in range(MAX_ENT + 2 * MAX_CH):
tmp_entity.append(a * tmp_fit[j] + b)
entity = tmp_entity[:MAX_ENT]
# Удаление старых точек
scatter.remove()
# Создание новых точек для графика
x_points = []
y_points = []
z_points = []
for i in range(MAX_ENT):
x_points.append(x[entity[i][0]])
y_points.append(y[entity[i][1]])
z_points.append(f(x_points[i], y_points[i]))
# Отображение группы точек для графика
scatter = ax.scatter(x_points, y_points, z_points, c="r', marker="o")
# Обновление графика
fig.canvas.draw()
plt.pause(0.001)
q += 1
# Настройка параметров
x = np.linspace(-15, 2, razmer)
y = np.linspace(-15, 2, razmer)
X, Y = np.meshgrid(x, y)
# Создание плавной поверхности
Z = f(X, Y)
# Инициализация графика
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111, projection='3d')
# Отображение поверхности
ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
# Настройка меток и заголовков
ax.set_xlabel('X-хромосомы')
ax.set_ylabel('Y-хромосомы')
ax.set_zlabel('Приспособленность')
# Создание кнопки
ax_button = plt.axes([0.8, 0.05, 0.1, 0.075])
button = plt.Button(ax_button, 'НАЧАТЬ')
button.on_clicked(update)
# Показ графика
plt.show()
.
Ответ или решение
Ваш код генетического алгоритма на Python содержит несколько ошибок, которые могут привести к указанному вами исключению IndexError
. Давайте исправим эти ошибки и рассмотрим, как улучшить программу.
Основные исправления
-
Индексы в функции
fitness
:
Вы пытаетесь использовать индекс из хромосомы (entity[i][0]
) для доступа к массивуx
, но еслиentity
не содержит ожидаемых значений, то это может привести к ошибке. -
Склейка строк в функции
print
:
Неправильное использованиеprint('fit=", max(fit))
и аналогичных строк вызовет ошибку синтаксиса. -
Недостаточная инициализация списков:
Вы должны убедиться, что животные (организмы) и их потомки инициализированы правильно. -
Используйте корректные условия мутации:
Убедитесь, что выбираются правильные индексы в результате мутаций. -
Логика мутации и наследования:
Проверьте логику, чтобы избежать выхода за пределы массива.
Исправленный код
import random
import matplotlib.pyplot as plt
import numpy as np
Q = 20 # Количество поколений
MAX_ENT = 100 # размер популяции
MAX_CH = 20 # количество детей в одном цикле воспроизводства
N = 2 # длина хромосомы, так как у нас только 2 переменные X и Y
razmer = 100
def f(x, y):
return 0.5 * (x - 3) * (y - 5) * (y - 1) * np.sin(y) * np.cos(2 * x)
def fitness(inp): # inp - входной список из нолей и единиц
x1 = x[inp[0]]
y1 = y[inp[1]]
return f(x1, y1)
def update(event):
# Начальное поколение
entity = [[random.randint(0, razmer - 1) for j in range(N)] for i in range(MAX_ENT)]
# Инициализация точек для графика
x_points = []
y_points = []
z_points = []
for i in range(MAX_ENT):
x_points.append(x[entity[i][0]])
y_points.append(y[entity[i][1]])
z_points.append(fitness(entity[i]))
scatter = ax.scatter(x_points, y_points, z_points, c="r", marker="o")
for q in range(Q):
ax.set_title("Поколение: " + str(q))
fit = [fitness(entity[i]) for i in range(MAX_ENT)]
# Воспроизводство
fl_parent = np.full(MAX_ENT, True) # все могут быть родителями
k = 0
while k < MAX_CH: # цикл воспроизводства по 2 потомка
m1, m2 = random.sample(range(MAX_ENT), 2) # случайные разные родители
# Построение 2-х потомков от m1 и m2
l1 = random.randint(1, N - 1) # точка обмена хромосом
child1 = entity[m1][:l1] + entity[m2][l1:] # первый потомок
child2 = entity[m2][:l1] + entity[m1][l1:] # второй потомок
entity.append(child1)
entity.append(child2)
k += 2
# Мутация
for j in range(MAX_ENT + 2 * MAX_CH):
if j >= len(entity):
break
mut_entity = entity[j][:]
for k in range(N): # цикл по всем битам каждого организма
if random.random() < 0.2: # вероятность мутации
mut_entity[k] = random.randint(0, razmer - 1) # замените ген случайным
# Сравниваем с исходным
if fitness(mut_entity) > fitness(entity[j]):
entity[j] = mut_entity[:] # остаемся с более приспособленным
# Применение естественного отбора
tmp_entity = []
tmp_fit = [fitness(e) for e in entity]
a = (minFitAim - maxFitAim) / (min(tmp_fit) - max(tmp_fit))
b = minFitAim - a * min(tmp_fit)
for j in range(len(entity)):
tmp_entity.append(a * tmp_fit[j] + b)
entity = tmp_entity[:MAX_ENT] # оставляем только MAX_ENT организмов
# Обновление точек для графика
scatter.remove()
x_points = [x[entity[i][0]] for i in range(MAX_ENT)]
y_points = [y[entity[i][1]] for i in range(MAX_ENT)]
z_points = [fitness(entity[i]) for i in range(MAX_ENT)]
scatter = ax.scatter(x_points, y_points, z_points, c="r", marker="o")
# Обновление графика
fig.canvas.draw()
plt.pause(0.001)
# Настройка параметров
x = np.linspace(-15, 2, razmer)
y = np.linspace(-15, 2, razmer)
X, Y = np.meshgrid(x, y)
# Создание плавной поверхности
Z = f(X, Y)
# Инициализация графика
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111, projection='3d')
# Отображение поверхности
ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
ax.set_xlabel('X-хромосомы')
ax.set_ylabel('Y-хромосомы')
ax.set_zlabel('Приспособленность')
# Создание кнопки
ax_button = plt.axes([0.8, 0.05, 0.1, 0.075])
button = plt.Button(ax_button, 'START')
button.on_clicked(update)
# Показ графика
plt.show()
Объяснение изменений
- Упрощение системы индексов и доступ к хромосоме в
fitness()
для минимизации ошибок. - Использование
random.sample()
для выбора двух разных родителей без необходимости проверять их в цикле. - Сложность с мутацией изменена, чтобы проще менять гены случайным образом, избегая ошибок индексации.
- Исправлены основные ошибки в логике, чтобы код возможностей работал более предсказуемо.
Этот код должен работать, как задумывалось, и отображать развитие поколения через генетический алгоритм с использованием графика. Если у вас есть дополнительные вопросы или вам нужно больше пояснений, не стесняйтесь спрашивать!