Министерство образования Республики Молдова.
Технический университет Молдовы.
Факультет Вычислительной техники, Информатики и Микроэлектроники.
Курсовая работа
по дисциплине «Анализ и проектирование алгоритмов»
Тема: «Анализ генетического алгоритма»
Выполнил студент группы :
Научный руководитель:
Скороходова Т.
Черней И.
Кишинев 2022
1
СОДЕРЖАНИЕ:
Введение…………………………………………………………………………..…..3
Глава 1. Алгоритм: понятия и свойства…………………………………………......4
Глава 2. Генетические алгоритмы……………………………………………….…..7
Реализация………………………………………………………………………..….12
Заключение…………………………………………………………………………..16
Список использованной литературы………………………………………………17
Приложение…………………………………………………………………………18
2
Введение:
Модели естественных вычислений широко применяются в современной науке. Область их
применения очень обширна, они используются для решения задач моделирования, искусственного
интеллекта, распознавания образов, управления.
Одним из наиболее распространенных методов естественных вычислений являются
генетические алгоритмы. Чтобы лучше разобраться, как эти алгоритмы устроены и как работают,
было решено воспроизвести один из таких алгоритмов — генетический. Для того, чтобы применять
какой-либо метод для решения конкретных задач этот метод необходимо освоить. Поэтому
генетический алгоритм, рассмотренный в данной работе, не решает никакой конкретной задачи.
Главными являются общие исследования и одновременно процесс, и результат работы по созданию
программы по моделированию и визуализации работы генетического алгоритма. Важен полученный
программистский опыт.
Программа моделирует поведение популяции самых примитивных живых организмов. Эта
программа вряд ли будет иметь какое-либо практическое применение, но она наглядно иллюстрирует
принцип работы генетических алгоритмов.
Актуальность данной темы заключается в том, что в нашем 21 веке биологические исследования
очень важны как для развития человека и человечества в целом, так и как способ для улучшения жизни
на всей планете и ее процветанию, на фоне глобальных загрязнений и вредных эффектов на экологию.
Это позволит человечеству выжить как виду.
3
Глава 1. Алгоритм: понятия и свойства
Алгоритм (от латинской формы имени среднеазиатского математика аль-Хорезми) - правило
действий, последовательность проведения вычислительных операций, способ нахождения искомого
результата.
Современное формальное определение алгоритма было дано в 30-50-е годы XX века в работах
Тьюринга, Поста, Чёрча, Н. Винера, А.А. Маркова. Само слово «алгоритм» произошло от имени
хорезмского учёного Абу Абдуллах Мухаммеда ибн Муса аль-Хорезми.
В течение следующих столетий появилось множество других трудов, посвящённых всё тому
же вопросу - обучению искусству счёта с помощью цифр. В названии каждого труда было слово
algoritmi или algorismi.
Одновременно с развитием понятия алгоритма постепенно происходила и его экспансия из
чистой математики в другие сферы. И начало ей положило появление компьютеров, благодаря
которому слово «алгоритм» вошло в 1985 г. во все школьные учебники информатики и обрело новую
жизнь. Вообще можно сказать, что его сегодняшняя известность напрямую связана со степенью
распространения компьютеров.
В традиционной трактовке алгоритм - это точный набор инструкций, описывающих
последовательность действий исполнителя для достижения результата решения задачи за конечное
время. По мере развития параллельности в работе компьютеров слово «последовательность» стали
заменять более общим словом «порядок». Это связано с тем, что какие-то действия алгоритма должны
быть выполнены только друг за другом, но какие-то могут быть и независимыми. Ранее часто писали
«алгорифм», сейчас такое написание используется редко.
Часто в качестве исполнителя выступает некоторый механизм (компьютер, токарный станок,
швейная машина), но понятие алгоритма необязательно относится к компьютерным программам, так,
например, чётко описанный рецепт приготовления блюда также является алгоритмом - в таком случае
исполнителем является человек.
Понятие алгоритма - одно из основных в программировании и информатике. Это
последовательность команд, предназначенная исполнителю, в результате выполнения которой он
должен решить поставленную задачу. Алгоритм должен описываться на формальном языке,
4
исключающем неоднозначность толкования. Исполнитель может быть человеком или машиной.
Исполнитель должен уметь выполнять все команды, составляющие алгоритм. Множество возможных
команд конечно и изначально строго задано. Действия, выполняемые по этим командам, называются
элементарными.
Запись алгоритма на формальном языке называется программой. Иногда само понятие
алгоритма отождествляется с его записью, так что слова «алгоритм» и «программа» - почти синонимы.
Небольшое различие заключается в том, что под алгоритмом, как правило, понимают основную идею
его построения. Программа же всегда связана с записью алгоритма на конкретном формальном языке.
Свойства алгоритма. Значение слова алгоритм очень схоже со значением слов рецепт,
инструкция. Однако любой алгоритм в отличие от рецепта или способа обязательно обладает
следующими свойствами.
А. Выполнение алгоритма разбивается на последовательность законченных действий-шагов.
Только выполнив одно действие (команду), можно приступать к исполнению следующего. Это
свойство алгоритма называется дискретностью. Произвести каждое отдельное действие исполнителю
предписывает специальное указание в записи алгоритма (команда).
Б. Понятность - алгоритм не должен содержать предписаний, смысл которых может
восприниматься исполнителем неоднозначно, т.е. запись алгоритма должна быть настолько четкой и
полной, чтобы у исполнителя не возникало потребности в принятии каких-либо самостоятельных
решений. Алгоритм всегда рассчитан на выполнение «не размышляющего» исполнителя. Алгоритм
составляется из команд, входящих в СКИ.
В. Детерминированность (определенность и однозначность). Каждая команда алгоритма
определяет однозначное действие исполнителя, и должно быть однозначно определено, какая команда
выполняется следующей. То есть если алгоритм многократно применяется к одному и тому же набору
исходных данных, то на выходе он получает каждый раз один и тот же результат.
Г. Результативность - исполнение алгоритма должно закончиться за конечное число шагов,
и при этом должен быть получен результат решения задачи. В качестве одного из возможных
результатов может быть и установление того факта, что задача решений не имеет.
Свойство результативности содержит в себе свойство конечности - завершение работы
5
алгоритма за конечное число шагов.
Д. Массовость - алгоритм пригоден для решения любой задачи из некоторого класса задач,
т.е. алгоритм правильно работает на некотором множестве исходных данных, которое называется
областью применимости алгоритма.
Свойство массовости определяет скорее качество алгоритма, а не относится к обязательным
свойствам (как дискретность, понятность и пр.). Существуют алгоритмы, область применимости
которых ограничивается единственным набором входных данных или даже отсутствием таковых
(например, получение фиксированного числа верных цифр числа p). Правильнее говорить о том, что
алгоритм должен быть применим к любым данным из своей области определения, и слово массовость
не всегда подходит для описания такого свойства.
6
Глава 2. Генетические алгоритмы
Генетические алгоритмы (ГА) — это стохастические, эвристические оптимизационные
методы, впервые предложенные Джоном Холландом в 1975 году. Они основываются на идее эволюции
с помощью естественного отбора. Кроме более быстрого нахождения экстремума, к положительным
свойствам генетических алгоритмов можно отнести и нахождение «глобального» экстремума. В
задачах, где целевая функция имеет значительное количество локальных экстремумов, в отличие от
градиентного метода, генетические алгоритмы не «застревают» в точках локального экстремума, а
позволяют найти «глобальный» минимум.
Генетические алгоритмы работают с совокупностью особей – популяцией, где каждая особь
представляет возможное решение данной проблемы. Она оценивается мерой ее «приспособленности»
согласно тому, насколько «хорошо» соответствующее ей решение задачи. В природе это эквивалентно
оценке того, насколько эффективен организм при конкуренции за ресурсы. Наиболее приспособленные
особи получают возможность «воспроизводить» потомство с помощью «перекрестного скрещивания»
с другими особями популяции. Это приводит к появлению новых особей, которые сочетают в себе
некоторые характеристики, наследуемые ими от родителей. Наименее приспособленные особи с
меньшей вероятностью смогут воспроизвести потомков, так что те свойства, которыми они обладали,
будут постепенно исчезать из популяции в процессе эволюции. Иногда происходят мутации, или
спонтанные изменения в генах.
Таким образом, из поколения в поколение, хорошие характеристики распространяются по всей
популяции. Скрещивание наиболее приспособленных особей приводит к тому, что наследуются
наиболее перспективные участки пространства поиска. В конечном итоге популяция будет сходиться
к оптимальному решению задачи. Преимущество ГА состоит в том, что он находит приблизительные
оптимальные
решения
за
относительно
короткое
время.
ГА оперирует следующей терминологией:

