Skip to content

Application of a genetic algorithm to solve a nonlinear programming problem

Notifications You must be signed in to change notification settings

Nekit-vp/Genetic_algorithm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

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

Genetic algoritm

Генетические алгоритмы - это очень популярные в настоящее время способы решения задач оптимизации. В их основе лежит использование эволюционных принципов для поиска оптимального решения.

Генетические алгоритмы в основном применяются для решения задач оптимизации, т.е. задач, в которых есть некоторая функция нескольких переменных F(x1, x2, ... ,xn) и необходимо найти либо её максимум, либо её минимум. Функция F называется целевой функцией, а переменные - параметрами функции. Генетические алгоритмы "пришиваются" к данной задаче следующим образом.

Параметры задачи являются генетическим материалом - генами. Совокупность генов составляет хромосому. Каждая особь обладает своей хромосомой, а, следовательно, своим набором параметров. Подставив параметры в целевую функцию, можно получить какое-то значение. То, насколько это значение удовлетворяет поставленным условиям, определяет характеристику особи, которая называется приспособленностью (fitness). Функция, определяющая приспособленность должна удовлетворять следующему условию: чем "лучше" особь, тем выше приспособленность.

Генетические алгоритмы работают с популяцией как правило фиксированного размера, состоящей из особей, заданных при помощи способа, описанного выше. Вот здесь начинается самое интересное. Особи "скрещиваются" между собой с помощью генетических операторов, естественно, получается потомство, причем часть потомков заменяют представителей более старого поколения в соответствии со стратегией формирования нового поколения. Кстати, выбор особей для скрещивания проводится согласно селективной стратегии (selection strategy). Так вот, заново сформированная популяция снова оценивается, затем выбираются наиболее достойные для скрещивания особи, которые "встречаются, влюбляются, женятся", получаются дети, занимают место престарелых индивидуумов и т.д.

Вся эта карусель продолжается до тех пор, пока не найдется особь, гены которой представляют оптимальный набор параметров, при которых значение целевой функции близко к максимуму или минимуму, либо равно ему. Останов работы ГА может произойти также в случае, если популяция вырождается, т.е. если практически нет разнообразия в генах особей популяции, либо если просто вышел лимит времени. Вырождение популяции называют преждевременной сходимостью (premature convergence).

Ход работы:

Для решения задачи я взял функцию двух переменных (то есть у каждой моей особи будет хромосома с двумя генами), потому что ее можно показать на графике. Можно взять и функцию с большим количеством переменных, необходимо будет лишь изменить константу количества генов в хромосоме и соответственно изменить саму фитнес-функцию.

В константах программы следующие значения:

  • POPULATION_SIZE = 100 # количество индивидуумов в популяции
  • MAX_GENERATIONS = 200 # максимальное количество поколений
  • P_CROSSOVER = 0.9 # вероятность скрещивания
  • P_MUTATION = 0.1 # вероятность мутации индивидуума
  • N_VECTOR = 2 # количество генов в хромосоме
  • LIMIT_VALUE_TOP = 100 # верхняя граница
  • LIMIT_VALUE_DOWN = -100 # нижняя граница

Фитнес-функция задается через функцию, и меняется в зависимости от задачи.

// python code
def fitness_function(f):
    return f[0] ** 2 + 1.5 * f[1] ** 2 - 2 * f[0] * f[1] + 4 * f[0] - 8 * f[1]

В качестве индивидуума (особи) выступает класс, унаследованный от list, также у каждой особи есть поле value в котором храниться значение фитнес-функции, то есть значение целевой функции.

// python code
class Individual(list):
    def __init__(self, *args):
        super().__init__(*args)
        self.value = 0

Рисунок SEQ Рисунок \ ARABIC 1. Класс особи*

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

// python code
def individualCreator():
    return Individual([random.randint(LIMIT_VALUE_DOWN, LIMIT_VALUE_TOP) for i in range(N_VECTOR)])

