\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage{booktabs}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочно   го интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
\usepackage{xcolor}




% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}

\usepackage{array}
\usepackage{multirow}

\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений

\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}


\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях

\hypersetup{colorlinks,
    allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)

% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ SQL}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
    breaklines,
    basicstyle=\footnotesize,
    columns=fullflexible,
    flexiblecolumns,
    numbers=left,
    numberstyle={\footnotesize},
    keywordstyle=\color{blue},
    inputencoding=cp1251,
    extendedchars=true
}
\lstdefinelanguage{MyC}{
    language=SQL,
%    ndkeywordstyle=\color{darkgray}\bfseries,
%    identifierstyle=\color{black},
%    morecomment=[n]{/**}{*/},
%    commentstyle=\color{blue}\ttfamily,
%    stringstyle=\color{red}\ttfamily,
%    morestring=[b]",
%    showstringspaces=false,
%    morecomment=[l][\color{gray}]{//},
    keepspaces=true,
    escapechar=\%,
    texcl=true
}

\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц


% Настройка листингов
\lstset{
    language=python,
    extendedchars=\true,
    inputencoding=utf8,
    keepspaces=true,
    % captionpos=b, % подписи листингов снизу
}

\begin{document} % начало документа
    


    % НАЧАЛО ТИТУЛЬНОГО ЛИСТА
    \begin{center}
        \hfill \break
        \hfill \break
        \normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
            федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
        \normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt] 
        \normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt] 
        \normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
        
        \hfill \break
        \hfill \break
        \hfill \break
        \hfill \break
        \large{Лабораторная работа №3}\\
        \large{по дисциплине}\\
        \large{<<Генетические алгоритмы>>}\\
        \large{Вариант 18}\\
        
        % \hfill \break
        \hfill \break
    \end{center}
    
    \small{ 
        \begin{tabular}{lrrl}
            \!\!\!Студент, & \hspace{2cm} & & \\
            \!\!\!группы 5130201/20101 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
            \!\!\!Преподаватель & \hspace{2cm} &  \underline{\hspace{3cm}} &  Большаков А. А. \\\\
            &&\hspace{4cm}
        \end{tabular}
        \begin{flushright}
            <<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
        \end{flushright}
    }
    
    \hfill \break
    % \hfill \break
    \begin{center} \small{Санкт-Петербург, 2025} \end{center}
    \thispagestyle{empty} % выключаем отображение номера для этой страницы
    
    % КОНЕЦ ТИТУЛЬНОГО ЛИСТА
    \newpage
    
    \tableofcontents

    \newpage
    \section {Постановка задачи}
    В данной работе были поставлены следующие задачи:

    \begin{itemize}
        \item Реализовать с использованием генетических алгоритмов решение задачи коммивояжера по индивидуальному заданию согласно номеру варианта.
        \item Сравнить найденное решение с представленным в условии задачи оптимальным решением.
        \item Представить графически найденное решение.
        \item Проанализировать время выполнения и точность нахождения результата в зависимости от вероятности различных видов кроссовера, мутации.
    \end{itemize}

    \textbf{Индивидуальное задание вариант 18:}

    \textbf{Дано:} Эвклидовы координаты городов 38 городов в Джибути (см.~Приложение~А). Оптимальный тур представлен на Рис.~\ref{fig:optimal_tour}, его длина равна 6659.

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.5\linewidth]{img/optimal_tour.png}
       \caption{Оптимальный тур для заданного набора данных}
       \label{fig:optimal_tour}
    \end{figure}

    \vspace{0.3cm}
    \textbf{Требуется:}

    \begin{enumerate}
        \item Реализовать с использованием генетических алгоритмов решение задачи коммивояжера. 
        \item Для туров использовать путевое представление.
    \end{enumerate}


    \newpage
    \section{Теоретические сведения}

    Генетические алгоритмы (ГА) используют принципы и терминологию, заимствованные у биологической науки – генетики. В ГА каждая особь представляет потенциальное решение некоторой
    проблемы. В классическом ГА особь кодируется строкой двоичных символов – хромосомой. Однако представление хромосомы зависит от постановки задачи: для непрерывных задач удобны векторы вещественных чисел (real-coded), тогда как для комбинаторных задач, таких как задача коммивояжера (ЗК), естественно представлять тур как перестановку городов. Длина хромосомы совпадает с числом элементов задачи; двоичное кодирование ЗК, как правило, неэффективно из‑за необходимости «ремонта» решений после применения операторов.

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

    Предварительно простой ГА случайным образом генерирует начальную популяцию стрингов
    (хромосом). Затем алгоритм генерирует следующее поколение (популяцию), с помощью трех основных генетических операторов:

    \begin{enumerate}
        \item Оператор репродукции (ОР);
        \item Оператор скрещивания (кроссинговера, ОК);
        \item Оператор мутации (ОМ).
    \end{enumerate}

    ГА работает до тех пор, пока не будет выполнено заданное количество поколений (итераций)
    процесса эволюции или на некоторой генерации будет получено заданное качество или вследствие
    преждевременной сходимости при попадании в некоторый локальный оптимум. На Рис.~\ref{fig:alg} представлен простой генетический алгоритм.

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.9\linewidth]{img/alg.png}
       \caption{Простой генетический алгоритм}
       \label{fig:alg}
    \end{figure}

    \newpage
    \subsection{Основная терминология в генетических алгоритмах}

    \textbf{Ген} -- элементарный код в хромосоме $s_i$, называемый также знаком или детектором 
    (в классическом ГА $s_i = 0, 1$).

    \textbf{Хромосома} -- упорядоченная последовательность генов в виде закодированной структуры 
    данных $S = (s_1, s_2, \ldots, s_n)$, определяющая решение. Представление зависит от типа задачи: для непрерывных задач — вектор вещественных чисел; для ЗК — перестановка городов (см. раздел о представлениях: соседское, порядковое и путевое).

    \textbf{Локус} -- местоположение (позиция, номер бита) данного гена в хромосоме.

    \textbf{Аллель} -- значение, которое принимает данный ген (например, 0 или 1).

    \textbf{Особь} -- одно потенциальное решение задачи (представляемое хромосомой).

    \textbf{Популяция} -- множество особей (хромосом), представляющих потенциальные решения.

    \textbf{Поколение} -- текущая популяция ГА на данной итерации алгоритма.

    \textbf{Генотип} -- набор хромосом данной особи. В популяции могут использоваться как отдельные 
    хромосомы, так и целые генотипы.

    \textbf{Генофонд} -- множество всех возможных генотипов.

    \textbf{Фенотип} -- набор значений, соответствующий данному генотипу. Это декодированное множество 
    параметров задачи (например, десятичное значение $x$, соответствующее двоичному коду).

    \textbf{Размер популяции $N$} -- число особей в популяции.

    \textbf{Число поколений} -- количество итераций, в течение которых производится поиск.

    \textbf{Селекция} -- совокупность правил, определяющих выживание особей на основе значений целевой функции.

    \textbf{Эволюция популяции} -- чередование поколений, в которых хромосомы изменяют свои признаки, 
    чтобы каждая новая популяция лучше приспосабливалась к среде.

    \textbf{Фитнесс-функция} -- функция полезности, определяющая меру приспособленности особи. 
    В задачах оптимизации она совпадает с целевой функцией или описывает близость к оптимальному решению.

    \subsection{Представления хромосом для задачи коммивояжера}

    Задача коммивояжера (ЗК) формулируется так: требуется посетить каждый из $N$ городов ровно один раз и вернуться в исходную точку, минимизируя суммарную стоимость (или длину) тура. Естественным является представление тура как перестановки городов. На практике используются три основных представления, каждое со своими операторами рекомбинации:

    \subsubsection{Представление соседства}

    Тур задаётся списком из $N$ городов, где в позиции $i$ указан город $j$, означающий переход из города $i$ в город $j$. Например, вектор $(2\;4\;8\;3\;9\;7\;1\;5\;6)$ соответствует туру $1\!\to\!2\!\to\!4\!\to\!3\!\to\!8\!\to\!5\!\to\!9\!\to\!6\!\to\!7$. У каждого корректного тура есть единственное соседское представление, однако не всякая строка в этом представлении корректна (возможны преждевременные циклы, например $1\!\to\!2\!\to\!4\!\to\!1\ldots$).

    \subsubsection{Порядковое представление}

    Тур представляется списком из $N$ позиций; $i$-й элемент равен индексу города в текущем упорядоченном списке доступных городов. Например, при опорном списке $C=(1\;2\;3\;4\;5\;6\;7\;8\;9)$ тур $1\!\to\!2\!\to\!4\!\to\!3\!\to\!8\!\to\!5\!\to\!9\!\to\!6\!\to\!7$ кодируется как $l=(1\;1\;2\;1\;4\;1\;3\;1\;1)$, последовательно «выбирая» элементы из $C$.

    \subsubsection{Путевое представление}

    Наиболее интуитивное представление: тур записывается как последовательность городов, например $5\!\to\!1\!\to\!7\!\to\!8\!\to\!9\!\to\!4\!\to\!6\!\to\!2\!\to\!3$ кодируется как $(5\;1\;7\;8\;9\;4\;6\;2\;3)$. Это представление сохраняет относительный порядок городов и широко применяется на практике.

    \subsection{Кроссинговеры для представлений ЗК}

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

    \subsubsection{Кроссинговеры для представления соседства}

    \textbf{Alternating Edges (обмен рёбрами):} потомок строится, поочерёдно выбирая ребра у родителей: одно ребро у первого родителя, следующее — у второго, затем снова у первого и т.д. Если выбранное ребро замыкает цикл преждевременно, выбирается другое ещё не использованное ребро того же родителя, не образующее цикл.

    \textbf{Subtour Chunks (обмен подтурами):} потомок формируется конкатенацией кусочков (подтуров), поочерёдно взятых у родителей. При образовании преждевременного цикла производится «ремонт» аналогично предыдущему оператору.

    \textbf{Heuristic Crossover (эвристический):} стартуя из случайного города, на каждом шаге сравниваются два инцидентных ребра, предлагаемых родителями, и выбирается более короткое; если возникает цикл или ребро уже использовано, выбирается случайный ещё не посещённый город. Оператор нацелен на сохранение коротких рёбер, но может иметь нестабильную производительность.

    \subsubsection{Кроссинговеры для порядкового представления}

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

    \subsubsection{Кроссинговеры для путевого представления}

    Для путевого представления широко применяются три оператора, гарантирующие корректную перестановку у потомков.

    \paragraph{PMX (Partially Mapped Crossover).}
    Идея: обменять подпоследовательности между родителями и построить отображение соответствий, которым затем разрешать конфликты (дубликаты).
    
    \textit{Пример.} Пусть точки разреза задают сегмент позиций $4\dots7$:
    $$
    p_1=(1\;2\;3\;|\;4\;5\;6\;7\;|\;8\;9),\quad
    p_2=(4\;5\;2\;|\;1\;8\;7\;6\;|\;9\;3).
    $$
    1) Копируем сегмент второго родителя в потомка $o_1$ и формируем отображение $\{4\leftrightarrow1,\;5\leftrightarrow8,\;6\leftrightarrow7,\;7\leftrightarrow6\}$:
    $$o_1=(\_\;\_\;\_\;|\;1\;8\;7\;6\;|\;\_\;\_).$$
    2) Заполняем прочие позиции по порядку из $p_1$, применяя отображение при конфликтах: $1\mapsto4$, $8\mapsto5$.
    $$o_1=(4\;2\;3\;|\;1\;8\;7\;6\;|\;5\;9).$$
    Аналогично для $o_2$ (копируем сегмент из $p_1$, заполняем остальное из $p_2$):
    $$o_2=(1\;8\;2\;|\;4\;5\;6\;7\;|\;9\;3).$$
    PMX сохраняет как позиции части элементов, так и относительный порядок/соответствия на остальной части хромосомы.

    \paragraph{OX (Order Crossover).}
    Идея: скопировать сегмент одного родителя и дозаполнить оставшиеся позиции элементами второго родителя в их порядке появления (пропуская уже скопированные).

    \textit{Пример.} С теми же родителями и разрезами $4\dots7$:
    $$
    p_1=(1\;2\;3\;|\;4\;5\;6\;7\;|\;8\;9),\quad
    p_2=(4\;5\;2\;|\;1\;8\;7\;6\;|\;9\;3).
    $$
    1) Копируем сегмент $p_1$ в $o_1$:
    $$o_1=(\_\;\_\;\_\;|\;4\;5\;6\;7\;|\;\_\;\_).$$
    2) Обходя $p_2$ с позиции после правого разреза, дозаполняем: получаем
    $$o_1=(2\;1\;8\;|\;4\;5\;6\;7\;|\;9\;3).$$
    Симметрично для $o_2$ (копируем сегмент из $p_2$ и дозаполняем порядком из $p_1$):
    $$o_2=(3\;4\;5\;|\;1\;8\;7\;6\;|\;9\;2).$$
    Оператор OX сохраняет относительный порядок городов; циклический сдвиг тура несущественен.

    \paragraph{CX (Cycle Crossover).}
    Идея: находить циклы позиций, индуцированные взаимным расположением значений у родителей, и наследовать циклы по очереди из разных родителей.

    \textit{Пример.} Возьмём
    $$
    p_1=(1\;2\;3\;4\;5\;6\;7\;8\;9),\quad
    p_2=(4\;5\;2\;1\;8\;7\;6\;9\;3).
    $$
    Построив циклы позиций, получим допустимых потомков, например:
    $$o_1=(1\;2\;3\;4\;7\;6\;9\;8\;5),\quad o_2=(4\;1\;2\;8\;5\;6\;7\;3\;9).$$
    CX сохраняет абсолютные позиции части элементов и способствует передаче «циклами» взаимных расположений.

    Отметим, что путевое представление акцентирует порядок городов (а не стартовый город), поэтому туры, отличающиеся циклическим сдвигом, эквивалентны.

    \subsection{Мутации для путевого представления}

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

    \paragraph{Swap (обмен двух элементов).}

    Идея: выбрать случайным образом две позиции в маршруте и обменять находящиеся на них города местами.
    
    \textit{Пример.} Пусть исходный тур:
    $$
    t=(1\;2\;3\;4\;5\;6\;7\;8\;9).
    $$
    Выбираем позиции $i=2$ и $j=6$ (элементы $3$ и $7$). После обмена получаем:
    $$
    t'=(1\;2\;7\;4\;5\;6\;3\;8\;9).
    $$
    Оператор swap обеспечивает локальную модификацию тура, изменяя положение только двух городов.

    \paragraph{Inversion (инверсия сегмента).}

    Идея: выбрать случайный сегмент маршрута и обратить порядок городов внутри него.
    
    \textit{Пример.} Для того же тура выбираем позиции разреза $i=3$ и $j=7$ (сегмент $4\;5\;6\;7$):
    $$
    t=(1\;2\;3\;|\;4\;5\;6\;7\;|\;8\;9).
    $$
    Инвертируем выделенный сегмент:
    $$
    t'=(1\;2\;3\;|\;7\;6\;5\;4\;|\;8\;9).
    $$
    Инверсия сохраняет связность частей маршрута, меняя направление обхода в подтуре. Этот оператор особенно эффективен при наличии пересечений рёбер, так как инверсия может «распутать» некоторые из них и улучшить длину маршрута.

    \paragraph{Insertion (вырезка и вставка).}
    
    Идея: выбрать случайный город, удалить его из текущей позиции и вставить в другую случайную позицию маршрута.
    
    \textit{Пример.} Пусть исходный тур:
    $$
    t=(1\;2\;3\;4\;5\;6\;7\;8\;9).
    $$
    Выбираем город на позиции $i=3$ (элемент $4$) и целевую позицию $j=7$. Удаляем элемент $4$:
    $$
    t_{\text{tmp}}=(1\;2\;3\;5\;6\;7\;8\;9).
    $$
    Вставляем $4$ на позицию $7$:
    $$
    t'=(1\;2\;3\;5\;6\;7\;4\;8\;9).
    $$
    insertion изменяет расположение одного города относительно других, смещая соседей.

    Все три оператора гарантируют сохранение корректной перестановки: каждый город остаётся в туре ровно один раз.

    \newpage
    \section{Особенности реализации}
    В рамках работы создана мини-библиотека \texttt{gen.py} для решения задачи коммивояжёра (TSP) генетическим алгоритмом с путевым представлением хромосом. Второй модуль
    \texttt{expirements.py} организует серийные эксперименты (перебор параметров,
    форматирование и сохранение результатов).

    \begin{itemize}
        \item \textbf{Кодирование особей}: каждая хромосома представлена как перестановка городов (\texttt{Chromosome = list[int]}), где каждый элемент -- индекс города. Популяция -- список хромосом (\texttt{Population = list[Chromosome]}). Инициализация случайными перестановками без повторений:
        \begin{itemize}
            \item \texttt{initialize\_random\_population(pop\_size: int, cities: Cites) -> Population}
        \end{itemize}
        \item \textbf{Фитнесс-функция}: целевая функция принимает хромосому (маршрут) и возвращает скалярное значение фитнесса (длину пути). Для режима минимизации используется внутреннее преобразование при селекции (сдвиг и инверсия знака), что позволяет применять рулетку:
        \begin{itemize}
            \item \texttt{eval\_population(population: Population, fitness\_func: FitnessFn) -> Fitnesses}
            \item Логика режима минимизации в \texttt{genetic\_algorithm(config: GARunConfig) -> GARunResult}
        \end{itemize}
        \item \textbf{Селекция (рулетка)}: вероятности нормируются после сдвига на минимальное значение в поколении (устойчиво к отрицательным фитнессам). Функция:
        \texttt{reproduction(population: Population, fitnesses: Fitnesses) -> Population}.
        \item \textbf{Кроссинговер}: реализованы специализированные операторы для перестановок: PMX (Partially Mapped Crossover), OX (Ordered Crossover) и CX (Cycle Crossover). Кроссинговер выполняется попарно по перемешанной популяции с вероятностью $p_c$. Функции:
        \begin{itemize}
            \item \texttt{partially\_mapped\_crossover\_fn(p1: Chromosome, p2: Chromosome) -> tuple[Chromosome, Chromosome]}
            \item \texttt{ordered\_crossover\_fn(p1: Chromosome, p2: Chromosome) -> tuple[Chromosome, Chromosome]}
            \item \texttt{cycle\_crossover\_fn(p1: Chromosome, p2: Chromosome) -> tuple[Chromosome, Chromosome]}
            \item \texttt{crossover(population: Population, pc: float, crossover\_fn: CrossoverFn) -> Population}
        \end{itemize}
        \item \textbf{Мутация}: реализованы три типа мутаций для перестановок: обмен двух городов (swap), инверсия сегмента (inversion), вырезка и вставка города (insertion). Мутация применяется с вероятностью $p_m$. Функции:
        \begin{itemize}
            \item \texttt{swap\_mutation\_fn(chrom: Chromosome) -> Chromosome}
            \item \texttt{inversion\_mutation\_fn(chrom: Chromosome) -> Chromosome}
            \item \texttt{insertion\_mutation\_fn(chrom: Chromosome) -> Chromosome}
            \item \texttt{mutation(population: Population, pm: float, mutation\_fn: MutationFn) -> Population}
        \end{itemize}

        \item \textbf{Критерий остановки}: поддерживаются критерии по максимальному количеству поколений, повторению лучшего результата, достижению порогового значения фитнесса. Хранится история всех поколений. Проверка выполняется в функции:
        
        \texttt{genetic\_algorithm(config: GARunConfig) -> GARunResult}.
        \item \textbf{Визуализация}: реализована отрисовка маршрутов обхода городов на плоскости с отображением лучшей особи поколения. Функции:
        \begin{itemize}
            \item \texttt{plot\_tour(cities: list[tuple[float, float]], tour: list[int], ax: Axes)}
            \item \texttt{save\_generation(generation: Generation, history: list[Generation], config: GARunConfig)}
            \item \texttt{plot\_fitness\_history(result: GARunResult, save\_path: str | None) -> None}
        \end{itemize}
        \item \textbf{Элитизм}: поддерживается перенос лучших особей без изменения в следующее поколение (\texttt{elitism} параметр).
        \item \textbf{Измерение времени}: длительность вычислений возвращается в миллисекундах как часть \texttt{GARunResult.time\_ms}.
        \item \textbf{Файловая организация}: результаты экспериментов сохраняются в структуре \texttt{experiments/N/} с таблицами результатов. Задействованные функции:
        \begin{itemize}
            \item \texttt{clear\_results\_directory(results\_dir: str) -> None}
            \item Функции для проведения экспериментов в модуле \texttt{expirements.py}
        \end{itemize}
    \end{itemize}

    В модуле \texttt{expirements.py} задаются координаты городов и параметры экспериментов.
    Серийные запуски и сохранение результатов реализованы для исследования влияния параметров ГА на качество решения задачи коммивояжёра.

    \newpage
    \section{Результаты работы}

    На Рис.~\ref{fig:gen1}--\ref{fig:lastgen} представлены результаты работы генетического алгоритма со следующими параметрами:
    \begin{itemize}
        \item $N = 500$ -- размер популяции.
        \item $p_c = 0.9$ -- вероятность кроссинговера.
        \item $p_m = 0.3$ -- вероятность мутации.
        \item $2500$ -- максимальное количество поколений.
        \item $3$ -- количество "элитных" особей, переносимых без изменения в следующее поколение.
        \item Partially mapped crossover - кроссовер.
        \item Inversion mutation - мутация
    \end{itemize}

    На Рис.~\ref{fig:fitness_history} показан график изменения фитнесса по поколениям. Видно, что алгоритм постепенно сходится к минимально возможному значению фитнеса. Лучший маршрут был найден на поколнении №1896 (см. Рис.~\ref{fig:lastgen}).

    \begin{figure}[h!]
       \centering
       \includegraphics[width=1\linewidth]{img/results/fitness_history.png}
       \caption{График изменения фитнесса по поколениям}
       \label{fig:fitness_history}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_001.png}
       \caption{Лучший маршрут поколения №1}
       \label{fig:gen1}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_005.png}
       \caption{Лучший маршрут поколения №5}
       \label{fig:gen5}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_050.png}
       \caption{Лучший маршрут поколения №50}
       \label{fig:gen50}
    \end{figure}


    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_100.png}
       \caption{Лучший маршрут поколения №100}
       \label{fig:gen100}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_300.png}
       \caption{Лучший маршрут поколения №300}
       \label{fig:gen300}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_500.png}
       \caption{Лучший маршрут поколения №500}
       \label{fig:gen500}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/generation_900.png}
       \caption{Лучший маршрут поколения №900}
       \label{fig:gen900}
    \end{figure}

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.7\linewidth]{img/results/best_generation_1896.png}
       \caption{Лучший маршрут поколения №1896}
       \label{fig:lastgen}
    \end{figure}


    \newpage
    \phantom{text}
    \newpage
    \phantom{text}
    \newpage
    \phantom{text}
    
    \newpage
    \section{Исследование реализации}
    \subsection{Проведение измерений}
    В рамках лабораторной работы необходимо было исследовать зависимость времени выполнения задачи и количества поколений от популяции и вероятностей кроссинговера и мутации хромосомы

    Для исследования были выбраны следующие значения параметров:
    \begin{itemize}
        \item $N = 10, 25, 50, 100$ -- размер популяции.
        \item $p_c = 0.3, 0.4, 0.5, 0.6, 0.7, 0.8$ -- вероятность кроссинговера.
        \item $p_m = 0.001, 0.01, 0.05, 0.1, 0.2$ -- вероятность мутации.
    \end{itemize}

    Измерения были проведены для двух критериев остановки:
    \begin{itemize}
        \item Лучшее значение фитнеса не изменялось 10 поколений.
        \item Лучшее значение фитнеса достигло заданного значения $0.005$.
    \end{itemize}

    \subsubsection*{Результаты для первого критерия остановки}

    Результаты измерений представлены в таблицах \ref{tab:pc_pm_results_10}--\ref{tab:pc_pm_results_100}. В ячейках указано время в миллисекундах нахождения минимума функции. В скобках указано количество поколений, за которое было найдено решение. Во второй строке указано усреднённое по всем запускам лучшее значение фитнеса. Если в ячейке стоит прочерк, то это означает, что решение не было найдено за 200 поколений. Лучшее значение по времени выполнения и по значению фитнеса для каждого размера популяции выделено цветом и жирным шрифтом.

    \newcolumntype{Y}{>{\centering\arraybackslash}X}
    % Автоматически сгенерированные LaTeX таблицы
