From 13895062f6bd72af879627b06f4f7fd29a5c8648 Mon Sep 17 00:00:00 2001 From: Anna-er Date: Tue, 4 Nov 2025 07:33:21 +0300 Subject: [PATCH 1/2] Add section on closure properties of Regular languages --- tex/RegularLanguages.tex | 96 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/tex/RegularLanguages.tex b/tex/RegularLanguages.tex index e07051a..919f24e 100644 --- a/tex/RegularLanguages.tex +++ b/tex/RegularLanguages.tex @@ -805,18 +805,100 @@ \section{Лемма о накачке} \section{Замкнутость регулярных языков относительно теоретико-множественных операций} \begin{theorem} - Регулярные языки замкнуты относительно перечисленных ниже операций. + Класс регулярных языков над алфавитом $\Sigma$ замкнут относительно следующих теоретико-множественных операций: \begin{enumerate} - \item Пересечение - \item Дополнение - \item Обращение - \item Разность + \item Объединение: если $L_1, L_2$~--- регулярные, то $L_1 \cup L_2$~--- регулярный; + \item Пересечение: если $L_1, L_2$~--- регулярные, то $L_1 \cap L_2$~--- регулярный; + \item Дополнение: если $L$~--- регулярный, то $\overline{L}$~--- регулярный; + \item Разность: если $L_1, L_2$~--- регулярные, то $L_1 \setminus L_2$~--- регулярный. \end{enumerate} \end{theorem} -Для пересечения построим автомат. +\begin{proof} + Пусть $L_1$ и $L_2$ распознаются конечными автоматами над одним алфавитом $\Sigma$: + \[ + M_1 = \langle Q^1, Q_S^1, Q_F^1, \delta^1, \Sigma \rangle, \qquad + M_2 = \langle Q^2, Q_S^2, Q_F^2, \delta^2, \Sigma \rangle. + \] + + + \paragraph{1. Объединение.} + Построим недетерминированный автомат с $\varepsilon$-переходами, + вводя новое начальное состояние $q_0$, из которого по $\varepsilon$ можно попасть + в начальные состояния обоих автоматов: + \[ + M = \langle Q^1 \cup Q^2 \cup \{q_0\},\; \{q_0\},\; Q_F^1 \cup Q_F^2,\; \delta,\; \Sigma \rangle, + \] + где $\delta$ совпадает с $\delta^1$ и $\delta^2$ на соответствующих состояниях, а дополнительно + \[ + \delta(q_0, \varepsilon) = Q_S^1 \cup Q_S^2. + \] + Тогда $L(M) = L_1 \cup L_2$. -Идея доказательства, что мы построили именно пересечение. + \paragraph{2. Пересечение.} + Пусть автоматы детерминированы. Построим автомат произведения: + \[ + M_3 = \langle Q^1 \times Q^2,\; Q_S^1 \times Q_S^2,\; Q_F^1 \times Q_F^2,\; \delta^3,\; \Sigma \rangle, + \] + где переходы определяются как: + \[ + \delta^3\big((q^1, q^2), t\big) = \big(\delta^1(q^1, t),\; \delta^2(q^2, t)\big). + \] + Тогда + \[ + w \in L(M_3) \iff w \in L_1 \text{ и } w \in L_2, + \] + следовательно, $L(M_3) = L_1 \cap L_2$. + + \paragraph{3. Дополнение.} + Пусть $M = \langle Q, \{q_S\}, Q_F, \delta, \Sigma \rangle$~--- детерминированный полный автомат. + Построим автомат + \[ + M' = \langle Q, \{q_S\}, Q \setminus Q_F, \delta, \Sigma \rangle. + \] + Очевидно, $L(M') = \overline{L(M)}$. + + \paragraph{4. Разность.} + Разность выражается через пересечение и дополнение: + \[ + L_1 \setminus L_2 = L_1 \cap \overline{L_2}. + \] + Регулярные языки замкнуты относительно обеих операций, следовательно, и относительно разности тоже замкнуты. +\end{proof} + +\begin{example}[Конструкция произведения]\label{ex:product-automaton} + Пусть $M_1$ и $M_2$~--- детерминированные автоматы над алфавитом $\Sigma=\{a,b\}$. + В автомате $M_1$ есть переходы + $q^1 \xrightarrow{a} p^1$, $q^1 \xrightarrow{b} p^1$ и $p^1 \xrightarrow{b} p^1$, + а в автомате $M_2$~--- переходы + $q^2 \xrightarrow{a} q^2$ и $q^2 \xrightarrow{b} p^2$. + Тогда в автомате произведения $M_1 \times M_2$ возникают переходы: + \begin{align*} + (q^1, q^2) \xrightarrow{a} (p^1, q^2), \quad + (p^1, q^2) \xrightarrow{b} (p^1, p^2), \quad + (q^1, q^2) \xrightarrow{b} (p^1, p^2), + \end{align*} + что проиллюстрировано на рис.~\ref{fig:product-automaton-example}. + Принимающими являются пары из принимающих состояний обоих автоматов. +\end{example} + + +\begin{marginfigure} + \centering + \scalebox{0.64}{ + \begin{tikzpicture} + \node[elliptic state,initial] (q0) {$(q^1, q^2)$}; + \node[elliptic state] (p0) [right=of q0] {$(p^1, q^2)$}; + \node[elliptic state,accepting] (p1) [below right=of p0] {$(p^1, p^2)$}; + + \path[->] + (q0) edge[bend left, above] node {$a$} (p0) + (p0) edge[bend left, right] node {$b$} (p1) + (q0) edge[bend right, below left] node[swap] {$b$} (p1); + \end{tikzpicture}} + \caption{Пример переходов в произведении автоматов.} + \label{fig:product-automaton-example} +\end{marginfigure} From a6f4c199a1df3dbfc6d91c09dabf91a23f43ac5a Mon Sep 17 00:00:00 2001 From: Anna-er Date: Tue, 4 Nov 2025 07:42:25 +0300 Subject: [PATCH 2/2] Fix typos and refactor --- tex/RegularLanguages.tex | 215 +++++++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 74 deletions(-) diff --git a/tex/RegularLanguages.tex b/tex/RegularLanguages.tex index 919f24e..4bef0fe 100644 --- a/tex/RegularLanguages.tex +++ b/tex/RegularLanguages.tex @@ -42,8 +42,8 @@ \section{Регулярные выражения} \item пустое множество $\varnothing$; \item множество из пустой цепочки $\varepsilon$; \item множество из одного символа $t$, $t \in \Sigma$; - \item объединение регулярных выражения (множеств) $R_1 \mid R_2$, где $R_1$ и $R_2$~--- регулярные выражения; - \item конкатенация регулярных выражения (множеств) $R_1 \cdot R_2$, где $R_1$ и $R_2$~--- регулярные выражения; + \item объединение регулярных выражений (множеств) $R_1 \mid R_2$, где $R_1$ и $R_2$~--- регулярные выражения; + \item конкатенация регулярных выражений (множеств) $R_1 \cdot R_2$, где $R_1$ и $R_2$~--- регулярные выражения; \item замыкание клини $R^*$, где $R$~--- регулярное выражение; \item группирующие скобки $(R)$, где $R$~--- регулярное выражение. \end{itemize} @@ -98,7 +98,7 @@ \section{Регулярные выражения} \section{Конечные автоматы} \emph{Конечный автомат} (Finite State Machine, FSM)~--- вычислительная машина, которая имеет конечный набор состояний и может совершать переходы между ними, основываясь на прочитанных входных данных. -Важно отметить, что ни какой дополнительной памяти классический конечный автомат не имеет и дополнительных действий (кроме чтения входной ленты) не производит % +Важно отметить, что никакой дополнительной памяти классический конечный автомат не имеет и дополнительных действий (кроме чтения входной ленты) не производит % \sidenote{Cуществуют автоматы с записью на отдельную (выходную) ленту (например, автоматы Мили~\cite{6771467}) и другие, основанные на конечных автоматах, вычислители, производящие дополнительные действия. Например, расширенные конечные автоматы (Extended Finite State Machine), которые умеют работать с памятью (переменными)~\cite{Alagar2011, foster.ea:efsm:2020}.}. @@ -192,8 +192,8 @@ \section{Конечные автоматы} Для описания работы автомата $M = \langle Q, Q_S, Q_F, \delta, \Sigma \rangle$ нам понадобятся следующие выделенные типы конфигураций. \begin{itemize} - \item Стартовая конфигурация $c_s = (q_s,w)$, $q_s \in Q_S$, $w$ --- цепочка, которая подаётся на вход автомату. - Для недетерминированного автомата естественно задать множество стартовых конфигурация $C_S = \bigcup_{q_s \in Q_S} (q_s,w)$. + \item Стартовая конфигурация $c_s = (q_s,w)$, $q_s \in Q_S$, $w$~--- цепочка, которая подаётся на вход автомату. + Для недетерминированного автомата естественно задать множество стартовых конфигураций $C_S = \bigcup_{q_s \in Q_S} (q_s,w)$. \item Финальная (принимающая) конфигурация $c_f = (q_f,\varepsilon)$, $q_f \in Q_F$. \end{itemize} @@ -229,7 +229,7 @@ \section{Конечные автоматы} В множестве появилась конфигурация, содержащая финальное состояние. Однако цепочка не прочитана до конца, потому продолжаем работу. Из нулевого состояния нет переходов по символу \texttt{b}, потому соответствующая конфигурация не породит новых. - Из второй же конфигурации возможет переход по символу \texttt{b} и по $\varepsilon$: + Из второй же конфигурации возможен переход по символу \texttt{b} и по $\varepsilon$: \[ \{ (0,\texttt{bb}), (1,\texttt{bb})\} \Rightarrow \{ (0,\texttt{bb}), (2,\texttt{b})\} \] @@ -252,8 +252,8 @@ \section{Конечные автоматы} \begin{itemize} \item $Q$~--- конечное множество состояний, $Q \neq \varnothing$; \item $q_S \in Q$~--- стартовое состояние; - \item $Q_F \subseteq Q$~--- множество финальных состояний\sidenote{Обатите внимание, стартовое состояниеможет входить в множество финальных.}, $Q_F \neq \varnothing$; - \item $\delta \subseteq Q \times \Sigma \times Q$~--- функция переходов\sidenote{При данном определении автомат будет ещё и \emph{полным}: для каждого состояния и каждого символа определён переход. Часто встречается вариант, когда функция переходов частично определёна: для некоторых состояний не определены переходы для некоторых символов.}; + \item $Q_F \subseteq Q$~--- множество финальных состояний\sidenote{Обатите внимание, стартовое состояние может входить в множество финальных.}\vspace{1.2\baselineskip}, $Q_F \neq \varnothing$; + \item $\delta \subseteq Q \times \Sigma \times Q$~--- функция переходов\sidenote{При данном определении автомат будет ещё и \emph{полным}: для каждого состояния и каждого символа определён переход. Часто встречается вариант, когда функция переходов частично определена: для некоторых состояний не определены переходы для некоторых символов.}; \item $\Sigma$~--- конечный алфавит. \end{itemize} \end{definition} @@ -269,7 +269,7 @@ \section{Конечные автоматы} \item $q_S = 0$; \item $Q_F = \{1\}$; \item $\Sigma = \{a,b\}$; - \item $\delta$ определена следующим образом\sidenote{В нашем случае автомат не будет полным, так что $\delta$ --- частично определённая функция.}: + \item $\delta$ определена следующим образом\sidenote{В нашем случае автомат не будет полным, так что $\delta$~--- частично определённая функция.}: \begin{alignat*}{6} \delta(0,a) =& 1 \qquad & \delta(1,a) =& 1 \\ \delta(1,b) =& 2 \qquad & \delta(2,b) =& 1 @@ -354,7 +354,7 @@ \section{Производные для регулярных языков} \item $\partial_t(x) = \varnothing \text{ для } t \neq x$ \item $\partial_t(R_1 \cdot R_2) = \partial_t(R_1) \cdot (R_2) \mid \mathcal{V}(R_1) \cdot \partial_t(R_2)$ \item $\partial_t(R_1 \mid R_2) = \partial_t(R_1) \mid \partial_t(R_2)$ - \item $\partial_t(R^*) =$\sidenote{Интересное упражнение --- показать это, расписав по определению звезду Клини.} $ \partial_t(R)\cdot R^*$. + \item $\partial_t(R^*) =$\sidenote{Интересное упражнение~--- показать это, расписав по определению звезду Клини.} $ \partial_t(R)\cdot R^*$. \end{itemize} \begin{example} @@ -409,51 +409,50 @@ \section{Производные для регулярных языков} \section{Построение конечного автомата по регулярному выражению} -Конечные автоматы и регулярные выражения --- два способа задать оди и тот же класс языков. -Для того, чтобы убедиться в их равной выразительной силе, для начала, научимся строить конечный автомат по регулярному выражению. -Использование производных позволит нам сразу построить полный детерминированный автомат% -\sidenote{Существуют и другие алгоритмы построения автомата по регулярному выражению. Например, алгоритм Томпсона~\cite{10.1145/363347.363387} или алгоритм Глушкова~\cite{Glushkov1961}. -Как правило, каждый алгоритм строит автомат со специфичными свойствами: детерминированный или нет, с $\varepsilon$-переходами или без них.}. +Конечные автоматы и регулярные выражения~--- два способа задать один и тот же класс языков. +Чтобы убедиться в их равной выразительной силе, начнём с построения конечного автомата по регулярному выражению. +Использование производных позволит нам сразу получить \emph{полный детерминированный автомат}% +\sidenote{Существуют и другие алгоритмы построения автомата по регулярному выражению, например, алгоритм Томпсона~\cite{10.1145/363347.363387} или алгоритм Глушкова~\cite{Glushkov1961}. +Каждый из них имеет свои особенности: некоторые строят недетерминированные автоматы, другие используют $\varepsilon$-переходы.}. -Состояниям автомата будут соответствовать регулярные выражения: если (в результирующем автомате) состояние выбрать стартовым, то получившийся автомат будет распознавать язык, задаваемый соответствующим регулярным выражением. -Чтобы автомат был минимальным нам будет необходимо проверять на эквивалентность языки, задаваемые регулярными выражениями и не дублировать состояния. -Хотя задача проверки эквивалентности регулярных языков разрешима, на практике, в рамках данного алгоритма, чаще пользуются более быстро проверяемой структурной эквивалентностью~\sidenote{На деле, при проверке структурной эквивалентности дополнительно пользуются знаниями об ассоциативности некоторых операций и другимим свойствами выражений.} регулярных выражений~\sidecite{OWENS_REPPY_TURON_2009}. +Состояниям автомата будем сопоставлять регулярные выражения. +Если выбрать некоторое состояние автомата в качестве стартового, то получившийся автомат будет распознавать язык, задаваемый соответствующим регулярным выражением. +Чтобы избежать дублирования состояний, необходимо проверять эквивалентность языков, которые задаются этими выражениями. +Хотя задача проверки эквивалентности регулярных языков разрешима, на практике в данном алгоритме используют более простую \emph{структурную эквивалентность} регулярных выражений% +\sidenote{При проверке структурной эквивалентности обычно учитывают ассоциативность, коммутативность и идемпотентность некоторых операций, чтобы избежать избыточных различий.}~\sidecite{OWENS_REPPY_TURON_2009}. + + +Таким образом, можно сформулировать следующий алгоритм построения автомата по регулярному выражению $R$. -Таким образом, получится алгоритм с рабочим множеством, который состоит в следующем. -В качестве стартового состояния возьмём состояние, соответствующее исходному регулярному выражению. -В рабочее множество добавим стартовое состояние. -Далее, пока рабочее множество не пусто, в цикле повторяем следующие шаги. \begin{enumerate} - \item Берём из множества очередное состояние $q$, соответствующее регулярному выражению $R_q$. - \item Для всех символов из алфавита вычисляем производные $R_q$:. - \item Для всех построенных состояний проверяем, существует ли уже + \item В качестве стартового состояния берём выражение $R$ и добавляем его в рабочее множество $W$. + \item Пока $W$ не пусто: + \begin{enumerate} + \item Извлекаем очередное состояние $q$, которому соответствует регулярное выражение $R_q$. + \item Для каждого символа $a \in \Sigma$ вычисляем производную $\partial_a(R_q)$. + \item Если полученное выражение задаёт новый (ранее не встречавшийся) язык, добавляем соответствующее состояние. + \item Если $\emph{IsNull}(R_q) = \emph{true}$, помечаем состояние как финальное. + \item Добавляем ребро $q \xrightarrow{a} q'$ для каждого вычисленного перехода. + \end{enumerate} \end{enumerate} -Берём очередное необработанное состояние, по каждому символу из алфавита берём производную соответствующего ему регулярного выражения. -Добавляем получившееся состояние (если ещё не было такого). -Если состояние isNullable, то помечаем его финальным. -Добавляем ребро. В результате получим полный детерминированный конечный автомат\sidenote{Формально, если честно проверять равенство языков, можно получить минимальный, но на практике это сложно. Но часто всё же достаточно близко к минимальному получается.}. \begin{example} - Построим автомат по регулярному выражению $a(a \mid (b \ b))^*$. - Состояние, помеченное данным выражением назначим стартовым и вычислим производные по символам. - Так как $\emph{IsNull}(a(a \mid (b \ b))^*) = \emph{false}$, финальным данное состояние не является. - Вычислим производные исходного выражения по всем символам из алфавита. - Проверим, что получившиеся выражения задают различные языки и добавим соответствующие переходы. - Одно из состояний соответствует пустому языку. - Данное состояние будет <<дьявольским>> или <<стоком>>. - Второе, помеченное $(a \mid (b \ b))^*$, соответствует языку, содержащему пустую цепочку. - То есть это состояние должно быть финальным. - В результате данного шага мы получим автомат, представленный на рисунке~\ref{fig:regexp_to_dfa_example_step_1}. - - Продолжаем работу. - Возьмём производные для двух новых состояний и проделаем все соответствующие процедуры. - Уже видно, почему одно из состояний (соответствующее пустому языку), является <<дьявольским>>: попав в него однажды, остаёмся в нём навсегда. - Обработаем аналогичным образом новые состояния. Итог~\ref{fig:regexp_to_dfa_example_step_2} - - Обработаем аналогичным образом новые состояния. Итог~\ref{fig:regexp_to_dfa_example_step_3} + Рассмотрим построение автомата для регулярного выражения $a(a \mid (b \ b))^*$. + + Стартовому состоянию соответствует выражение $a(a \mid (b \ b))^*$. + Так как $\emph{IsNull}(a(a \mid (b \ b))^*) = \emph{false}$, это состояние не является финальным. + Вычислим производные по всем символам из алфавита: + \[ + \partial_a(a(a \mid (b \ b))^*) = (a \mid (b \ b))^*, \quad + \partial_b(a(a \mid (b \ b))^*) = \varnothing. + \] + В результате появляются два новых состояния: $(a \mid (b \ b))^*$ и $\varnothing$. + Второе состояние соответствует пустому языку и является \emph{поглощающим} (или \emph{дьявольским}) состоянием, а первое~--- финальным, так как $\emph{IsNull}((a \mid (b \ b))^*) = \emph{true}$. + На рисунке~\ref{fig:regexp_to_dfa_example_step_1} показан автомат после первого шага алгоритма. + \begin{marginfigure} \begin{center} \scalebox{0.64}{ @@ -469,6 +468,14 @@ \section{Построение конечного автомата по регу \caption{Построение автомата по регулярному выражению с помощью производных: первый шаг} \label{fig:regexp_to_dfa_example_step_1} \end{marginfigure} + + На следующем шаге вычислим производные для состояния $(a \mid (b \ b))^*$: + \[ + \partial_a((a \mid (b \ b))^*) = (a \mid (b \ b))^*, \quad + \partial_b((a \mid (b \ b))^*) = b(a \mid (b \ b))^*. + \] + Таким образом, появляется новое состояние $b(a \mid (b \ b))^*$, а автомат принимает вид, показанный на рисунке~\ref{fig:regexp_to_dfa_example_step_2}. + \begin{marginfigure} \begin{center} \scalebox{0.64}{ @@ -489,6 +496,14 @@ \section{Построение конечного автомата по регу \caption{Построение автомата по регулярному выражению с помощью производных: второй шаг} \label{fig:regexp_to_dfa_example_step_2} \end{marginfigure} + + Осталось обработать состояние $b(a \mid (b \ b))^*$: + \[ + \partial_a(b(a \mid (b \ b))^*) = \varnothing, \quad + \partial_b(b(a \mid (b \ b))^*) = (a \mid (b \ b))^*. + \] + В результате добавляются новые переходы, и автомат принимает окончательный вид (рисунок~\ref{fig:regexp_to_dfa_example_step_3}). + \begin{marginfigure} \begin{center} \scalebox{0.64}{ @@ -513,8 +528,8 @@ \section{Построение конечного автомата по регу \end{marginfigure} \end{example} -В результате построения мы получили автомат, очень похожий на автомат из примера~\ref{example:DFA}. -Единственная разница заключается в том, что автомат из примера не является полным. +В результате построения получен автомат, близкий по структуре к автомату из примера~\ref{example:DFA}. +Разница лишь в том, что приведённый здесь автомат является полным. Само же сходство не случайно: автоматы действительно задают один и тот же регулярный язык. \section{Построение регулярного выражения по конечному автомату} @@ -523,8 +538,22 @@ \section{Построение регулярного выражения по к Регулярное выражение будем строить по недетерминированному автомату специального вида: потребуем, чтобы у него было ровно одно стартовое состояние и ровно одно финальное% \sidenote{Любой автомат можно привести к такому виду. Предположим, что в автомате два стартовых состояния $q_0^s$ и $q_1^s$. -Добавим новое сотояние $q_s$, назначим его стартовым, добавим переходы $q_s \xrightarrow{\varepsilon} q_0^s$ и $q_s \xrightarrow{\varepsilon} q_1^s$, уберём $q_0^s$ и $q_1^s$ из стартовых. +Добавим новое состояние $q_s$, назначим его стартовым, добавим переходы $q_s \xrightarrow{\varepsilon} q_0^s$ и $q_s \xrightarrow{\varepsilon} q_1^s$, уберём $q_0^s$ и $q_1^s$ из стартовых. Аналогично можно поступить и с финальными состояниями.}. + +Будем в цикле выполнять последовательно две операции. +\begin{enumerate} + \item Объединение параллельных рёбер. + \item Устранение состояния $v$. За один шаг можем устранить любое состояние кроме стартового или финального. +\end{enumerate} +Цикл повторяется до тех пор, пока в автомате не останется ровно два состояния: стартовое и финальное. +После завершения цикла необходимо ещё раз объединить параллельные рёбра. +После этого, по полученному автомату можно построить итоговое регулярное выражение. + +Параллельные рёбра вида $p_i \xrightarrow{R_1} q_i, \ldots, p_i \xrightarrow{R_k} q_i$ объединяются в одно ребро вида $p_i \xrightarrow{R_1 \mid \ldots \mid R_k} q_i$, метка которого~--- объединение всех регулярных выражений с параллельных рёбер. +Пример такого объединения приведён на рисунках~\ref{fa:fa1} и~\ref{fa:fa2}. + + \begin{marginfigure} \begin{center} \begin{tikzpicture} @@ -559,18 +588,6 @@ \section{Построение регулярного выражения по к \label{fa:fa2} \end{marginfigure} -Будем в цикле выполнять последовательно две операции. -\begin{enumerate} - \item Объединение параллельных рёбер. - \item Устранение состояния $v$. За один шаг можем устранить любое состояние кроме стартового или финального. -\end{enumerate} -Цикл повторяется до тех пор, пока в автомате не останется ровно два состояния: стартовое и финальное. -После завершения цикла необходимо ещё раз объединить параллельные рёбра. -После этого, по полученному автомату можно построить итоговое регулярное выражение. - -Параллельные рёбра вида $p_i \xrightarrow{R_1} q_i, \ldots, p_i \xrightarrow{R_k} q_i$ объединяются в одно ребро вида $p_i \xrightarrow{R_1 \mid \ldots \mid R_k} q_i$, метка которого --- объединение всех регулярных выражений с параллельных рёбер. -Пример такого объединения приведён на рисунках~\ref{fa:fa1} и~\ref{fa:fa2}. - Операция устранения состояния $v$ устроена следующим образом. Рассмотрим три типа рёбер. \begin{enumerate} @@ -682,8 +699,8 @@ \section{Построение регулярного выражения по к После устранения состояния \circled{2} получим автомат, представленный на рисунке~\ref{fig:nfa_to_regexp}. Теперь наш автомат принял вид, соответствующий представленному на рисунке~\ref{fig:fa_to_regexp_final}, и можно выписать результирующее регулярное выражение, которое будет иметь следующий вид% - \sidenote{Конесно, получившесея выражение не <<минимально>>: дослаточно легко можно придумать более простое и компактное регулярное выражение, задающее тот же самый язык. - Но алгоритм нам и не обещал ни каких дополнительных свойств получившегося выражения.}: + \sidenote{Конечно, получившесея выражение не <<минимально>>: дослаточно легко можно придумать более простое и компактное регулярное выражение, задающее тот же самый язык. + Но алгоритм нам и не обещал никаких дополнительных свойств получившегося выражения.}: \[ a^*(a \ (b \ b)^* \ \varepsilon \ a^*)^* \ a \ (b \ b)^* = a^*(a \ (b \ b)^* \ a^*)^* \ a \ (b \ b)^*. @@ -713,13 +730,13 @@ \section{Лево(право)линейные грамматики} Наложив некоторые ограничения на внешний вид правил грамматики можно получить грамматики, задающие регулярные языки. \begin{definition}[Леволинейная грамматика] - Грамматика $G=\langle \Sigma, N, P, S \rangle$ называется леволиненйной, если все её правила имеют вид + Грамматика $G=\langle \Sigma, N, P, S \rangle$ называется леволинейной, если все её правила имеют вид \[N_i \to \alpha w,\] где $N_i \in N$, $\alpha \in \{\varepsilon\} \cup N$, $w \in \Sigma ^*$. \end{definition} \begin{definition}[Праволинейная грамматика] - Грамматика $G=\langle \Sigma, N, P, S \rangle$ называется праволиненйной, если все её правила имеют вид + Грамматика $G=\langle \Sigma, N, P, S \rangle$ называется праволинейной, если все её правила имеют вид \[N_i \to w \alpha,\] где $N_i \in N$, $\alpha \in \{\varepsilon\} \cup N$, $w \in \Sigma ^*$. \end{definition} @@ -741,23 +758,73 @@ \section{Лево(право)линейные грамматики} N_i & \to tN_l \\ N_l & \to wN_k, \end{align*} -после чего аналогично преобразуется правило для $N_l$. +а если цепочка $w$ содержит более одного символа, то преобразование продолжается аналогичным образом для нетерминала $N_l$ (и далее), пока все правила не примут нужный вид. -\begin{example}[Построение граммтики по автомату] +\begin{example}[Построение грамматики по автомату] Построим грамматику по автомату, представленному на рисунке~\ref{fig:dfa_example}. -В автомате три состояние, соответственно, в грамматике будет три нетерминала: $q_0, q_1, q_2$. -Нетерминал $q_0$ будет стартовым, так как он соответствует стартовому состоянию. +В автомате три состояния, соответственно, в грамматике будет три нетерминала: $Q_0, Q_1, Q_2$. +Нетерминал $Q_0$ будет стартовым, так как он соответствует стартовому состоянию. Правила грамматики формируются на основе переходов в автомате и правил для финальных состояний, и в нашем случае будут следующими: \begin{align*} - q_0 \to a \ q_1 \quad & \quad q_1 \to a \ q_1 \\ - q_1 \to b \ q_2 \quad & \quad q_2 \to b \ q_1 \\ - \quad & \quad q_1 \to \varepsilon. + Q_0 \to a Q_1 \quad & \quad Q_1 \to a Q_1 \\ + Q_1 \to b Q_2 \quad & \quad Q_2 \to b Q_1 \\ + \quad & \quad Q_1 \to \varepsilon. \end{align*} +Таким образом, полученная грамматика порождает тот же язык, что и данный автомат. \end{example} +\begin{marginfigure} + \begin{center} + \begin{tikzpicture} + \node[state,initial] (S) {$S$}; + \node[state,accepting,right=of S] (N1) {$N_1$}; + \node[state,above=of N1] (N2) {$N_2$}; + + \path[->] + (S) edge[bend left, above] node{$a$} (N1) + (N1) edge[loop below, below] node{$a$} (N1) + (N1) edge[bend left, left] node{$b$} (N2) + (N2) edge[bend left, right] node{$b$} (N1); + \end{tikzpicture} + \end{center} + \caption{Автомат, построенный по грамматике $S \to aN_1$, $N_1 \to aN_1 \mid bbN_1 \mid \varepsilon$. + Эквивалентен автомату из примера~\ref{example:DFA}.} + \label{fig:grammar_to_dfa} +\end{marginfigure} + \begin{example}[Построение автомата по грамматике] -Возьмём грамматику -$S \to a N_1; N_1 \to a \ N_1; N_1 \to b \ b \ N_1$ +Рассмотрим грамматику: +\begin{align*} + S \to a N_1, \quad + N_1 \to a N_1 \mid b b N_1 \mid \varepsilon. +\end{align*} +Построим по ней конечный автомат. + +Множество состояний автомата соответствует нетерминалам грамматики, а также добавим дополнительное состояние для цепочки из двух символов $b$: +\begin{align*} + Q = \{S, N_1, N_2\}. +\end{align*} +Алфавит: $\Sigma = \{a, b\}$. +Переходы автомата определяются на основе правил грамматики: +\begin{align*} +\delta = \{ +(S, a, N_1),\; +(N_1, a, N_1),\; +(N_1, b, N_2),\; +(N_2, b, N_1) +\}. +\end{align*} +Финальные состояния~--- те, для которых в грамматике есть правило с правой частью $\varepsilon$: +\begin{align*} +Q_F = \{ N_1 \}. +\end{align*} +Таким образом, получаем автомат +\begin{align*} +M = \langle \Sigma, Q, S, Q_F, \delta \rangle, +\end{align*} +распознающий язык всех цепочек, начинающихся с символа $a$ и содержащих произвольное количество $a$ и пар $bb$ после него. + +Построенный автомат показан на рисунке~\ref{fig:grammar_to_dfa}. Обратите внимание, что этот автомат эквивалентен автомату из примера~\ref{example:DFA}, только обозначения состояний изменены: $S \leftrightarrow 0$, $N_1 \leftrightarrow 1$, $N_2 \leftrightarrow 2$. \end{example} \section{Лемма о накачке}