Генетический алгоритм на Python [закрыто]

Вопрос или проблема

Задача: создать программу для симуляции генетического алгоритма на 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. Давайте исправим эти ошибки и рассмотрим, как улучшить программу.

Основные исправления

  1. Индексы в функции fitness:
    Вы пытаетесь использовать индекс из хромосомы (entity[i][0]) для доступа к массиву x, но если entity не содержит ожидаемых значений, то это может привести к ошибке.

  2. Склейка строк в функции print:
    Неправильное использование print('fit=", max(fit)) и аналогичных строк вызовет ошибку синтаксиса.

  3. Недостаточная инициализация списков:
    Вы должны убедиться, что животные (организмы) и их потомки инициализированы правильно.

  4. Используйте корректные условия мутации:
    Убедитесь, что выбираются правильные индексы в результате мутаций.

  5. Логика мутации и наследования:
    Проверьте логику, чтобы избежать выхода за пределы массива.

Исправленный код

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()

Объяснение изменений

  1. Упрощение системы индексов и доступ к хромосоме в fitness() для минимизации ошибок.
  2. Использование random.sample() для выбора двух разных родителей без необходимости проверять их в цикле.
  3. Сложность с мутацией изменена, чтобы проще менять гены случайным образом, избегая ошибок индексации.
  4. Исправлены основные ошибки в логике, чтобы код возможностей работал более предсказуемо.

Этот код должен работать, как задумывалось, и отображать развитие поколения через генетический алгоритм с использованием графика. Если у вас есть дополнительные вопросы или вам нужно больше пояснений, не стесняйтесь спрашивать!

Оцените материал
Добавить комментарий

Капча загружается...