% Лучший результат по времени и по фитнесу выделены жирным отдельно
% Убедитесь, что подключен \usepackage{tabularx}
% ВНИМАНИЕ: Убедитесь, что подключен \usepackage{xcolor} для цветового выделения
% Используйте \newcolumntype{Y}{>{\centering\arraybackslash}X} перед таблицами

\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 10$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 1.3 (13) 0.36281 & 1.7 (18) 7.55685 & 1.2 (13) 1.55537 & \textcolor{magenta}{\textbf{1.0 (11)}} 1.78411 & 9.4 (87) 0.04271 \\
    \textbf{0.4} & 1.3 (14) 0.03913 & 1.6 (17) 0.02868 & 1.3 (13) 0.36232 & 2.1 (20) 0.10641 & — \\
    \textbf{0.5} & 1.4 (15) 0.87081 & 1.7 (18) 1.71634 & 2.3 (21) 0.10401 & 3.4 (25) 0.00461 & — \\
    \textbf{0.6} & 2.8 (19) 0.06375 & 1.8 (13) 0.72202 & 2.9 (22) 0.01473 & 3.4 (25) 0.01162 & 29.4 (184) \textcolor{magenta}{\textbf{0.00033}} \\
    \textbf{0.7} & 1.5 (15) 1.25409 & 2.3 (22) 8.67464 & 1.9 (18) 0.13319 & 8.6 (66) 0.00078 & 8.9 (48) 0.11136 \\
    \textbf{0.8} & 1.9 (15) 3.10415 & 1.4 (13) 1.09275 & 2.1 (19) 0.43094 & 6.4 (54) 0.00191 & — \\
    \bottomrule
    \end{tabularx}
    \label{tab:pc_pm_results_10}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 25$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 3.0 (18) 0.16836 & \textcolor{magenta}{\textbf{2.2 (13)}} 0.04190 & 4.7 (27) 0.00544 & — & — \\
    \textbf{0.4} & 4.1 (24) 0.00808 & 4.6 (26) 0.01101 & 5.8 (31) 0.02330 & 3.8 (19) 0.05414 & — \\
    \textbf{0.5} & 3.1 (17) 0.05259 & 5.0 (26) 0.47018 & 27.8 (138) \textcolor{magenta}{\textbf{0.00024}} & 14.5 (67) 0.00312 & — \\
    \textbf{0.6} & 6.1 (31) 0.01033 & 6.8 (34) 0.00148 & — & — & — \\
    \textbf{0.7} & 4.1 (21) 0.00107 & 3.2 (16) 0.32522 & — & — & — \\
    \textbf{0.8} & 23.9 (109) 0.00352 & 15.8 (72) 0.11662 & 28.3 (123) 0.00038 & — & — \\
    \bottomrule
    \end{tabularx}
    \label{tab:pc_pm_results_25}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 50$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 14.9 (51) 0.05874 & 19.3 (59) \textcolor{magenta}{\textbf{0.00003}} & 36.7 (113) 0.00190 & — & — \\
    \textbf{0.4} & 12.5 (40) 0.01955 & \textcolor{magenta}{\textbf{5.6 (18)}} 0.00022 & — & — & — \\
    \textbf{0.5} & 65.0 (195) 0.04790 & 26.4 (78) 0.01673 & — & — & — \\
    \textbf{0.6} & 16.4 (47) 0.00329 & 18.5 (50) 0.00065 & — & — & — \\
    \textbf{0.7} & 51.0 (137) 0.00120 & 59.3 (158) 0.00010 & — & — & — \\
    \textbf{0.8} & 48.8 (126) 0.01393 & 67.6 (172) 0.00650 & — & — & — \\
    \bottomrule
    \end{tabularx}
    \label{tab:pc_pm_results_50}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 100$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 24.2 (44) 0.00110 & 17.9 (32) 0.00113 & \textcolor{magenta}{\textbf{17.6 (29)}} 0.00193 & — & — \\
    \textbf{0.4} & 30.7 (51) 0.00173 & — & — & — & — \\
    \textbf{0.5} & 27.4 (43) 0.00016 & — & — & — & — \\
    \textbf{0.6} & 20.4 (31) 0.00115 & 129.8 (186) 0.00025 & — & — & — \\
    \textbf{0.7} & 115.4 (162) 0.00002 & — & — & — & — \\
    \textbf{0.8} & 106.5 (143) \textcolor{magenta}{\textbf{0.00001}} & — & — & — & — \\
    \bottomrule
    \end{tabularx}
    \label{tab:pc_pm_results_100}