Хромосома – решение рассматриваемой проблемы, носитель наследственной информации.
Совокупность хромосом (значений параметров целевой функции) характеризует особь. Хромосома
состоит из генов.
7

Гены – элементы кодирования наследственной информации (параметров целевой функции). В
качестве генов чаще всего выступает битовое кодирование информации.

Особь – набор хромосом (совокупность параметров, для которой ищется значение целевой функции).

Приспособленность особи– значение целевой функции для данного набора параметров по
отношению к требуемому значению.
ГА производит над особями следующие действия

Генерация начальной популяции хромосом – случайным образом выбираются значения
параметров целевой функции и для этих значений параметров находится значение целевой функции.

Селекция – выбор особей с наилучшей приспособленностью для воспроизводства (сортировка по
значению целевой функции). Чем лучше приспособленность особи, тем выше ее шансы на
скрещивание и наследование ее генов следующим поколением.

Кроссовер – скрещивание. Случайным образом выбирается точка разрыва – участок между
соседними битами в строке. Обе родительские структуры разрываются на два сегмента по этой точке.
Затем, соответствующие сегменты различных родителей склеиваются и получаются два генотипа
потомков.
Рис 1. Соответствие сегментов различных родителей для получения потомков
8

Мутация – случайное изменение генов. Случайным образом выбранный ген с некоторой
вероятностью меняется на другой.
Рис 2. Мутация гена

