Files
algorithm/lab1/report/report.tex

794 lines
58 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\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{graphicx}
\usepackage{tabularx}
\usepackage{amssymb}
\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} %для перечислений
\newtheorem{theorem}{Теорема} % Создание нового окружения для теорем
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ C++}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=C++,
% 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=C++,
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{Отчет по лабораторной работе №1}\\
\large{<<Реализация двумерного клеточного автомата>>}\\
\large{по дисциплине <<Теория алгоритмов>>}\\
\large{Вариант 25}\\
\hfill \break
\hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Востров А. В. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2024г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2024} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
\newpage
\section*{Введение}
\addcontentsline{toc}{section}{Введение}
Данная лабораторная работа по дисциплине <<Теория алгоритмов>> заключается в разработке консольного приложения на языке C++, которое позволяет создавать и запускать двумерные клеточные автоматы с различными настройками и функцией переходов, заданной вариантом лабораторной работы. Также в этом отчёте к лабораторной работе проводится анализ заданного клеточного автомата.
\newpage
\section{Постановка задачи}
Лабораторная работа заключалась в следующем:
\begin{itemize}
\item Реализовать двумерный клеточный автомат с окрестностью фон Неймана в соответствии с полученным номером (№109063350), который задаёт функцию перехода автомата.
\item Граничные условия: тороидальные, нулевые, единичные.
\item Обеспечить возможность пользователю задавать ширину поля и количество итераций.
\item Учесть возможность ввода различных начальных условий (как вручную, так и случайным образом) по выбору пользователя.
\item Реализовать автомат в консольном или графическом интерфейсе.
\item Проанализировать поведение клеточного автомата, выявить паттерны, оценить "сходимость" и другие характеристики в отчете.
\end{itemize}
\newpage
\section {Математическое описание}
\subsection{Клеточные автоматы}
Клеточные автоматы~\cite{vostrov} это регулярная структура динамических объектов (клеток), функционирующих синхронно. Клеточные автоматы моделируют процессы, разворачивающиеся в дискретном пространстве и в дискретном времени. Клеточный автомат имеет состояние, определяемое как набор (вектор или матрица) состояний компонентных автоматов. Каждый автомат функционирует как автомат Мура, т.е. это автомат без выхода, выходом является его состояние. Вход на каждом шаге клеточного автомата состояния его соседей. На следующем шаге (в следующем такте) новое состояние каждого автомата определяется как функция его текущего состояния и текущих состояний его соседей. Обычно правила изменения состояний всех автоматов (кроме крайних) идентичны (однородность системы), множество состояний каждого автомата конечно. Изменение состояния системы во всех клетках происходит синхронно: состояния клеток меняются одновременно, в каждом такте.
\subsection{Двумерные клеточные автоматы}
Двумерные клеточные автоматы являются расширением одномерных клеточных автоматов, описанных ранее. В одномерных автоматах состояние каждой клетки определяется её собственным состоянием и состояниями соседних клеток на линии. В двумерных клеточных автоматах клетки расположены на двумерной сетке, и их состояние зависит от собственного состояния и состояний соседних клеток в двух измерениях.
Основные элементы клеточного автомата:
\begin{enumerate}
\item \textbf{Сетка клеток:} Двумерный массив клеток $C(i, j)$, где $i \in \{0, 1, \dots, N-1\}$ и $j \in \{0, 1, \dots, M-1\}$ обозначают индексы клетки в сетке, \(N\) и \(M\) — размеры сетки.
\item \textbf{Состояния:} Каждая клетка может находиться в одном из $k \in \mathbb{N}$ возможных состояний: $S = \{s_0, s_1, \dots, s_{k-1}\}$. В данной лабораторной работе рассматриваются автоматы с двумя возможными состояниями <<0>> (<<мёртвые>> клетки) и <<1>> (<<живые>> клетки).
\item \textbf{Тип окрестности:} Для клетки $C(i, j)$ задаётся множество соседей $\mathcal{N}(i, j)$. Окрестность фон Неймана (см. Рис.~\ref{fig:fon}) задаётся следующим образом (включает 4 соседа и саму клетку):
\[
\mathcal{N}_N(i, j) = (C(i, j), C(i-1, j), C(i+1, j), C(i, j-1), C(i, j+1)).
\]
\item \textbf{Функция перехода:} Функция $f$ определяет состояние клетки $C(i, j)$ на следующем шаге:
\[
C'(i, j) = f\left(\mathcal{N}(i, j)\right),
\]
где $C'(i, j)$ — состояние клетки после обновления.
\item \textbf{Граничные условия:} Определяют, как будет выглядеть окрестность клеток на границах сетки. В этой работе рассматриваются несколько вариантов граничных условий:
\begin{itemize}
\item \textit{Нулевые граничные условия:} За пределами сетки клетки считаются находящимися в нулевом состоянии.
\[
S(i, j) =
\begin{cases}
0, & \text{если } i < 0 \text{ или } i \geq N \text{ или } j < 0 \text{ или } j \geq M, \\
C(i, j), & \text{иначе}.
\end{cases}
\]
\item \textit{Единичные граничные условия:} За пределами сетки клетки считаются находящимися в единичном состоянии.
\[
S(i, j) =
\begin{cases}
1, & \text{если } i < 0 \text{ или } i \geq N \text{ или } j < 0 \text{ или } j \geq M, \\
C(i, j), & \text{иначе}.
\end{cases}
\]
\item \textit{Тороидальные граничные условия:} Сетка рассматривается как тор, то есть клетки на одной границе соединены с противоположной границей.
\[
S(i, j) =
\begin{cases}
C((i + N)\!\!\!\! \mod N, (j + M)\!\!\!\! \mod M), & \text{если } i < 0 \text{ или } i \geq N \\
& \quad \text{или } j < 0 \text{ или } j \geq M, \\
C(i, j), & \text{иначе}.
\end{cases}
\]
\end{itemize}
\end{enumerate}
\begin{figure}[h!]
\centering
\includegraphics[width=0.3\linewidth]{img/fon.png}
\caption{Двумерная окрестность фон Неймана.}
\label{fig:fon}
\end{figure}
\subsection{Функция перехода}
Рассматриваемому варианту лабораторной работы соответствует №109063350. В двоичном виде, после добавления ведущих нулей до 32 разрядов, это число выглядит следующим образом:
$$
00000110100000000010110010110110_2
$$
Битовое представление этого числа в обратном порядке задаёт вектор значений для булевой функции переходов от пяти переменных ($2^5 = 32$). Каждая переменная соответствует состоянию клетки из окресности фон Неймана в определённом порядке, который указан на Рис.~\ref{fig:fon2}. В таблице~\ref{tbl:istin} представлена таблица истинности для функции переходов.
\begin{table}[h!]
\centering
\caption{Таблица истинности для функции переходов.}
\label{tbl:istin}
\footnotesize
\begin{tabular}{|c|c|c|c|c|c|}
\hline
$\mathbf{s_0}$ & $\mathbf{s_1}$ & $\mathbf{s_2}$ & $\mathbf{s_3}$ & $\mathbf{s_4}$ & $\mathbf{f(s_0, s_1, s_2, s_3, s_4)}$ \\ \hline
0 & 0 & 0 & 0 & 0 & 0 \\ \hline
0 & 0 & 0 & 0 & 1 & 1 \\ \hline
0 & 0 & 0 & 1 & 0 & 1 \\ \hline
0 & 0 & 0 & 1 & 1 & 0 \\ \hline
0 & 0 & 1 & 0 & 0 & 1 \\ \hline
0 & 0 & 1 & 0 & 1 & 1 \\ \hline
0 & 0 & 1 & 1 & 0 & 0 \\ \hline
0 & 0 & 1 & 1 & 1 & 1 \\ \hline
0 & 1 & 0 & 0 & 0 & 0 \\ \hline
0 & 1 & 0 & 0 & 1 & 0 \\ \hline
0 & 1 & 0 & 1 & 0 & 1 \\ \hline
0 & 1 & 0 & 1 & 1 & 1 \\ \hline
0 & 1 & 1 & 0 & 0 & 0 \\ \hline
0 & 1 & 1 & 0 & 1 & 1 \\ \hline
0 & 1 & 1 & 1 & 0 & 0 \\ \hline
0 & 1 & 1 & 1 & 1 & 0 \\ \hline
1 & 0 & 0 & 0 & 0 & 0 \\ \hline
1 & 0 & 0 & 0 & 1 & 0 \\ \hline
1 & 0 & 0 & 1 & 0 & 0 \\ \hline
1 & 0 & 0 & 1 & 1 & 0 \\ \hline
1 & 0 & 1 & 0 & 0 & 0 \\ \hline
1 & 0 & 1 & 0 & 1 & 0 \\ \hline
1 & 0 & 1 & 1 & 0 & 0 \\ \hline
1 & 0 & 1 & 1 & 1 & 1 \\ \hline
1 & 1 & 0 & 0 & 0 & 0 \\ \hline
1 & 1 & 0 & 0 & 1 & 1 \\ \hline
1 & 1 & 0 & 1 & 0 & 1 \\ \hline
1 & 1 & 0 & 1 & 1 & 0 \\ \hline
1 & 1 & 1 & 0 & 0 & 0 \\ \hline
1 & 1 & 1 & 0 & 1 & 0 \\ \hline
1 & 1 & 1 & 1 & 0 & 0 \\ \hline
1 & 1 & 1 & 1 & 1 & 0 \\ \hline
\end{tabular}
\end{table}
\begin{figure}[h!]
\centering
\includegraphics[width=0.3\linewidth]{img/fon2.png}
\caption{Окрестность фон Неймана с метками для соседей.}
\label{fig:fon2}
\end{figure}
\subsection{Паттерны, сходимость и классификация клеточных автоматов}
Паттерны -- это устойчивые структуры, которые формируются в процессе эволюции клеточного автомата. В зависимости от правил, эти структуры могут быть статичными (не изменяются с течением времени), циклическими (повторяются через несколько итераций), или распространяющимися (разрастаются в пространстве).
Сходимость -- это поведение клеточного автомата, при котором его состояние стабилизируется спустя некоторое количество итераций. Это может быть достижение статического состояния, циклического паттерна или полное угасание активности (все клетки становятся "мёртвыми").
Стивен Вольфрам в своей книге A New Kind of Science~\cite{wolfram} предложил 4 класса, на которые все клеточные автоматы могут быть разделены в зависимости от типа их эволюции:
\begin{itemize}
\item Класс 1: Результатом эволюции начальных условий является быстрый переход к гомогенной стабильности. Любые негомогенные конструкции быстро исчезают.
\item Класс 2: Результатом эволюции начальных условий является быстрый переход в неизменяемое негомогенное состояние либо возникновение циклической последовательности. Большинство структур начальных условий быстро исчезает, но некоторые остаются. Локальные изменения в начальных условиях оказывают локальный характер на дальнейший ход эволюции системы.
\item Класс 3: Результатом эволюции почти всех начальных условий являются псевдо-случайные, хаотические последовательности. Любые стабильные структуры, которые возникают почти сразу же уничтожаются окружающим их шумом. Локальные изменения в начальных условиях оказывают неопределяемое влияние на ход эволюции системы.
\item Класс 4: Результатом эволюции являются структуры, которые взаимодействуют сложным образом с формированием локальных, устойчивых структур. В результате эволюции могут получаться некоторые последовательности Класса 2, описанного выше. Локальные изменения в начальных условиях оказывают неопределяемое влияние на ход эволюции системы. Некоторые клеточные автоматы этого класса обладают свойством универсальности по Тьюрингу.
\end{itemize}
\newpage
\section{Особенности реализации}
\subsection{Класс CellularAutomaton}
В листинге~\ref{lst:CellularAutomaton} представлен код объявления класса \texttt{CellularAutomaton}.
Класс содержит следующие атрибуты:
\begin{itemize}
\item \texttt{static const unsigned int m\_functionValues} -- хранит число, соответствующее номеру варианта лабораторной работы, его битовое представление соответствует функции переходов двумерного клеточного автомата;
\item \texttt{int m\_fieldWidth} -- ширина поля клеточного автомата;
\item \texttt{int m\_fieldHeight} -- высота поля клеточного автомата;
\item \texttt{std::vector<std::vector<int> > m\_field} -- двумерный вектор, представляющий текущее состояние клеточного автомата;
\item \texttt{std::vector<std::vector<int> > m\_fieldNextState} -- двумерный вектор для хранения следующего состояния клеточного автомата;
\item \texttt{BoundaryCondition m\_boundaryCondition} -- граничные условия, задаются значением из перечисления \texttt{BoundaryCondition}.
\end{itemize}
Перечисление \texttt{BoundaryCondition} имеет три возможных значения:
\begin{itemize}
\item \texttt{BOUNDARY\_ONES} -- единичные граничные условия;
\item \texttt{BOUNDARY\_ZEROS} -- нулевые граничные условия;
\item \texttt{BOUNDARY\_TOROIDAL} -- тороидальные граничные условия.
\end{itemize}
Методы класса описываются в последующих разделах.
\begin{lstlisting}[caption={Код объявления класса CellularAutomaton.}, label={lst:CellularAutomaton}]
enum BoundaryCondition {
BOUNDARY_ONES,
BOUNDARY_ZEROS,
BOUNDARY_TOROIDAL
};
class CellularAutomaton
{
static const unsigned int m_functionValues = 25 * 11 * 2003 * 18 * 11;
int m_fieldWidth, m_fieldHeight;
std::vector<std::vector<int>> m_field;
std::vector<std::vector<int>> m_fieldNextState;
BoundaryCondition m_boundaryCondition;
void initializeRandom();
void initializeManual();
int getCellState(int x, int y) const;
int getNeighborhoodIndex(int x, int y) const;
public:
CellularAutomaton(int width, int height, bool fillWithRandom, BoundaryCondition boundaryCondition);
void update();
void displayField() const;
};
\end{lstlisting}
\subsubsection{Конструктор CellularAutomaton}
Конструктор класса CellularAutomaton, код которого представлен в листиге~\ref{lst:CellularAutomatonConstructor}, принимает следующие параметры:
\begin{itemize}
\item \texttt{int width} -- ширина поля клеточного автомата;
\item \texttt{int height} -- высота поля клеточного автомата;
\item \texttt{bool fillWithRandom} -- флаг, определяющий, инициализировать ли поле случайными значениями;
\item \texttt{BoundaryCondition boundaryCondition} -- условие на границе поля.
\end{itemize}
Конструктор создает объект \texttt{CellularAutomaton} с заданными размерами и граничными условиями. Если \texttt{fillWithRandom} равно \texttt{true}, то поле инициализируется случайным образом с помощью метода \texttt{initializeRandom}, иначе пользователь может вручную ввести начальное состояние с помощью метода \texttt{initializeManual}.
\begin{lstlisting}[caption={Код конструктора CellularAutomaton.}, label={lst:CellularAutomatonConstructor}]
CellularAutomaton::CellularAutomaton(int width, int height, bool fillWithRandom, BoundaryCondition boundaryCondition)
: m_fieldWidth(width), m_fieldHeight(height), m_boundaryCondition(boundaryCondition)
{
m_field.resize(m_fieldHeight, std::vector<int>(m_fieldWidth, 0));
m_fieldNextState.resize(m_fieldHeight, std::vector<int>(m_fieldWidth, 0));
if (fillWithRandom) initializeRandom();
else initializeManual();
}
\end{lstlisting}
\subsubsection{Метод initializeRandom}
В листинге~\ref{lst:initializeRandom} представлен код метода \texttt{initializeRandom}. Метод явно ничего не принимает и не возвращает, а работает только с атрибутами класса \texttt{CellularAutomaton}. В результате его работы атрибут \texttt{m\_field} заполняется нулями и единицами случайным образом, для этого используется равномерное распределение.
\begin{lstlisting}[caption={Код метода initializeRandom.}, label={lst:initializeRandom}]
void CellularAutomaton::initializeRandom()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 1);
for (int y = 0; y < m_fieldHeight; ++y)
{
for (int x = 0; x < m_fieldWidth; ++x)
{
m_field[y][x] = dis(gen);
}
}
}
\end{lstlisting}
\subsubsection{Метод initializeManual}
В листинге~\ref{lst:initializeManual} представлен код метода \texttt{initializeManual}. Метод не принимает аргументов и ничего не возвращает. Он позволяет пользователю вручную ввести начальное состояние поля клеточного автомата. Для каждой клетки запрашивается значение 0 или 1, которые сохраняются в атрибуте \texttt{m\_field}.
\begin{lstlisting}[caption={Код метода initializeManual.}, label={lst:initializeManual}]
void CellularAutomaton::initializeManual()
{
std::cout << "Введите начальное состояние поля (" << m_fieldWidth << " x " << m_fieldHeight << ").\n";
std::cout << "Введите 0 или 1 для каждой клетки.\n";
for (int y = 0; y < m_fieldHeight; ++y)
{
for (int x = 0; x < m_fieldWidth; ++x)
{
std::cout << "Клетка (" << x << ", " << y << "): ";
int cellValue = inputNumber(0, 1);
m_field[y][x] = cellValue;
}
}
}
\end{lstlisting}
\subsubsection{Метод getCellState}
В листинге~\ref{lst:getCellState} представлен код метода \texttt{getCellState}. Метод принимает на вход координаты клетки \texttt{int x} и \texttt{int y}. Возвращает \texttt{int} -- состояние клетки по указанным координатам. Если координаты выходят за пределы поля, то поведение определяется граничными условиями, заданными атрибутом \texttt{m\_boundaryCondition}.
\begin{lstlisting}[caption={Код метода getCellState.}, label={lst:getCellState}]
int CellularAutomaton::getCellState(int x, int y) const
{
if (x < 0 || x >= m_fieldWidth || y < 0 || y >= m_fieldHeight)
{
switch (m_boundaryCondition)
{
case BOUNDARY_ONES:
return 1;
case BOUNDARY_ZEROS:
return 0;
case BOUNDARY_TOROIDAL:
x = (x + m_fieldWidth) % m_fieldWidth;
y = (y + m_fieldHeight) % m_fieldHeight;
return m_field[y][x];
default:
return 0;
}
}
return m_field[y][x];
}
\end{lstlisting}
\subsubsection{Метод getNeighborhoodIndex}
В листинге~\ref{lst:getNeighborhoodIndex} представлен код метода \texttt{getNeighborhoodIndex}. Метод принимает на вход координаты клетки \texttt{int x} и \texttt{int y}. Возвращает \texttt{int} -- индекс конфигурации окрестности фон Неймана клетки. Индекс вычисляется на основе состояний центральной клетки и её четырёх соседей (сверху, снизу, слева и справа), где каждый сосед соответствует одному биту в индексе. Этот индекс используется для определения следующего состояния клетки по функции переходов в методе \texttt{update}.
\begin{lstlisting}[caption={Код метода getNeighborhoodIndex.}, label={lst:getNeighborhoodIndex}]
int CellularAutomaton::getNeighborhoodIndex(int x, int y) const
{
int s0 = getCellState(x, y);
int s1 = getCellState(x, y - 1);
int s2 = getCellState(x, y + 1);
int s3 = getCellState(x - 1, y);
int s4 = getCellState(x + 1, y);
int index = (s0 << 4) | (s1 << 3) | (s2 << 2) | (s3 << 1) | s4;
return index;
}
\end{lstlisting}
\subsubsection{Метод update}
В листинге~\ref{lst:update} представлен код метода \texttt{update}. Метод не принимает аргументов и ничего не возвращает. Он обновляет состояние клеточного автомата на следующий временной шаг. Для каждой клетки вычисляется новое состояние на основе текущего состояния и функции переходов, значения которой хранятся в битах числа \texttt{m\_functionValues}. После вычисления новое состояние сохраняется в \texttt{m\_fieldNextState}, а затем происходит обмен содержимого \texttt{m\_field} и \texttt{m\_fieldNextState}.
\begin{lstlisting}[caption={Код метода update.}, label={lst:update}]
void CellularAutomaton::update()
{
for (int y = 0; y < m_fieldHeight; ++y)
{
for (int x = 0; x < m_fieldWidth; ++x)
{
int neighborhood = getNeighborhoodIndex(x, y);
m_fieldNextState[y][x] = (m_functionValues >> neighborhood) & 1;
}
}
m_field.swap(m_fieldNextState);
}
\end{lstlisting}
\subsubsection{Метод displayField}
В листинге~\ref{lst:displayField} представлен код метода \texttt{displayField}. Метод не принимает аргументов и ничего не возвращает. Он выводит текущее состояние поля клеточного автомата в консоль, отображая каждую клетку как '0' или '1'.
\begin{lstlisting}[caption={Код метода displayField.}, label={lst:displayField}]
void CellularAutomaton::displayField() const
{
for (const auto& row : m_field)
{
for (const auto& cell : row)
{
std::cout << (cell ? '1' : '0') << ' ';
}
std::cout << '\n';
}
}
\end{lstlisting}
\subsection{Функция main}
В функции main, код которой представлен в листинге~\ref{lst:main}, содержится бесконечный цикл, который обрабатывает пользовательский ввод. На каждой итерации цикла, пользователю предлагается выбрать конфигурацию конечного двумерного автомата и количество итераций. Затем внутри функции создаётся объект класса \texttt{CellularAutomaton}, с заданными пользователем параметрами, и у него вызывается метод \texttt{update} согласно указанному количеству итераций. Функция \texttt{main} возвращает целое число, которое является кодом завершения программы - 0, если программа выполнилась успешно, и ненулевое значение, если произошла какая-либо ошибка.
\begin{lstlisting}[caption={Код функции main.}, label={lst:main}]
int main()
{
setlocale(LC_ALL, "Russian");
while (true) {
clear();
cout << "Выберите граничные условия:\n"
"Единичные (0)\n"
"Нулевые (1)\n"
"Тороидальные (2)\n"
"Завершить работу (3)\n\n";
int actionId = inputNumber(0, 3);
clear();
if (actionId == 3) {
cout << "Выйти из программы? (yes/no)\n";
if (userApprove()) return 0;
continue;
}
BoundaryCondition boundaryCondition = static_cast<BoundaryCondition>(actionId);
cout << "Укажите ширину поля (min 1): ";
int fieldWidth = inputNumber(1);
cout << "Укажите высоту поля (min 1): ";
int fieldHeight = inputNumber(1);
cout << "Укажите количество итераций (min 1): ";
int iterationsCount = inputNumber(1);
cout << "Заполнить поле случайными значениями? (yes/no)\n";
bool fillWithRandom = userApprove();
CellularAutomaton ca(fieldWidth, fieldHeight, fillWithRandom, boundaryCondition);
clear();
cout << "\nИтерация 0:\n";
ca.displayField();
for (int i = 0; i < iterationsCount; ++i)
{
cout << "\nИтерация " << i + 1 << ":\n";
ca.update();
ca.displayField();
}
cout << "\nНажмите на enter, чтобы продолжить...";
waitForEnter();
}
}
\end{lstlisting}
\subsection{Пользовательский ввод}
Одним из требований к лабораторным работам являлась защита от некорректного пользовательского ввода. Для реализации такой защиты и большей читаемости кода все функции связанные с пользовательским вводом были вынесены в отдельный файл. Все функции проверяют данные вводимые пользователем и, если что-то не так, печатают информацию о неверном выводе.
\begin{itemize}
\item {\tt int inputNumber(int minVal, int maxVal)} - принимает два числа, которые указывают диапозон возможных для ввода значений. Возвращает введённое пользователем число.
\item {\tt char* inputString(int maxLen)} - принимает число, максимальную длину строки, возвращает указатель на строку введённую пользователем. Не позволяет вводить строки больше указанной длины.
\item {\tt bool userApprove()} - возвращает true, если пользователь ввёл <<yes>> или <<y>> и false, если пользователь ввёл <<no>> или <<n>>.
\item {\tt void waitForEnter()} - останавливает выполнение программы пока пользователь не нажмёт на клавишу <<Enter>>.
\end{itemize}
\newpage
\section {Результаты работы программы}
В данном разделе представлены скриншоты с примерами ввода-вывода, демонстрирующие работу программы и её основной функционал.
На Рис.~\ref{fig:results_1} показано основное стартовое меню программы. Пользователю предоставляется возможность выбрать граничные условия или завершнить работу с приложением. В верхней строке выводится вектор значений функции переходов, соответствующий варианту лабораторной работы.
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/results_1.png}
\caption{Начальное меню приложения.}
\label{fig:results_1}
\end{figure}
На Рис.~\ref{fig:results_2} демонстрируется процесс задания ширины и высоты поля клеточного автомата, а также количества итераций. Программа также предлагает выбрать способ задания начальной конфигурации. В случае утвердительного ответа, поле заполняется нулями и единицами случайным образом. Если ответ отрицательный, то программа предлагает пользователю заполнить значения для всех полей вручную, этот процесс демонстрируется на Рис.~\ref{fig:results_4}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/results_2.png}
\caption{Заполнение параметров поля автомата и количества итераций.}
\label{fig:results_2}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/results_4.png}
\caption{Демонстрация процесса заполнения значений клеток поля вручную.}
\label{fig:results_4}
\end{figure}
После заполнения значений клеток поля в консоль выводится последовательность состояний поля по итерациям (см. Рис.~\ref{fig:results_3}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/results_3.png}
\caption{Вывод состояний автомата по итерациям.}
\label{fig:results_3}
\end{figure}
\newpage
\section{Анализ клеточного автомата}
\subsection{Паттерны}
В ходе работы были исследованы паттерны клеточного автомата на поле размером $5 \times 5$ клеток в течение 25 итераций с различными начальными конфигурациями и граничными условиями. Краткие результаты для каждой комбинации граничных условий и начальных конфигураций представлены в таблице~\ref{tbl:patters}. Начальные конфигурации представлены на Рис.~\ref{fig:start_zeros}-\ref{fig:start_ones}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_zeros.png}
\caption{Начальная конфигурация <<Пустое поле>>.}
\label{fig:start_zeros}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_hline.png}
\caption{Начальная конфигурация <<Горизонтальная палочка>>.}
\label{fig:start_hline}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_vline.png}
\caption{Начальная конфигурация <<Вертикальная палочка>>.}
\label{fig:start_vline}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_square.png}
\caption{Начальная конфигурация <<Квадратик>>.}
\label{fig:start_square}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_ones.png}
\caption{Начальная конфигурация <<Единичное поле>>.}
\label{fig:start_ones}
\end{figure}
\begin{table}[h!]
\centering
\caption{Результаты анализа клеточного автомата при различных начальных конфигурациях и граничных условиях.}
\label{tbl:patters}
\footnotesize
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\textbf{Исходная конфигурация} & \textbf{Граничные условия} & \textbf{Результат} \\
\hline
\multirow{3}{*}{Пустое поле} & Единичные & Случайные паттерны \\
\cline{2-3}
& Нулевые & Пустое поле \\
\cline{2-3}
& Тороидальные & Пустое поле \\
\hline
\multirow{3}{*}{Горизонтальная палочка} & Единичные & Случайные паттерны \\
\cline{2-3}
& Нулевые & Движение вверх и нулевое поле \\
\cline{2-3}
& Тороидальные & Циклическое движение вверх \\
\hline
\multirow{3}{*}{Вертикальная палочка} & Единичные & Случайные паттерны \\
\cline{2-3}
& Нулевые & Зацикливание \\
\cline{2-3}
& Тороидальные & Зацикливание \\
\hline
\multirow{3}{*}{Квадратик} & Единичные & Случайные паттерны \\
\cline{2-3}
& Нулевые & Зацикливание \\
\cline{2-3}
& Тороидальные & Случайные паттерны \\
\hline
\multirow{3}{*}{Единичное поле} & Единичные & Случайные паттерны \\
\cline{2-3}
& Нулевые & Зацикливание \\
\cline{2-3}
& Тороидальные & Превратилось в нулевое поле \\
\hline
\end{tabularx}
\end{table}
Как видно по таблице~\ref{tbl:patters} в результате анализа удалось обнаружить несколько циклических паттернов, рассмотрим их подробнее.
\newpage
При задании начальной конфигурации <<Горизонтальная палочка>> (см. Рис.~\ref{fig:start_hline}) и нулевых или тороидальных граничных условий палочка каждый такт времени сдвигается вверх по сетке автомата на одну строку. При нулевых граничных условиях палочка доходит до границы поля и исчезает (см. Рис~\ref{fig:hline_zeros}). При тороидальных граничных условиях палочка доходит до границы, затем появляется снизу и снова движется вверх по сетке (см. Рис~\ref{fig:hline_toroid}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/hline_zeros.png}
\caption{Работа автомата при нулевых граничных условиях и начальной конфигурации <<Горизонтальная палочка>>.}
\label{fig:hline_zeros}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/hline_toroid.png}
\caption{Работа автомата при тороидальных граничных условиях и начальной конфигурации <<Горизонтальная палочка>>.}
\label{fig:hline_toroid}
\end{figure}
\newpage
При задании начальной конфигурации <<Вертикальная палочка>> (см. Рис.~\ref{fig:vline_zeros_toroid}) и нулевых или тороидальных граничных условий палочка сначала раздваивается и расходится в стороны до границ сетки, потом обратно сдвигается на одну клетку к центру и зацикливается (см. Рис.~\ref{fig:vline_zeros_toroid}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/vline_zeros_toroid.png}
\caption{Работа автомата при нулевых и тороидальных граничных условиях и начальной конфигурации <<Вертикальная палочка>>.}
\label{fig:vline_zeros_toroid}
\end{figure}
При задании начальной конфигурации <<Квадратик>> (см. Рис.~\ref{fig:start_square}) или <<Единичное поле>> (см. Рис.~\ref{fig:start_ones}) и нулевых граничных условий автомат зацикливается после 18-ой итерации (см. Рис.~\ref{fig:square_zeros}). При этом паттерны перед зацикливанием отличаются для разных начальных конфигураций и выглядят случайными.
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/square_zeros.png}
\caption{Зацикливание автомата при нулевых граничных условиях и начальной конфигурации <<Квадратик>> или <<Единичное поле>>.}
\label{fig:square_zeros}
\end{figure}
\newpage
Также автомат был несколько раз запущен на том же размере сетки (5 x 5), нулевых начальных условиях и случайных начальных конфигурациях для большего числа итераций ($n=300$). Таким образом удалось обнаружить ещё несколько циклических паттернов, к которым сходится рассматриваемый автомат. На Рис.~\ref{fig:zeros_random} представлен пример достаточно короткого циклического паттерна, а на Рис.~\ref{fig:start_cycle_8} представлена конфигурация, которая повторяется снова каждые 8 итераций.
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/zeros_random.png}
\caption{Один из циклических паттернов рассматриваемого автомата.}
\label{fig:zeros_random}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.14\linewidth]{img/start_cycle_8.png}
\caption{Пример конфигурации, повторяющейся каждые 8 итераций.}
\label{fig:start_cycle_8}
\end{figure}
\subsection{Сходимость}
По таблице \ref{tbl:patters} видно, что автомат ведёт себя по разному, в зависимости от начальной конфигурации и граничных условий. В некоторых случаях автомат сходился к пустому полю, все клетки которого мертвы. В некоторых случаях он сходится к различным циклическим паттернам. А для нескольких конфигураций не удалось определить сходимость на заданном числе итераций.
\subsection{Классификация}
Результаты запуска автомата для пяти произвольных начальных конфигураций представлены на графике, который изображён на Рис.~\ref{fig:conv_exps}. На Рис.~\ref{fig:conv_mean}, изображён график среднего значения количества живых клеток для всех пяти экспериментов. По этому графику видно, что количество живых клеток стабилизируется после 400 итераций на уровне 70 клеток. На Рис.~\ref{fig:conv_aprox} изображён график аппроксимирующей функции количества живых клеток от итераций. По нему также видно, что количество живых клеток сходится к, примерно, 70 клеткам.
Исходя из описания классов и анализа паттернов клеточного автомата, можно сделать вывод, что при различных начальных конфигурациях и граничных условиях, автомат с полем 5 на 5 проявляет свойства 1 (все ячейки становятся мёртвыми) и 2 (переход к циклическим паттернам) классов. Если же увеличить размер поля до 20 клеток и задать нулевые граничные условия, то автомат перестаёт проявлять признаки этих классов и, кажется, что его можно отнести к 3 классу, так как результатом почти всех начальных условий становятся псевдо-случайные хаотические последовательности.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/conv_exps.png}
\caption{График количества «живых» клеток относительно номера итерации при нулевых граничных условиях для сетки размером 20 x 20 для пяти произвольных начальных конфигураций.}
\label{fig:conv_exps}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/conv_mean.png}
\caption{График среднего количества «живых» клеток относительно номера итерации при нулевых граничных условиях для сетки размером 20 x 20 по всем экспериментам.}
\label{fig:conv_mean}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/conv_aprox.png}
\caption{График полиномиальной аппроксимирующей функции (n=10) количества «живых» клеток относительно номера итерации при нулевых граничных условиях для сетки размером 20 x 20.}
\label{fig:conv_aprox}
\end{figure}
\newpage
\phantom{text}
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В ходе выполнения лабораторной работы был реализован двумерный клеточный автомат в консоли с окрестностью фон Неймана в соответствии с заданным номером 109063350. Двоичное представление этого числа, дополненное ведущими нулями, соответствует вектору значений функции переходов рассматриваемого клеточного автомата. Анализ паттернов был проведён для трёх вариантов граничных условий: единичные, нулевые и тороидальные. Было обнаружено как минимум 6 различных циклических паттернов для поля размером 5 на 5. Для поля размером 20 на 20 и нулевых начальных условий были построены графики количества <<живых>> клеток для различных начальных конфигураций. Также по результатам анализа, было определено, что при размере поля 5 на 5 рассматриваемый автомат проявляет признаки первого и второго классов по классификации Стивена Вольфрама, однако при большем размере поля в 20 на 20 клеток он больше подходит под определение третьего класса.
Из достоинств выполнения лабораторной работы можно выделить структурирование кода за счёт использования ООП. Вся логика работы клеточного автомата вынесена в отдельный класс \texttt{CellularAutomaton}, который может быть переиспользован в других программах. Также достоинством является то, что приложение позволяет пользователю выбирать граничные условия.
Во время разработки упор был сделан на упрощении и понятности кода, поэтому в качестве недостатка можно отметить не самую лучшую его эффективность, в особенности в использовании памяти. Поскольку каждая клетка может быть в одном из двух состояний можно было бы использовать битовые структуры для хранения поля, однако в работе для этих целей используются векторы целых чисел. Таким образом для хранения состояния каждой отдельной клетки выделяется по 32 бита, вместо одного необходимого.
Функционал программы достаточно несложно масштабировать. Например, сейчас функция переходов жёстко задаётся в классе \texttt{CellularAutomaton}, с помощью незначительных изменений кода можно было бы предоставить пользователю возможность задавать функцию перехода, посредством ввода вектора значений функции или натурального числа, двоичное представление которого соответствовало бы вектору значений функции переходов.
Работа выполнена в среде разработки Visual Studio 2022, стандарт ISO C++ 14, компилятор Microsoft (R) C/C++ версии 19.33.31629.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{vostrov}
Востров А. В, <<Теория алгоритмов>> URL: \url{https://tema.spbstu.ru/algorithm/} (Дата обращения: 01.12.2024).
\bibitem{wolfram}
Wolfram, Stephen <<A New Kind of Science>>. — Wolfram Media (2002) — 1197 с.
\end{thebibliography}
\end{document}