\end{table}

    \newpage
    \phantom{text}
    \newpage
    \subsubsection*{Результаты для второго критерия остановки}

Результаты измерений представлены в таблицах \ref{tab:1_pc_pm_results_10}--\ref{tab:1_pc_pm_results_100}.


% Автоматически сгенерированные LaTeX таблицы
% Лучший результат по времени и по фитнесу выделены жирным отдельно
% Убедитесь, что подключен \usepackage{tabularx}
% ВНИМАНИЕ: Убедитесь, что подключен \usepackage{xcolor} для цветового выделения
% Используйте \newcolumntype{Y}{>{\centering\arraybackslash}X} перед таблицами

\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 10$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & — & — & — & 15.6 (155) 0.00063 & 7.8 (69) 0.00409 \\
    \textbf{0.4} & — & — & — & 8.9 (81) \textcolor{magenta}{\textbf{0.00038}} & \textcolor{magenta}{\textbf{4.6 (40)}} 0.00317 \\
    \textbf{0.5} & — & — & 8.7 (85) 0.00199 & — & 16.5 (140) 0.00453 \\
    \textbf{0.6} & — & — & — & 8.9 (77) 0.00310 & 14.3 (117) 0.00082 \\
    \textbf{0.7} & — & — & 8.2 (70) 0.00089 & 5.6 (49) 0.00431 & 7.1 (58) 0.00047 \\
    \textbf{0.8} & — & 19.7 (180) 0.00397 & — & 5.0 (42) 0.00494 & 5.5 (44) 0.00357 \\
    \bottomrule
    \end{tabularx}
    \label{tab:1_pc_pm_results_10}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 25$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 1.1 (7) 0.00277 & 30.0 (173) \textcolor{magenta}{\textbf{0.00059}} & — & 2.2 (12) 0.00191 & 30.2 (139) 0.00200 \\
    \textbf{0.4} & 1.8 (10) 0.00384 & — & 12.2 (63) 0.00164 & 6.6 (33) 0.00354 & 18.5 (82) 0.00224 \\
    \textbf{0.5} & — & — & 12.5 (58) 0.00233 & 2.3 (11) 0.00196 & 17.1 (73) 0.00116 \\
    \textbf{0.6} & — & 30.9 (151) 0.00265 & 36.7 (175) 0.00146 & 10.0 (46) 0.00449 & 5.7 (23) 0.00281 \\
    \textbf{0.7} & 1.1 (6) 0.00472 & — & 0.8 (4) 0.00233 & 3.9 (17) 0.00112 & \textcolor{magenta}{\textbf{0.3 (2)}} 0.00371 \\
    \textbf{0.8} & — & — & 10.3 (43) 0.00137 & 7.7 (32) 0.00379 & 10.5 (41) 0.00155 \\
    \bottomrule
    \end{tabularx}
    \label{tab:1_pc_pm_results_25}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 50$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 3.7 (12) 0.00354 & 3.4 (9) 0.00075 & 23.7 (73) 0.00467 & 4.9 (14) 0.00043 & 2.1 (6) 0.00029 \\
    \textbf{0.4} & 3.6 (12) 0.00270 & 4.2 (13) 0.00061 & 9.2 (25) 0.00251 & 18.2 (51) 0.00490 & 6.6 (16) 0.00063 \\
    \textbf{0.5} & 4.0 (10) 0.00099 & 48.8 (141) 0.00324 & 3.8 (11) 0.00087 & 14.7 (39) \textcolor{magenta}{\textbf{0.00017}} & 1.2 (3) 0.00115 \\
    \textbf{0.6} & 1.6 (5) 0.00070 & 51.6 (139) 0.00217 & 4.7 (13) 0.00294 & 2.6 (7) 0.00397 & 11.5 (27) 0.00053 \\
    \textbf{0.7} & — & — & 2.6 (7) 0.00144 & 3.5 (9) 0.00182 & \textcolor{magenta}{\textbf{1.1 (3)}} 0.00072 \\
    \textbf{0.8} & 4.1 (11) 0.00240 & 3.5 (8) 0.00380 & 2.5 (6) 0.00422 & 2.7 (7) 0.00126 & 4.3 (10) 0.00060 \\
    \bottomrule
    \end{tabularx}
    \label{tab:1_pc_pm_results_50}