Инверсия – изменение порядка следования частей кода. Случайным образом выбирается точка
разрыва – участок между соседними битами в строке. Обе части родительские структуры, разорванной
по этой точке, меняются местами, после чего склеиваются.
Рис 3. Инверсия родительских генов в определенной точке
9
Деревья поколений.
В генетическом программировании особи из популяции представляют собой программы.
Удобно представлять эти программы в виде деревьев, где функции представлены внутренними
узлами, к которым в качестве входных параметров присоединены поддеревья. Листьями такого
дерева будут константы, входные параметры задачи или директивные команды программы.
Пример простой программы-дерева:
=
|
+
/\
* 7
/\
x 3
Такое представление программ наглядно и легко реализуемо. Однако, работа с деревьями не
всегда удобна при выполнении таких операторов, как кроссинговер и мутация. По сути, необходимо
реализовать совершенно новые операторы.
Кроссинговер будет заключаться в подмене одного из поддеревьев первого родителя на какое-либо
поддерево второго родителя.
Мутация будет выполнять случайное изменение одного из узлов дерева (например смена функции
или константы).
Таким образом, использование деревьев влечет за собой несколько проблем: необходимость создания
новых операторов мутации и кроссинговера; динамическая длина хромосомы, кодирующей дерево.
10
Вначале ГА-функция генерирует определенное количество возможных решений (особей), а
затем вычисляет для каждого приспособленность – близость к истине. Эти решения дают потомство
(производится операция кроссовера). Более приспособленные решения имеют больший шанс к
воспроизводству, а «слабые» особи постепенно «отмирают». Таким образом, происходит процесс
эволюции. На определенных этапах данного процесса происходят спонтанные изменения генов
(мутации и инверсии). Полезные изменения, приводящие к увеличению приспособленности особи,
дают свое потомство, в то время как «бесполезные» изменения «отмирают». После скрещивания,
мутаций и инверсий снова определяется приспособленность особей нового поколения. Процесс
повторяется до тех пор, пока не найдено решение или не получено достаточное к нему приближение.
В качестве примера применения генетического алгоритма рассмотрим задачу численного поиска
решения.
Целевая функция будет иметь вид
Рис 4. Целевая функция
11
Реализация на С++
В качестве функции кроссовера будем использовать операцию нахождения среднего
арифметического двух рассматриваемых точек. Для скрещивания выбираются несколько точек с
наилучшим решением (со значением целевой функции, наиболее близким к нулю).
Мутацией будет являться операция генерации нового случайного числа рассматриваемой популяции.
Инверсия будет изменять значение хромосомы на некоторую небольшую величину, таким образом
осуществляя поиск в окрестностях точки с наилучшим решением.
Функция генетического алгоритма:
double func(double x)
{
return sin(M_PI * x / 180) - 1 / x;
}
double mutation(double x0, double x1) // мутация: генерация случайной величины
{
const int NUM = 100000000;
return fabs((double)((rand() * NUM) % (int)((x1 - x0)*NUM) + 1) / NUM) + x0;
}
double inversion(double x, double eps) // инверсия: поиск в окрестностях точки
{
static int sign = 0;
sign++;
sign %= 2;
if (sign == 0) return x - eps;
else return x + eps;
}
void crossover(double *x, double eps, double x0, double x1) // кроссовер: среднее арифметическое
12
{
int k = 99;
for (int i = 0; i < 8; i++)
for (int j = i + 1; j < 8; j++)
{
x[k] = (x[i] + x[j]) / 2;
k--;
}
for (int i = 0; i < 8; i++)
{
x[k] = inversion(x[i], eps); k--;
x[k] = inversion(x[i], eps); k--;
}
for (int i = 8; i < k; i++)
x[i] = mutation(x0, x1);
}
void sort(double *x, double *y) // сортировка
{
for (int i = 0; i < 100; i++)
for (int j = i + 1; j < 100; j++)
if (fabs(y[j]) < fabs(y[i])) {
double temp = y[i];
y[i] = y[j];
y[j] = temp;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
double genetic(double x0, double x1, double eps) // поиск решения с использованием ГА
{
double population[100];
13
double f[100];
int iter = 0;
for (int i = 0; i < 100; i++) // формирование начальной популяции
{
population[i] = mutation(x0, x1);
f[i] = func(population[i]);
}
sort(population, f);
do {
iter++;
crossover(population, eps, x0, x1);
for (int i = 0; i < 100; i++)
f[i] = func(population[i]);
sort(population, f);
} while (fabs(f[0]) > eps && iter<20000);
cout « iter « " iterations" « endl;
return population[0];
}
14
Вывод программы:
Используя генетический алгоритм, реализованный в данной программе, я сумел получить
наилучшее значение хромосомы определённого генома спустя определённое итераций, которые в моём
случае означают, что каждая 200 особь будет содержать лучший ген.
15
Заключение:
В результате выполненной курсовой работы был рассмотрен генетический алгоритм и
реализован на языке программирования С++. Был достаточно детально рассмотрен данный алгоритм
со стороны теоретической, как в общем понятии, так и в узкоспециализированном плане, что
подразумевается, как биологической частью. Поставленные цели были выполнены, и можно сказать,
что разбор данной темы снова представил её актуальность, так как всё же генетика является
достаточно важным фрагментом жизни человека и человечества в общем, так как благодаря ей
возможно сделать определённые заключения о развитии человечества как живого организма.
Необходимо сказать, что выполнение данного алгоритма с программной стороны имеет особо
важное значение, так как облегчает исследования над геномом человека. Конечно же алгоритм,
выполненный в данной программе не учитывает всех условий мутаций и т.д., так как со временем они
также развиваются и их количество видов тоже увеличивается, но всё же для рассмотрения
генетический изменений в общем данный алгоритм подходит.
16
БИБЛИОГРАФИЯ
1. Статья по общему понятию алгоритмов и генетическим алгоритмам в частности.
[Электронный ресурс] - «https://habr.com/ru/post/264433/»
2. Статья
на
тему
генетических
алгоритмов
[Электронный ресурс] – «https://prog-cpp.ru/genetic/»
3. Что такое генетическое программирование?
[Электронный ресурс] – «http://www.codenet.ru/progr/alg/smart/Genetic-Programming.php»
4. Простой генетический алгоритм
[Электронный ресурс] – « http://www.cyberguru.ru/algorithms/algorithms-theory/algorithmssimple-genetic-algorithm.html?showall=1 »
17
Приложение
Код программы:
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <ctime>
using namespace std;
double func(double x)
{
return sin(M_PI * x / 180) - 1 / x;
}
double mutation(double x0, double x1) // мутация: генерация случайной величины
{
const int NUM = 100000000;
return fabs((double)((rand() * NUM) % (int)((x1 - x0)*NUM) + 1) / NUM) + x0;
}
double inversion(double x, double eps) // инверсия: поиск в окрестностях точки
{
static int sign = 0;
sign++;
sign %= 2;
if (sign == 0) return x - eps;
else return x + eps;
}
void crossover(double *x, double eps, double x0, double x1) // кроссовер: среднее арифметическое
{
int k = 99;
for (int i = 0; i < 8; i++)
for (int j = i + 1; j < 8; j++)
18
{
x[k] = (x[i] + x[j]) / 2;
k--;
}
for (int i = 0; i < 8; i++)
{
x[k] = inversion(x[i], eps); k--;
x[k] = inversion(x[i], eps); k--;
}
for (int i = 8; i < k; i++)
x[i] = mutation(x0, x1);
}
void sort(double *x, double *y) // сортировка
{
for (int i = 0; i < 100; i++)
for (int j = i + 1; j < 100; j++)
if (fabs(y[j]) < fabs(y[i])) {
double temp = y[i];
y[i] = y[j];
y[j] = temp;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
double genetic(double x0, double x1, double eps) // поиск решения с использованием ГА
{
double population[100];
double f[100];
int iter = 0;
for (int i = 0; i < 100; i++) // формирование начальной популяции
{
19
population[i] = mutation(x0, x1);
f[i] = func(population[i]);
}
sort(population, f);
do {
iter++;
crossover(population, eps, x0, x1);
for (int i = 0; i < 100; i++)
f[i] = func(population[i]);
sort(population, f);
} while (fabs(f[0]) > eps && iter<20000);
cout « iter « " iterations" « endl;
return population[0];
}
int main()
{
srand(time(NULL));
cout « genetic(1.0, 10.0, 0.000001);
cin.get();
return 0;
}
20