664 lines
42 KiB
TeX
664 lines
42 KiB
TeX
\documentclass[a4paper, final]{article}
|
||
%\usepackage{literat} % Нормальные шрифты
|
||
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
|
||
\usepackage{tabularx}
|
||
\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[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{Лабораторная работа №2}\\
|
||
\large{<<Конечный автомат и регулярное выражение для распознавания форматов вещественных чисел>>}\\
|
||
\large{по дисциплине}\\
|
||
\large{<<Математическая логика>>}\\
|
||
\large{Вариант 15}\\
|
||
|
||
% \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}} 2025г.
|
||
\end{flushright}
|
||
}
|
||
|
||
\hfill \break
|
||
% \hfill \break
|
||
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
|
||
\thispagestyle{empty} % выключаем отображение номера для этой страницы
|
||
|
||
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
|
||
\newpage
|
||
|
||
\tableofcontents
|
||
|
||
|
||
\newpage
|
||
|
||
\section*{Введение}
|
||
\addcontentsline{toc}{section}{Введение}
|
||
Лабораторная №2 по дисциплине <<Математическая логика>> заключается в следующем. Необходимо построить регулярное выражение для заданного варианта, затем создать недетерминированный конечный автомат и детерминировать его. Реализовать программу, которая проверяет введённый текст через реализацию конечного автомата, с вариантами вывода: строка соответствует, не соответствует, символы не из алфавита. Также необходимо реализовать функцию случайной генерации верной строки по полученному конечному автомату.
|
||
|
||
\textit{Вариант 15}. Соответствие вещественного числа разным форматам представления.
|
||
|
||
\newpage
|
||
\section {Математическое описание}
|
||
\subsection{Форматы представления вещественных чисел}
|
||
|
||
В данной лабораторной работе рассматриваются следующие форматы представления вещественных чисел.
|
||
\begin{itemize}
|
||
\item Целые числа, например: \texttt{''123''}, \texttt{''-456''}, \texttt{''0''}, в т. ч. \texttt{''+0''}, \texttt{''-0''}.
|
||
\item Десятичные числа с двумя возможными разделителями (точка или запятая), например: \texttt{''123.456''}, \texttt{''-456,789''}.
|
||
\item Экспоненциальная форма (буква E может быть как в верхнем, так и в нижнем регистре), например: \texttt{''1.23E4''}, \texttt{''-4,56e-7''}, \texttt{''7e8''}.
|
||
\end{itemize}
|
||
|
||
Формальное определение синтаксиса предложенного формата вещественных чисел в БНФ нотации:
|
||
\begin{verbatim}
|
||
real ::= decimal | exponential
|
||
decimal ::= integer [separator digit {digit}]
|
||
integer ::= [sign] (nonzerodigit {digit} | "0")
|
||
exponential ::= decimal ("e" | "E") integer
|
||
sign ::= "+" | "-"
|
||
nonzerodigit ::= "1" | "2" | ... | "9"
|
||
digit ::= "0" | nonzerodigit
|
||
separator ::= "." | ","
|
||
\end{verbatim}
|
||
Где:
|
||
\begin{itemize}
|
||
\item \lbrack R\rbrack -- необязательный элемент (0 или 1 раз)
|
||
\item \{R\} -- повторение элемента (0 или более раз)
|
||
\item P|Q -- альтернатива (либо P, либо Q)
|
||
\end{itemize}
|
||
|
||
|
||
|
||
\subsection{Языки и грамматики}
|
||
Языком над конечным словарем $\Sigma$ называется произвольное множество конечных цепочек над этим словарем.
|
||
|
||
\begin{itemize}
|
||
\item Цепочки языка называются словами (предложениями).
|
||
\item Над конечным непустым словарем можно определить бесконечное
|
||
количество слов конечной длины (счетное множество).
|
||
\item Над конечным
|
||
непустым словарем можно определить бесконечное количество языков, т.е.
|
||
подмножество множества всех возможных слов
|
||
(континуум, как число подмножеств счетного множества).
|
||
\end{itemize}
|
||
|
||
Языки могут быть конечными и бесконечными (содержать бесконечное число цепочек). Словарь всегда конечен.
|
||
|
||
Формальная грамматика – способ описания того, какие предложения возможны в языке. Существует два вида грамматик:
|
||
\begin{itemize}
|
||
\item порождающие грамматики – правила, позволяющие
|
||
строить любое предложение языка,
|
||
\item распознающие грамматики (алгоритмы) - позволяют
|
||
определить, принадлежит ли данное предложение языку.
|
||
\end{itemize}
|
||
|
||
Распознающая грамматика – это конечный набор
|
||
правил, алгоритм, который по введенной цепочке
|
||
определяет, принадлежит цепочка языку, или нет.
|
||
|
||
\subsection{Регулярные множества}
|
||
Регулярные множества, как множества цепочек, построенные над конечным словарем (по определенным правилам) – это языки. Их называют регулярными языками.
|
||
|
||
Правила построения регулярных множеств:
|
||
\begin{itemize}
|
||
\item Объединение двух регулярных множеств $L_1$ и $L_2$ обозначается $L_1 \cup L_2$ и состоит из цепочек, которые принадлежат хотя бы одному из множеств $L_1$ или $L_2$.
|
||
$$L_1 \cup L_2 = \{ \alpha \mid \alpha \in L_1 \text{ или } \alpha \in L_2 \}$$
|
||
|
||
\item Конкатенация (произведение) двух регулярных множеств $L_1$ и $L_2$ обозначается $L_1 \cdot L_2$ и состоит из цепочек, которые можно разбить на две части, одна из которых принадлежит $L_1$, а другая $L_2$.
|
||
$$L_1 \cdot L_2 = \{ \alpha \beta \mid \alpha \in L_1 \text{ и } \beta \in L_2 \}$$
|
||
|
||
Обозначим $L^0 = \{ \varepsilon \}$, $L^1 = L$, $L^2 = L \cdot L$, $L^{k + 1} = L^k \cdot L$, и так далее. Обозначение $\varepsilon$ обозначает пустую цепочку.
|
||
|
||
\item Итерация регулярного множества $L$ обозначается $L^*$ и состоит из цепочек, которые можно разбить на произвольное количество повторений множества $L$.
|
||
$$L^* = \{ \varepsilon \} \cup L \cup L^2 \cup L^3 \cup \ldots$$
|
||
\end{itemize}
|
||
|
||
\subsection{Регулярные выражения}
|
||
Регулярные выражения -- формальный язык шаблонов для поиска и выполнения манипуляций с подстроками в тексте. Регулярное выражение -- это формула (pattern, шаблон), задающая правило поиска подстрок в потоке символов.
|
||
|
||
Регулярное выражение показывает, как можно построить регулярное множество цепочек из одноэлементных множеств с использованием трех операций: конкатенации, объединения и итерации.
|
||
|
||
Примеры регулярных выражений:
|
||
\begin{itemize}
|
||
\item $ab + ba^*$ -- представляет регулярное множество:
|
||
$$\{ a\} \{b \} \cup \{ b \} \{ a \}^*$$
|
||
\item $(ac)^*b+c^*$ -- представляет регулярное множество:
|
||
$$\{b, acb, acacb, acacacb, \ldots, \varepsilon, c, cc, ccc, \ldots \}$$
|
||
\end{itemize}
|
||
|
||
В реальных программах и языках программирования используется расширенный синтаксис регулярных выражений, который добавляет множество удобных конструкций. Среди дополнительных возможностей: классы символов (например, \verb|[a-z0-9]|), квантификаторы (\verb|?|, \verb|+|, \verb|{n,m}|), группировка с помощью скобок, обратные ссылки, опережающие и ретроспективные проверки. Эти расширения делают регулярные выражения более компактными и удобными для использования, но не меняют их выразительную мощность с теоретической точки зрения.
|
||
|
||
Если регулярные множества это языки, то регулярные выражения -- это распознающие грамматики этих языков.
|
||
|
||
\subsection{Регулярные выражения для заданного варианта}
|
||
|
||
Для разных форматов представления вещественных чисел были построены следующие регулярные выражения в соответствии с определённой БНФ нотацией:
|
||
\begin{itemize}
|
||
\item Десятичные и целые числа: \\
|
||
\texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?}
|
||
\item Экспоненциальная форма: \\
|
||
\texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?[eE][+-]?([1-9][0-9]*|0)}
|
||
\end{itemize}
|
||
|
||
Объединяя все форматы в соответствии с нашей БНФ нотацией, получаем следующее регулярное выражение, которое распознает все форматы вещественных чисел:
|
||
|
||
\texttt{[+-]?([1-9][0-9]*|0)([.,][0-9]+)?([eE][+-]?([1-9][0-9]*|0))?}
|
||
|
||
Разберём структуру этого выражения:
|
||
\begin{itemize}
|
||
\item \texttt{[+-]?} -- необязательный знак числа (плюс или минус)
|
||
\item \texttt{([1-9][0-9]*|0)} -- целая часть числа, которая может быть либо нулём, либо цифрой от 1 до 9, за которой следует произвольное количество цифр
|
||
\item \texttt{([.,][0-9]+)?} -- необязательная десятичная часть, состоящая из разделителя (точка или запятая) и как минимум одной цифры
|
||
\item \texttt{([eE][+-]?([1-9][0-9]*|0))?} -- необязательная экспоненциальная часть, состоящая из буквы E (в любом регистре), необязательного знака и целого числа
|
||
\end{itemize}
|
||
|
||
Таким образом, полученное регулярное выражение распознаёт формат представления вещественных чисел, рассматриваемый в данной работе, и полностью соответствует формальному определению, представленному в БНФ нотации.
|
||
|
||
\subsection{Конечный автомат-распознаватель}
|
||
Конечный автомат-распознаватель – это математическая модель, которая используется для распознавания цепочек символов в соответствии с заданным формальным языком.
|
||
|
||
Конечный автомат-распознаватель $A = (S, \Sigma, s_0, \delta, F)$, где:
|
||
\begin{itemize}
|
||
\item $S$ – конечное множество состояний
|
||
\item $\Sigma$ – конечное множество входных символов
|
||
\item $s_0 \in S$ – начальное состояние
|
||
\item $\delta: S \times \Sigma \rightarrow S$ – функция переходов
|
||
\item $F \subseteq S$ – множество финальных (допускающих) состояний
|
||
\end{itemize}
|
||
|
||
Автомат $A$ допускает (распознает) цепочку, если эта цепочка переводит $A$ из начального в одно из финальных состояний. Автомат $A$ допускает язык $L$, если он допускает все цепочки этого языка – и только их.
|
||
|
||
Конечный автомат-распознаватель является распознающей грамматикой.
|
||
|
||
\subsection{Недетерминированный КА-распознаватель}
|
||
Недетерминизм - очень удобное свойство формальной
|
||
модели, его можно определенным образом трактовать,
|
||
даже и не реализовывая, ограничиваясь только
|
||
формальными аналитическими преобразованиями.
|
||
|
||
В недетерминированном конечном автомате-распознавателе могут быть следующие неоднозначности:
|
||
\begin{itemize}
|
||
\item несколько начальных состояний,
|
||
\item несколько переходов, помеченных одним и тем
|
||
же символом,
|
||
\item переходы, помеченные пустым символом $\varepsilon$.
|
||
\end{itemize}
|
||
|
||
Цепочка допускается конечным автоматом, если существует путь, по которому эта цепочка переводит автомат из какого-нибудь начального состояния в какое-нибудь финальное состояние.
|
||
|
||
Недетерминированный конечный автомат-распознаватель $A = (S, \Sigma, S_0, \delta, F)$, где:
|
||
\begin{itemize}
|
||
\item $S$ – конечное множество состояний
|
||
\item $\Sigma$ – конечное множество входов
|
||
\item $S_0 \subseteq S$ – множество начальных состояний
|
||
\item $\delta: S \times \Sigma \rightarrow 2^S$ – функция переходов
|
||
\item $F \subseteq S$ – множество финальных состояний
|
||
\end{itemize}
|
||
|
||
\subsection{Теорема Клини}
|
||
\textbf{Теорема Клини}. Классы регулярных множеств и автоматных языков совпадают. Это значит, что:
|
||
\begin{itemize}
|
||
\item Любой язык, распознаваемый конечным автоматом, может быть задан регулярным выражением.
|
||
\item Для любого регулярного выражения существует конечный автомат, распознающий соответствующий язык.
|
||
\end{itemize}
|
||
|
||
\subsection{Недетерминированный КА-распознаватель для заданного варианта}
|
||
|
||
На Рис.~\ref{fig:nka} представлен недетерминированный КА-распознаватель, соответствующий регулярному выражению для заданного варианта.
|
||
|
||
\begin{figure}[h!]
|
||
\centering
|
||
\includegraphics[width=1\linewidth]{img/nka.png}
|
||
\caption{Недетерминированный КА-распознаватель для заданного варианта.}
|
||
\label{fig:nka}
|
||
\end{figure}
|
||
|
||
Матрица переходов для данного автомата представлена в Таблице~\ref{tab:nka}.
|
||
|
||
\begin{table}[h!]
|
||
\centering
|
||
\caption{Таблица переходов для недетерминированного КА-распознавателя.}
|
||
\footnotesize
|
||
\begin{tabularx}{\textwidth}{|c|X|X|X|X|X|}
|
||
\hline
|
||
\textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.,} & \textbf{eE} \\
|
||
\hline
|
||
$S_0$ & $S_1$ & $S_8$ & $S_2$ & -- & -- \\
|
||
\hline
|
||
$S_1$ & -- & $S_8$ & $S_2$ & -- & -- \\
|
||
\hline
|
||
$S_2$ & -- & $S_2$ & $S_2$ & $S_3$ & $S_5$ \\
|
||
\hline
|
||
$S_3$ & -- & $S_4$ & $S_4$ & -- & -- \\
|
||
\hline
|
||
$S_4$ & -- & $S_4$ & $S_4$ & -- & $S_5$ \\
|
||
\hline
|
||
$S_5$ & $S_6$ & $S_9$ & $S_7$ & -- & -- \\
|
||
\hline
|
||
$S_6$ & -- & $S_9$ & $S_7$ & -- & -- \\
|
||
\hline
|
||
$S_7$ & -- & -- & $S_7$ & -- & -- \\
|
||
\hline
|
||
$S_8$ & -- & -- & -- & $S_3$ & -- \\
|
||
\hline
|
||
$S_9$ & -- & -- & -- & -- & -- \\
|
||
\hline
|
||
\end{tabularx}
|
||
\label{tab:nka}
|
||
\end{table}
|
||
|
||
\subsection{Детерминированный КА-распознаватель для заданного варианта}
|
||
|
||
Для того, чтобы преобразовать недетерминированный КА-распознаватель (Рис.~\ref{fig:nka}) в детерминированный, достаточно добавить ещё одно состояние $S_E$, соответствующее недопустимой цепочке символов, и переходы в него из всех остальных состояний.
|
||
|
||
На Рис.~\ref{fig:ka} представлен детерминированный КА-распознаватель. Символом \textit{C} (от англ. Complement -- дополнение) обозначены переходы, соответствующие любым символам, кроме тех, по которым уже есть переходы в другие состояния. Символом \textit{A} (от англ. Any -- любой) обозначен переход, соответствующий любому символу.
|
||
|
||
\begin{figure}[h!]
|
||
\centering
|
||
\includegraphics[width=1\linewidth]{img/ka.png}
|
||
\caption{Детерминированный КА-распознаватель для заданного варианта.}
|
||
\label{fig:ka}
|
||
\end{figure}
|
||
|
||
Матрица переходов для данного автомата представлена в Таблице~\ref{tab:ka}.
|
||
|
||
\begin{table}[h!]
|
||
\centering
|
||
\caption{Таблица переходов для детерминированного КА-распознавателя.}
|
||
\footnotesize
|
||
\begin{tabularx}{\textwidth}{|c|X|X|X|X|X|}
|
||
\hline
|
||
\textbf{Состояние\textbackslash Вход} & \textbf{+-} & \textbf{0} & \textbf{1-9} & \textbf{.,} & \textbf{eE} \\
|
||
\hline
|
||
$S_0$ & $S_1$ & $S_8$ & $S_2$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_1$ & $S_E$ & $S_8$ & $S_2$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_2$ & $S_E$ & $S_2$ & $S_2$ & $S_3$ & $S_5$ \\
|
||
\hline
|
||
$S_3$ & $S_E$ & $S_4$ & $S_4$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_4$ & $S_E$ & $S_4$ & $S_4$ & $S_E$ & $S_5$ \\
|
||
\hline
|
||
$S_5$ & $S_6$ & $S_9$ & $S_7$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_6$ & $S_E$ & $S_9$ & $S_7$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_7$ & $S_E$ & $S_E$ & $S_7$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
$S_8$ & $S_E$ & $S_E$ & $S_E$ & $S_3$ & $S_E$ \\
|
||
\hline
|
||
$S_9$ & $S_E$ & $S_E$ & $S_E$ & $S_E$ & $S_E$ \\
|
||
\hline
|
||
\end{tabularx}
|
||
\label{tab:ka}
|
||
\end{table}
|
||
|
||
|
||
\newpage
|
||
\phantom{text}
|
||
\newpage
|
||
\section{Особенности реализации}
|
||
\subsection{Общая структура программы}
|
||
Программа состоит из двух файлов:
|
||
\begin{itemize}
|
||
\item \texttt{finite\_automaton.py} -- содержит класс \texttt{FiniteAutomaton} для создания конечных автоматов.
|
||
\item \texttt{main.py} -- содержит определение конечного автомата для распознавания вещественных чисел, а также функцию \texttt{main}, которая реализует интерактивный интерфейс для проверки и генерации строк.
|
||
\end{itemize}
|
||
|
||
\subsection{Класс \texttt{FiniteAutomaton}}
|
||
|
||
Класс \texttt{FiniteAutomaton} это класс для представления конечных автоматов. Код конструктора класса представлен в листинге~\ref{lst:FiniteAutomaton}.
|
||
|
||
В классе определены четыре поля.
|
||
\begin{itemize}
|
||
\item \texttt{transitions} -- \texttt{dict[str, list[tuple[str, str]]]} -- словарь, определяющий переходы между состояниями. Ключами словаря являются состояния, значениями -- списки кортежей вида \texttt{(transition, next\_state)}, определяющие переходы из данного состояния. \texttt{transition} это строка, содержащая символы, по которым можно перейти из данного состояния в следующее состояние -- \texttt{next\_state}.
|
||
\item \texttt{initial\_state} -- \texttt{str} -- начальное состояние.
|
||
\item \texttt{final\_states} -- \texttt{set[str]} -- множество финальных состояний.
|
||
\item \texttt{alphabet} -- \texttt{set[str]} -- множество символов, которые может содержать входная строка.
|
||
\end{itemize}
|
||
|
||
\begin{lstlisting}[caption={Код конструктора класса FiniteAutomaton.}, label={lst:FiniteAutomaton}]
|
||
class FiniteAutomaton:
|
||
def __init__(
|
||
self,
|
||
transitions: dict[str, list[tuple[str, str]]],
|
||
initial_state: str,
|
||
final_states: set[str],
|
||
alphabet: set[str],
|
||
):
|
||
self.transitions = transitions
|
||
self.initial_state = initial_state
|
||
self.final_states = final_states
|
||
self.alphabet = alphabet
|
||
\end{lstlisting}
|
||
|
||
Класс \texttt{FiniteAutomaton} содержит три метода: \texttt{\_get\_next\_state}, \texttt{process\_input} и \texttt{generate\_random\_string}.
|
||
|
||
\subsection{Метод \texttt{\_get\_next\_state}}
|
||
Приватный метод \texttt{\_get\_next\_state} принимает три параметра: \texttt{self} -- ссылку на объект класса, \texttt{current\_state} (\texttt{str}) -- текущее состояние, и \texttt{char} (\texttt{str}) -- символ, по которому нужно перейти из текущего состояния. Возвращает следующее состояние (\texttt{str}), либо \texttt{None}, если переход невозможен.
|
||
|
||
\begin{lstlisting}[caption={Код метода \texttt{\_get\_next\_state}.}, label={lst:get_next_state}]
|
||
def _get_next_state(self, current_state: str, char: str) -> str | None:
|
||
if current_state in self.transitions:
|
||
for transition, next_state in self.transitions[current_state]:
|
||
if char in transition:
|
||
return next_state
|
||
return None
|
||
\end{lstlisting}
|
||
|
||
|
||
\subsection{Метод \texttt{process\_input}}
|
||
Метод \texttt{process\_input} принимает два параметра: \texttt{self} -- ссылку на объект класса, и входную строку \texttt{input\_string}. Возвращает кортеж из двух элементов: строку с сообщением о результате проверки, и список пройденных состояний.
|
||
|
||
\begin{lstlisting}[caption={Код метода \texttt{process\_input}.}, label={lst:process_input}]
|
||
def process_input(self, input_string: str) -> tuple[str, list[str]]:
|
||
current_state = self.initial_state
|
||
transitions_path = [current_state]
|
||
|
||
for char in input_string:
|
||
if char not in self.alphabet:
|
||
return f"Символ '{char}' не из алфавита", transitions_path
|
||
|
||
next_state = self._get_next_state(current_state, char)
|
||
|
||
if next_state is None:
|
||
return "Строка не соответствует", transitions_path
|
||
|
||
transitions_path.append(next_state)
|
||
current_state = next_state
|
||
|
||
return (
|
||
"Строка соответствует"
|
||
if current_state in self.final_states
|
||
else "Строка не соответствует"
|
||
), transitions_path
|
||
\end{lstlisting}
|
||
|
||
|
||
\subsection{Метод \texttt{generate\_random\_string}}
|
||
Метод \texttt{generate\_random\_string} принимает два параметра: \texttt{self} -- ссылку на объект класса, и вероятность остановки в финальном состоянии -- \texttt{stop\_probability} (\texttt{float}). Возвращает сгенерированную строку.
|
||
|
||
Шаг алгоритма заключается в следующем:
|
||
\begin{enumerate}
|
||
\item Проверяем условие остановки: если текущее состояние является финальным и случайное число оказывается меньше заданной вероятности остановки, то генерация завершается.
|
||
\item Случайным образом выбираем переход из текущего состояния в следующее.
|
||
\item Случайным образом выбираем символ из множества символов выбранного перехода.
|
||
\item Добавляем выбранный символ в результат и переходим в следующее состояние.
|
||
\end{enumerate}
|
||
|
||
\begin{lstlisting}[caption={Код метода \texttt{generate\_random\_string}.}, label={lst:generate_random_string}]
|
||
def generate_random_string(self, stop_probability: float = 0.3) -> str:
|
||
result = []
|
||
current_state = self.initial_state
|
||
|
||
while True:
|
||
if (
|
||
current_state in self.final_states
|
||
and random.random() < stop_probability
|
||
):
|
||
break
|
||
|
||
transition, next_state = random.choice(self.transitions[current_state])
|
||
|
||
char = random.choice(transition)
|
||
result.append(char)
|
||
current_state = next_state
|
||
|
||
return "".join(result)
|
||
\end{lstlisting}
|
||
|
||
|
||
|
||
\subsection{Функция \texttt{main}}
|
||
В функции \texttt{main} (листинг~\ref{lst:Main}) заданы параметры конечного автомата и реализован интерактивный интерфейс пользователя. Функция не принимает параметров и ничего не возвращает.
|
||
|
||
Пользователю доступны следующие команды:
|
||
|
||
\begin{itemize}
|
||
\item \texttt{check <строка>} -- проверяет, соответствует ли строка автомату.
|
||
\item \texttt{gen [<вероятность\_остановки>]} -- сгенерировать случайную строку.
|
||
\item \texttt{q} -- выход из программы.
|
||
\end{itemize}
|
||
|
||
\begin{lstlisting}[caption={Функция main.}, label={lst:Main}]
|
||
def main():
|
||
alphabet = set("+-0123456789.,eE")
|
||
initial_state = "S0"
|
||
final_states = {"S2", "S4", "S7", "S8", "S9"}
|
||
|
||
transitions = {
|
||
"S0": [("+-", "S1"), ("123456789", "S2"), ("0", "S8")],
|
||
"S1": [("123456789", "S2"), ("0", "S8")],
|
||
"S2": [("0123456789", "S2"), (".,", "S3"), ("eE", "S5")],
|
||
"S3": [("0123456789", "S4")],
|
||
"S4": [("0123456789", "S4"), ("eE", "S5")],
|
||
"S5": [("+-", "S6"), ("123456789", "S7"), ("0", "S9")],
|
||
"S6": [("123456789", "S7"), ("0", "S9")],
|
||
"S7": [("0123456789", "S7")],
|
||
"S8": [(".,", "S3")],
|
||
}
|
||
|
||
automaton = FiniteAutomaton(
|
||
transitions=transitions,
|
||
initial_state=initial_state,
|
||
final_states=final_states,
|
||
alphabet=alphabet,
|
||
)
|
||
|
||
print("Конечный автомат для распознавания форматов вещественных чисел")
|
||
print("=" * 60)
|
||
print("Варианты команд:")
|
||
print(" - check <строка> - проверить, соответствует ли строка автомату")
|
||
print(
|
||
" - gen [<вероятность_остановки>] - сгенерировать случайную строку (по умолчанию 0.3)"
|
||
)
|
||
print(" - q - выход из программы")
|
||
print("=" * 60)
|
||
|
||
while True:
|
||
command = input("\nВведите команду: ").strip()
|
||
|
||
if not command:
|
||
continue
|
||
|
||
parts = command.split()
|
||
cmd = parts[0].lower()
|
||
|
||
if cmd == "q":
|
||
print("Выход из программы.")
|
||
break
|
||
|
||
elif cmd == "check":
|
||
input_string = ""
|
||
if len(parts) > 1:
|
||
input_string = " ".join(parts[1:]).strip()
|
||
|
||
message, transitions = automaton.process_input(input_string)
|
||
|
||
print(f"Результат: {message}")
|
||
print("Путь переходов:", " -> ".join(transitions))
|
||
|
||
elif cmd == "gen":
|
||
stop_prob = 0.3
|
||
if len(parts) > 1:
|
||
try:
|
||
stop_prob = float(parts[1])
|
||
if not (0 < stop_prob <= 1):
|
||
raise ValueError(
|
||
"Вероятность должна быть больше 0 и меньше либо равна 1"
|
||
)
|
||
except ValueError as e:
|
||
print(f"Ошибка: {e}")
|
||
continue
|
||
|
||
random_string = automaton.generate_random_string(stop_prob)
|
||
print(f"Сгенерированная строка: {random_string}")
|
||
|
||
else:
|
||
print(f"Неизвестная команда: {cmd}")
|
||
\end{lstlisting}
|
||
|
||
\newpage
|
||
\section{Результаты работы программы}
|
||
Результаты работы программы представлены на Рис.~\ref{fig:result1}.
|
||
|
||
\begin{figure}[h!]
|
||
\centering
|
||
\includegraphics[width=1\linewidth]{img/result1.png}
|
||
\caption{Результаты работы программы.}
|
||
\label{fig:result1}
|
||
\end{figure}
|
||
|
||
На Рис.~\ref{fig:wrong} представлена реакция программы на некорректный пользовательский ввод.
|
||
|
||
\begin{figure}[h!]
|
||
\centering
|
||
\includegraphics[width=0.8\linewidth]{img/wrong.png}
|
||
\caption{Реакция программы на некорректный пользовательский ввод.}
|
||
\label{fig:wrong}
|
||
\end{figure}
|
||
|
||
|
||
\newpage
|
||
\section*{Заключение}
|
||
\addcontentsline{toc}{section}{Заключение}
|
||
В ходе выполнения лабораторной работы было построено регулярное выражение для распознавания различных форматов вещественных чисел, созданы недетерминированный и детерминированный конечные автоматы-распознаватели. На основе разработанного автомата была реализована программа, которая проверяет соответствие входной строки заданному формату и генерирует случайные корректные строки.
|
||
|
||
Из достоинств выполнения лабораторной работы можно выделить структурирование кода за счёт использования ООП. Вся логика работы с конечными автоматами вынесена в отдельный класс \texttt{FiniteAutomaton} с четко разделенными методами для проверки строк и генерации случайных строк. Создана удобная интерактивная консольная оболочка для взаимодействия с пользователем, позволяющая выполнять различные команды.
|
||
|
||
К недостаткам текущей реализации можно отнести следующие аспекты. Во-первых, переходы в автомате представлены в виде строк, содержащих допустимые символы, такой способ представления переходов не является самым оптимальным с точки зрения производительности. Во-вторых, в реализации генерации случайных строк вероятность остановки одинакова для всех финальных состояний, что может приводить к неравномерному распределению различных форматов чисел в генерируемых строках.
|
||
|
||
Функционал программы несложно масштабировать. Класс \texttt{FiniteAutomaton} может быть использован для работы с различными конечными автоматами-распознавателями. Для изменения распознаваемого языка достаточно задать новые параметры для автомата, не меняя базовую логику программы. Однако, текущая реализация работает только с символьными переходами, поэтому задать строчные переходы в виде, например, регулярных выражений не представляется возможным. Однако подобный функционал также несложно реализовать, взяв за основу существующий код.
|
||
|
||
На выполнение лабораторной работы ушло около 10 часов. Работа была выполнена в среде разработки Visual Studio Code. Программа написана на Python версии 3.10.
|
||
|
||
\newpage
|
||
\section*{Список литературы}
|
||
\addcontentsline{toc}{section}{Список литературы}
|
||
|
||
\vspace{-1.5cm}
|
||
\begin{thebibliography}{0}
|
||
\bibitem{vostrov}
|
||
Востров, А.В. Курс лекций по дисциплине <<Математическая логика>>. URL \url{https://tema.spbstu.ru/compiler/} (дата обращения 01.04.2025 г.)
|
||
\bibitem{lutz}
|
||
Лутц, М. Изучаем Python. 5-е изд. / М. Лутц. — СПб.: Питер, 2019. — 1216 с.
|
||
\bibitem{friedl}
|
||
Фридл, Дж. Регулярные выражения = Mastering Regular Expressions / Дж. Фридл. — СПб.: Питер, 2001. — 352 с. — (Библиотека программиста).
|
||
\end{thebibliography}
|
||
|
||
\end{document} |