\end{table}


\begin{table}[h!]
    \centering
    \small
    \caption{Результаты для $N = 100$}
    \begin{tabularx}{\linewidth}{l *{5}{Y}}
    \toprule
    $\mathbf{P_c \;\backslash\; P_m}$ & \textbf{0.001} & \textbf{0.010} & \textbf{0.050} & \textbf{0.100} & \textbf{0.200} \\
    \midrule
    \textbf{0.3} & 9.3 (17) 0.00451 & 6.0 (11) 0.00344 & 10.0 (17) 0.00343 & 5.3 (8) 0.00046 & 9.8 (14) 0.00412 \\
    \textbf{0.4} & 5.7 (9) \textcolor{magenta}{\textbf{0.00005}} & 8.4 (14) 0.00108 & 3.5 (6) 0.00254 & 4.0 (6) 0.00186 & 6.5 (9) 0.00283 \\
    \textbf{0.5} & 3.8 (6) 0.00019 & 4.9 (8) 0.00103 & 3.6 (6) 0.00260 & 11.1 (16) 0.00204 & 7.5 (10) 0.00374 \\
    \textbf{0.6} & — & 6.5 (10) 0.00107 & 3.6 (5) 0.00079 & \textcolor{magenta}{\textbf{0.9 (2)}} 0.00324 & 10.1 (13) 0.00044 \\
    \textbf{0.7} & 1.7 (3) 0.00106 & 6.6 (10) 0.00489 & 4.1 (6) 0.00031 & 12.4 (16) 0.00240 & 4.8 (6) 0.00276 \\
    \textbf{0.8} & 5.0 (7) 0.00387 & 58.4 (77) 0.00453 & 7.8 (10) 0.00259 & 11.2 (13) 0.00210 & 6.1 (7) 0.00493 \\
    \bottomrule
    \end{tabularx}
    \label{tab:1_pc_pm_results_100}