Далее функция, которая создает популяцию из наших особей.

// python code
def populationCreator(n=0):
    return list([individualCreator() for i in range(n)])

Создаем популяцию, размерность которую мы указали в константах программы, вычисляем приспособленность каждой особи, (вычисление фитнес-функции), и эти значения записываем в каждую особь.

// python code

population = populationCreator(n=POPULATION_SIZE)

fitnessValues = list(map(fitness_function, population))

for individual, fitnessValue in zip(population, fitnessValues):
    individual.value = fitnessValue

В итоге мы имеем популяцию особей размерностью POPULATION_SIZE у каждой из которой в хромосоме N_VECTOR генов.

Для наглядности отсортируем популяцию по значению приспособленности и выведем на экран:

// python code

population = populationCreator(n=POPULATION_SIZE)

fitnessValues = list(map(fitness_function, population))

for individual, fitnessValue in zip(population, fitnessValues):
    individual.value = fitnessValue

Этапы генетического алгоритма:

  • Селекция (отбор)
  • Скрещивание
  • Мутация
  • Новое поколение

Селекция происходит таким образом: из всей популяции выбираются 4 случайные особи, из этих 4 выбирается более приспособленная особь и она добавляется в новую популяцию, и так до тех пор, пока новая популяцию не будет таких же размеров что и старая. Логично предположить, что в новой популяции будут попадаться одни и та же особи дважды, поэтому нужно ввести функцию клонирования, которая будет клонировать особи, для того, чтобы каждая особь представляла собой отдельный объект.

// python code

def clone(value):
    ind = Individual(value[:])
    ind.value = value.value
    return ind

Функция селекции выглядит следующим образом:

// python code

def selection(popula, n=POPULATION_SIZE):
    offspring = []
    for i in range(n):
        i1 = i2 = i3 = i4 = 0
        while i1 in [i2, i3, i4] or i2 in [i1, i3, i4] or i3 in [i1, i2, i4] or i4 in [i1, i2, i3]:
            i1, i2, i3, i4 = random.randint(0, n - 1), random.randint(0, n - 1), random.randint(0,
                                                                                                n - 1), random.randint(
                0, n - 1)

        offspring.append(
            min([popula[i1], popula[i2], popula[i3], popula[i4]], key=lambda ind: ind.value))

    return offspring

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

// python code

def crossbreeding(object_1, object_2):
    s = random.randint(1, len(object_1) - 1)
    object_1[s:], object_2[s:] = object_2[s:], object_1[s:]

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

// python code

def mutation(mutant, indpb=0.04, percent=0.05):
    for index in range(len(mutant)):
        if random.random() < indpb:
            mutant[index] += random.randint(-1, 1) * percent * mutant[index]

Для основного цикла программы добавим счетчик поколений:

// python code

generationCounter = 0

Основной цикл работы алгоритма:

  • Увеличение счетчика поколения
  • Селекция популяции
  • Клонирование популяции (избежать одинаковых ссылок на объекты)
  • Попарное скрещивание популяции
  • Мутация популяции
  • Вычисление нового значения фитнес-функции популяции
  • Добавление значения фитнес-функции в каждую особь
  • Вычисление лучшей, средней и худшей особи для постройки графика
  • Прорисовка всех особей на 3d графике для визуализации.
  • Вывод данных в консоль

Рисунок SEQ Рисунок \ ARABIC 2. Поколение 0*

Рисунок SEQ Рисунок \ ARABIC 3. Поколение 1*

Рисунок SEQ Рисунок \ ARABIC 4. Поколение 2*

Рисунок SEQ Рисунок \ ARABIC 5. Поколение 7*

Рисунок SEQ Рисунок \ ARABIC 6. Поколение 35*

Рисунок SEQ Рисунок \ ARABIC 7. Поколение 76*

Рисунок SEQ Рисунок \ ARABIC 8. График работы 200 поколений.*

About

Application of a genetic algorithm to solve a nonlinear programming problem

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages