Замкнутость регулярных языков относительно различных операций — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Доказательство)
м (rollbackEdits.php mass rollback)
 
(не показано 30 промежуточных версий 7 участников)
Строка 1: Строка 1:
==Основные операции==
+
== Теорема ==
Пусть <tex>L_1, L_2</tex> - регулярные языки над одним алфавитом <tex>\Sigma</tex>. Тогда следующие языки также являются регулярными:
+
{{Теорема
#<tex>L_1 \cup L_2</tex>
+
|statement=
#<tex>L_1 L_2</tex>
+
Пусть <tex>L_1, L_2</tex> {{---}} [[Регулярные языки: два определения и их эквивалентность|регулярные языки]] над одним алфавитом <tex>\Sigma</tex>. Тогда следующие языки также являются регулярными:
#<tex>L_1^*</tex>
+
#Языки, полученные путём применения следующих теоретико-множественных операций:
#<tex>\overline{L_1}</tex>
+
#*<tex>L_1 \cup L_2</tex>,
#<tex>L_1 \cap L_2</tex>
+
#*<tex>\overline{L_1}</tex>,
#<tex>L_1 \setminus L_2</tex>
+
#*<tex>L_1 \cap L_2</tex>,
===Доказательство===
+
#*<tex>L_1 \setminus L_2</tex>;
Свойства 1,2,3 непосредственно следуют из определения регулярных языков.
+
#<tex>L_1^*</tex>;
 +
#<tex>L_1 L_2</tex>;
 +
#<tex>\overset{\leftarrow}{L_1}</tex>.
 +
|proof=
 +
Как известно, [[Теорема Клини (совпадение классов автоматных и регулярных языков|классы регулярных и автоматных языков совпадают]]. Пусть языки <tex>L_1</tex> и <tex>L_2</tex> распознаются автоматами <tex>A_1 = \langle \Sigma , Q_1 , s_1 , T_1 , \delta_1 : Q_1 \times \Sigma \rightarrow 2^{Q_1} \rangle </tex> и <tex>A_2 = \langle \Sigma , Q_2 , s_2 , T_2 , \delta_2 : Q_2 \times \Sigma \rightarrow 2^{Q_2} \rangle </tex> соответственно.
 +
#
 +
#*<tex>L_1 \cup L_2</tex> является регулярным по определению [[Регулярные языки: два определения и их эквивалентность|регулярных языков]].
 +
#*Рассмотрим автомат <tex>A_1' = \langle \Sigma , Q_1 , s_1 , Q_1 \setminus T_1 , \delta_1 \rangle </tex>, то есть автомат <tex>A</tex>, в котором терминальные и нетерминальные состояния инвертированы (при таком построении следует помнить, что если в исходном автомате было опущено дьявольское состояние, его нужно явно добавить и сделать допускающим.) Очевидно, он допускает те и только те слова, которые не допускает автомат <tex>A_1</tex>, а значит, задаёт язык <tex>\overline{L_1}</tex>. Таким образом, <tex>\overline{L_1}</tex> {{---}} регулярный.
 +
#*<tex>L_1 \cap L_2 = \overline{\overline{L_1} \cup \overline{L_2}}</tex>. Тогда <tex>L_1 \cap L_2</tex> {{---}} регулярный. Также автомат для пересечения языков можно построить явно, используя конструкцию [[Прямое произведение ДКА|произведения автоматов]].
 +
#*<tex>L_1 \setminus L_2 = L_1 \cap \overline{L_2}</tex>. Тогда <tex>L_1 \setminus L_2</tex> {{---}} регулярный.
 +
#<tex>L_1^*</tex> является регулярным по определению [[Регулярные языки: два определения и их эквивалентность|регулярных языков]].
 +
#<tex>L_1 L_2</tex> также является регулярным по определению [[Регулярные языки: два определения и их эквивалентность|регулярных языков]].
 +
#Рассмотрим [[Автоматы_с_eps-переходами._Eps-замыкание|НКА c <tex>\varepsilon</tex>-переходами]] <tex>A_1' = \langle \Sigma, Q_1, s' , \lbrace s_1 \rbrace, \delta_1' \rangle </tex>, где <tex>\delta_1' (v,c) = \lbrace u | \delta_1(u,c) = v \rbrace </tex>; <tex>\delta_1'(s', \varepsilon) = \lbrace T_i \rbrace</tex>. Если в исходном автомате путь по <tex>\alpha</tex> из <tex>s_1</tex> приводил в терминальное состояние, то в новом автомате существует путь по <tex>\alpha</tex> из этого терминального состояния в <tex>s_1</tex> (и наоборот). Следовательно, этот автомат распознает в точности развернутые слова языка <tex>L_1</tex>. Тогда язык <tex>\overset{\leftarrow}{L_1}</tex> {{---}} регулярный.
 +
}}
 +
== Примеры доказательств ==
 +
=== Гомоморфизм цепочек ===
 +
{{Утверждение
 +
|id=st1
 +
|statement=
 +
<tex>L \subset \Sigma_1^*</tex> {{---}} регулярный , <tex>\varphi:\Sigma_1^* \rightarrow \Sigma_2^* </tex> {{---}} [[Основные определения: алфавит, слово, язык, конкатенация, свободный моноид слов; операции над языками#Гомоморфизм_языков | гомоморфизм цепочек]]. Тогда  <tex>\varphi(L)</tex> {{---}} регулярный.
 +
|proof=
 +
Рассмотрим [[Детерминированные_конечные_автоматы|ДКА]], распознающий <tex>L</tex>. Заменим в нем все переходы по символам на переходы по их образам при гомоморфизме. Полученный автомат (с переходами по строкам) распознает в точности <tex>\varphi(L)</tex> и [[Автоматы_с_eps-переходами._Eps-замыкание|имеет эквивалентный ДКА]].
 +
}}
 +
{{Утверждение
 +
|id=st2
 +
|statement=
 +
<tex>L \subset \Sigma_2^*</tex> {{---}} регулярный , <tex>\varphi:\Sigma_1^* \rightarrow \Sigma_2^* </tex> {{---}} [[Основные определения: алфавит, слово, язык, конкатенация, свободный моноид слов; операции над языками#Гомоморфизм_языков | гомоморфизм цепочек]]. Тогда  <tex>\varphi^{-1}(L)</tex> {{---}} регулярный.
 +
|proof=
 +
Рассмотрим [[Детерминированные_конечные_автоматы|ДКА]], распознающий <tex>L</tex>. Отследим для каждого состояния <tex>u</tex> и символа <tex>c</tex> строку <tex>\varphi(c)</tex>: <tex> \langle u,\varphi(c) \rangle \vdash^* \langle v,\varepsilon \rangle</tex> и положим <tex>\delta (u,c) = v</tex> в новом автомате (на том же множестве состояний). Автомат с построенной таким образом функцией переходов, очевидно, распознает слова языка <tex>\varphi^{-1}(L)</tex> и только их.
 +
}}
 +
=== Язык half(L) ===
 +
{{Определение
 +
|definition = Определим <tex>\mathrm{half(L)}</tex> как множество первых половин цепочек языка <tex>L</tex>, то есть множество <tex>\{ w \mid \exists x : wx \in L \land |w| = |x| \}</tex>. }}
 +
Например, если <tex>L = \{ \varepsilon, 0010, 011, 010110 \}</tex>, то <tex>\mathrm{half(L)} = \{ \varepsilon, 00, 010 \}</tex>. Заметим, что цепочки нечетной длины не влияют на <tex>\mathrm{half(L)}</tex>.
  
При доказательстве дальнейших свойств воспользуемся эквивалентностью регулярных и автоматных языков. Пусть языки <tex>L_1, L_2</tex> распознаются автоматами <tex>A_1 = \langle \Sigma , Q_1 , s_1 , T_1 , \delta_1 : Q_1 \times \Sigma \rightarrow 2^{Q_1} \rangle </tex> и <tex>A_2 = \langle \Sigma , Q_2 , s_2 , T_2 , \delta_2 : Q_2 \times \Sigma \rightarrow 2^{Q_2} \rangle </tex> соответственно.
+
{{Утверждение
 +
|id = st3
 +
|statement =
 +
Пусть <tex>L</tex> {{---}} [[Регулярные языки: два определения и их эквивалентность|регулярный язык]]. Тогда язык <tex>\mathrm{half(L)}</tex> также регулярен.
 +
|proof =
 +
Так как <tex>L</tex> {{---}} регулярный язык, то существует ДКА <tex>M = \langle \Sigma , Q , q_0 , F , \delta \rangle </tex>, допускающий его. Рассмотрим строку <tex>x</tex>. Для того, чтобы проверить, что <tex>x \in \mathrm{half(L)}</tex>, нам надо убедиться, что существует строка <tex>y</tex> такой же длины, что и <tex>x</tex>, которая, будучи сконкатенированной с <tex>x</tex>, даст строку из <tex>L</tex>, то есть если на вход автомату подать <tex>xy</tex>, то в конце обработки мы окажемся в терминальном состоянии. Предположим, что автомат, закончив обработку <tex>x</tex>, находится в состоянии <tex>q_i</tex>, то есть <tex>\delta(q_0, x) = q_i</tex>. Мы должны проверить, что существует строка <tex>y, |y| = |x|,</tex> которая ведет из состояния <tex>q_i</tex> до какого-нибудь терминального состояния <tex>M</tex>, то есть <tex>\delta(q_i, y) \in F</tex>.
  
4. Инвертируем множество допускающих состояний: рассмотрим автомат <tex>A_1' = \langle \Sigma , Q_1 , s_1 , Q_1 \setminus T_1 , \delta_1 : Q_1 \times \Sigma \rightarrow 2^{Q_1} \rangle </tex>. Очевидно, он допускает те и только те слова, которые не допускает автомат <tex>A_1</tex>.
+
Предположим, что мы прошли <tex>n</tex> вершин автомата, то есть <tex>|x| = n</tex>. Обозначим за <tex>S_n</tex> множество всех состояний, с которых можно попасть в терминальные за <tex>n</tex> шагов. Тогда <tex>q_i \in S_n \Leftrightarrow x \in \mathrm{half(L)}</tex>. Если мы сможем отслеживать <tex>S_n</tex> и <tex>q_i</tex>, то сможем определять, верно ли, что <tex>x \in \mathrm{half(L)}</tex>. Заметим, что <tex>S_0 \equiv F</tex>. Очевидно мы можем построить <tex>S_{n+1}</tex> зная <tex>S_n</tex> и <tex>\delta</tex>: <tex>S_{n+1} = prev(S_n) = \{ q \in Q \mid \exists a \in \Sigma, q' \in S_n, \delta(q, a) = q' \}</tex> {{---}} множество состояний, из которых есть переход в какое-либо состояние из <tex>S_n</tex> (по единственному символу). Теперь надо найти способ отслеживать и обновлять <tex>S_n</tex>.
  
При таком построении следует помнить, что если в исходном автомате было опущено дьявольское состояние, его нужно явно добавить и сделать допускающим.
+
Построим ДКА <tex>M'</tex>, который будет хранить эту информацию в своих состояниях. Определим <tex>Q' = Q \times 2^Q</tex>, то есть каждое состояние <tex>M'</tex> {{---}} это пара из одиночного состояния из <tex>M</tex> и множества состояний из <tex>M</tex>. Функцию перехода <tex>\delta'</tex> автомата <tex>M'</tex> определим так, чтобы если по какой-то строке <tex>x</tex> длины <tex>n</tex> в автомате <tex>M</tex> мы перешли в состояние <tex>q_i</tex>, то по этой же строке в автомате <tex>M'</tex> мы перейдем в состояние <tex>(q_i, S_n)</tex>, где <tex>S_n</tex> {{---}} множество состояний из <tex>M</tex>, определенное выше. Вспомним приведенную выше функцию <tex>prev(S_n) = S_{n+1}</tex>. С ее помощью мы можем определить функцию перехода следующим образом: <tex>\delta'((q, S), a) = (\delta(q, a), prev(S))</tex>. Начальное состояние <tex>q_0' = (q_0, S_0) = (q_0, F)</tex>. Множество терминальных состояний {{---}} <tex>F' = \{ (q, S) \mid q \in S, S \in 2^Q \}</tex>.
5.
+
 
 +
Теперь по индукции не сложно доказать, что <tex>\delta'(q_0', x) = (\delta(q_0, x), S_n)</tex>, где <tex>|x| = n</tex>. По определению множества терминальных вершин, автомат <tex>M'</tex> допускает строку <tex>x</tex> тогда и только тогда, когда <tex>\delta(q_0, x) \in S_n</tex>. Следовательно, автомат <tex>M'</tex> допускает язык <tex>\mathrm{half(L)}</tex>.Таким образом, мы построили ДКА, который допускает язык <tex>\mathrm{half(L)}</tex>. Следовательно, данный язык является регулярным.
 +
}}
 +
=== Язык cycle(L) ===
 +
{{Определение
 +
|definition = Определим <tex>\mathrm{cycle(L)}</tex> как множество <tex>\{ w \mid </tex> цепочку <tex>w</tex> можно представить в виде <tex>w = xy</tex>, где <tex>yx \in L \}</tex>. }}
 +
Например, если <tex>L = \{ 01, 011 \}</tex>, то <tex>\mathrm{cycle(L)} = \{ 01, 10, 011, 110, 101 \}</tex>.
 +
 
 +
{{Утверждение
 +
|id = st5
 +
|statement =
 +
Пусть <tex>L</tex> {{---}} [[Регулярные языки: два определения и их эквивалентность|регулярный язык]]. Тогда язык <tex>\mathrm{cycle(L)}</tex> также регулярен.
 +
|proof =
 +
[[Файл:Enfa_before.jpg|right|thumb|380px|Рис. 1. Разбиение автомата.]]
 +
[[Файл:Enfa-after.jpg|right|thumb|380px|Рис. 2. Перестроение.]]
 +
Так как <tex>L</tex> {{---}} регулярный язык, то существует допускающий его ДКА <tex>M = \langle \Sigma , Q , q_0 , F , \delta \rangle </tex>. Построим из <tex>M</tex> [[Автоматы_с_eps-переходами._Eps-замыкание|недетерминированный автомат с <tex>\varepsilon</tex>-переходами]] следующим образом: рассмотрим состояние <tex>q \in Q</tex>, из которого есть переходы в другие состояния (то есть начиная с <tex>q</tex> можно построить непустое слово, заканчивающееся в терминальной вершине). Тогда если какое-то слово проходит через это состояние, оно может быть зациклено таким образом, что его суффикс, начинающийся с <tex>q</tex>, станет префиксом нового слова, а префикс, заканчивающийся в <tex>q</tex> {{---}} суффиксом. Разделим автомат на две части <tex>A_1</tex> и <tex>A_2</tex> такие, что <tex>A_1</tex> будет содержать все вершины, из которых достижима <tex>q</tex>, а <tex>A_2</tex> {{---}} все вершины, которые достижимы из <tex>q</tex> (см. рис. 1). Заметим, что каждая вершина может содержаться в обеих частях одновременно, такое может случиться, если автомат <tex>M</tex> содержит циклы. Теперь перестроим автомат так, что он будет принимать слова "зацикленные" вокруг <tex>q</tex>, то есть начинающиеся с <tex>q</tex> и после достижения терминальной вершины продолжающиеся с <tex>q_0</tex> (см. рис. 2). Для этого стартовой вершиной сделаем <tex>q</tex> и построим от нее часть <tex>A_2</tex>. Теперь добавим состояние <tex>q_0</tex> и соединим с ним все терминальные состояния из <tex>A_2</tex> с помощью <tex>\varepsilon</tex>-переходов. Далее построим от <tex>q_0</tex> часть <tex>A_1</tex>. Добавим вершину <tex>q'</tex>, эквивалентную <tex>q</tex>, и сделаем ее терминальной. Данный автомат принимает слова, зацикленные вокруг выбранной вершины <tex>q</tex>. Мы хотим, чтобы автомат принимал слова, зацикленные вокруг любой такой <tex>q</tex>. Для этого создадим новую стартовую вершину <tex>q_0'</tex> и свяжем ее <tex>\varepsilon</tex>-переходами со всеми перестроенными автоматами (зацикленными вокруг всех подходящих <tex>q</tex>), в том числе и с изначальным автоматом. Построенный автомат допускает язык <tex>\mathrm{cycle(L)}</tex>, следовательно, данный язык является регулярным.
 +
}}
 +
[[Файл:Ex_1_before.jpg|left|thumb|260px|Рис. 3. Автомат, принимающий язык <tex>L</tex>.]]
 +
[[Файл:Ex_1_after.jpg|right|thumb|380px|Рис. 4. Автомат, принимающий язык <tex>\mathrm{cycle(L)}</tex>.]]
 +
Для лучшего понимания алгоритма перестроения автомата рассмотрим пример.
 +
 
 +
На рис. 3 представлен автомат, допускающий язык <tex>L = \{ ab, abb, ac \}</tex>. На рис. 4 показано, как этот автомат был перестроен. Были добавлены части, зацикленные  относительно вершин <tex>2</tex> и <tex>3</tex>. Появилась новая стартовая вершина <tex>0</tex>, которая связана <tex>\varepsilon</tex>-переходами с изначальным автоматом и его измененными версиями. Данный автомат распознает язык <tex>\mathrm{cycle(L)} = \{ ab, abb, ac, ba, bba, ca, bab \}</tex>: первые три слова распознает первая часть, которая совпадает с изначальным автоматом; следующие три {{---}} вторая, перестроенная относительно вершины <tex>2</tex>; последнее слово распознает третья часть, зацикленная относительно вершины <tex>3</tex>.
 +
 
 +
<br><br><br><br><br><br><br><br><br><br><br>
 +
 
 +
=== Язык alt(L, M) ===
 +
{{Определение
 +
|definition = Пусть <tex>w = w_1 w_2 \dots w_n</tex> и <tex>x = x_1 x_2 \dots x_n</tex>. Определим <tex>alternation(w, x) = w_1 x_1 w_2 x_2 \dots w_n x_n</tex>.}}
 +
Теперь распространим это определение:
 +
{{Определение
 +
|definition = Пусть <tex>L</tex> и <tex>M</tex> {{---}} два языка над одним алфавитом <tex>\Sigma</tex>. Тогда <tex>\mathrm{alt(L, M)} = \{ alternation(w, x) \mid |w| = |x|, w \in L, x \in M \}</tex>.}}
 +
Например, если <tex>L = \{ 10, 00, 111, 1001 \}</tex> и <tex>M = \{ 11, 0101 \}</tex>, то <tex>\mathrm{alt(L, M)} = \{ 1101, 0101, 10010011 \}</tex>.
 +
 
 +
{{Утверждение
 +
|id = st4
 +
|statement = Пусть <tex>L</tex> и <tex>M</tex> {{---}} [[Регулярные языки: два определения и их эквивалентность|регулярные языки]]. Тогда <tex>\mathrm{alt(L, M)}</tex> также является регулярным.
 +
|proof = Так как <tex>L</tex> и <tex>M</tex> {{---}} регулярные языки, то существуют ДКА <tex>D_L = \langle \Sigma , Q_L , q_{0L} , F_L, \delta_L \rangle</tex>, распознающий язык <tex>L</tex>, и <tex>D_M = \langle \Sigma , Q_M , q_{0M} , F_M, \delta_M \rangle</tex>, распознающий язык <tex>M</tex>. Построим автомат <tex>D_{alt}</tex>, который будет распознавать язык <tex>\mathrm{alt(L, M)}</tex>. Идея следующая: каждое состояние этого автомата будем описывать тремя значениями <tex>(p, q, b)</tex>, где <tex>p \in Q_L</tex>, <tex>q \in Q_M</tex> и <tex>b \in \{ 1, 0 \}</tex>. Нам нужно организовать чередование переходов по состояниям автоматов, то есть если мы на определенном шаге перешли от одного состояния автомата <tex>D_L</tex> до другого, то на следующем мы обязаны совершить переход по состояниям автомата <tex>D_M</tex>. Для этого нам нужно обновлять состояние одного автомата и при этом сохранять состояние другого для следующего перехода. Тут мы будем использовать третье значение: если <tex>b = 0</tex>, то будет двигаться по состояниям первого автомата, то есть значение <tex>p</tex> при переходе в новое состояние автомата <tex>D_{alt}</tex> поменяется, <tex>q</tex> останется неизменной, <tex>b</tex> станет <tex>1</tex>, если <tex>b = 1</tex>, то, соответственно, все наоборот. То есть у нас будут две функции перехода, выбирать нужную будем в зависимости от четности третьего параметра. Важно, что на каждом шаге мы инвертируем значение <tex>b</tex>, что гарантирует чередование. Определим автомат <tex>D_{alt} = \langle \Sigma, Q', q_0', F', \delta' \rangle</tex> следующим образом:
 +
# <tex>Q' = Q_L \times Q_M \times \{ 0, 1 \}</tex>
 +
# <tex>q_0' = (q_{0L}, q_{0M}, 0)</tex>
 +
# <tex>F' = F_L \times F_M \times \{ 0 \}</tex>
 +
# <tex>\delta'((p, q, 0), a) = (\delta_L(p, a), q, 1)</tex> и <tex>\delta'((p, q, 1), a) = (p, \delta_M(q, a), 0)</tex>
 +
Стартовая вершина имеет третий параметр <tex>b = 0</tex>, так как первое значение должно быть получено из автомата <tex>D_L</tex>. Аналогично все терминальные вершины должны иметь то же значение последнего параметра, так как количество переходов должно быть четным и последний переход должен был быть осуществлен по автомату <tex>D_M</tex>. Функция перехода <tex>\delta'</tex> использует <tex>\delta_L</tex> для получения нечетных символов и <tex>\delta_M</tex> для четных. Таким образом, <tex>D_{alt}</tex> состоит из чередующихся символов <tex>D_L</tex> и <tex>D_M</tex>. При этом <tex>D_{alt}</tex> принимает <tex>w</tex> тогда и только тогда, когда <tex>D_L</tex> последовательно принимает все нечетные символы <tex>w</tex> и <tex>D_M</tex> {{---}} все четные, а так же <tex>w</tex> имеет четную длину. Следовательно, <tex>D_{alt}</tex> распознает язык <tex>\mathrm{alt(L, M)}</tex>, что доказывает, что <tex>\mathrm{alt(L, M)}</tex> является регулярным.
 +
}}
 +
[[Файл:Alt ex 1.jpg|left|thumb|265px|Рис. 5. Автоматы для языков <tex>L</tex> и <tex>M</tex>.]]
 +
[[Файл:Alt ex 2.jpg|right|thumb|390px|Рис. 6. Автомат, принимающий язык <tex>\mathrm{alt(L, M)}</tex>.]]
 +
Чтобы более наглядно показать, как строится автомат <tex>D_{alt}</tex>, разберем пример. Пусть <tex>L = \{ 1, 11 \}</tex> и <tex>M = \{ 00 \}</tex> (см. рис. 5). Все состояния нового автомата представлены на рис. 6. Стартовая вершина <tex>q_0' = (1, 1, 0)</tex>, множество терминальных вершин {{---}} <tex>F' = \{ (2, 3, 0), (3, 3, 0) \}</tex>. Мы видим, что построенные по функции <tex>\delta'</tex> переходы на каждом шаге меняют состояние одного из автоматов, а именно того, по которому происходит переход, сохраняя состояние другого для следующего шага. Таким образом, каждый следующий символ получен из автомата, отличного от того, что был использован на предыдущем шаге. Декартово произведение состояний гарантирует, что мы рассмотрим все состояния и переходы изначальных автоматов. Для данного примера мы получаем, что <tex>\mathrm{alt(L, M)} = \{ 1010 \}</tex>.
 +
 
 +
<br><br><br><br><br><br><br>
 +
 
 +
== См. также ==
 +
* [[Анализ свойств регулярных языков (пустота, совпадение, включение, конечность, подсчет числа слов)]]
 +
* [[Теорема Клини (совпадение классов автоматных и регулярных языков)]]
 +
 
 +
== Источники ==
 +
* Хопкрофт Д., Мотвани Р., Ульман Д. "Введение в теорию автоматов, языков и вычислений", 2-е изд. : Пер. с англ. — М.:Издательский дом «Вильямс», 2002. {{---}} С. 149 — ISBN 5-8459-0261-4
 +
[[Категория: Теория формальных языков]]
 +
[[Категория: Автоматы и регулярные языки]]
 +
[[Категория: Свойства конечных автоматов]]

Текущая версия на 19:30, 4 сентября 2022

Теорема

Теорема:
Пусть [math]L_1, L_2[/math]регулярные языки над одним алфавитом [math]\Sigma[/math]. Тогда следующие языки также являются регулярными:
  1. Языки, полученные путём применения следующих теоретико-множественных операций:
    • [math]L_1 \cup L_2[/math],
    • [math]\overline{L_1}[/math],
    • [math]L_1 \cap L_2[/math],
    • [math]L_1 \setminus L_2[/math];
  2. [math]L_1^*[/math];
  3. [math]L_1 L_2[/math];
  4. [math]\overset{\leftarrow}{L_1}[/math].
Доказательство:
[math]\triangleright[/math]

Как известно, классы регулярных и автоматных языков совпадают. Пусть языки [math]L_1[/math] и [math]L_2[/math] распознаются автоматами [math]A_1 = \langle \Sigma , Q_1 , s_1 , T_1 , \delta_1 : Q_1 \times \Sigma \rightarrow 2^{Q_1} \rangle [/math] и [math]A_2 = \langle \Sigma , Q_2 , s_2 , T_2 , \delta_2 : Q_2 \times \Sigma \rightarrow 2^{Q_2} \rangle [/math] соответственно.

    • [math]L_1 \cup L_2[/math] является регулярным по определению регулярных языков.
    • Рассмотрим автомат [math]A_1' = \langle \Sigma , Q_1 , s_1 , Q_1 \setminus T_1 , \delta_1 \rangle [/math], то есть автомат [math]A[/math], в котором терминальные и нетерминальные состояния инвертированы (при таком построении следует помнить, что если в исходном автомате было опущено дьявольское состояние, его нужно явно добавить и сделать допускающим.) Очевидно, он допускает те и только те слова, которые не допускает автомат [math]A_1[/math], а значит, задаёт язык [math]\overline{L_1}[/math]. Таким образом, [math]\overline{L_1}[/math] — регулярный.
    • [math]L_1 \cap L_2 = \overline{\overline{L_1} \cup \overline{L_2}}[/math]. Тогда [math]L_1 \cap L_2[/math] — регулярный. Также автомат для пересечения языков можно построить явно, используя конструкцию произведения автоматов.
    • [math]L_1 \setminus L_2 = L_1 \cap \overline{L_2}[/math]. Тогда [math]L_1 \setminus L_2[/math] — регулярный.
  1. [math]L_1^*[/math] является регулярным по определению регулярных языков.
  2. [math]L_1 L_2[/math] также является регулярным по определению регулярных языков.
  3. Рассмотрим НКА c [math]\varepsilon[/math]-переходами [math]A_1' = \langle \Sigma, Q_1, s' , \lbrace s_1 \rbrace, \delta_1' \rangle [/math], где [math]\delta_1' (v,c) = \lbrace u | \delta_1(u,c) = v \rbrace [/math]; [math]\delta_1'(s', \varepsilon) = \lbrace T_i \rbrace[/math]. Если в исходном автомате путь по [math]\alpha[/math] из [math]s_1[/math] приводил в терминальное состояние, то в новом автомате существует путь по [math]\alpha[/math] из этого терминального состояния в [math]s_1[/math] (и наоборот). Следовательно, этот автомат распознает в точности развернутые слова языка [math]L_1[/math]. Тогда язык [math]\overset{\leftarrow}{L_1}[/math] — регулярный.
[math]\triangleleft[/math]

Примеры доказательств

Гомоморфизм цепочек

Утверждение:
[math]L \subset \Sigma_1^*[/math] — регулярный , [math]\varphi:\Sigma_1^* \rightarrow \Sigma_2^* [/math] гомоморфизм цепочек. Тогда [math]\varphi(L)[/math] — регулярный.
[math]\triangleright[/math]
Рассмотрим ДКА, распознающий [math]L[/math]. Заменим в нем все переходы по символам на переходы по их образам при гомоморфизме. Полученный автомат (с переходами по строкам) распознает в точности [math]\varphi(L)[/math] и имеет эквивалентный ДКА.
[math]\triangleleft[/math]
Утверждение:
[math]L \subset \Sigma_2^*[/math] — регулярный , [math]\varphi:\Sigma_1^* \rightarrow \Sigma_2^* [/math] гомоморфизм цепочек. Тогда [math]\varphi^{-1}(L)[/math] — регулярный.
[math]\triangleright[/math]
Рассмотрим ДКА, распознающий [math]L[/math]. Отследим для каждого состояния [math]u[/math] и символа [math]c[/math] строку [math]\varphi(c)[/math]: [math] \langle u,\varphi(c) \rangle \vdash^* \langle v,\varepsilon \rangle[/math] и положим [math]\delta (u,c) = v[/math] в новом автомате (на том же множестве состояний). Автомат с построенной таким образом функцией переходов, очевидно, распознает слова языка [math]\varphi^{-1}(L)[/math] и только их.
[math]\triangleleft[/math]

Язык half(L)

Определение:
Определим [math]\mathrm{half(L)}[/math] как множество первых половин цепочек языка [math]L[/math], то есть множество [math]\{ w \mid \exists x : wx \in L \land |w| = |x| \}[/math].

Например, если [math]L = \{ \varepsilon, 0010, 011, 010110 \}[/math], то [math]\mathrm{half(L)} = \{ \varepsilon, 00, 010 \}[/math]. Заметим, что цепочки нечетной длины не влияют на [math]\mathrm{half(L)}[/math].

Утверждение:
Пусть [math]L[/math]регулярный язык. Тогда язык [math]\mathrm{half(L)}[/math] также регулярен.
[math]\triangleright[/math]

Так как [math]L[/math] — регулярный язык, то существует ДКА [math]M = \langle \Sigma , Q , q_0 , F , \delta \rangle [/math], допускающий его. Рассмотрим строку [math]x[/math]. Для того, чтобы проверить, что [math]x \in \mathrm{half(L)}[/math], нам надо убедиться, что существует строка [math]y[/math] такой же длины, что и [math]x[/math], которая, будучи сконкатенированной с [math]x[/math], даст строку из [math]L[/math], то есть если на вход автомату подать [math]xy[/math], то в конце обработки мы окажемся в терминальном состоянии. Предположим, что автомат, закончив обработку [math]x[/math], находится в состоянии [math]q_i[/math], то есть [math]\delta(q_0, x) = q_i[/math]. Мы должны проверить, что существует строка [math]y, |y| = |x|,[/math] которая ведет из состояния [math]q_i[/math] до какого-нибудь терминального состояния [math]M[/math], то есть [math]\delta(q_i, y) \in F[/math].

Предположим, что мы прошли [math]n[/math] вершин автомата, то есть [math]|x| = n[/math]. Обозначим за [math]S_n[/math] множество всех состояний, с которых можно попасть в терминальные за [math]n[/math] шагов. Тогда [math]q_i \in S_n \Leftrightarrow x \in \mathrm{half(L)}[/math]. Если мы сможем отслеживать [math]S_n[/math] и [math]q_i[/math], то сможем определять, верно ли, что [math]x \in \mathrm{half(L)}[/math]. Заметим, что [math]S_0 \equiv F[/math]. Очевидно мы можем построить [math]S_{n+1}[/math] зная [math]S_n[/math] и [math]\delta[/math]: [math]S_{n+1} = prev(S_n) = \{ q \in Q \mid \exists a \in \Sigma, q' \in S_n, \delta(q, a) = q' \}[/math] — множество состояний, из которых есть переход в какое-либо состояние из [math]S_n[/math] (по единственному символу). Теперь надо найти способ отслеживать и обновлять [math]S_n[/math].

Построим ДКА [math]M'[/math], который будет хранить эту информацию в своих состояниях. Определим [math]Q' = Q \times 2^Q[/math], то есть каждое состояние [math]M'[/math] — это пара из одиночного состояния из [math]M[/math] и множества состояний из [math]M[/math]. Функцию перехода [math]\delta'[/math] автомата [math]M'[/math] определим так, чтобы если по какой-то строке [math]x[/math] длины [math]n[/math] в автомате [math]M[/math] мы перешли в состояние [math]q_i[/math], то по этой же строке в автомате [math]M'[/math] мы перейдем в состояние [math](q_i, S_n)[/math], где [math]S_n[/math] — множество состояний из [math]M[/math], определенное выше. Вспомним приведенную выше функцию [math]prev(S_n) = S_{n+1}[/math]. С ее помощью мы можем определить функцию перехода следующим образом: [math]\delta'((q, S), a) = (\delta(q, a), prev(S))[/math]. Начальное состояние [math]q_0' = (q_0, S_0) = (q_0, F)[/math]. Множество терминальных состояний — [math]F' = \{ (q, S) \mid q \in S, S \in 2^Q \}[/math].

Теперь по индукции не сложно доказать, что [math]\delta'(q_0', x) = (\delta(q_0, x), S_n)[/math], где [math]|x| = n[/math]. По определению множества терминальных вершин, автомат [math]M'[/math] допускает строку [math]x[/math] тогда и только тогда, когда [math]\delta(q_0, x) \in S_n[/math]. Следовательно, автомат [math]M'[/math] допускает язык [math]\mathrm{half(L)}[/math].Таким образом, мы построили ДКА, который допускает язык [math]\mathrm{half(L)}[/math]. Следовательно, данный язык является регулярным.
[math]\triangleleft[/math]

Язык cycle(L)

Определение:
Определим [math]\mathrm{cycle(L)}[/math] как множество [math]\{ w \mid [/math] цепочку [math]w[/math] можно представить в виде [math]w = xy[/math], где [math]yx \in L \}[/math].

Например, если [math]L = \{ 01, 011 \}[/math], то [math]\mathrm{cycle(L)} = \{ 01, 10, 011, 110, 101 \}[/math].

Утверждение:
Пусть [math]L[/math]регулярный язык. Тогда язык [math]\mathrm{cycle(L)}[/math] также регулярен.
[math]\triangleright[/math]
Рис. 1. Разбиение автомата.
Рис. 2. Перестроение.
Так как [math]L[/math] — регулярный язык, то существует допускающий его ДКА [math]M = \langle \Sigma , Q , q_0 , F , \delta \rangle [/math]. Построим из [math]M[/math] недетерминированный автомат с [math]\varepsilon[/math]-переходами следующим образом: рассмотрим состояние [math]q \in Q[/math], из которого есть переходы в другие состояния (то есть начиная с [math]q[/math] можно построить непустое слово, заканчивающееся в терминальной вершине). Тогда если какое-то слово проходит через это состояние, оно может быть зациклено таким образом, что его суффикс, начинающийся с [math]q[/math], станет префиксом нового слова, а префикс, заканчивающийся в [math]q[/math] — суффиксом. Разделим автомат на две части [math]A_1[/math] и [math]A_2[/math] такие, что [math]A_1[/math] будет содержать все вершины, из которых достижима [math]q[/math], а [math]A_2[/math] — все вершины, которые достижимы из [math]q[/math] (см. рис. 1). Заметим, что каждая вершина может содержаться в обеих частях одновременно, такое может случиться, если автомат [math]M[/math] содержит циклы. Теперь перестроим автомат так, что он будет принимать слова "зацикленные" вокруг [math]q[/math], то есть начинающиеся с [math]q[/math] и после достижения терминальной вершины продолжающиеся с [math]q_0[/math] (см. рис. 2). Для этого стартовой вершиной сделаем [math]q[/math] и построим от нее часть [math]A_2[/math]. Теперь добавим состояние [math]q_0[/math] и соединим с ним все терминальные состояния из [math]A_2[/math] с помощью [math]\varepsilon[/math]-переходов. Далее построим от [math]q_0[/math] часть [math]A_1[/math]. Добавим вершину [math]q'[/math], эквивалентную [math]q[/math], и сделаем ее терминальной. Данный автомат принимает слова, зацикленные вокруг выбранной вершины [math]q[/math]. Мы хотим, чтобы автомат принимал слова, зацикленные вокруг любой такой [math]q[/math]. Для этого создадим новую стартовую вершину [math]q_0'[/math] и свяжем ее [math]\varepsilon[/math]-переходами со всеми перестроенными автоматами (зацикленными вокруг всех подходящих [math]q[/math]), в том числе и с изначальным автоматом. Построенный автомат допускает язык [math]\mathrm{cycle(L)}[/math], следовательно, данный язык является регулярным.
[math]\triangleleft[/math]
Рис. 3. Автомат, принимающий язык [math]L[/math].
Рис. 4. Автомат, принимающий язык [math]\mathrm{cycle(L)}[/math].

Для лучшего понимания алгоритма перестроения автомата рассмотрим пример.

На рис. 3 представлен автомат, допускающий язык [math]L = \{ ab, abb, ac \}[/math]. На рис. 4 показано, как этот автомат был перестроен. Были добавлены части, зацикленные относительно вершин [math]2[/math] и [math]3[/math]. Появилась новая стартовая вершина [math]0[/math], которая связана [math]\varepsilon[/math]-переходами с изначальным автоматом и его измененными версиями. Данный автомат распознает язык [math]\mathrm{cycle(L)} = \{ ab, abb, ac, ba, bba, ca, bab \}[/math]: первые три слова распознает первая часть, которая совпадает с изначальным автоматом; следующие три — вторая, перестроенная относительно вершины [math]2[/math]; последнее слово распознает третья часть, зацикленная относительно вершины [math]3[/math].












Язык alt(L, M)

Определение:
Пусть [math]w = w_1 w_2 \dots w_n[/math] и [math]x = x_1 x_2 \dots x_n[/math]. Определим [math]alternation(w, x) = w_1 x_1 w_2 x_2 \dots w_n x_n[/math].

Теперь распространим это определение:

Определение:
Пусть [math]L[/math] и [math]M[/math] — два языка над одним алфавитом [math]\Sigma[/math]. Тогда [math]\mathrm{alt(L, M)} = \{ alternation(w, x) \mid |w| = |x|, w \in L, x \in M \}[/math].

Например, если [math]L = \{ 10, 00, 111, 1001 \}[/math] и [math]M = \{ 11, 0101 \}[/math], то [math]\mathrm{alt(L, M)} = \{ 1101, 0101, 10010011 \}[/math].

Утверждение:
Пусть [math]L[/math] и [math]M[/math]регулярные языки. Тогда [math]\mathrm{alt(L, M)}[/math] также является регулярным.
[math]\triangleright[/math]

Так как [math]L[/math] и [math]M[/math] — регулярные языки, то существуют ДКА [math]D_L = \langle \Sigma , Q_L , q_{0L} , F_L, \delta_L \rangle[/math], распознающий язык [math]L[/math], и [math]D_M = \langle \Sigma , Q_M , q_{0M} , F_M, \delta_M \rangle[/math], распознающий язык [math]M[/math]. Построим автомат [math]D_{alt}[/math], который будет распознавать язык [math]\mathrm{alt(L, M)}[/math]. Идея следующая: каждое состояние этого автомата будем описывать тремя значениями [math](p, q, b)[/math], где [math]p \in Q_L[/math], [math]q \in Q_M[/math] и [math]b \in \{ 1, 0 \}[/math]. Нам нужно организовать чередование переходов по состояниям автоматов, то есть если мы на определенном шаге перешли от одного состояния автомата [math]D_L[/math] до другого, то на следующем мы обязаны совершить переход по состояниям автомата [math]D_M[/math]. Для этого нам нужно обновлять состояние одного автомата и при этом сохранять состояние другого для следующего перехода. Тут мы будем использовать третье значение: если [math]b = 0[/math], то будет двигаться по состояниям первого автомата, то есть значение [math]p[/math] при переходе в новое состояние автомата [math]D_{alt}[/math] поменяется, [math]q[/math] останется неизменной, [math]b[/math] станет [math]1[/math], если [math]b = 1[/math], то, соответственно, все наоборот. То есть у нас будут две функции перехода, выбирать нужную будем в зависимости от четности третьего параметра. Важно, что на каждом шаге мы инвертируем значение [math]b[/math], что гарантирует чередование. Определим автомат [math]D_{alt} = \langle \Sigma, Q', q_0', F', \delta' \rangle[/math] следующим образом:

  1. [math]Q' = Q_L \times Q_M \times \{ 0, 1 \}[/math]
  2. [math]q_0' = (q_{0L}, q_{0M}, 0)[/math]
  3. [math]F' = F_L \times F_M \times \{ 0 \}[/math]
  4. [math]\delta'((p, q, 0), a) = (\delta_L(p, a), q, 1)[/math] и [math]\delta'((p, q, 1), a) = (p, \delta_M(q, a), 0)[/math]
Стартовая вершина имеет третий параметр [math]b = 0[/math], так как первое значение должно быть получено из автомата [math]D_L[/math]. Аналогично все терминальные вершины должны иметь то же значение последнего параметра, так как количество переходов должно быть четным и последний переход должен был быть осуществлен по автомату [math]D_M[/math]. Функция перехода [math]\delta'[/math] использует [math]\delta_L[/math] для получения нечетных символов и [math]\delta_M[/math] для четных. Таким образом, [math]D_{alt}[/math] состоит из чередующихся символов [math]D_L[/math] и [math]D_M[/math]. При этом [math]D_{alt}[/math] принимает [math]w[/math] тогда и только тогда, когда [math]D_L[/math] последовательно принимает все нечетные символы [math]w[/math] и [math]D_M[/math] — все четные, а так же [math]w[/math] имеет четную длину. Следовательно, [math]D_{alt}[/math] распознает язык [math]\mathrm{alt(L, M)}[/math], что доказывает, что [math]\mathrm{alt(L, M)}[/math] является регулярным.
[math]\triangleleft[/math]
Рис. 5. Автоматы для языков [math]L[/math] и [math]M[/math].
Рис. 6. Автомат, принимающий язык [math]\mathrm{alt(L, M)}[/math].

Чтобы более наглядно показать, как строится автомат [math]D_{alt}[/math], разберем пример. Пусть [math]L = \{ 1, 11 \}[/math] и [math]M = \{ 00 \}[/math] (см. рис. 5). Все состояния нового автомата представлены на рис. 6. Стартовая вершина [math]q_0' = (1, 1, 0)[/math], множество терминальных вершин — [math]F' = \{ (2, 3, 0), (3, 3, 0) \}[/math]. Мы видим, что построенные по функции [math]\delta'[/math] переходы на каждом шаге меняют состояние одного из автоматов, а именно того, по которому происходит переход, сохраняя состояние другого для следующего шага. Таким образом, каждый следующий символ получен из автомата, отличного от того, что был использован на предыдущем шаге. Декартово произведение состояний гарантирует, что мы рассмотрим все состояния и переходы изначальных автоматов. Для данного примера мы получаем, что [math]\mathrm{alt(L, M)} = \{ 1010 \}[/math].








См. также

Источники

  • Хопкрофт Д., Мотвани Р., Ульман Д. "Введение в теорию автоматов, языков и вычислений", 2-е изд. : Пер. с англ. — М.:Издательский дом «Вильямс», 2002. — С. 149 — ISBN 5-8459-0261-4