\end{table}

        
    \newpage
    \phantom{text}
    \newpage
    \phantom{text}
    \newpage
    \phantom{text}
    \subsection{Анализ результатов}
    
    \subsubsection*{Обоснование применения двух критериев остановки}
    
    В исследовании использовались два различных критерия остановки алгоритма, поскольку критерий по количеству поколений (отсутствие улучшения в течение 10 поколений) не всегда обеспечивал достижение достаточно хороших значений фитнеса, особенно для малых популяций. Это делало некорректным сравнение эффективности различных комбинаций параметров только по времени выполнения. Введение второго критерия (достижение фитнеса 0.005) позволило получить более объективную оценку скорости нахождении качественных решений.

    \subsubsection*{Первый критерий остановки (отсутствие улучшения в течение 10 поколений)}

    При использовании первого критерия остановки наблюдаются следующие закономерности:

    \begin{itemize}
        \item \textbf{Малые популяции ($N=10$):} Оптимальный баланс достигается при умеренных значениях параметров. Лучший результат по времени показывает комбинация $p_c=0.3$, $p_m=0.1$ (1.0 мс, 11 поколений), однако лучшее значение фитнеса достигается при $p_c=0.6$, $p_m=0.2$ (0.00033). Качество решений существенно варьируется.
        
        \item \textbf{Средние популяции ($N=25$):} Демонстрируют высокую эффективность при низких значениях мутации. Минимальное время выполнения достигается при $p_c=0.3$, $p_m=0.01$ (2.2 мс, 13 поколений), а наилучший фитнес — при $p_c=0.5$, $p_m=0.05$ (0.00024).
        
        \item \textbf{Большие популяции ($N=50, 100$):} Характеризуются критической чувствительностью к высоким значениям мутации и демонстрируют заметное улучшение качества фитнеса. Для $N=50$ лучшие результаты при $p_c=0.4$, $p_m=0.01$ (5.6 мс по времени) и $p_c=0.3$, $p_m=0.01$ (фитнес 0.00003). Для $N=100$ работают только комбинации с очень низкой мутацией, но обеспечивают отличное качество (фитнес до 0.00001).
        
        \item \textbf{Проблема сходимости:} С увеличением размера популяции значительно возрастает количество комбинаций параметров, не обеспечивающих сходимость за 200 поколений, особенно при $p_m \geq 0.05$.
    \end{itemize}

    \subsubsection*{Второй критерий остановки (достижение фитнеса 0.005)}

    Использование фиксированного порога фитнеса демонстрирует принципиально иную картину и подтверждает правильность введения альтернативного критерия:

    \begin{itemize}
        \item \textbf{Инверсия требований к мутации:} В отличие от первого критерия, здесь малые популяции требуют более высоких значений мутации для достижения целевого фитнеса. Для $N=10$ большинство комбинаций с $p_m \leq 0.01$ вообще не достигают порога, что подтверждает проблему качества при первом критерии.
        
        \item \textbf{Лучшие результаты больших популяций:} Популяции $N=50$ и $N=100$ показывают отличные результаты — достижение высокого качества за минимальное время: $N=50$ при $p_c=0.7$, $p_m=0.2$ (1.1 мс, 3 поколения) и $N=100$ при $p_c=0.6$, $p_m=0.1$ (0.9 мс, 2 поколения).
    \end{itemize}

    
    \newpage
    \section{Ответ на контрольный вопрос}

    \textbf{Вопрос}: Опишите понятие «оптимизационная задача».

    \textbf{Ответ}: Оптимизационная задача — это математическая задача, в которой требуется найти такие значения переменных, при которых некоторая функция, называемая целевой, принимает наибольшее или наименьшее значение. При этом искомые значения должны удовлетворять определённым условиям или ограничениям, задающим допустимую область решений. Цель оптимизации заключается в выборе наилучшего варианта среди множества возможных с точки зрения заданного критерия эффективности.

    Такие задачи широко применяются в науке, технике, экономике и управлении для рационального распределения ресурсов, минимизации затрат или максимизации прибыли. В зависимости от формы целевой функции и ограничений оптимизационные задачи могут быть линейными, нелинейными, дискретными или непрерывными. Их решение позволяет принимать обоснованные решения и повышать эффективность различных процессов и систем.
        

    \newpage
    \section*{Заключение}
    \addcontentsline{toc}{section}{Заключение}

    В ходе второй лабораторной работы была успешно решена задача оптимизации функции Axis parallel hyper-ellipsoid function с использованием генетических алгоритмов:

    \begin{enumerate}
        \item Изучен теоретический материал о real-coded генетических алгоритмах и различных операторах кроссинговера и мутации;
        \item Создана программная библиотека на языке Python с реализацией арифметического и геометрического кроссоверов, случайной мутации и селекции методом рулетки;
        \item Проведено исследование влияния параметров ГА на эффективность поиска для популяций размером 10, 25, 50 и 100 особей;
    \end{enumerate}

\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}

\vspace{-1.5cm}
\begin{thebibliography}{0}
    \bibitem{vostrov}
    Методические указания по выполнению лабораторных работ к курсу «Генетические алгоритмы», 119 стр.
\end{thebibliography}

\end{document}