diff --git a/tex/CYK_for_CFPQ.tex b/tex/CYK_for_CFPQ.tex index 0341979..7cfced5 100644 --- a/tex/CYK_for_CFPQ.tex +++ b/tex/CYK_for_CFPQ.tex @@ -6,33 +6,31 @@ \chapter{CYK для вычисления КС запросов}\label{chpt:CFPQ_ \section{Алгоритм CYK}\label{sect:lin_CYK} -Алгоритм CYK (Cocke-Younger-Kasami) --- один из классических алгоритмов синтаксического анализа. Его асимптотическая сложность в худшем случае --- $O(n^3 * |N|)$, где $n$ --- длина входной строки, а $N$ --- количество нетерминалов во входной граммтике~\cite{Hopcroft+Ullman/79/Introduction}. +Алгоритм CYK (Cocke-Younger-Kasami) --- один из классических алгоритмов синтаксического анализа. Его асимптотическая сложность в худшем случае --- $O(n^3 * |N|)$, где $n$ --- длина входной строки, а $N$ --- количество нетерминалов во входной грамматике~\cite{Hopcroft+Ullman/79/Introduction}. -Для его применения необходимо, чтобы подаваемая на вход грамматика находилась в Нормальной Форме Хомского (НФХ)~\ref{section:CNF}. Других ограничений нет и, следовательно,данный алгоритм применим для работы с произвольными контекстно-своболными языками. +Для его применения необходимо, чтобы подаваемая на вход грамматика находилась в Нормальной Форме Хомского (НФХ)~\ref{section:CNF}. Других ограничений нет и, следовательно, данный алгоритм применим для работы с произвольными контекстно-своболными языками. В основе алгоритма лежит принцип динамического программирования. Используются два соображения: \begin{enumerate} -\item Для правила вида $A \to a$ очевидно, что из $A$ выводится $\omega$ (с применением этого правила) тогда и только тогда, когда $a = \omega$: - +\item Из нетерминала $A$ выводится цепочка $\omega$ при помощи правила $A \to a$ тогда и только тогда, когда $a= \omega$: \[ A \derives \omega \iff \omega = a \] -\item Для правила вида $A \to B C$ понятно, что из $A$ выводится $\omega$ (с применением этого правила) тогда и только тогда, когда существуют две цепочки $\omega_1$ и $\omega_2$ такие, что $\omega_1$ выводима из $B$, $\omega_2$ выводима из $C$ и при этом $\omega = \omega_1 \omega_2$: - +\item Из нетерминала $A$ выводится цепочка $\omega$ при помощи правила $A \to B C$ тогда и только тогда, когда существуют две цепочки $\omega_1$ и $\omega_2$ такие, что $\omega_1$ выводима из $B$, $\omega_2$ выводима из $C$ и при этом $\omega = \omega_1 \omega_2$: \[ A \derives[] B C \derives \omega \iff \exists \omega_1, \omega_2 : \omega = \omega_1 \omega_2, B \derives \omega_1, C \derives \omega_2 \] -Или в терминах позиций в строке: - +Переформулируем эти утверждения в терминах позиций в строке: \[ A \derives[] B C \derives \omega \iff \exists k \in [1 \dots |\omega|] : B \derives \omega[1 \dots k], C \derives \omega[k+1 \dots |\omega|] \] \end{enumerate} -В процессе работы алгоритма заполняется булева трехмерная матрица $M$ размера $n \times n \times |N|$ таким образом, что $$M[i, j, A] = true \iff A \derives \omega[i \dots j]$$. +В процессе работы алгоритма заполняется булева трехмерная матрица $M$ размера $n \times n \times |N|$ таким образом, что +\[M[i, j, A] = true \iff A \derives \omega[i \dots j]\]. Первым шагом инициализируем матрицу, заполнив значения $M[i, i, A]$: @@ -43,7 +41,6 @@ \section{Алгоритм CYK}\label{sect:lin_CYK} Далее используем динамику: на шаге $m > 1$ предполагаем, что ячейки матрицы $M[i', j', A]$ заполнены для всех нетерминалов $A$ и пар $i', j': j' - i' < m$. Тогда можно заполнить ячейки матрицы $M[i, j, A] \text{, где } j - i = m$ следующим образом: - \[ M[i, j, A] = \bigvee_{A \to B C}^{}{\bigvee_{k=i}^{j-1}{M[i, k, B] \wedge M[k, j, C]}} \] По итогу работы алгоритма значение в ячейке $M[0, |\omega|, S]$, где $S$ --- стартовый нетерминал грамматики, отвечает на вопрос о выводимости цепочки $\omega$ в грамматике. @@ -239,7 +236,7 @@ \section{Алгоритм для графов на основе CYK} \begin{itemize} \item Как и раньше, с помощью продукций вида \[A \to a \text{, где } A \in N, a \in \Sigma\] заменяем терминалы на ребрах входного графа на множества нетерминалов, из которых они выводятся. -\item Добавляем в каждую вершину петлю, помеченную множеством нетерминалов для которых в данной граммтике есть правила вида $$A \to \varepsilon\text{, где } A \in N.$$ +\item Добавляем в каждую вершину петлю, помеченную множеством нетерминалов для которых в данной грамматике есть правила вида $$A \to \varepsilon\text{, где } A \in N.$$ \end{itemize} Затем используем матрицу смежности получившегося графа (обозначим ее $M$) в качестве начального значения. Дальнейший ход алгоритма можно описать псевдокодом, представленным в листинге~\ref{alg:graphParseCYK}. @@ -271,7 +268,7 @@ \section{Алгоритм для графов на основе CYK} \end{algorithmic} \end{algorithm} -После завершения алгоритма, если в некоторой ячейке результируюшей матрицы с номером $(i, j)$ находятся стартовый нетерминал, то это означает, что существует путь из вершины $i$ в вершину $j$, удовлетворяющий данной грамматике. Таким образом, полученная матрица является ответом для задачи достижимости для заданных графа и граммтики. +После завершения алгоритма, если в некоторой ячейке результируюшей матрицы с номером $(i, j)$ находятся стартовый нетерминал, то это означает, что существует путь из вершины $i$ в вершину $j$, удовлетворяющий данной грамматике. Таким образом, полученная матрица является ответом для задачи достижимости для заданных графа и грамматики. \begin{example} \label{CYK_algorithm_ex} @@ -474,12 +471,12 @@ \section{Алгоритм для графов на основе CYK} m = r = \{(A,0,1),(A,1,2),(A,2,0),(B,2,3),(B,3,2)\} $$ - \textbf{Итерации внешнего цикла.} Будем считеть, что $r$ и $m$ --- упорядоченные списки и $pick$ возврпщает его голову, оставляя хвост. + \textbf{Итерации внешнего цикла.} Будем считеть, что $r$ и $m$ --- упорядоченные списки и $pick$ возвращает его голову, оставляя хвост. Новые элементы добавляются в конец. \begin{enumerate} \item Обрабатываем $(A,0,1)$. Ни один из вложенных циклов не найдёт новых путей, так как для рассматриваемого ребра есть только две возможности достроить путь: $2 \xrightarrow{A} 0 \xrightarrow{A} 1$ и $0 \xrightarrow{A} 1 \xrightarrow{A} 2$ - и ни одна из соответствующих строк не выводтся в заданной граммтике. + и ни одна из соответствующих строк не выводтся в заданной грамматике. \item Перед началом итерации $$ m = \{(A,1,2),(A,2,0),(B,2,3),(B,3,2)\}, diff --git a/tex/Context-Free_Languages.tex b/tex/Context-Free_Languages.tex index a1152eb..8558414 100644 --- a/tex/Context-Free_Languages.tex +++ b/tex/Context-Free_Languages.tex @@ -7,7 +7,7 @@ \chapter{Контекстно-свободные грамматики и язы \begin{itemize} \item $\Sigma$ --- это терминальный алфавит; \item $N$ --- это нетерминальный алфавит; - \item $P$ --- это множество правил или продукций, таких что каждая продукция имеет вид $N_i \to \alpha$, где $N_i \in N$ и $\alpha \in \{\Sigma \cup N\}^* \cup {\varepsilon}$; + \item $P$ --- это множество правил (продукций), таких что каждая продукция имеет вид $N_i \to \alpha$, где $N_i \in N$ и $\alpha \in \{\Sigma \cup N\}^* \cup {\varepsilon}$; \item $S$ --- стартовый нетерминал. Отметим, что $\Sigma \cap N = \varnothing$. \end{itemize} @@ -15,16 +15,12 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} Грамматика, задающая язык целых чисел в двоичной записи без лидирующих нулей: $G = \langle \{0, 1, -\}, \{S, N, A\}, P, S \rangle$, где $P$ определено следующим образом: - -\[ -\begin{array}{rcl} -S& \rightarrow & 0 \mid N \mid - N \\ -N& \rightarrow & 1 A \\ -A& \rightarrow & 0 A \mid 1 A \mid \varepsilon\\ -\end{array} -\] +\begin{align*} + S & \rightarrow 0 \mid N \mid - N \\ + N & \rightarrow 1 A \\ + A & \rightarrow 0 A \mid 1 A \mid \varepsilon\\ +\end{align*} \end{example} - При спецификации грамматики часто опускают множество терминалов и нетерминалов, оставляя только множество правил. При этом нетерминалы часто обозначаются прописными латинскими буквами, терминалы --- строчными, а стартовый нетерминал обозначается буквой~$S$. Мы будем следовать этим обозначениям, если не указано иное. @@ -41,9 +37,9 @@ \chapter{Контекстно-свободные грамматики и язы \end{definition} \begin{definition} -\textit{Отношение выводимости} является рефлексивно-транзитивным замыканием отношения непосредственной выводимости +\textit{Отношение выводимости} является рефлексивно-транзитивным замыканием отношения непосредственной выводимости; обозначается $\derives$. \begin{itemize} - \item $\alpha \derives \beta$ означает $\exists \gamma_0, \dots \gamma_k: \ \alpha \derives[] \gamma_0 \derives[] \gamma_1 \derives[] \dots \derives[] \gamma_{k-1} \derives[] \gamma_{k} \derives[] \beta$ + \item $\alpha \derives \beta$ означает $\exists \gamma_0, \dots \gamma_k \in \{\Sigma \cup N\}^* \cup {\varepsilon}: \ \alpha \derives[] \gamma_0 \derives[] \gamma_1 \derives[] \dots \derives[] \gamma_{k-1} \derives[] \gamma_{k} \derives[] \beta$ \item Транзитивность: $\forall \alpha, \beta, \gamma \in \{\Sigma \cup N\}^* \cup {\varepsilon}: \ \alpha \derives \beta, \beta \derives \gamma \Rightarrow \alpha \derives \gamma$ \item Рефлексивность: $\forall \alpha \in \{\Sigma \cup N\}^* \cup {\varepsilon}: \ \alpha \derives \alpha$ \item $\alpha \derives \beta$ --- $\alpha$ выводится из $\beta$ @@ -55,16 +51,14 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} Пример вывода цепочки $-1101$ в грамматике: - - \[ - \begin{array}{rcl} - S& \rightarrow & 0 \mid N \mid - N \\ - N& \rightarrow & 1 A \\ - A& \rightarrow & 0 A \mid 1 A \mid \varepsilon\\ - \end{array} - \] - - \[ S \Rightarrow - N \Rightarrow - 1 A \Rightarrow - 1 1 A \derives - 1 1 0 1 A \Rightarrow - 1 1 0 1 \] +\begin{align*} + S &\rightarrow 0 \mid N \mid - N \\ + N &\rightarrow 1 A \\ + A &\rightarrow 0 A \mid 1 A \mid \varepsilon\\ +\end{align*} +\[ + S \Rightarrow - N \Rightarrow - 1 A \Rightarrow - 1 1 A \derives - 1 1 0 1 A \Rightarrow - 1 1 0 1 +\] \end{example} @@ -83,20 +77,17 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} -Пример левостороннего вывода цепочки в грамматике - - \[ - \begin{array}{rcl} - S& \rightarrow & A A \mid s \\ - A& \rightarrow & A A \mid B b \mid a \\ - B& \rightarrow & c \mid d - \end{array} - \] - +Приведем пример левостороннего вывода цепочки $cbaa$ в грамматике: +\begin{align*} + S &\rightarrow A A \mid s \\ + A &\rightarrow A A \mid B b \mid a \\ + B &\rightarrow c \mid d +\end{align*} + Жирным выделен нетерминал, заменяемый на каждом шагу вывода. \[ \boldsymbol{S} \derives[] \boldsymbol{A} A \derives[] \boldsymbol{B} b A \derives[] c b \boldsymbol{A} \derives[] c b \boldsymbol{A} A \derives[] c b a \boldsymbol{A} \derives[] c b a a \] \end{example} -Аналогично можно определить правосторонний вывод. +Аналогично левостороннему можно определить правосторонний вывод. \begin{definition} \textit{Язык, задаваемый грамматикой} --- множество строк, выводимых в грамматике $L(G) = \{ \omega \in \Sigma^* \mid S \derives \omega \}$. @@ -110,28 +101,25 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} Пример эквивалентных грамматик для языка целых чисел в двоичной системе счисления. \begin{tabular}{p{0.4\textwidth} | p{0.5\textwidth}} - - \[ - \begin{array}{rcl} - \Sigma &=& \{ 0, 1, - \} \\ - N &=& \{ S, N, A \} \\~\\ - S& \rightarrow & 0 \mid N \mid - N \\ - N& \rightarrow & 1 A \\ - A& \rightarrow & 0 A \mid 1 A \mid \varepsilon\\ - \end{array} - \] - + \[ + \begin{aligned} + \Sigma & = \{ 0, 1, - \} \\ + N & = \{ S, N, A \} \\~\\ + S & \rightarrow 0 \mid N \mid - N \\ + N & \rightarrow 1 A \\ + A & \rightarrow 0 A \mid 1 A \mid \varepsilon\\ + \end{aligned} + \] & - - \[ - \begin{array}{rcl} - \Sigma &=& \{ 0, 1, - \} \\ - N &=& \{ S, A \} \\~\\ - S& \rightarrow & 0 \mid 1 A \mid - 1 A \\ - A& \rightarrow & 0 A \mid 1 A \mid \varepsilon\\ - \end{array} - \] - \end{tabular} + \[ + \begin{aligned} + \Sigma & = \{ 0, 1, - \} \\ + N & = \{ S, A \} \\~\\ + S & \rightarrow 0 \mid 1 A \mid - 1 A \\ + A & \rightarrow 0 A \mid 1 A \mid \varepsilon\\ + \end{aligned} + \] + \end{tabular} \end{example} @@ -141,11 +129,13 @@ \chapter{Контекстно-свободные грамматики и язы \end{definition} \begin{example} - Неоднозначная грамматика для правильных скобочных последовательностей - + Неоднозначная грамматика для правильных скобочных последовательностей: \[ S \to (S) \mid S S \mid \varepsilon \] +Два различных левосторонних вывода строки $()()()$: +\[S \derives[] S S \derives [] (S) S \derives[] () S \derives[] () S S \derives[] () (S) S \derives[] () () S \derives[] () () (S) \derives[] () () ()\] +\[S \derives[] S S \derives[] S S S \derives[] (S) S S \derives[] () S S \derives[] () (S) S \derives[] () () S \derives[] () () (S) \derives[] () () ()\] \end{example} \begin{definition} @@ -154,7 +144,6 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} Однозначная грамматика для правильных скобочных последовательностей - \[ S \to (S)S \mid \varepsilon \] @@ -166,7 +155,6 @@ \chapter{Контекстно-свободные грамматики и язы \begin{example} Пример существенно неоднозначного языка - \[\{a^n b^n c^m \mid n, m \in \mathds{Z}\} \cup \{a^n b^m c^m \mid n,m \in \mathds{Z}\}\] \end{example} @@ -215,7 +203,7 @@ \section{Пустота КС-языка} \end{proof} \begin{lemma} - Если в данной грамматике выводится некоторая цепочка, то существует цепочка, дерево вывода которой не содержит ветвей длиннее m, где m --- количество нетерминалов грамматики. + Если в данной грамматике выводится некоторая цепочка, то существует цепочка, дерево вывода которой не содержит ветвей длиннее $m$, где $m$ --- количество нетерминалов грамматики. \end{lemma} \begin{proof} @@ -223,13 +211,15 @@ \section{Пустота КС-языка} Предположим, $n_1$ расположен ближе к корню дерева, чем $n_2$. - $S \derives \alpha A_{n_1} \beta \derives \alpha \omega_1 \beta; S \derives \alpha \gamma A_{n_2} \delta \beta \derives \alpha \gamma \omega_2 \delta \beta$, при этом $\omega_2$ является подцепочкой $\omega_1$. + Вывод цепочки $\omega$ имеет следующий вид: + \[S \derives \alpha A_{n_1} \beta \derives \alpha \omega_1 \beta; S \derives \alpha \gamma A_{n_2} \delta \beta \derives \alpha \gamma \omega_2 \delta \beta \derives \omega,\] + при этом $\omega_2$ является подцепочкой $\omega_1$. - Заменим в изначальном дереве узел $n_1$ на $n_2$. Полученное дерево является деревом вывода $\alpha \omega_2 \delta$. + Заменим в изначальном дереве узел $n_1$ на $n_2$. Полученное дерево является деревом вывода цепочки $\alpha \omega_2 \delta$. Повторяем процесс замены одинаковых нетерминалов до тех пор, пока в дереве не останутся только уникальные нетерминалы. - В полученном дереве не может быть ветвей длины большей, чем m. + В полученном дереве не может быть ветвей длины большей, чем $m$. По построению оно является деревом вывода. \end{proof} @@ -242,9 +232,9 @@ \section{Нормальная форма Хомского} Контекстно-свободная грамматика $\langle \Sigma, N, P, S\rangle$ находится в \textit{Нормальной Форме Хомского}, если она содержит только правила следующего вида: \begin{itemize} - \item $A \to B C \text{, где } A, B, C \in N \text{, S не содержится в правой части правила }$ + \item $A \to B C \text{, где } A, B, C \in N$, а стартовый нетерминал $S$ не содержится в правой части правила. \item $A \to a \text{, где } A \in N, a \in \Sigma$ - \item $S \to \varepsilon$ + \item $S \to \varepsilon$: только из стартового нетерминала выводима пустая строка. \end{itemize} \end{definition} @@ -271,11 +261,14 @@ \section{Нормальная форма Хомского} \end{lemma} \begin{proof} - Каждое правило $A \to B_0 B_1 \dots B_k, k \geq 1$ заменить на множество правил: - \begin{itemize} - \item $A \to C_0 C_1 \dots C_k$ - \item $\{ C_i \to B_i \mid B_i \in \Sigma, C_i \text{ --- новый нетерминал} \}$ - \end{itemize} + Каждое правило $A \to B_0 B_1 \dots B_k, k \geq 1$ заменить на множество правил, где $C_i$ --- новый нетерминал: +\begin{align*} + A & \to C_0 C_1 \dots C_k \\ + C_0 & \to B_0 \\ + C_1 & \to B_1 \\ + & \dots \\ + C_k & \to B_k +\end{align*} \end{proof} \begin{lemma} @@ -284,13 +277,13 @@ \section{Нормальная форма Хомского} \begin{proof} Каждое правило $A \to B_0 B_1 \dots B_k, k \geq 2$ заменить на множество правил: - \begin{itemize} - \item $A \to B_0 C_0$ - \item $C_0 \to B_1 C_1$ - \item $\dots$ - \item $C_{k-3} \to B_{k-2} C_{k-2}$ - \item $C_{k-2} \to B_{k-1} B_k$ - \end{itemize} + \begin{align*} + A & \to B_0 C_0 \\ + C_0 & \to B_1 C_1 \\ + & \dots \\ + C_{k-3} & \to B_{k-2} C_{k-2} \\ + C_{k-2} & \to B_{k-1} B_k + \end{align*} \end{proof} @@ -299,21 +292,21 @@ \section{Нормальная форма Хомского} \end{lemma} \begin{proof} - Определим $\varepsilon$-правила: + Рекурсивно определим $\varepsilon$-правила: \begin{itemize} - \item $A \to \varepsilon$ - \item $A \to B_0 \dots B_k, \forall i: \ B_i$ --- $\varepsilon$-правило. + \item $A \to \varepsilon$ --- $\varepsilon$-правило + \item $A \to B_0 \dots B_k$ --- $\varepsilon$-правило, если $\forall i: \ B_i$ --- $\varepsilon$-правило. \end{itemize} Каждое правило $A \to B_0 B_1 \dots B_k$ заменяем на множество правил, где каждое $\varepsilon$-правило удалено во всех возможных комбинациях. \end{proof} \begin{lemma} - Можно удалить все цепные правила + Для любой КС-грамматики можно построить эквивалентную, не содержащую цепные правила. \end{lemma} \begin{proof} - \textit{Цепное правило} --- правило вида $A \to B\text{, где } A, B \in N\\$. + \textit{Цепное правило} --- правило вида $A \to B\text{, где } A, B \in N$. \textit{Цепная пара} --- упорядоченная пара $(A,B)$, в которой $A\derives B$, используя только цепные правила. Алгоритм: @@ -353,23 +346,18 @@ \section{Нормальная форма Хомского} Приведем в Нормальную Форму Хомского однозначную грамматику правильных скобочных последовательностей: $S \to a S b S \mid \varepsilon$ Первым шагом добавим новый нетерминал и сделаем его стартовым: - \begin{align*} S_0 &\to S \\ S &\to a S b S \mid \varepsilon \end{align*} - Заменим все терминалы на новые нетерминалы: - \begin{align*} S_0 &\to S \\ S &\to L S R S \mid \varepsilon \\ L &\to a \\ R &\to b \end{align*} - Избавимся от длинных правил: - \begin{align*} S_0 &\to S \\ S &\to L S' \mid \varepsilon \\ @@ -378,9 +366,7 @@ \section{Нормальная форма Хомского} L &\to a \\ R &\to b \end{align*} - Избавимся от $\varepsilon$-продукций: - \begin{align*} S_0 &\to S \mid \varepsilon \\ S &\to L S' \\ @@ -389,9 +375,7 @@ \section{Нормальная форма Хомского} L &\to a \\ R &\to b \end{align*} - Избавимся от цепных правил: - \begin{align*} S_0 &\to L S' \mid \varepsilon \\ S &\to L S' \\ @@ -434,7 +418,7 @@ \section{Лемма о накачке} \item Теперь мы можем копировать кусок дерева между этими повторениями $N_1$ и таким образом накачивать исходную цепочку. \end{enumerate} -Надо только проверить выполение ограничений на длины. +Надо только проверить выполнение ограничений на длины. Нахождение разбиения и пример накачки продемонстрированы на рисунках~\ref{fig:pumping1} и~\ref{fig:pumping2}. @@ -477,33 +461,35 @@ \section{Замкнутость КС языков относительно оп \item Объединение: если $L_1$ и $L_2$ --- контекстно-свободные языки, то и $L_3 = L_1 \cup L_2$ --- контекстно-свободный. \item Конкатенация: если $L_1$ и $L_2$ --- контекстно-свободные языки, то и $L_3 = L_1 \cdot L_2$ --- контекстно-свободный. \item Замыкание Клини: если $L_1$ --- контекстно-свободный, то и $L_2 = \bigcup\limits_{i=0}^{\infty} L_1^i $ --- контекстно-свободный. - \item Разворот: если $L_1$ --- контекстно-свободный, то и $L_2 = {L_1}^r$ --- контекстно-свободный. + \item Разворот: если $L_1$ --- контекстно-свободный, то и $L_2 = {L_1}^r = \{ l^r \mid l \in L_1\}$ является контекстно-свободным. \item Пересечение с регулярными языками: если $L_1$ --- контекстно-свободный, а $L_2$ --- регулярный, то $L_3 = L_1 \cap L_2$ --- контекстно-свободный. \item Разность с регулярными языками: если $L_1$ --- контекстно-свободный, а $L_2$ --- регулярный, то $L_3 = L_1 \setminus L_2$ --- контекстно-свободный. \end{enumerate} \end{theorem} -Для доказательства пунктов 1--4 можно построить КС граммтику нового языка имея грамматики для исходных. -Будем предполагать, что множества нетерминальных символов различных граммтик для исходных языков не пересекаются. +Для доказательства пунктов 1--4 можно построить КС грамматику нового языка, имея грамматики для исходных. +Будем предполагать, что множества нетерминальных символов различных грамматик для исходных языков не пересекаются. +Пусть $G_1=\langle\Sigma_1,N_1,P_1,S_1\rangle$ --- грамматика для $L_1$, $G_1=\langle\Sigma_2,N_2,P_2,S_2\rangle$ --- грамматика для $L_2$. \begin{enumerate} -\item $G_1=\langle\Sigma_1,N_1,P_1,S_1\rangle$ --- граммтика для $L_1$, $G_1=\langle\Sigma_2,N_2,P_2,S_2\rangle$ --- граммтика для $L_2$, тогда $G_3=\langle\Sigma_1 \cup \Sigma_2, N_1 \cup N_2 \cup \{S_3\}, P_1 \cup P_2 \cup \{S_3 \to S_1 \mid S_2\} ,S_3\rangle$ --- граммтика для $L_3$. +\item $G_3=\langle\Sigma_1 \cup \Sigma_2, N_1 \cup N_2 \cup \{S_3\}, P_1 \cup P_2 \cup \{S_3 \to S_1 \mid S_2\} ,S_3\rangle$ --- грамматика для $L_3$. + +\item $G_3=\langle\Sigma_1 \cup \Sigma_2, N_1 \cup N_2 \cup \{S_3\}, P_1 \cup P_2 \cup \{S_3 \to S_1 S_2\} ,S_3\rangle$ --- грамматика для $L_3$. + +\item $G_2=\langle\Sigma_1, N_1 \cup \{S_2\}, P_1 \cup \{S_2 \to S_1 S_2\ \mid \varepsilon\}, S_2\rangle$ --- грамматика для $L_2$. -\item $G_1=\langle\Sigma_1,N_1,P_1,S_1\rangle$ --- граммтика для $L_1$, $G_1=\langle\Sigma_2,N_2,P_2,S_2\rangle$ --- граммтика для $L_2$, тогда $G_3=\langle\Sigma_1 \cup \Sigma_2, N_1 \cup N_2 \cup \{S_3\}, P_1 \cup P_2 \cup \{S_3 \to S_1 S_2\} ,S_3\rangle$ --- граммтика для $L_3$. +\item $G_2=\langle\Sigma_1, N_1, \{N^i \to \omega^R \mid N^i \to \omega \in P_1 \}, S_1\rangle$ --- грамматика для $L_2 = L_1^r$. -\item $G_1=\langle\Sigma_1,N_1,P_1,S_1\rangle$ --- граммтика для $L_1$, тогда $G_2=\langle\Sigma_1, N_1 \cup \{S_2\}, P_1 \cup \{S_2 \to S_1 S_2\ \mid \varepsilon\}, S_2\rangle$ --- граммтика для $L_2$. -\item $G_1=\langle\Sigma_1,N_1,P_1,S_1\rangle$ --- граммтика для $L_1$, тогда $G_2=\langle\Sigma_1, N_1, \{N^i \to \omega^R \mid N^i \to \omega \in P_1 \}, S_1\rangle$ --- граммтика для $L_2$. \end{enumerate} Чтобы доказать замкнутость относительно пересечения с регулярными языками, построим по КС грамматике рекурсивный автомат $R_1$, по регулярному выражению --- детерминированный конечный автомат $R_2$, и построим их прямое произведение $R_3$. Переходы по терминальным символам в новом автомате возможны тогда и только тогда, когда они возможны одновременно и в исходном рекурсивном автомате и в исходном конечном. -За рекурсивные вызовы отвечает исходныа рекурсивный автомат. +За рекурсивные вызовы отвечает исходный рекурсивный автомат. Значит цепочка принимается $R_3$ тогда и только тогда, когда она принимается одновременно $R_1$ и $R_2$: так как состояния $R_3$ --- это пары из состояния $R_1$ и $R_2$, то по трассе вычислений $R_3$ мы всегда можем построить трассу для $R_1$ и $R_2$ и наоборот. -Чтобы доказать замкнутость относительно разности с регулятным языком, достаточно вспомнить, что регулярные языки замкнуты относительно дополнения, и выразить разность через пересечение с дополнением: -$$ -L_1 \setminus L_2 = L_1 \cap \overline{L_2} -$$ - +Чтобы доказать замкнутость относительно разности с регулярным языком, достаточно вспомнить, что регулярные языки замкнуты относительно дополнения, и выразить разность через пересечение с дополнением: +\[ + L_1 \setminus L_2 = L_1 \cap \overline{L_2} +\] \qed \begin{theorem} @@ -523,19 +509,22 @@ \section{Замкнутость КС языков относительно оп \begin{enumerate} \item Рассмотрим языки $L_4 = \{a^m b^n c^k \mid m \neq n, k \geq 0\}$ и $L_5 = \{a^m b^n c^k \mid n \neq k, m \geq 0\}$. Эти языки являются контекстно-свободными. -Это легко заметить, если знать, что язык $L'_4 = \{a^m b^n c^k \mid 0 \leq m < n, k \geq 0\}$ задаётся следующей граммтикой: -\begin{align*} -S \to & S c & T \to & a T b \\ -S \to & T & T \to & T b \\ - & & T \to & b. -\end{align*} +Это легко заметить, если знать, что язык $L'_4 = \{a^m b^n c^k +\mid 0 \leq m < n, k \geq 0\}$ задаётся следующей грамматикой: + \begin{align*} + S & \to S c \\ + S & \to T \\ + T & \to a T b \\ + T & \to T b \\ + T & \to b + \end{align*} \item Рассмотрим язык $L_6 = \overline{L'_6} = \overline{\{a^n b^m c^k \mid n \geq 0, m \geq 0, k \geq 0\}}$. Данный язык является регулярным. -\item Рассмотрим язык $L_7 = L_4 \cup L_5 \cup L_6$ --- контектсно свободный, так как является объединением контекстно-свободных. +\item Рассмотрим язык $L_7 = L_4 \cup L_5 \cup L_6$ --- контекстно-свободный, так как является объединением контекстно-свободных. \item Рассмотрим $\overline{L_7} = \{a^n b^n c^n \mid n \geq 0\} = L_3$: $L_4$ и $L_5$ задают языки с правильным порядком символов, но неравным их количеством, $L_6$ задаёт язык с неправильным порядком символов. -Из пердыдущего пункта мы знаем, что $L_3$ не является контекстно-свободным. +Из предыдущего пункта мы знаем, что $L_3$ не является контекстно-свободным. \end{enumerate} diff --git a/tex/FLPQ.tex b/tex/FLPQ.tex index 6b3cec2..a312a7f 100644 --- a/tex/FLPQ.tex +++ b/tex/FLPQ.tex @@ -3,7 +3,7 @@ \chapter{Задача о поиске путей с ограничениями В данной главе сформулируем постановку задачи о поиске путей в графе с ограничениями. -А также приведём несколько примеров областей, в которых применяются алгоритмы решения этой задачи. +Также мы приведём несколько примеров областей, в которых применяются алгоритмы решения этой задачи. \section{Постановка задачи } @@ -13,7 +13,7 @@ \section{Постановка задачи } Очевидно, для пустого пути данная функция будет возвращать пустое слово, а для пути длины $n > 0$ --- непустое слово длины $n$. Если теперь рассматривать задачу поиска путей, то окажется, что то множество путей, которое мы хотим найти, задаёт множество слов, то есть язык. -А значит, критерий поиска мы можем сформулировать следующим образом: нас интересуют такие пути, что слова из меток вдоль них принадлежат заданному языку. +А значит, критерий поиска мы можем сформулировать следующим образом: нас интересуют такие пути, что слова, составленные из меток вдоль них, принадлежат заданному языку. \begin{definition} \label{def1} \textit{Задача поиска путей с ограничениями в терминах формальных языков} заключается в поиске множества путей $\Pi = \{\pi \mid \omega(\pi) \in \mathcal{L}\}$. @@ -31,36 +31,32 @@ \section{Постановка задачи } При этом, множество $\Pi$ может являться бесконечным, тогда как $\Pi'$ конечно, по причине конечности графа $\mathcal{G}$. -Язык $\mathcal{L}$ может принадлежать разным классам и быть задан разными способами. Например, он может быть регулярным, или контекстно-свободным, или многокомпонентным контекстно-свободным. +Язык $\mathcal{L}$ может принадлежать разным классам и быть задан разными способами. Например, он может быть регулярным, контекстно-свободным, или многокомпонентным контекстно-свободным. -Если $\mathcal{L}$ --- регулярный, $\mathcal{G}$ можно рассматривать как недетерминированный конечный автомат (НКА), в котором все вершины и стартовые, и конечные. +Если $\mathcal{L}$ --- регулярный, $\mathcal{G}$ можно рассматривать как недетерминированный конечный автомат (НКА), в котором все вершины являются одновременно и стартовыми, и конечными. Тогда задача поиска путей, в которой $\mathcal{L}$ --- регулярный, сводится к пересечению двух регулярных языков. Более подробно мы рассмотрим случай, когда $\mathcal{L}$ --- контекстно-свободный язык. -Путь $G = \langle \Sigma, N, P \rangle$ --- контекстно-свободная граммтика. +Путь $G = \langle \Sigma, N, P \rangle$ --- контекстно-свободная грамматика. Будем считать, что $L \subseteq \Sigma$. Мы не фиксируем стартовый нетерминал в определении грамматики, поэтому, чтобы описать язык, задаваемый ей, нам необходимо отдельно зафиксировать стартовый нетерминал. -Таким образом, будем говорить, что $L(G,N_i) = \{ w | N_i \xRightarrow[G]{*} w \}$ --- это язык задаваемый граммтикой $G$ со стартовым нетерминалом $N_i$. +Таким образом, будем говорить, что $L(G,N_i) = \{ w | N_i \xRightarrow[G]{*} w \}$ --- это язык задаваемый грамматикой $G$ со стартовым нетерминалом $N_i$. \begin{example} Пример задачи поиска путей. - Дана грамматика $G:$ + Дана грамматика $G$, задающая язык $\mathcal{L} = a^n b^n$: \begin{align*} S &\to a b \\ S &\to a S b \end{align*} - - Эта грамматика задаёт язык $\mathcal{L} = a^n b^n$. - И дан граф $\mathcal{G}:$ - \begin{center} \input{figures/graph/graph0.tex} \end{center} - Тогда примерами путей, принадлежащих множеству $\Pi = \{\pi \mid \omega(\pi) \in \mathcal{L}\}$, являются: + Кратчайшими путями, принадлежащими множеству $\Pi = \{\pi \mid \omega(\pi) \in \mathcal{L}\}$, являются: \begin{center} \input{figures/flpq/path1.tex} @@ -117,11 +113,11 @@ \section{О разрешимости задачи} \section{Области применения} -Поиск путей с ограничениями в виде формальных языков широко применяется вразличных областях. Ниже даны ключевые работы по применению поиска путей с контекстно-свободными ограничениями и сылки на них для более детального ознакомления. +Поиск путей с ограничениями в виде формальных языков широко применяется в различных областях. Ниже даны ключевые работы по применению поиска путей с контекстно-свободными ограничениями и ссылки на них для более детального ознакомления. \begin{itemize} \item Межпроцедурный Статанализ кода. - Идея начала активо разрабатываться Томасом Репсом~\cite{Reps}. Далее последовал ряд, в том числе инженерных работ, применяющих достижимость с контекстно-свободными ограничениями для анализа указателей, анализа алиасов и других прикладных задач~\cite{LabelFlowCFLReachability,specificationCFLReachability,Zheng}. + Идея начала активно разрабатываться Томасом Репсом~\cite{Reps}. Далее последовал ряд, в том числе инженерных работ, применяющих достижимость с контекстно-свободными ограничениями для анализа указателей, анализа алиасов и других прикладных задач~\cite{LabelFlowCFLReachability,specificationCFLReachability,Zheng}. \item Графовые БД. Впервые задача сформулирована Михалисом Яннакакисом~\cite{Yannakakis}. Запросы с контекстно-свободными ограничениями нашли своё применение различных областях. \begin{itemize} \item Социальные сети~\cite{Hellings2015PathRF}. diff --git a/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib b/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib index 9085336..a097687 100644 --- a/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib +++ b/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib @@ -1427,3 +1427,21 @@ @article{ArlDinKro70 url = {http://mi.mathnet.ru/dan35675} } +@book{doi:10.1137/1.9780898719918, +author = {Kepner, Jeremy and Gilbert, John},editor = {Jeremy Kepner and John Gilbert}, +title = {Graph Algorithms in the Language of Linear Algebra}, +publisher = {Society for Industrial and Applied Mathematics}, +year = {2011}, +doi = {10.1137/1.9780898719918}, +address = {}, +edition = {}, +URL = {https://epubs.siam.org/doi/abs/10.1137/1.9780898719918}, +eprint = {https://epubs.siam.org/doi/pdf/10.1137/1.9780898719918} +} + +@inproceedings{Baras2010PathPI, + title={Path Problems in Networks}, + author={J. Baras and George Theodorakopoulos}, + booktitle={Path Problems in Networks}, + year={2010} +} \ No newline at end of file diff --git a/tex/FormalLanguageTheoryIntro.tex b/tex/FormalLanguageTheoryIntro.tex index b7aefbe..242702d 100644 --- a/tex/FormalLanguageTheoryIntro.tex +++ b/tex/FormalLanguageTheoryIntro.tex @@ -13,7 +13,7 @@ \chapter{Общие сведения теории формальных язык \begin{itemize} \item Латинский алфавит $\Sigma = \{ a, b, c, \dots, z\}$ \item Кириллический алфавит $\Sigma = \{ \text{а, б, в, \dots, я}\}$ - \item Алфавит чисел в шестнадцатеричной записи + \item Алфавит натуральных чисел в шестнадцатеричной записи $$\Sigma = \{0, 1, 2, 3, 4, 5, 6, 7 ,8,9, A, B, C, D, E, F \}$$ \end{itemize} \end{example} @@ -25,7 +25,7 @@ \chapter{Общие сведения теории формальных язык При записи выражений символ точки (обозначение операции конкатенации) часто будем опускать: $a \cdot b = ab$. \begin{definition} -\textit{Слово} над алфавитом $\Sigma$ --- это конечная конкатенация символов алфавита $\Sigma$: $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$, где $\omega$ --- слово, а для любого $i$ $a_i \in \Sigma$. +\textit{Слово} над алфавитом $\Sigma$ --- это конечная конкатенация символов алфавита $\Sigma$: $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$, где $\omega$ --- слово, а $a_i \in \Sigma$ для любого $i$. \end{definition} \begin{definition} @@ -47,7 +47,7 @@ \chapter{Общие сведения теории формальных язык \end{itemize} \end{example} -Любой язык над алфавитом $\Sigma$ является подмножеством $\Sigma^*$ --- множества всех слов над алфавитом $\Sigma$. +Любой язык над алфавитом $\Sigma$ является подмножеством универсального множества $\Sigma^*$ --- множества всех слов над алфавитом $\Sigma$. Заметим, что язык не обязан быть конечным множеством, в то время как алфавит всегда конечен и изучаем мы конечные слова. @@ -61,7 +61,7 @@ \chapter{Общие сведения теории формальных язык %Теоретико-множественные задачи над языками и их применение. -%О том, что моногое --- про пересечение, проверку пустоты, вложенность. +%О том, что многое --- про пересечение, проверку пустоты, вложенность. diff --git a/tex/GLL-based_CFPQ.tex b/tex/GLL-based_CFPQ.tex index ee51771..95ed77b 100644 --- a/tex/GLL-based_CFPQ.tex +++ b/tex/GLL-based_CFPQ.tex @@ -398,7 +398,7 @@ \section{LL(k)-алгоритм синтаксического анализа} Данное семейство всё так же не работает с леворекурсивными грамматиками и с неоднозначными грамматиками. -Таким образом, по некоторым граммтикам можно построить LL(k) анализатор (назовём их LL(k) граммтиками), но не по всем. +Таким образом, по некоторым грамматикам можно построить LL(k) анализатор (назовём их LL(k) грамматиками), но не по всем. С левой рекурсией, конечно, можно бороться, так как существуют алгоритмы устранения левой и скрытой левой рекурсии, а вот с неоднозначностями ничего не поделаешь. diff --git a/tex/GLR-based_CFPQ.tex b/tex/GLR-based_CFPQ.tex index e17a3a4..9d65065 100644 --- a/tex/GLR-based_CFPQ.tex +++ b/tex/GLR-based_CFPQ.tex @@ -86,7 +86,7 @@ \subsection{LR(0) алгоритм} \end{definition} Теперь мы можем построить LR(0) автомат. -Первым шагом необходимо расширить грамматику: добавить к исходной граммтике правило вида $S' \to S \$$, где $S$ --- стартовый нетерминал исходной граммтики, $S'$ --- новый стартовый нетерминал (не использовался ранее в грамматике), $\$$ --- маркер конца строки (не входил в терминальный алфавит исходной граммтики). +Первым шагом необходимо расширить грамматику: добавить к исходной грамматике правило вида $S' \to S \$$, где $S$ --- стартовый нетерминал исходной грамматики, $S'$ --- новый стартовый нетерминал (не использовался ранее в грамматике), $\$$ --- маркер конца строки (не входил в терминальный алфавит исходной грамматики). Далее строим автомат по следующим принципам. @@ -383,7 +383,7 @@ \subsection{Сравнение классов LL и LR} Из диаграммы видно, что класс языков, распознаваемых LL(k) алгоритмом уже, чем класс языков, распознаваемый LR(k) алгоритмом, при любом конечном $k$. Приведём несколько примеров. \begin{enumerate} -\item $L = \{a^mb^nc \mid m \geq n \geq 0\} $ является LR(0), но для него не существует LL(1) граммтики. +\item $L = \{a^mb^nc \mid m \geq n \geq 0\} $ является LR(0), но для него не существует LL(1) грамматики. \item $L = \{ a^n b^n + a^n c^n \mid n > 0\}$ является LR, но не LL. \item Больше примеров можно найти в работе Джона Битти~\cite{BEATTY1980193}. \end{enumerate} diff --git a/tex/GraphTheoryIntro.tex b/tex/GraphTheoryIntro.tex index 4acd641..c505773 100644 --- a/tex/GraphTheoryIntro.tex +++ b/tex/GraphTheoryIntro.tex @@ -1,47 +1,60 @@ -\chapter{Общие сведения теории графов}\label{chpt:GraphTheoryIntro} +\chapter{Некоторые сведения из теории графов}\label{chpt:GraphTheoryIntro} -В данном разделе мы дадим определения базовым понятиям из теории графов, рассмотрим несколько классических задач из области анализа графов и алгоритмы их решения. +В данном разделе мы дадим определения базовым понятиям из теории графов, рассмотрим несколько классических задач из области анализа графов и алгоритмы их решения. Кроме этого, поговорим о связи между линейной алгеброй и некоторыми задачами анализа графов. Всё это понадобится нам при последующей работе. \section{Основные определения} \begin{definition} - \textit{Граф} $\mathcal{G} = \langle V, E, L \rangle$, где $V$ --- конечное множество вершин, $E$ --- конечное множество рёбер, т.ч. $E \subseteq V \times L \times V$, $L$ --- конечное множество меток на рёбрах. + \textit{Помеченный ориентированный граф} $\mathcal{G} = \langle V, E, L \rangle$, где $V$ --- конечное множество вершин, $E$ --- конечное множество рёбер, т.ч. $E \subseteq V \times L \times V$, $L$ --- конечное множество меток на рёбрах. В некоторых случаях метки называют \textit{весами}\footnote{Весами метки называют, как правило, тогда, когда они берутся из какого-либо поля, например $\mathbb{R}$ или $\mathbb{N}$.} и тогда говорят о \textit{взвешенном} графе. \end{definition} + +\begin{definition} + В случае, если для любого ребра $(u,l,v)$ в графе также содержится ребро $(v,l,u)$, говорят, что граф \textit{неориентированный}. +\end{definition} + + В дальнейшем речь будет идти о конечных ориентированных помеченных графах. Мы будем использовать термин \textit{граф} подразумевая именно конечный ориентированный помеченный граф, если только не оговорено противное. Также мы будем считать, что все вершины занумерованы подряд с нуля. -То есть можно считать, что $V$ --- это отрезок $[0, |V| - 1]$ неотрицательных целых чисел, где $|V|$ --- размер множества $V$. +То есть можно считать, что $V$ --- это отрезок $[0, |V| - 1]$ неотрицательных целых чисел, где $|V|$ --- мощность множества $V$. \begin{example}[Пример графа и его графического представления] - Пусть дан граф $$\mathcal{G}_1 = \langle \{0,1,2,3\}, \{(0,a,1), (1,a,2), (2,a,0), (2,b,3), (3,b,2)\}, \{a,b\} \rangle.$$ - Графическое представление графа $\mathcal{G}_1$: + Пусть дан граф + \begin{align*} + \mathcal{G} = \langle V&=\{0,1,2,3\},\\ + E&=\{(0,a,1), (1,a,2), (2,a,0), (2,b,3), (3,b,2)\}, \\ + L&=\{a,b\} \rangle. + \end{align*} + + Графическое представление графа $\mathcal{G}$: \begin{center} \input{figures/graph/graph0} \end{center} \end{example} -\begin{definition} - \textit{Ребро} ориентированного помеченного графа $\mathcal{G} = \langle V, E, L \rangle$ это упорядоченная тройка $e = (v_i,l,v_j) \in V \times L \times V$. -\end{definition} - \begin{example}[Пример рёбер графа] -$(0,a,1)$ и $(3,b,2)$ --- это рёбра графа $\mathcal{G}_1$. При этом, $(3,b,2)$ $(2,b,3)$ --- это разные рёбра, что видно из рисунка. +$(0,a,1)$ и $(3,b,2)$ --- это рёбра графа $\mathcal{G}_1$. При этом $(3,b,2)$ $(2,b,3)$ --- это разные рёбра. \end{example} \begin{definition} - \textit{Путём} $\pi$ в графе $\mathcal{G}$ будем называть последовательность рёбер такую, что для любых двух последовательных рёбер $e_1=(u_1,l_1,v_1)$ и $e_2=(u_2,l_2,v_2)$ в этой последовательности, конечная вершина первого ребра является начальной вершиной второго, то есть $v_1 = u_2$. Будем обозначать путь из вершины $v_0$ в вершину $v_n$ как $$v_0 \pi v_n = e_0,e_1, \dots, e_{n-1} = (v_0, l_0, v_1),(v_1,l_1,v_2),\dots,(v_{n-1},l_n,v_n).$$ + \textit{Путём} $\pi$ в графе $\mathcal{G}$ будем называть последовательность рёбер такую, что для любых двух последовательных рёбер $e_1=(u_1,l_1,v_1)$ и $e_2=(u_2,l_2,v_2)$ в этой последовательности, конечная вершина первого ребра является начальной вершиной второго, то есть $v_1 = u_2$. Будем обозначать путь из вершины $v_0$ в вершину $v_n$ как $v_0 \pi v_n$. Иными совами, $$v_0 \pi v_n = e_0,e_1, \dots, e_{n-1} = (v_0, l_0, v_1),(v_1,l_1,v_2),\dots,(v_{n-1},l_{n-1},v_n).$$ + Часто для представления пути мы буем использовать следующие нотации: \begin{center} \input{figures/graph/path0.tex} \end{center} \end{definition} + или +$$ +v_0 \xrightarrow[]{l_0} v_1 \xrightarrow[]{l_1} v_2 \xrightarrow[]{l_2} \ldots \xrightarrow[]{l_{n-2}} v_{n-1} \xrightarrow[]{l_{n-1}} v_n. +$$ \begin{example}[Пример путей графа] $(0,a,1),(1,a,2) = 0\pi_1 2$ --- путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$. -При этом, $(0,a,1),(1,a,2),(2,b,3),(3,b,2) = 0\pi_2 2$ --- это тоже путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$, но он не равен $0\pi_1 2$. +При этом $(0,a,1),(1,a,2),(2,b,3),(3,b,2) = 0\pi_2 2$ --- это тоже путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$, но он не равен $0\pi_1 2$. \end{example} Кроме того, нам потребуется отношение, отражающее факт существования пути между двумя вершинами. @@ -51,66 +64,83 @@ \section{Основные определения} $(v_i,v_j) \in P \iff \exists v_i \pi v_j$. \end{definition} -Отметим, что рефлексивность этого отношения часто зависит от контекста. -В некоторых задачах по-умолчанию $(v_i,v_i) \notin P$, а чтобы это было верно, требуется явное наличие ребра-петли. +Отметим, что в некоторых задачах удобно считать по умолчанию, что $(v_i,v_i) \in P$, однако наше определение такого не допускает. Исправить ситуацию можно явно добавив петли $(v_i,l,v_i)$ для всех вершин. Один из способов задать граф --- это задать его \textit{матрицу смежности}. \begin{definition} - \textit{Матрица смежности} графа $\mathcal{G}=\langle V,E,L \rangle$ --- это квадратная матрица $M$ размера $n \times n$, где $|V| = n$ и ячейки которой содержат множества. - При этом $l \in M[i,j] \iff \exists e = (i,l,j) \in E$. -\end{definition} + \textit{Матрица смежности} графа $\mathcal{G}=\langle V,E,L \rangle$ --- это квадратная матрица $M$ размера $n \times n$, где $|V| = n$, построенная над коммутативным моноидом $\mathbb{G} = (S,\circ\colon S \times S \to S)$, который конструируется следующим образом. -Заметим, что наше определение матрицы смежности отличается от классического, в котором матрица отражает лишь факт наличия хотя бы одного ребра и, соответственно, является булевой. То есть $M[i,j] = 1 \iff \exists e = (i,\_,j) \in E$. + \begin{enumerate} + \item $L \subseteq S$. + \item $\circ$ --- коммутативная бинарная операция. + \item Существует $ \mathbb{0} \in (S \setminus L)$ --- нейтральный элемент относительно $\circ$. + \end{enumerate} + При этом $M[i,j] = \bigcirc_{(i,l,j) \in E}l$, где $\bigcirc_\varnothing = \mathbb{0}$. +\end{definition} -Также можно встретить матрицы смежности, в ячейках которых всё же хранится некоторая информация, однако, в единственном экземпляре. То есть запрещены параллельные рёбра. -Такой подход часто можно встретить в задачах о кратчайших путях: в этом случае в ячейке хранится расстояние между двумя вершинами. -При этом, так как в качестве весов часто рассматривают произвольные (в том числе отрицательные) числа, то в задачах о кратчайших путях отдельно вводят значение ``бесконечность'' для обозначения ситуации, когда между двумя вершинами нет пути или его длина ещё не известна. -Всё это приводит к тому, что \textit{матрица смежности} --- это обобщённое понятие, нежели конкретный специальный тип матриц. -Данная конструкция даёт общее представление о том, как в матричном виде ханить различную информацию о смежноти вершин в графе. +Заметим, что наше определение матрицы смежности отличается от классического, в котором матрица является булевой и отражает лишь факт наличия хотя бы одного ребра. То есть $M[i,j] = 1 \iff \exists e = (i,\_,j) \in E$. -\begin{example}[Пример матрицы смежности неориентированного графа] - Неориентированный граф: +\begin{example}[Пример матрицы смежности неориентированного графа]\label{exmpl:undirectedGraphMatrix} + Пусть дан следующий неориентированный граф. \begin{center} \input{figures/graph/graph1.tex} \end{center} - И его матрица смежности: +$\mathbb{G} = (S,\circ)$ в этом случае конструируется следующим образом. Во-первых, придётся предположить, что $L$ --- множество с одним элементом, скажем $s$, и считать, что все рёбра помечены им\footnote{А раз все рёбра имеют одинаковый заранее известный вес, то можно его и не писать для каждого ребра при задании графа. Поэтому привычное нам изображение получается достаточно логичным.}. Далее, $S = L \cup{\{n\}} = \{s,n\}$, где $n$ --- нейтральный элемент относительно $\circ$. Тогда $\circ$ можно определить поточечно следующим образом. +\begin{itemize} + \item $s \circ s = s$ + \item $s \circ n = n \circ s = s$ + \item $n \circ n = n$ +\end{itemize} + +Таким образом, матрица смежности данного графа выглядит следующим образом: +$$ +\begin{pmatrix} + n & s & s & n \\ + s & n & s & n \\ + s & s & n & s \\ + n & n & s & n +\end{pmatrix} +$$ +, что может показаться несколько непривычным. Однако заметим, что построенная нами структура $\mathbb{G} = (\{s,n\}, \circ)$ изоморфна $\mathbb{G}' = (\{1,0\}, \vee)$. При переходе к $\mathbb{G}'$ мы получим привычную нам булеву матрицу смежности: $$ \begin{pmatrix} - 1 & 1 & 1 & 0 \\ - 1 & 1 & 1 & 0 \\ - 1 & 1 & 1 & 1 \\ - 0 & 0 & 1 & 1 + 0 & 1 & 1 & 0 \\ + 1 & 0 & 1 & 0 \\ + 1 & 1 & 0 & 1 \\ + 0 & 0 & 1 & 0 \end{pmatrix} $$ + Заметим, что матрица смежности неориентированного графа всегда симметрична относительно главной диагонали. \end{example} -\begin{example}[Пример матрицы смежности ориентированного графа] - Ориентированный граф: +\begin{example}[Пример матрицы смежности ориентированного графа]\label{example:diGraph} + Дан ориентированный граф: \begin{center} \input{figures/graph/graph2.tex} \end{center} - И его матрица смежности: + Построить его булеву матрицу смежности можно применив рассуждения из предыдущего примера (\ref{exmpl:undirectedGraphMatrix}) и выглядеть она будет следующим образом: $$ \begin{pmatrix} - 1 & 1 & 0 & 0 \\ - 0 & 1 & 1 & 0 \\ - 1 & 0 & 1 & 1 \\ - 0 & 0 & 1 & 1 + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 \end{pmatrix} $$ \end{example} \begin{example}[Пример матрицы смежности помеченного графа] - Помеченный граф: + Пусть дан следующий помеченный граф. \begin{center} \input{figures/graph/graph3.tex} \end{center} - И его матрица смежности: + В данном случае $L = \{\{a\},\{b\}\}$, а $\mathbb{G} = ( \{\{a\},\{b\},\{a,b\},\varnothing\} ,\cup)$, где $\varnothing$ --- нейтральный элемент. + Тогда матрица матрица смежности исходного графа выглядит следующим образом: $$ \begin{pmatrix} \varnothing & \{a\} & \varnothing & \varnothing \\ @@ -121,13 +151,17 @@ \section{Основные определения} $$ \end{example} -\begin{example}[Пример матрицы смежности взвешенного графа] - Взвешенный граф для задачи о кратчайших путях: +Необходимо заметить, что свойства структуры $\mathbb{G}$, а значит и детали её построения, зависят от задачи, в рамках которой рассматривается граф. В примерах выше мы строили $\mathbb{G}$ из некоторых общих соображений, не специфицируя решаемую задачу, стараясь получить ожидаемый результат. Далее мы рассмотрим пример, в котором видно, как решаемая задача влияет на построение $\mathbb{G}$. + +\begin{example}[Пример матрицы смежности взвешенного графа]\label{example:apspGraph} + Пусть дан следующий взвешенный граф: \begin{center} \input{figures/graph/graph4.tex} \end{center} - И его матрица смежности (для задачи о кратчайших путях): + Будем считать, что веса берутся из $\mathbb{R}$, а решаемая задача --- поиск кратчайших путей между вершинами. В таком случае естественно предположить, что для любой вершины $v_i$ существует петля $(v_i,0,v_i)$, хоть она явно и не изображена. Далее, $\mathbb{G} = ( \mathbb{R}\cup \{\infty\} , \min)$, где $\infty$ --- нейтральный элемент относительно операции $\min$. + + В результате мы получим следующую матрицу смежности: $$ \begin{pmatrix} 0 & -1.4 & \infty & \infty \\ @@ -138,54 +172,77 @@ \section{Основные определения} $$ \end{example} -Мы ввели лишь общие понятия. -Специальные понятия, необходимые для изложения конкретного материала, будут даны в соответствующих главах. +Таким образом, уже можно заметить, что введение моноида как абстракции позволяет достаточно унифицированным образом смотреть на различные графы и их матрицы смежности. Далее мы увидим, что данный путь позволит решать унифицированным образом достаточно широкий круг задач, связанных с анализом путей в графах. Но сперва мы сформулируем различные варианты задачи поиска путей в графе. % Это необходимо для формулировки задач, на решение которых мы в конечном итоге нацелены. + \section{Задачи поиска путей} Одна из классических задач анализа графов --- это задача поиска путей между вершинами с различными ограничениями. -При этом, возможны различные постановки задачи. -С одной стороны, по тому, что именно мы хотим получить в качестве результата: +При этом возможны различные постановки задачи. +С одной стороны, постановки различаются тем, что именно мы хотим получить в качестве результата. Здесь наиболее частыми являются следующие варианты. + \begin{itemize} \item Наличие хотя бы одного пути, удовлетворяющего ограничениям, в графе. В данном случае не важно, между какими вершинами существует путь, важно лишь наличие его в графе. + \item Наличие пути, удовлетворяющего ограничениям, между некоторыми вершинами: задача достижимости. - При данной постановке задачи, нас интересует ответ на вопрос достижимости вершина $v_1$ из вершины $v_2$ по пути, удовлетворяющему ограничениям. - Такая постановка требует лишь проверить существование пути, но не обязательно его предоставлять в явном виде. -\item Поиск одного пути, удовлетворяющего ограничениям: необходимо не только установить факт наличия пути, но и предъявить его. При этом часто подразумевается, что возвращается любой путь, являющийся решением, без каких-либо дополнительных ограничений. Хотя, например, в некоторых задачах дополнительное требование простоты или наименьшей длинны выглядит достаточно естественным. -\item Поиск всех путей: необходимо предоставить все пути, удовлетворяющеие заданным ограничениям. + При данной постановке задачи, нас интересует ответ на вопрос достижимости вершины $v_i$ из вершины $v_j$ по пути, удовлетворяющему ограничениям. + Такая постановка требует лишь проверить существование пути, но не его предоставления в явном виде. + +\item Поиск одного пути, удовлетворяющего ограничениям: необходимо не только установить факт наличия пути, но и предъявить его. При этом часто подразумевается, что возвращается любой путь, являющийся решением, без каких-либо дополнительных ограничений. Хотя, например, в некоторых задачах дополнительное требование простоты или наименьшей длины выглядит достаточно естественным. + +\item Поиск всех путей: необходимо предоставить все пути, удовлетворяющие заданным ограничениям. \end{itemize} -С другой стороны, задачи различаются ещё и по тому, как фиксируются множества стартовых и конечных вершин. +С другой стороны, задачи могут различаться ещё и тем, как фиксируются множества стартовых и конечных вершин. Здесь возможны следующие варианты: \begin{itemize} \item от одной вершины до всех, \item между всеми парами вершин, -\item межу фиксированной парой вершин, -\item между двумя множествами вершин. +\item между фиксированной парой вершин, +\item между двумя множествами вершин $V_1$ и $V_2$, что подразумевает решение задачи для всех $(v_i,v_j) \in V_1 \times V_2$. \end{itemize} -Стоит отметить, что последний вариант является самым общим и сотальные --- лишь его частные случаи. -Однако этот вариант часто выделяют отдельно, подразумевая, что остальные, выделенные, варианты в него не включаются. В итоге мы можем сформулировать прямое произведение различных постановок задач о поиске путей, перебирая возможные варианты желаемого результата и фиксируя стартоыве и финальные множетсва разными способами. +Стоит отметить, что последний вариант является самым общим и остальные --- лишь его частные случаи. +Однако этот вариант часто выделяют отдельно, подразумевая, что остальные, выделенные, варианты в него не включаются. -Часто при поиске путей на них накладывают дополнительные ограничения. Например, можно потребовать, чтобы пути были простыми или не проходили через определённые вершины. -Ограничение, имеющее важное прикладное значение, --- минимальность длины искомого пути. -Одна из важных задач, имеющих как прикладное, так и теоретическое значение --- \textit{поиск кратчайших путей в графе между всеми парами вершин(англ. APSP --- all-pairs shortest paths)}. Рассмотрим её более подробно. Тем более, что данная задача в определённом смысле близка к задаче, которая будет основной в данной работе, и из алгоритмов для APSP можно почерпнуть идеи для алгоритмов решения задачи поиска путей с ограничениями в терминах формальных языков. +В итоге, перебирая возможные варианты желаемого результата и способы фиксации стартовых и финальных вершин, мы можем сформулировать достаточно большое количество задач. Например, задачу поиска всех путей между двумя заданными вершинами, задачу поиска одного пути от фиксированной стартовой вершины до каждой вершины в графе, или задачу достижимости между всеми парами вершин. +Часто поиск путей сопровождается изучением их свойств, что далее приводит к формулированию дополнительных ограничений на пути в терминах этих свойств. Например, можно потребовать, чтобы пути были простыми или не проходили через определённые вершины. Один из естественных способов описывать свойства и, как следствие, задавать ограничения --- это использовать ту алгебраическую структуру, из которой берутся веса рёбер графа\footnote{На самом деле здесь наблюдается некоторая двойственность. С одной стороны, действительно, удобно считать, что свойства описываются в терминах некоторой заданной алгебраической структуры. Но, вместе с этим, структура подбирается исходя из решаемой задачи.}. -\section{APSP и транзитивное замыкание графа} +Предположим, что дан граф $\mathcal{G} = \langle V, E, L\rangle $, где $L = \langle S, \oplus, \otimes \rangle$ --- это полукольцо. Тогда изучение свойств путей можно описать следующим образом: +\begin{equation} \label{eq:algPathProblem} + \{(v_i, v_j, c) \mid \exists v_i \pi v_j, c = \bigoplus_{\forall v_i \pi v_j} \bigotimes_{(u,l,v) \in \pi } l \}. +\end{equation} -Заметим, что отношение достижимости (\ref{def:reach}) является транзитивным. -Действительно, если существует путь из $v_i$ в $v_j$ и путь из $v_j$ в $v_k$, то существует путь из $v_i$ в $v_k$. +Иными словами, для каждой пары вершин, для которой существует хотя бы один путь, их соединяющий, мы агрегируем (с помощью операции $\oplus$ из полукольца) информацию обо всех путях между этими вершинами. При этом информация о пути получается как свёртка меток рёбер пути с использованием операции $\otimes$\footnote{Заметим, что детали свёртки вдоль пути зависят от свойств полукольца (и от решаемой задачи). Так, если полукольцо коммутативно, то нам не обязательно соблюдать порядок рёбер. В дальнейшем мы увидим, что данные особенности полукольца существенно влияют на особенности алгоритмов решения соответствующих задач.}. -\begin{definition} - \textit{Транзитивным замыканием графа} называется транзитивное замыкание отношения достижимости по всему графу. -\end{definition} +Естественным требованием (хотя бы для прикладных задач, решаемых таким способом) является существование и конечность указанной суммы. На данном этапе мы не будем касаться того, какие именно свойства полукольца могут нам обеспечить данное свойство, однако в дальнейшем будем считать, что оно выполняется. Более того, будем стараться приводить частные для конкретной задачи рассуждения, показывающие, почему это свойство выполняется в рассматриваемых в задаче ограничениях. + +Описанная выше задача общего вида называется анализом свойств путей алгебраическими методами (Algebraic Path Problem~\cite{Baras2010PathPI}) и предоставляет общий способ для решения широкого класса прикладных задач\footnote{В работе ``Path Problems in Networks''~\cite{Baras2010PathPI} собран действительно большой список прикладных задач с описанием соответствующих полуколец. Сводная таблица на страницах 58--59 содержит 29 различных прикладных задач и соответствующих полуколец.}. Наиболее известными являются такие задачи, как построение транзитивного замыкания графа и поиск кратчайших путей (All PAirs Shortest Path или APSP). Далее мы подробнее обсудим эти две задачи и предложим алгоритмы их решения. + + +\section{Алгоритм Флойда-Уоршелла} + +Наиболее естественным образом решение обсуждаемых выражается в терминах операций над матрицей смежности исходного графа. Поэтому предположим, что исходный граф задан матрицей над моноидом $\mathbb{G} = (S,\oplus)$. + +Как мы видели ранее, операция $\oplus$ позволяет нам агрегировать информацию по всем параллельным рёбрам. Ровно она же и будет агрегировать информацию по всем путям между двумя вершинами\footnote{Вообще говоря, работая с матрицей смежности мы не видим разницу между путём и ребром, так как любая запись в матрице смежности в ячейке $[i,j]$ говорит нам только о том, что вершины $i$ и $j$ связаны и эта связь обладает некоторым свойством (значение в ячейке), и ничего не говорит о том, как эта связь устроена.}. Таким образом, осталось сконструировать операцию, отвечающую за агрегацию информации вдоль пути. Здесь мы будем исходить из того, что новый путь может быть получен из двух подпутей, а свойство нового пути зависит только от свойств исходных подпутей. -Как несложно заметить, транзитивное замыкание графа --- это тоже граф. -Более того, если решить задачу поиска кратчайших путей между всеми парами вершин, то мы построим транзитивное замыкание. +Таким образом, дополнительная операция, обозначим её $\otimes: S \times S \to S$\footnote{При первом рассмотрении такой выбор кажется контринтуитивным. Действительно, ведь при соединении путей мы как бы ``складываем'' их веса. Но при более детальном анализе поведения этой операции, в частности, относительно нейтрального элемента, становится понятно, что она ведёт себя очень похоже на умножение. Вероятно, стоит обратить внимание на операцию конкатенации, которая, с одной стороны, ``делает то, что нам нужно'', а с другой, (и неспроста) часто обозначается $\cdot$.}, должна вести себя следующим образом. Пусть $S$ --- носитель моноида, $\mathbb{0} \in S$ --- нейтральный элемент относительно $\oplus$. +\begin{itemize}\label{itm:otimesIntro} + \item $s_1 \otimes s_2 = s_3, s_i \in S, s_i \neq \mathbb{0}$ : если существует путь $i \pi j$ со свойством $s_1$ и путь $j \pi k$ со свойством $s_2$, то существует путь $i \pi k$ со свойством $s_3$. + \item $s \otimes \mathbb{0} = \mathbb{0}$ : если существует путь $i \pi j$ со свойством $s$ и не существует пути $j \pi k$, то не существует и пути $i \pi k$. + \item $\mathbb{0} \otimes s = \mathbb{0}$ : если не существует пути $i \pi j$ и существует путь $j \pi k$ со свойством $s$, то не существует и пути $i \pi k$. + \item $\mathbb{0} \otimes \mathbb{0} = \mathbb{0}$ : если не существует пути $i \pi j$ и не существует пути $j \pi k$, то не существует и пути $i \pi k$. +\end{itemize} + +Новую операцию добавим к моноиду и получим новую алгебраическую структуру $\mathbb{G}' = (S, \oplus,\otimes)$. Данная структура является коммутативным моноидом по сложению (по построению) с нейтральным элементом $\mathbb{0}$. Из построения $\otimes$ видно, что $\mathbb{0}$ является аннигилятором. Ничего более про операцию $\otimes$, а значит и про $\mathbb{G}'$ мы сказать, исходя из построения, не можем. Классический фреймворк для решения algebraic path problem подразумевает, что $\mathbb{G}'$ является полукольцом, однако далее мы увидим, что существуют задачи, в которых $\otimes$, например, не является ассоциативной\footnote{Такой будет рассматриваемая в данной работе задача достижимости с ограничениями в терминах формальных языков. Другие примеры можно найти в уже упоминавшейся работе~\cite{Baras2010PathPI}}. А значит, согласно нашему определению, $\mathbb{G}'$ полукольцом не является. + +Теперь, когда построена алгебраическая структура, обеспечивающая вычисление формулы~ +\ref{eq:algPathProblem}, мы можем предложить алгоритм вычисления этой формулы и данным алгоритмом в интересующих нас частных случаях будет являться алгоритм Флойда-Уоршелла~\cite{Floyd1962, Bernard1959, Warshall1962}. Псевдокод алгоритма представлен на листинге~\ref{lst:algoFloydWarxhall}, а его сложность $O(n^3)$. Он практически дословно основан на описанной выше идее сборки путей из двух подпутей: тройной вложенный цикл перебирает все возможные разбиения пути на две части, а в строке 7 как раз и происходит вычисление формулы~ +\ref{eq:algPathProblem}. -Поэтому сразу рассмотрим алгоритм Флойда-Уоршелла~\cite{Floyd1962, Bernard1959, Warshall1962}, который является общим алгоритмом поиска кратчайших путей. Данный алгоритм умеет обрабатывать рёбра с отрицательными весами, чего не может, например, алгоритм Дейкстры. Его сложность: $O(n^3)$, где $n$ --- количество вершин в графе. При этом, данный алгоритм легко упростить до алгоритма построения транзитивного замыкания. Псевдокод алгоритма представлен на листинге~\ref{lst:algoFloydWarxhall}. +Необходимо обратить внимание на несколько вещей. Первая --- порядок обхода. Внешний цикл перебирает возможные точки разбиения (хотя мог бы, например, перебирать начальные вершины) для того, чтобы гарантировать правильный порядок вычисления подпутей (информация ни о каких подпутях не будет получена после того, как они поучаствовали в построении более длинного пути). Вторая --- количество итераций. В данном случае мы ограничились тройным вложенным циклом от 0 до $n$ и для наших задач этого будет достаточно, однако, как доказательство этого факта, так и построение аналогичного алгоритма для других задач требует аккуратного анализа решаемой задачи и последующего доказательства корректности построенного алгоритма. \begin{algorithm} \floatname{algorithm}{Listing} @@ -194,7 +251,8 @@ \section{APSP и транзитивное замыкание графа} \label{lst:algoFloydWarxhall} \Function{FloydWarshall}{$\mathcal{G}$} \State{$M \gets$ матрица смежности $\mathcal{G}$} - \State{$n \gets$ $|V(\mathcal{G})|$} + \Comment{Матрица над $\mathbb{G}=(S,\oplus,\otimes)$} + \State{$n \gets |V(\mathcal{G})|$} \For{k = 0; k < n; k++} \For{i = 0; i < n; i++} \For{j = 0; j < n; j++} @@ -207,29 +265,29 @@ \section{APSP и транзитивное замыкание графа} \end{algorithmic} \end{algorithm} -В зависимости от того, над каким полукольцом построена матрица смежности (какого рода веса на рёбрах графа) данный алгоритм может решать несколько разные задачи. Например, если возьмём трописеское полукольцо $(\mathbb{R}_{+\infty}, \min, +)$, то получим алгоритм для поимка кратчайших путей. Если же возьмём булево полукольцо, то получим алгоритм для построения транзитивного замыкания графа. +Хотя изначально данный алгоритм был предложен для решения задачи о кратчайших путях, при абстрагировании алгебраической структуры он превращается в алгоритм решения целого ряда задач. В частности --- нахождения транзитивного замыкания. Так, если возьмём тропическое полукольцо $(\mathbb{R}_{+\infty}, \min, +)$, то получим алгоритм для поиска кратчайших путей. Если же возьмём булево полукольцо, то получим алгоритм для построения транзитивного замыкания графа. -\begin{example}[Транзитивное замыкание графа] +\begin{example}[Транзитивное замыкание графа]\label{exmpl:transitiveClosure} Пусть дан следующий граф: \begin{center} \input{figures/graph/graph2.tex} \end{center} Его матрица смежности: - $$ M = + $$ M = \begin{pmatrix} - 1 & 1 & 0 & 0 \\ - 0 & 1 & 1 & 0 \\ - 1 & 0 & 1 & 1 \\ - 0 & 0 & 1 & 1 + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 \end{pmatrix} $$ - Здесь мы считаем, что отношение достижимости рефлексивно: все диагональные элементы матрицы $M$ равны 1, хотя петель у вершин нету. + Здесь мы считаем, что отношение достижимости не рефлексивно: все диагональные элементы матрицы $M$ равны 0. Воспользовавшись алгоритмом из листинга~\ref{lst:algoFloydWarxhall}, специализированного на случай булева полукольца, можно получить следующую матрицу смежности. - $$ M' = + $$ M' = \begin{pmatrix} 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ @@ -239,37 +297,47 @@ \section{APSP и транзитивное замыкание графа} $$ А значит, транзитивным замыканием исходного графа является полный граф и он выглядит следующим образом. - + \begin{center} \input{figures/graph/graph5.tex} \end{center} \end{example} -Заметим, что рефлексивность отношения (значения элементов на главной диагонали матрицы смежности) непосредственно связана с особенностями решаемой задачи. Например, если говорить о кратчайших расстояних, то кажется естественным считать расстояние от вершины до самой себя равной нулю. Однако для задачи транзитивного замыкания это уже не столь естественное предположение и часто отдельно говорят от рефлексивно-транзитивном замыкании, которое отдельно явным образом привносит рефлексивность (петли, диагональные элементы матрицы смежности). +Заметим, что рефлексивность отношения (значения элементов на главной диагонали матрицы смежности) непосредственно связана с особенностями решаемой задачи. Например, если говорить о кратчайших расстояниях, то кажется естественным считать расстояние от вершины до самой себя равной нулю. Однако для задачи транзитивного замыкания это уже не столь естественное предположение и часто отдельно говорят о рефлексивно-транзитивном замыкании, которое отдельно явным образом привносит рефлексивность (петли, диагональные элементы матрицы смежности). +Аналогичным образом, используя данный алгоритм, но уже для тропического полукольца, можно решить задачу о поиске кратчайших путей для графа из примера~\ref{example:apspGraph}. +Идеи, заложенные в алгоритме Флойда-Уоршелла, а также возможность абстрагировать его, помогут нам в дальнейшем предложить алгоритм для задачи достижимости с ограничениями в терминах формальных языков. -\section{APSP и произведение матриц} +\section{Анализ путей в графе и линейная алгебра} -Алгоритм Флойда-Уоршелла можно переформулировать в терминах перемножения матриц над тропическим полукольцом. +В данной главе мы рассмотрим некоторые связи\footnote{Связь между графами и линейной алгеброй --- обширная область, в которой можно даже выделить отдельные направления, такие как спектральная теория графов. С точки зрения практики данная связь также подмечена давно и более полно с ней можно ознакомиться, например, в работах~\cite{doi:10.1137/1.9780898719918, Davis2018Algorithm9S}. Кроме этого, много полезной информации можно найти на сайте \url{https://graphblas.github.io/GraphBLAS-Pointers/}.} между графами и операциями над ними и матрицами и операциями над матрицами. + +Как мы видели, достаточно естественное представление графа --- это его матрица смежности. Далее можно заметить некоторое сходство между определением матричного умножения~\ref{def:MxM} и мыслями, которыми мы руководствовались, вводя операцию $\otimes$ (\ref{itm:otimesIntro}). Действительно, пусть есть матрица $M$ размера $n \times n$ над $mathbb{G} = (S,\oplus,\otimes)$\footnote{Здесь мы уже сталкиваемся с тем, что могут иметь смысл относительно экзотические алгебраические структуры. Действительно, как мы выяснили, матрица смежности может быть определена на чем-то более бедным, чем полукольцо, а матичное умножение мы определяли над полукольцом. Но если задуматься, то и для определения произведения матриц полукольцо вовсе необязательно, достаточно более бедной структуры.} --- матрица смежности графа. Умножим её саму на себя: вычислим $M'= M \cdot M$. Тогда, по~\ref{def:MxM}, $M'[i,j] = \bigoplus_{0 \leq l < n} M[i,l] \otimes M[l,j]$. Размер $M'$ также $n \times n$. То есть $M'$ задаёт такой граф, что в нём будет путь со свойством, являющимся агрегацией свойств всех путей, составленных из двух подпутей в исходном графе. А именно, если в исходном графе есть путь из $i$ в $l$ с некоторым свойством (его значение хранится в $M[i,l]$), и был путь из $l$ в $j$ (его значение хранится в $M[l,j]$), то в новом графе свойство $M[i,l] \otimes M[l,j]$ аддитивно (используя $\oplus$) учтётся в свойстве пути из $i$ в $j$. + +Таким образом, произведение матриц смежности соответствует обработке информации о путях интересующим нас образом. Это наблюдение позволяет предложить решение задач анализа свойств путей, основанное на операциях над матрицами. Рассмотрим такое решение для задачи о кратчайших путях. Пусть $D_k$ --- матрица кратчайших путей, состоящих не более чем из $k$ рёбер. То есть $D_k[i,j]$ --- это длина кратчайшего пути из вершины $i$ в вершину $j$, такого, что он состоит не более чем из $k$ ребер. Если такого пути нет, то $D_k[i,j] = \infty$. -Таким образом, $D_1 = M$, где $M$ --- это матрица смежности исходного графа, а решением APSP является $D_{n-1}$. +Таким образом, $D_1 = M$, где $M$ --- это матрица смежности исходного графа, а решением APSP является $D_{n-1}$, вычисляемая с помощью следующего рекуррентного соотношения: \begin{center} $D(1) = M$ \\ $D(2) = D(1) \cdot M = M^2$ \\ $D(3) = D(2) \cdot M = M^3$ \\ $\dots$ \\ - $D(n-1) = D(n-2) \cdot M = M^{n-1}$ \\ + $D(n-1) = D(n-2) \cdot M = M^{(n - 1)}$ \\ \end{center} -Итак, мы можем решить APSP за $O(n K(n))$, где $K(n)$ --- сложность алгоритма умножения матриц. +Здесь мы пользуемся той особенностью задачи, что кратчайший путь в ориентированном графе (без отрицательных циклов) не может быть длиннее $n$\footnote{Раз отрицательных циклов нету, то проходить через одну вершину, коих $n$, больше одного раза бессмысленно.}. +Более того, мы пользуемся тем, что используемая структура именно полукольцо, а исходное отношение рефлексивно\footnote{Тот факт, что в любой вершине есть петля с весом 0, а 0 --- нейтральный для $\otimes$, позволяет не суммировать матрицы. Итоговая матрица содержит данные о путях длины \textit{не больше чем} вычисляемая степень, хотя должна бы содержать данные о путях ровно и только такой длины. Предлагается самостоятельно исследовать данный феномен.}. + +Таким образом, решение APSP сведено к произведению матриц над тропическим полукольцом, однако вычислительная сложность решения слишком большая: $O(n K(n))$, где $K(n)$ --- сложность алгоритма умножения матриц. -Сразу заметим, что, например, $D_3$ считать не обязательно, т.к. можем посчитать $D_4$ как $D_2 \cdot D_2$. -Поэтому: +Чтобы улучшить сложность, заметим, что, например, $D_3$ вычислять не обязательно, так как можно сразу вычислить $D_4$ как $D_2 \cdot D_2$. + +В итоге получим следующую последовательность вычислений: \begin{center} $D_1 = M$ \\ @@ -281,11 +349,10 @@ \section{APSP и произведение матриц} $D_{n-1} = D_{2^{\log(n-1)}}$ \\ \end{center} -Теперь вместо $n$ итераций нам нужно $\log{n}$. В итоге, сложность --- $O(\log{n} K(n))$. -Данный алгоритм называется \textit{repeated squaring}\footnote{Пример решения APSP с помощью repeated squaring: \url{http://users.cecs.anu.edu.au/~Alistair.Rendell/Teaching/apac_comp3600/module4/all_pairs_shortest_paths.xhtml}}. - +Теперь вместо $n$ итераций нам нужно $\log{n}$, а итоговая сложность решения --- $O(\log{n} K(n))$\footnote{Заметим, что это оценка для худшего случая. На практике при использовании данного подхода можно прекращать вычисления как только при двух последовательных шагах получились одинаковые матрицы ($D_i = D_{i-1}$). Это приводит нас к понятию \textit{неподвижной точки}, обсуждение которого лежит за рамками повествования.}. +Данный алгоритм называется \textit{repeated squaring}\footnote{Пример решения APSP с помощью repeated squaring: \url{http://users.cecs.anu.edu.au/~Alistair.Rendell/Teaching/apac_comp3600/module4/all_pairs_shortest_paths.xhtml}}. Здесь мы предполагаем, что $n-1 = 2^k$ для какого-то $k$. На практике такое верно далеко не всегда. Если это условие не выполняется, то необходимо взять ближайшую сверху степень двойки\footnote{Кажется, что это приведёт к избыточным вычислениям. Попробуйте оценить, на сколько много лишних вычислений будет сделано в худшем случае.}. -Таким образом, APSP сводится к умножению матриц над полукольцом, что, к сожалению, не позволяет этим путём получить истинно субкубический алгоритм для задачи. тем неменее, позволяет получить слегка субкубический. Приведем некоторые работы по APSP для ориентированных графов с вещественными весами (здесь $n$ --- количество вершин в графе): +Таким образом, APSP сводится к умножению матриц над полукольцом, что, к сожалению, не позволяет этим путём получить истинно субкубический алгоритм для задачи. тем не менее, позволяет получить слегка субкубический. Приведем некоторые работы по APSP для ориентированных графов с вещественными весами (здесь $n$ --- количество вершин в графе), по которым можно более детально ознакомиться как с историей вопроса, так и с текущими результатами: \begin{itemize} \item M.L. Fredman (1976) --- $O(n^3(\log \log n / \log n)^\frac{1}{3})$ --- использование дерева решений~\cite{FredmanAPSP1976} \item W. Dobosiewicz (1990) --- $O(n^3 / \sqrt{\log n})$ --- использование операций на Word Random Access Machine~\cite{Dobosiewicz1990} @@ -295,17 +362,18 @@ \section{APSP и произведение матриц} \item T. Takoaka (2005) --- $O(n^3 \log \log n / \log n)$~\cite{Takaoka2005} \item U. Zwick (2004) --- $O(n^3 \sqrt{\log \log n} / \log n)$~\cite{Zwick2004} \item T.M. Chan (2006) --- $O(n^3 / \log n)$ --- многомерный принцип ``разделяй и властвуй''~\cite{Chan2008} - \item и др. \end{itemize} -Таким образом, вопрос о субкубических алгоритмах решения APSP всё ещё открыт~\cite{Chan2010}. +Вопрос же о истинно субкубических алгоритмах решения APSP всё ещё открыт~\cite{Chan2010} и активно обсуждается в научном сообществе. +Аналогичным образом можно свести транзитивное замыкание к матричным операциям. Предлагаем проделать это самостоятельно, заодно обратив внимание на важность рефлексивности (в примере~\ref{exmpl:transitiveClosure} её нет). +Заметим, что оптимизация, связанная с возведением в квадрат возможна только при ассоциативности произведения матриц, что зависит от свойств алгебраической структуры, над которой построены матрицы. Для полукольца такая оптимизация законна, однако в некоторых случаях её применить нельзя. Таким случаем как раз и будет рассматриваемая в нашей работе задача. Поэтому построение алгоритма её решения через операции над матрицами, хотя и будет основано на указанных выше соображениях, но будет сопряжено с некоторыми трудностями. %\section{Вопросы и задачи} %\begin{enumerate} -% \item Реализуйте абстракцию полукльца, позволяющую конструировать полукольца с произвольными операциями. +% \item Реализуйте абстракцию полукольца, позволяющую конструировать полукольца с произвольными операциями. % \item Реализуйте алгоритм произведения матриц над произвольным полукольцом. Используйте результат решения предыдущей задачи. % \item Используя результаты предыдущих задач, реализуйте алгоритм построения транзитивного замыкания через произведение матриц. % \item Используя результаты предыдущих задач, реализуйте алгоритм решения задачи APSP для ориентированного через произведение матриц. diff --git a/tex/Introduction.tex b/tex/Introduction.tex index 2bf93f3..e50b798 100644 --- a/tex/Introduction.tex +++ b/tex/Introduction.tex @@ -2,13 +2,13 @@ \chapter*{Введение} Теория формальных языков находит применение не только для ставших уже классическими задач синтаксического анализа кода (языков программирования, искусственных языков) и естественных языков, но и в других областях, таких как статический анализ кода, графовые базы данных, биоинформатика, машинное обучение. -Например, в машинном обучении использование формальных грамматик позволяет передать искусственной нейронной сети, предназначенной для генерации цепочек с определёнными свойствами (генеративной нейронной сети), знания о синтаксической структуре этих цепочек, что позволяет существенно упростить процесс обучения и повысить качество результата~\cite{10.5555/3305381.3305582}. +Например, в машинном обучении использование формальных грамматик позволяет передать искусственной генеративной нейронной сети, предназначенной для построения цепочек с определёнными свойствами, знания о синтаксической структуре этих цепочек, что позволяет существенно упростить процесс обучения и повысить качество результата~\cite{10.5555/3305381.3305582}. Вместе с этим, развиваются подходы, позволяющие нейронным сетям наоборот извлекать синтаксическую структуру (строить дерево вывода) для входных цепочек~\cite{kasai-etal-2017-tag,kasai-etal-2018-end}. В биоинформатике формальные грамматики нашли широкое применение для описания особенностей вторичной структуры геномных и белковых последовательностей~\cite{Dyrka2019,WJAnderson2012,zier2013rna}. Соответствующие алгоритмы синтаксического анализа используются при создании инструментов обработки данных. -Таким образом, теория формальных языков выступает в качестве основы для многих прикладных областей, а алгоритмы синтаксического анлиза применимы не только для обработки естественных языков или языков программирования. +Таким образом, теория формальных языков выступает в качестве основы для многих прикладных областей, а алгоритмы синтаксического анализа применимы не только для обработки естественных языков или языков программирования. Нас же в данной работе будет интересовать применение теории формальных языков и алгоритмов синтаксического анализа для анализа графовых баз данных и для статического анализа кода. Одна из классических задач, связанных с анализом графов --- это поиск путей в графе. @@ -30,7 +30,7 @@ \chapter*{Введение} Граф-структурированные данные встречаются не только в графовых базах данных, но и при статическом анализе кода: по программе можно построить различные графы отображающие её свойства. Скажем, граф вызовов, граф потока данных и так далее. -Оказывается, что поиск путей в специального вида графах с использованием ограничений в терминах формальных языков позволяет исследовать некоторые свойства программы. +Оказывается, что поиск путей в специального вида графах с использованием ограничений в терминах формальных языков позволяет исследовать некоторые нетривиальные свойства программы. Например проводить межпроцедурный анализ указателей или анализ алиасов~\cite{Zheng,10.1145/2001420.2001440,10.1145/2714064.2660213}, строить срезы программ~\cite{10.1145/193173.195287}, проводить анализ типов~\cite{10.1145/373243.360208}. В данной работе представлен ряд алгоритмов для поиска путей с ограничениями в терминах формальных языков. @@ -39,9 +39,9 @@ \chapter*{Введение} Структура данной работы такова. -В начале (в части~\ref{chpt:GraphTheoryIntro}) мы рассмотрим основные понятия из теории графов, необходимые в данной работе. Данные разделы являются подготовительными и не обязательны к прочтению, если такие понятия как \textit{ориентированный граф} и \textit{матрица смежности} уже известны читателю. Более того, они лишь вводят определения, подазумевая, что более детальное изучение соответствующих разделов науки остается за рамками этой работы и скорее всего уже проделано читателем. +В начале (в части~\ref{chpt:GraphTheoryIntro}) мы рассмотрим основные понятия из теории графов, необходимые в данной работе. Данные разделы являются подготовительными и не обязательны к прочтению, если такие понятия как \textit{ориентированный граф} и \textit{матрица смежности} уже известны читателю. Более того, они лишь вводят определения, подразумевая, что более детальное изучение соответствующих разделов науки остается за рамками этой работы и скорее всего уже проделано читателем. Затем, в главе~\ref{chpt:FormalLanguageTheoryIntro} мы введём основные понятия из теории формальных языков. -Далее, в главе~\ref{chpt:FLPQ} рассмотрим различные варианты постановки задачи поиска путей с ограничениями в терминах формальнх языков, обсудим базовые свойства задач, её разрешимость в различных постановках и т.д.. +Далее, в главе~\ref{chpt:FLPQ} рассмотрим различные варианты постановки задачи поиска путей с ограничениями в терминах формальных языков, обсудим базовые свойства задач, её разрешимость в различных постановках и т.д.. И в итоге зафиксируем постановку, которую будем изучать далее. После этого, в главах~\ref{chpt:CFPQ_CYK}--\ref{chpt:GLR} мы будем подробно рассматривать различные алгоритмы решения этой задачи, попутно вводя специфичные для рассматриваемого алгоритма структуры данных. Большинство алгоритмов будут основаны на классических алгоритмах синтаксического анализа, таких как CYK или LR. diff --git a/tex/LinearAlgebra.tex b/tex/LinearAlgebra.tex index 7b4c7ba..a050eab 100644 --- a/tex/LinearAlgebra.tex +++ b/tex/LinearAlgebra.tex @@ -40,7 +40,7 @@ \section{Бинарные операции и их свойства} \begin{example} Рассмотрим несколько примеров коммутативных и некоммутативных операций. \begin{itemize} \item Операция сложения на целых числах $+$ является коммутативной: известный ещё со школы перестановочный закон сложения. - \item Операция конкатенации на строках $+$ не является коммутативной: $$``ab" + ``c" \ = ``abc" \neq ``c" + ``ab" \ = ``cab".$$ + \item Операция конкатенации на строках $\cdot$ не является коммутативной: $$``ab" \cdot ``c" \, = ``abc" \neq ``cab" \, = ``c" \cdot ``ab".$$ \item Операция умножения на целых числах является коммутативной: известный ещё со школы перестановочный закон умножения. \item Операция умножения матриц (над целыми числами) $\cdot$ не является коммутативной: $$\begin{pmatrix} @@ -55,6 +55,10 @@ \section{Бинарные операции и их свойства} 1 & 1 \\ 0 & 0 \end{pmatrix} \neq + \begin{pmatrix} + 0 & 0 \\ 1 & 1 + \end{pmatrix} + = \begin{pmatrix} 0 & 0 \\ 1 & 1 \end{pmatrix} @@ -62,10 +66,6 @@ \section{Бинарные операции и их свойства} \begin{pmatrix} 1 & 1 \\ 0 & 0 \end{pmatrix} - = - \begin{pmatrix} - 0 & 0 \\ 1 & 1 - \end{pmatrix} .$$ \end{itemize} \end{example} @@ -78,9 +78,9 @@ \section{Бинарные операции и их свойства} \begin{itemize} \item Операция сложения на целых числах $+$ является ассоциативной. \item Операция умножения на целых числах является ассоциативной. - \item Операция конкатенации на строках $+$ является ассоциативной: $$(``a" + ``b") + ``c" \ = ``a" + (``b" + ``c") = ``abc" .$$ + \item Операция конкатенации на строках $\cdot$ является ассоциативной: $$(``a" \cdot ``b") \cdot ``c" \, = ``a" \cdot (``b" \cdot ``c") = ``abc" .$$ \item Операция возведения в степень (над целыми числами) $\hat{\mkern6mu}$ не является ассоциативной: - $$(2\hat{\mkern6mu}2)\hat{\mkern6mu}3 = 4 \hat{\mkern6mu} 3 = 64 \neq 2\hat{\mkern6mu}(2\hat{\mkern6mu}3) = 2 \hat{\mkern6mu} 8 = 256.$$ + $$(2\hat{\mkern6mu}2)\hat{\mkern6mu}3 = 4 \hat{\mkern6mu} 3 = 64 \neq 256 = 2 \hat{\mkern6mu} 8 = 2\hat{\mkern6mu}(2\hat{\mkern6mu}3).$$ \end{itemize} \end{example} @@ -100,7 +100,7 @@ \section{Бинарные операции и их свойства} \begin{itemize} \item Умножение целых чисел дистрибутивно относительно сложения и вычитания: классический \textit{распределительный закон}, знакомый всем со школы. - \item Операция деления (допустим, на действительных числах) не коммутативна. при этом, она дистрибутивна справа относительно сложения и вычитания, но не дистрибутивна слева. + \item Операция деления (допустим, на действительных числах) не коммутативна. При этом, она дистрибутивна справа относительно сложения и вычитания, но не дистрибутивна слева. $$(a + b) / c = (a / c) + (b / c) $$ но $$c / (a + b) \neq (c / a) + (c / b)\footnote{Здесь может быть уместно вспомнить правила сложения дробей. Дроби с общим знаминателем складывать проще как раз из-за дистрибутивности справа.}.$$ @@ -126,7 +126,7 @@ \section{Бинарные операции и их свойства} \end{example} \begin{definition} -Пусть есть коммутативная бинарная операция $\circ$ на множестве $S$. Говорят, что $x\in S$ является \emph{нейтральным элементом} по операции $\circ$, если для любого $y\in S$ верно, что $x \circ y = y \circ x = y$. Если бинарная операция не является коммутативной, то можно пределить \textit{нейтральный слева} и \textit{нейтральный справа} элементы по аналогии. +Пусть есть коммутативная бинарная операция $\circ$ на множестве $S$. Говорят, что $x\in S$ является \emph{нейтральным элементом} по операции $\circ$, если для любого $y\in S$ верно, что $x \circ y = y \circ x = y$. Если бинарная операция не является коммутативной, то можно определить \textit{нейтральный слева} и \textit{нейтральный справа} элементы по аналогии. \end{definition} @@ -134,15 +134,15 @@ \section{Полугруппа} \begin{definition} -Множество с заданной на нём ассоциативной бинарной операцией $(S,\cdot : S \times S \to S )$ называется \emph{полугруппой}. +Множество $S$ с заданной на нём ассоциативной бинарной операцией $\cdot : S \times S \to S$ называется \emph{полугруппой} и обозначается $(S, \cdot)$. Если операция $\cdot$ является коммутативной, то говорят о \textit{коммутативной полугруппе}. \end{definition} \begin{example} Приведём несколько примеров полугрупп. \begin{itemize} - \item Положительные целые числа с операцией сложения являются полугруппой. Более того, коммутативной полугруппой. - \item Целые числа с операцией взятия наибольшего из двух ($\max$) являются полугруппой. Более того, коммутативной полугруппой. + \item Множество положительных целых чисел с операцией сложения является коммутативной полугруппой. + \item Множество целых чисел с операцией взятия наибольшего из двух ($\max$) является коммутативной полугруппой. \item Множество всех строк конечной длины (без пустой строки) над фиксированным алфавитом $\Sigma$ с операцией конкатенации является полугруппой. Так как конкатенация на строках не является коммутативной операцией, то и полугруппа не является коммутативной. \end{itemize} \end{example} @@ -152,7 +152,7 @@ \section{Моноид} \begin{definition} - \emph{Моноидом} называется полугруппа с нейтральным элементом. Если операция является коммутативной, то можно гворить о коммутативном моноиде. + \emph{Моноидом} называется полугруппа с нейтральным элементом. Если операция является коммутативной, то можно говорить о \emph{коммутативном моноиде}. \end{definition} \begin{example} Приведём примеры моноидов, построенных на основе полугрупп из предыдущего раздела. @@ -188,7 +188,7 @@ \section{Полукольцо} \begin{definition} -Непустое множество $R$ с двумя бинарными операциями $\oplus\colon R \times R \to R$ (часто называют умножением) и $\otimes \colon R \times R \to R$ (часто называют сложением) называется \emph{полукольцом}, если выполнены следующие условия. +Непустое множество $R$ с двумя бинарными операциями $\oplus \colon R \times R \to R$ (часто называют сложением) и $\otimes \colon R \times R \to R$ (часто называют умножением) называется \emph{полукольцом}, если выполнены следующие условия. \begin{enumerate} \item $(R, \oplus)$ --- это коммутативный моноид, нейтральный элемент которого --- $\mathbb{0}$. Для любых $a,b,c \in R$: @@ -211,8 +211,10 @@ \section{Полукольцо} \end{itemize} -\item $\mathbb{0}$ является \textit{аннигилятором} по умножению: для любого $a \in R$ -$\mathbb{0} \otimes a = a \otimes 0 = 0$ +\item $\mathbb{0}$ является \textit{аннигилятором} по умножению: +\begin{itemize} + \item $\forall a \in R: \mathbb{0} \otimes a = a \otimes \mathbb{0} = \mathbb{0}$ +\end{itemize} \end{enumerate} @@ -225,7 +227,7 @@ \section{Полукольцо} Рассмотрим пример полукольца, а заодно покажем, что левая и правая дистрибутивность могут существовать независимо для некоммутативного умножения\footnote{Хороший пример того, почему левую и правую дистрибутивность в случае некоммутативного умножения нужно проверять независимо (правда, для колец), приведён Николаем Александровичем Вавиловым в книге ``Конкретная теория колец'' на странице 6~\cite{VavilovRings}.}. В качестве $R$ возьмём множество множеств строк конечной длины над некоторым алфавитом $\Sigma$. В качестве сложения возьмём теоретико-множественное объединение: $\oplus \equiv \cup$. Нейтральный элемент по сложению --- это пустое множество ($\varnothing$). -В качестве умножения возьмём конкатенацию множеств ($\otimes \equiv \odot$) и оперделим её следующим образом: +В качестве умножения возьмём конкатенацию множеств ($\otimes \equiv \odot$) и определим её следующим образом: $$ S_1 \odot S_2 = \{ w_1 \cdot w_2 \mid w_1 \in S_1, w_2 \in S_2\}$$, где $\cdot$ --- конкатенация строк. Нейтральным элементом по умножению будет являться множество из пустой строки: $\{\varepsilon\}$, где $\varepsilon$ --- обозначение для пустой строки. Проверим, что $(R, \cup, \odot)$ действительно полукольцо по нашему определению. @@ -251,7 +253,7 @@ \section{Полукольцо} \item $a \odot (b \cup c) = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \cup c\} = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \} \cup \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in c \} = (a \odot b) \cup (a \odot c)$ \item Аналогично, $(a \cup b) \odot c = (a \odot c) \cup (b \odot c)$ \end{itemize} -При этом, в общем случае, $a \odot (b \cup c) \neq (a \cup b) \odot c$. +При этом, в общем случае, $a \odot (b \cup c) \neq (b \cup c) \odot a$ из-за некоммутативности операции $\odot$. \item $\varnothing$ является \textit{аннигилятором} по умножению: для любого $a \in R$ верно, что @@ -317,7 +319,7 @@ \section{Матрицы и вектора} \begin{example}[Матрица] -Пусть есть моноид $(S,\cdot)$, где $S$ --- множества строк конечной длины над алфавитом \{a,b,c\}. +Пусть есть моноид $(S,\cdot)$, где $S$ --- множество строк конечной длины над алфавитом \{a,b,c\}. Тогда можно построить, например, следующую матрицу $2\times 3$. $$ M_{2\times 3} = @@ -345,10 +347,10 @@ \section{Матрицы и вектора} Операции над матрицами можно условно разделить на две группы: \begin{itemize} \item \textit{структурные} --- не зависящие от алгебраической структуры, над которой строилась матрица, и работающие только с её структурой; - \item \textit{алгебраические} --- определение таковых опирается на свойства алгебраигеской структуры, над которой построена матрица. + \item \textit{алгебраические} --- определение таковых опирается на свойства алгебраической структуры, над которой построена матрица. \end{itemize} -Примерами структурных операций является \textit{транспонирование}, \textit{взятие подматрицы} и \textit{взятие элеиента по индексу}. +Примерами структурных операций является \textit{транспонирование}, \textit{взятие подматрицы} и \textit{взятие элемента по индексу}. \begin{definition}[Транспонирование матрицы] Пусть дана матрица $M_{n\times m}$. Тогда результат её \emph{транспонирования} @@ -561,6 +563,11 @@ \section{Матрицы и вектора} \end{definition} +\begin{note}\label{note:KronIsNotCommutative} +Произведение Кронекера не является коммутативным. +При этом всегда существуют две матрицы перестановок $P$ и $Q$ такие, что $A \otimes B = P(B \otimes A)Q$. +\end{note} + \newcommand{\examplemtrx} { \begin{pmatrix} @@ -612,7 +619,7 @@ \section{Теоретическая сложность умножения мат В рамках такого раздела теории сложности, как мелкозернистая сложность (fine-grained complexity) задача умножения двух матриц оказалась достаточно важной, так как через вычислительную сложность этой задачи можно оценить сложность большого класса различных задач. С примерами таких задач можно ознакомиться в работе~\cite{Williams:2010:SEP:1917827.1918339}. Поэтому рассмотрим алгоритмы нахождения произведения двух матриц более подробно. Далее для простоты мы будем предполагать, что перемножаются две квадратные матрицы одинакового размера $n \times n$. -Для начал построим наивный алгоритм, сконструированный на основе определении произведения матриц. Такой алгоритм представлен на листинге~\ref{algo:MxM}. Его работу можно описать следующим образом: для каждой строки в первой матрице и для каждого столбца в второй матрице найти сумму произведений соответствующих элеиентов. Данная сумма будет значением соответствующей ячейки результирующей матрицы. +Для начала построим наивный алгоритм, сконструированный на основе определении произведения матриц. Такой алгоритм представлен на листинге~\ref{algo:MxM}. Его работу можно описать следующим образом: для каждой строки в первой матрице и для каждого столбца в второй матрице найти сумму произведений соответствующих элементов. Данная сумма будет значением соответствующей ячейки результирующей матрицы. \begin{algorithm} \floatname{algorithm}{Listing} @@ -633,11 +640,11 @@ \section{Теоретическая сложность умножения мат \end{algorithmic} \end{algorithm} -Сложность наивного произведения двух матриц составляет $O(n^3)$, что очевидным образом следует из псевдокода. Но можно ли улучшить этот алгоритм? Первый положительный ответ был опубликовал Ф. Штрассен в 1969 году~\cite{Strassen1969}. Сложность предложенного им алгоритма --- $O(n^{\log_2 7}) \approx O(n^{2.81})$. Основная идея --- рекурсивное разбиение исходных матриц на блоки $2 \times 2$ и вычисление их произведения с помощью только 7 умножений, а не 8. +Сложность наивного произведения двух матриц составляет $O(n^3)$, что очевидным образом следует из псевдокода. Но можно ли улучшить этот алгоритм? Первый положительный ответ был опубликовал Ф. Штрассен в 1969 году~\cite{Strassen1969}. Сложность предложенного им алгоритма --- $O(n^{\log_2 7}) \approx O(n^{2.81})$. Основная идея --- рекурсивное разбиение исходных матриц на блоки и вычисление их произведения с помощью только 7 умножений, а не 8. Рассмотрим алгоритм Штрассена более подробно. Пусть $A$ и $B$ --- две квадратные матрицы размера $2^n \times 2^n$\footnote{Если размер умножаемых матриц не является натуральной степенью двойки, мы дополняем исходные матрицы дополнительными нулевыми строками и столбцами.} над кольцом $R=(S,\oplus,\otimes)$. Наша задача найти матрицу $C = A \cdot B$. -Разделим матрицы $A, B$ и $C$ на четрые равные по размеру блока. +Разделим матрицы $A, B$ и $C$ на четыре равные по размеру блока. $$ A = \begin{pmatrix} @@ -687,15 +694,15 @@ \section{Теоретическая сложность умножения мат При таком способе вычисления мы получаем на одно умножение подматриц меньше, чем при наивном подходе. Это и приводит, в конечном итоге, к улучшению сложности всего алгоритма, который основывается на рекурсивном повторении проделанной выше процедуры. -Впоследствии сложность постепенно понижалась в ряде работ, таких как ~\cite{Pan1978,BiniCapoRoma1979,Schonhage1981,CoppWino1982,CoppWino1990}. Было введено специальное обозначение для показателя степени в данной оценке: $\omega$. То есть сложность умножения матриц --- это $O(n^\omega)$, и задача сводится к уменьшению значения $\omega$. В настоящее время работа над уменьшением показателя степени продолжается и сейчас уже предложены решения с $\omega < 2.373$\footnote{В данной области достаточно регулярно появляются новые результаты, дающие сравнительно небольшие, в терминах абсолютных величин, изменения. Так, в 2021 была педставлена работа, улучшающая значение $\omega$ в пятом знаке после запятой~\cite{alman2020refined}. Несмотря на кажущуюся несерьёзность результата, подобные работы имеют большое теоретическое значение, так как улучшают наше понимание исходной задачи и её свойств.}. +Впоследствии сложность постепенно понижалась в ряде работ, таких как ~\cite{Pan1978,BiniCapoRoma1979,Schonhage1981,CoppWino1982,CoppWino1990}. Было введено специальное обозначение для показателя степени в данной оценке: $\omega$. То есть сложность умножения матриц --- это $O(n^\omega)$, и задача сводится к уменьшению значения $\omega$. В настоящее время работа над уменьшением показателя степени продолжается и сейчас уже предложены решения с $\omega < 2.373$\footnote{В данной области достаточно регулярно появляются новые результаты, дающие сравнительно небольшие, в терминах абсолютных величин, изменения. Так, в 2021 была представлена работа, улучшающая значение $\omega$ в пятом знаке после запятой~\cite{alman2020refined}. Несмотря на кажущуюся несерьёзность результата, подобные работы имеют большое теоретическое значение, так как улучшают наше понимание исходной задачи и её свойств.}. -Всё тем же Ф. Штрассеном ещё в 1969 году была выдвинута гипотеза о том, что для достатого больших $n$ существует алгоритм, который для любого сколь угодно маленького наперёд заданного $\varepsilon$ перемножает матрицы за $O(n^{2+\varepsilon})$. На текущий момент ни доказательства, ни опровержения этой гипотезы не предъявлено. +Всё тем же Ф. Штрассеном ещё в 1969 году была выдвинута гипотеза о том, что для достаточно больших $n$ существует алгоритм, который для любого сколь угодно маленького наперёд заданного $\varepsilon$ перемножает матрицы за $O(n^{2+\varepsilon})$. На текущий момент ни доказательства, ни опровержения этой гипотезы не предъявлено. -Важной особенностью указанного выше направления улучшения алгоритмов является то, что оно допускает использования (и даже основывается на использовании) более богатых алгебраических структур, чем требуется для определения умножения двух матриц. Так, уже алгоритм Штрасеена использует операцию вычитания, что приводит к необходимости иметь обратные элементы по сложению, а значит определять матрицы над кольцом. Хотя для исходного определения (\ref{def:MxM}) достаточно более бедной структуры. При этом, часто, структуры, возникающие в прикладных задачах кольцами не являются. Примерами могут служить тропическое (или $\{min,+\}$) полукольцо, играющее ключевую роль в тропической математике, или булево ($\{\vee,\wedge\}$) полукольцо, возникающее, например, при работе с отношениями\footnote{Вообще говоря, в некоторых прикладных задачах возникают структуры, не являющиеся даже полукольцом. Предположим, что есть три различных множества $S_1, S_2$ и $S_3$ и две двухместные функции $f:S_1 \times S_2 \to S_3$ и $g: S_3 \times S_3 \to S_3$. Этого достаточно, чтобы определить произведение двух матриц $M_1$ и $M_2$, построенных из элементов множеств $S_1$ и $S_2$ соответственно. Результирующая матрица будет состоять из элеиентов $S_3$. Как видно, функции не являются бинарными операциями в смысле нашего определения. Несмотря на кажущуюся экзотичность, подобные структуры возникают на практике при работе с графами и учитываются, например, в стандарте GraphBLAS (\url{https://graphblas.github.io/}), где, кстати, называются полукольцами, что выглядит не вполне корректно.}. Значит, описанные выше решения не применимы и вопрос о существовании алгоритма с менее чем кубической сложностью снова актуален. +Важной особенностью указанного выше направления улучшения алгоритмов является то, что оно допускает использования (и даже основывается на использовании) более богатых алгебраических структур, чем требуется для определения умножения двух матриц. Так, уже алгоритм Штрасеена использует операцию вычитания, что приводит к необходимости иметь обратные элементы по сложению, а значит определять матрицы над кольцом. Хотя для исходного определения (\ref{def:MxM}) достаточно более бедной структуры. При этом, часто, структуры, возникающие в прикладных задачах кольцами не являются. Примерами могут служить тропическое (или $\{min,+\}$) полукольцо, играющее ключевую роль в тропической математике, или булево ($\{\vee,\wedge\}$) полукольцо, возникающее, например, при работе с отношениями\footnote{Вообще говоря, в некоторых прикладных задачах возникают структуры, не являющиеся даже полукольцом. Предположим, что есть три различных множества $S_1, S_2$ и $S_3$ и две двухместные функции $f:S_1 \times S_2 \to S_3$ и $g: S_3 \times S_3 \to S_3$. Этого достаточно, чтобы определить произведение двух матриц $M_1$ и $M_2$, построенных из элементов множеств $S_1$ и $S_2$ соответственно. Результирующая матрица будет состоять из элементов $S_3$. Как видно, функции не являются бинарными операциями в смысле нашего определения. Несмотря на кажущуюся экзотичность, подобные структуры возникают на практике при работе с графами и учитываются, например, в стандарте GraphBLAS (\url{https://graphblas.github.io/}), где, кстати, называются полукольцами, что выглядит не вполне корректно.}. Значит, описанные выше решения не применимы и вопрос о существовании алгоритма с менее чем кубической сложностью снова актуален. -В попытках ответить на этот вопрос появились так называемые комбинаторные алгоритмы умножения матриц\footnote{В противовес описанным выше, не являющимся комбинаторными. Стоит отметить, что строгое определение комбинаторных алгоритмов отсутствует, хотя этот термин и получил широкое употребление. В частности, Н.~Бансал (Nikhil Bansal) и Р.~Уильямс (Ryan Williams) в работе~\cite{5438580} дают определение комбинаторного алгоритма, но тут же замечают следующее: ``We would like to give a definition of ``combinatorial algorithm'', but this appears elusive. Although the term has been used in many of the cited references, nothing in the literature resembles a definition. For the purposes of this paper, let us think of a ``combinatorial algorithm'' simply as one that does not call an oracle for ring matrix multiplication.''. Ещё один вариант определения и его обсуждение можно найти в~\cite{das2018lower}.}. Классический результат в данной области --- это алгоритм четырёх русских, предложенный В. Л. Арлазаровым, Е. А. Диницем, М. А. Кронродом и И. А. Фараджевым в 1970 году~\cite{ArlDinKro70}, позволяющий перемножить матрицы над конечным полукольцом за $O(n^3/\log n)$. Лучшим результатом\footnote{В работе~\cite{das2018lower} предложен алгоритм со сложностью $\Omega(n^{7/3}/2^{O(\sqrt{\log n})})$, однако авторы утверждают, тчо сами не уверены в комбинаторности предложенного решения. По-видимому, полученные результаты ещё должны быть проверены сообществом.} в настоящее время является алгоритм со сложностью $\hat{O}(n^3/\log^4 n)$\footnote{Нотация $\hat{O}$ скрывает $poly(\log\log)$ коэффициенты.}~\cite{10.1007/978-3-662-47672-7_89}. +В попытках ответить на этот вопрос появились так называемые комбинаторные алгоритмы умножения матриц\footnote{В противовес описанным выше, не являющимся комбинаторными. Стоит отметить, что строгое определение комбинаторных алгоритмов отсутствует, хотя этот термин и получил широкое употребление. В частности, Н.~Бансал (Nikhil Bansal) и Р.~Уильямс (Ryan Williams) в работе~\cite{5438580} дают определение комбинаторного алгоритма, но тут же замечают следующее: ``We would like to give a definition of ``combinatorial algorithm'', but this appears elusive. Although the term has been used in many of the cited references, nothing in the literature resembles a definition. For the purposes of this paper, let us think of a ``combinatorial algorithm'' simply as one that does not call an oracle for ring matrix multiplication.''. Ещё один вариант определения и его обсуждение можно найти в~\cite{das2018lower}.}. Классический результат в данной области --- это алгоритм четырёх русских, предложенный В. Л. Арлазаровым, Е. А. Диницем, М. А. Кронродом и И. А. Фараджевым в 1970 году~\cite{ArlDinKro70}, позволяющий перемножить матрицы над конечным полукольцом за $O(n^3/\log n)$. Лучшим результатом\footnote{В работе~\cite{das2018lower} предложен алгоритм со сложностью $\Omega(n^{7/3}/2^{O(\sqrt{\log n})})$, однако авторы утверждают, что сами не уверены в комбинаторности предложенного решения. По-видимому, полученные результаты ещё должны быть проверены сообществом.} в настоящее время является алгоритм со сложностью $\hat{O}(n^3/\log^4 n)$\footnote{Нотация $\hat{O}$ скрывает $poly(\log\log)$ коэффициенты.}~\cite{10.1007/978-3-662-47672-7_89}. -Как видим, особенности алгебраических структур накладывают серьёзные ограничения на возможности конструирования алгоритмов. Отметим, что, хотя, в указанных случаях и предлагаются решения лучшие, чем наивное кубическое, они обладают принципиально разной асимптотической сложностью. в первом случае сложность оценивается полиномом, степень которого меньше третьей. Такие решения принято называть \textit{истинно субкубическими} (truly subcubic). В то время как в случае комбинаторных алгоритмов степень полинома остается прежней, третьей, хотя сложность и уменьшается на логарифмический фактор. Такие решения принято называть \textit{слегка субкубическими} (mildly subcubic). Естественный вопрос о существовании истинно субкубического агоритма перемножения матриц над полукольцами (или же комбинаторного перемножения матриц) всё ещё не решён\footnote{Один из кандидатов --- работа~\cite{das2018lower}, однако на текущий момент предложенное в ней решение требует проверки.}. +Как видим, особенности алгебраических структур накладывают серьёзные ограничения на возможности конструирования алгоритмов. Отметим, что, хотя, в указанных случаях и предлагаются решения лучшие, чем наивное кубическое, они обладают принципиально разной асимптотической сложностью. в первом случае сложность оценивается полиномом, степень которого меньше третьей. Такие решения принято называть \textit{истинно субкубическими} (truly subcubic). В то время как в случае комбинаторных алгоритмов степень полинома остается прежней, третьей, хотя сложность и уменьшается на логарифмический фактор. Такие решения принято называть \textit{слегка субкубическими} (mildly subcubic). Естественный вопрос о существовании истинно субкубического алгоритма перемножения матриц над полукольцами (или же комбинаторного перемножения матриц) всё ещё не решён\footnote{Один из кандидатов --- работа~\cite{das2018lower}, однако на текущий момент предложенное в ней решение требует проверки.}. %Заметим, что скалярная операция --- это частный случай произвеления Кронекера: достаточно превратить элемент носителя полугруппы в матрицу размера $1\times 1$. diff --git a/tex/Matrix-based_CFPQ.tex b/tex/Matrix-based_CFPQ.tex index bbaf13c..b4927ed 100644 --- a/tex/Matrix-based_CFPQ.tex +++ b/tex/Matrix-based_CFPQ.tex @@ -1,6 +1,6 @@ \chapter{КС и конъюнктивная достижимость через произведение матриц}\label{chpt:MatrixBasedAlgos} -В данном разделе мы рассмотрим алгоритм решения задачи контекстно-свободной и конъюнктивной достижимости, основанный на произведении матриц. Будет показано, что при использовании конъюнктивных граммтик, представленный алгоритм находит переапроксимацию истинного решения задачи. +В данном разделе мы рассмотрим алгоритм решения задачи контекстно-свободной и конъюнктивной достижимости, основанный на произведении матриц. Будет показано, что при использовании конъюнктивных грамматик, представленный алгоритм находит переапроксимацию истинного решения задачи. \section{КС достижимость через произведение матриц} \label{Matrix-CFPQ} @@ -24,7 +24,7 @@ \section{КС достижимость через произведение ма Для частного случая этой задачи, синтаксического анализа линейного входа, существует алгоритм Валианта~\cite{Valiant:1975:GCR:1739932.1740048}, использующий эту идею. Однако он не обобщается на графы из-за того, что существенно использует возможность упорядочить обход матрицы (см. разницу в CYK для линейного случая и для графа). -Поэтому, хотя для линейного случая алгоритм Валианта является алгоритмом синтаксического анализа для произвольных КС граммтик за субкубическое время, его обобщение до задачи КС достижимости в произвольных графах с сохранением асимптотики является нетривиальной задачей~\cite{Yannakakis}. +Поэтому, хотя для линейного случая алгоритм Валианта является алгоритмом синтаксического анализа для произвольных КС грамматик за субкубическое время, его обобщение до задачи КС достижимости в произвольных графах с сохранением асимптотики является нетривиальной задачей~\cite{Yannakakis}. В настоящее время алгоритм с субкубической сложностью получен только для частного случая --- языка Дика с одним типом скобок --- Филипом Брэдфорlом~\cite{8249039}. В случае с линейным входом, отдельного внимания заслуживает работа Лиллиан Ли (Lillian Lee)~\cite{Lee:2002:FCG:505241.505242}, где она показывает, что задача перемножения матриц сводима к синтаксическому анализу линейного входа. Аналогичных результатов для графов на текущий момент не известно. @@ -210,7 +210,7 @@ \subsection{Расширение алгоритма для конъюнктив \input{figures/multi/graph0.tex} \end{center} Применяя алгоритм, получим, что существует путь из вершины 0 в вершину 4, выводимый из нетерминала $S$. Однако очевидно, что в графе такого пути нет. - Такое поведение алгоритма наблюдается из-за того, что существует путь ``abcc'', соответствующий $L(AB) = \{abc^*\}$ и путь ``aabc'', соответствующий $L(DC) = \{a^{*}bc\}$, но они различны. Однако алгоритм не может это проверить, так как оперирует понятием достижимости между вершинами, а не наличием различных путей. Более того, в общем случае для конъюнктивных граммтик такую проверку реалиховать нельзя. Поэтому для классической семантики достидимости с ограничениями в терминах конъюнктивных граммтик результат работы алгоритма является оценкой сверху. + Такое поведение алгоритма наблюдается из-за того, что существует путь ``abcc'', соответствующий $L(AB) = \{abc^*\}$ и путь ``aabc'', соответствующий $L(DC) = \{a^{*}bc\}$, но они различны. Однако алгоритм не может это проверить, так как оперирует понятием достижимости между вершинами, а не наличием различных путей. Более того, в общем случае для конъюнктивных грамматик такую проверку реалиховать нельзя. Поэтому для классической семантики достидимости с ограничениями в терминах конъюнктивных грамматик результат работы алгоритма является оценкой сверху. Существует альтернативная семантика, когда мы трактуем конъюнкцию в праой части правил как крнъюнкцию в Datalog (подробнее о Datalog в параграфе~\ref{Subsection Datalog}). Т.е если есть правило $S \to AB \& DC$, то должен быть путь принадлежащий языку $L(AB)$ и путь принадлежащий языку $L(DC)$. В такой семантике алгоритм дает точный ответ. \end{example} @@ -253,7 +253,7 @@ \section{Особенности реализации} 1 & 0 & 0 & 0 \\ \end{pmatrix} \end{alignat*} -Тогда при наличии правила $S \to A B$ в граммтике получим: +Тогда при наличии правила $S \to A B$ в грамматике получим: \[ T_{1\_S} =T_{0\_A} \times T_{0\_B} = \begin{pmatrix} 0 & 0 & 0 & 0 \\ @@ -264,13 +264,13 @@ \section{Особенности реализации} \] \end{example} -Алгоритм же может быть переформулирован так, как показано в листинге~\ref{lst:algo1}. Такой взгляд на алгоритм позволяет использдвать для его реализации существующие высокорпоизводительные библиотеки для работы с булевыми матрицами (например M4RI\footnote{M4RI --- одна из высокопроизводительных библиотек для работы с логическими матрицами на CPU. Реализует Метод Четырёх Русских. Исходный код библиотеки: \url{https://bitbucket.org/malb/m4ri/src/master/}. Дата посещения: 30.03.2020.}~\cite{DBLP:journals/corr/abs-0811-1714}) или библиотеки для линейной алгебры (например CUSP~\cite{Cusp}). +Алгоритм же может быть переформулирован так, как показано в листинге~\ref{lst:cfpq_mtx_bool}. Такой взгляд на алгоритм позволяет использовать для его реализации существующие высокорпоизводительные библиотеки для работы с булевыми матрицами (например M4RI\footnote{M4RI --- одна из высокопроизводительных библиотек для работы с логическими матрицами на CPU. Реализует Метод Четырёх Русских. Исходный код библиотеки: \url{https://bitbucket.org/malb/m4ri/src/master/}. Дата посещения: 30.03.2020.}~\cite{DBLP:journals/corr/abs-0811-1714}) или библиотеки для линейной алгебры (например CUSP~\cite{Cusp}). \begin{algorithm} \floatname{algorithm}{Listing} \begin{algorithmic}[1] -\caption{Context-free path quering algorithm. Boolean matrix version} -\label{lst:algo1} +\caption{Context-free path querying algorithm. Boolean matrix version} +\label{lst:cfpq_mtx_bool} \Function{evalCFPQ}{$D=(V,E), G=(N,\Sigma,P)$} \State{$n \gets$ |V|} \State{$T \gets \{T^{A_i} \mid A_i \in N, T^{A_i}$ is a matrix $n \times n$, $T^{A_i}_{k,l} \gets$ \texttt{false}\} } @@ -295,7 +295,7 @@ \section{Особенности реализации} \end{algorithmic} \end{algorithm} -С другой стороны, для запросов, выразимых в терминах граммтик с небольшим количеством нетерминалов, практически может быть выгодно представлять множества нетерминалов в ячейке матрицы в виде битового вектора следующим образом. +С другой стороны, для запросов, выразимых в терминах грамматик с небольшим количеством нетерминалов, практически может быть выгодно представлять множества нетерминалов в ячейке матрицы в виде битового вектора следующим образом. Нумеруем все нетерминалы с нуля, в векторе стоит 1 на позиции $i$, если в множестве есть нетерминал с номером $i$. Таким образом, в каждой ячейке хранится битовый вектор длины $|N|$. Тогда операция умножения определяется следующим образом: @@ -328,18 +328,18 @@ \section{Особенности реализации} На практике в роли векторов могут выступать беззнаковые целые числа. -Например, 32 бита под ячейки в матрице и 64 бита под правила (или 8 и 16, если позволяет количество нетерминалов в граммтике, или 16 и 32). +Например, 32 бита под ячейки в матрице и 64 бита под правила (или 8 и 16, если позволяет количество нетерминалов в грамматике, или 16 и 32). Тогда умножение выражается через битовые операции и сравнение, что довольно эффективно с точки зрения вычислений. -Для небольших запросов такой подход к реализации может оказаться быстрее --- в данном случае скорость зависит от деталей. Минус подхода в том, что нет возможности использовать готовые библиотеку ленейной алгебры без предварительной модификации. Только если они не являются параметризуемыми и не позволяют задать собственный тип и собственную операцию умножения и сложения (иными словами, собственное полукольцо). Такую возможность предусматривает, например, стандарт GraphBLAS\footnote{GraphBLAS --- открытый стандарт, описывающий набор примитивов и операций, необходимый для реализации графовых алгоритмов в терминах лнейной алгебры. Web-страница проекта: \url{https://github.com/gunrock/graphblast}. Дата доступа: 30.03.2020.} и, соответственно, его реализации, такие как SuiteSparce\footnote{SuteSparse --- это специализированное программное обеспечения для работы с разреженными матрицами, которое включает в себя реализацию GraphBLAS API. Web-страница проекта: \url{http://faculty.cse.tamu.edu/davis/suitesparse.html}. Дата доступа: 30.03.2020.}~\cite{Davis2018Algorithm9S}. +Для небольших запросов такой подход к реализации может оказаться быстрее --- в данном случае скорость зависит от деталей. Минус подхода в том, что нет возможности использовать готовые библиотеку линейной алгебры без предварительной модификации. Только если они не являются параметризуемыми и не позволяют задать собственный тип и собственную операцию умножения и сложения (иными словами, собственное полукольцо). Такую возможность предусматривает, например, стандарт GraphBLAS\footnote{GraphBLAS --- открытый стандарт, описывающий набор примитивов и операций, необходимый для реализации графовых алгоритмов в терминах линейной алгебры. Web-страница проекта: \url{https://github.com/gunrock/graphblast}. Дата доступа: 30.03.2020.} и, соответственно, его реализации, такие как SuiteSparse\footnote{SuiteSparse --- это специализированное программное обеспечения для работы с разреженными матрицами, которое включает в себя реализацию GraphBLAS API. Web-страница проекта: \url{http://faculty.cse.tamu.edu/davis/suitesparse.html}. Дата доступа: 30.03.2020.}~\cite{Davis2018Algorithm9S}. -Также стоит замеить, что при работе с реальными графами матрицы как правило оказываются разреженными, а значит необходимо использовать соответствующие представления матриц (CRS, покоординатное, Quad Tree~\cite{quadtree}) и библиотеки, работающие с таким представлениями. +Также стоит заметить, что при работе с реальными графами матрицы как правило оказываются разреженными, а значит необходимо использовать соответствующие представления матриц (CRS, покоординатное, Quad Tree~\cite{quadtree}) и библиотеки, работающие с таким представлениями. -Однако даже при использовании разреженных матриц, могут возникнуть проблемы с размером реальных данных и объёмом памяти. Напрмиер, для вычислений на GPGPU лучше всего, когда все нужные для вычисления матрицы помещаются на одну карту. Тогда можно свести обмен данными сежду хостом и графическим сопроцессором к мимнимуму. Если не помещаются все, то нужно, чтобы помещалясь хотя бы тройка непостредственно обрабатываемых матриц (два операнда и результат). В самом тяжёлом случае в памяти не удаётся раместить даже операнды целиком и тогда приходится прибегать к поблочному умнодению матриц. +Однако даже при использовании разреженных матриц, могут возникнуть проблемы с размером реальных данных и объёмом памяти. Например, для вычислений на GPGPU лучше всего, когда все нужные для вычисления матрицы помещаются на одну карту. Тогда можно свести обмен данными между хостом и графическим сопроцессором к минимуму. Если не помещаются все, то нужно, чтобы помещалась хотя бы тройка непосредственно обрабатываемых матриц (два операнда и результат). В самом тяжёлом случае в памяти не удаётся разместить даже операнды целиком и тогда приходится прибегать к поблочному умножению матриц. Отдельной инженерной проблемой является масштабирование алгоритмов на несколько вычислительных узлов, как на несколько CPU, так и на несколько GPGPU. -Важным свойством рассмотренного алгоритма является то, что описанные проблемы с объёмом памяти и масштабированием могут эффективно решаться в рамках библиотек линейной алгебры общего назначения, что избавляет от необходимости создавать специализированные решения для конкетных задач. +Важным свойством рассмотренного алгоритма является то, что описанные проблемы с объёмом памяти и масштабированием могут эффективно решаться в рамках библиотек линейной алгебры общего назначения, что избавляет от необходимости создавать специализированные решения для конкретных задач. %\section{Вопросы и задачи} diff --git a/tex/SPPF.tex b/tex/SPPF.tex index b009d21..95b0fbf 100644 --- a/tex/SPPF.tex +++ b/tex/SPPF.tex @@ -1,14 +1,14 @@ \chapter{Сжатое представление леса разбора} Матричный алгоритм даёт нам ответ на вопрос о достижимости, но не предоставляет самих путей. -Что делать, если мы хотим построить все пути, удовлетворяющие ограичениям? +Что делать, если мы хотим построить все пути, удовлетворяющие ограничениям? Проблема в том, что искомое множество путей может быть бесконечным. Можем ли мы предложить конечную структуру, однозначно описывающую такое множество? Вспомним, что пересечение контекстно-свободного языка с регулярным --- это контекстно-свободный язык. -Мы знаем, что конекстно-свободный язык можно описать коньекстно-своюодной граммтикой, которая конечна. +Мы знаем, что контекстно-свободный язык можно описать контекстно-свободной грамматикой, которая конечна. Это и есть решение нашего вопроса. -Осталось толко научиться строить такую грамматику. +Осталось только научиться строить такую грамматику. Прежде, чем двинуться дальше, рекомендуется вспомнить всё, что касается деревьев вывода~\ref{sect:DerivTree}. @@ -16,12 +16,12 @@ \section{Лес разбора как представление контекс Для начала нам потребуется внести некоторые изменения в конструкцию дерева вывода. -Во-первых, заметим, что в дереве вывода каждый узел соответсвует выводу какой-то подстроки с известными позициями начала и конца. +Во-первых, заметим, что в дереве вывода каждый узел соответствует выводу какой-то подстроки с известными позициями начала и конца. Давайте будем сохранять эту информацию в узлах дерева. Таким образом, метка любого узла это тройка вида $(i,q,j)$, где $i$ --- координата начала подстроки, соответствующей этому узлу, $j$ --- координата конца, $q \in \Sigma \cup N$ --- метка как в исходном определении. -Во-вторых, заметим, что внутренний узел со своими сыновьями связаны с продукцией в граммтике: узел появляется благодаря применению конкретной продукции в процессе вывода. -Давайте занумеруем все продукции в граммтике и добавим в дерево вывода ещё один тип узлов (дополнительные узлы), в которых будем хранить номер применённой продукции. +Во-вторых, заметим, что внутренний узел со своими сыновьями связаны с продукцией в грамматике: узел появляется благодаря применению конкретной продукции в процессе вывода. +Давайте занумеруем все продукции в грамматике и добавим в дерево вывода ещё один тип узлов (дополнительные узлы), в которых будем хранить номер применённой продукции. Получим следующую конструкцию: непосредственный предок дополнительного узла --- это левая часть продукции, а непосредственные сыновья дополнительного узла --- это правая часть продукции. \begin{example} @@ -150,15 +150,15 @@ \section{Лес разбора как представление контекс & \} \rangle \end{align*} -Пердположим, что мы строим левосторонний вывод. -Тогда после первого применеия продукции 0 у нас есть два варианта переписывания первого нетерминала: либо с применением продукции 0, либо с применением продукции 1: +Предположим, что мы строим левосторонний вывод. +Тогда после первого применения продукции 0 у нас есть два варианта переписывания первого нетерминала: либо с применением продукции 0, либо с применением продукции 1: \begin{align*} &\textbf{S} \xrightarrow{0} \textbf{S}S \xrightarrow{0} \textbf{S}SS \xrightarrow{1} a\textbf{S}bSS \xrightarrow{2} ab\textbf{S}S \xrightarrow{1} aba\textbf{S}bS \xrightarrow{2} abab\textbf{S} \xrightarrow{1} ababa\textbf{S}b \xrightarrow{2} ababab \\ &\textbf{S} \xrightarrow{0} \textbf{S}S \xrightarrow{1} a\textbf{S}bS \xrightarrow{2} ab\textbf{S} \xrightarrow{0} ab\textbf{S}S \xrightarrow{1} aba\textbf{S}bS \xrightarrow{2} abab\textbf{S} \xrightarrow{1} ababa\textbf{S}b \xrightarrow{2} ababab \end{align*} -Сначал рассмотрим первый вариант (применили переписываение по подукции 0). +Сначала рассмотрим первый вариант (применили переписывание по продукции 0). Все остальные шаги вывода деретерминированы и в результате мы получим следующее дерево разбора: \begin{center} @@ -349,7 +349,7 @@ \section{Лес разбора как представление контекс В двух построенных деревьях большое количество одинаковых узлов. Построим структуру, которая содержит оба дерева и при этом никакие нетерминальные и терминальные узлы не встречаются дважды. -В результате мы молучим следующий граф: +В результате мы получим следующий граф: \begin{center} \resizebox{0.9\textwidth}{!}{ @@ -448,8 +448,8 @@ \section{Лес разбора как представление контекс Мы получили очень простой вариант сжатого представления леса разбора (Shared Packed Parse Forest, SPPF). Впервые подобная идея была предложена Джоаном Рекерсом в его кандидатской диссертации~\cite{SPPF}. -В дальнейшем она нашла широкое применеие в обобщённом (generalized) синтаксическом анализе и получила серьёзное развитие. -В частности, наш вариант, хоть и позволяет избежать экспоненциального разростания леса разбора, всё же не является оптимальным. +В дальнейшем она нашла широкое применение в обобщённом (generalized) синтаксическом анализе и получила серьёзное развитие. +В частности, наш вариант, хоть и позволяет избежать экспоненциального разрастания леса разбора, всё же не является оптимальным. Оптимальное асимптотическое поведение достигается при использовании бинаризованного SPPF~\cite{Billot:1989:SSF:981623.981641} --- в этом случае объём леса составляет $O(n^3)$, где $n$ --- это длина входной строки. Различные модификации SPPF применяются в таких алгоритмах синтаксического анализа, как RNGLR~\cite{Scott:2006:RNG:1146809.1146810}, бинаризованная верся SPPF в BRNGLR~\cite{Scott:2007:BCT:1289813.1289815} и GLL~\cite{Scott:2010:GP:1860132.1860320,10.1007/978-3-662-46663-6_5}\footnote{Ещё немного полезной информации про SPPF: \url{http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/}.}. @@ -561,7 +561,7 @@ \section{Лес разбора как представление контекс Мы построили дерево вывода для одного пути из вершины 2 в неё же. - Но можно заметить, что таких путей бесконечно моного: мы можем бесконечное число раз повтроять уже выполненный обход и получать всё более длинные пути. + Но можно заметить, что таких путей бесконечно много: мы можем бесконечное число раз повторять уже выполненный обход и получать всё более длинные пути. В терминах дерева вывода это будет означать, что к узлу $_1S_3$ мы добавим сына, соответствующего применению продукции 0, а не 1 для нетерминала $S$. В таком случае мы получим узел $_2S_2$, который уже существует в дереве и таким образом замкнём цикл. @@ -711,7 +711,7 @@ \section{Лес разбора как представление контекс % \item Как связаны между собой леса, полученные в предыдущих двух задачах (\ref{t1} и \ref{t2})? Какие выводы можно сделать из такой связи? % \item Постройте сжатое представление леса разбора, полученного в задаче~\ref{t1}. % \item Постройте сжатое представление леса разбора, полученного в задаче~\ref{t2}. -% \item \label{t3}Предъявите контекстно-свободную граммтику существенно неоднозначного языка. -% Возьмите цепочку длины болше пяти, при надлежащую этому языку, и постройте все деревья вывода этой цепочки в предъявленной граммтике. +% \item \label{t3}Предъявите контекстно-свободную грамматику существенно неоднозначного языка. +% Возьмите цепочку длины больше пяти, при надлежащую этому языку, и постройте все деревья вывода этой цепочки в предъявленной грамматике. % \item Постройте сжатое представление леса, полученного в задаче~\ref{t3}. %\end{enumerate} diff --git a/tex/TensorProduct.tex b/tex/TensorProduct.tex index 7376920..553f17f 100644 --- a/tex/TensorProduct.tex +++ b/tex/TensorProduct.tex @@ -60,61 +60,6 @@ \section{Рекурсивные автоматы и сети} \section{Тензорное произведение} \label{section2} -Тензорное произведение матриц или произведение Кронекера --- это бинарная операция, обозначаемая $\otimes$ и определяемая следующим образом. - -\begin{definition} -Пусть даны две матрицы: $A$ размера $m\times n$ и $B$ размера $p\times q$. -Произведение Кронекера или тензорное произведение матриц $A$ и $B$ --- это блочная матрица $C$ размера $mp \times nq$, вычисляемая следующим образом: -$$ -C = A \otimes B = -\begin{pmatrix} -A_{0,0}B & \cdots & A_{0,n-1}B \\ -\vdots & \ddots & \vdots \\ -A_{m-1,0}B & \cdots & A_{m-1,n-1}B -\end{pmatrix} -$$ -\end{definition} - -%\newcommand{\examplemtrx} -%{ -%\begin{pmatrix} -%5 & 6 & 7 & 8 \\ -%9 & 10 & 11 & 12 \\ -%13 & 14 & 15 & 16 -%\end{pmatrix} -%} - -\begin{example} -\begin{align} -\begin{pmatrix} -1 & 2 \\ -3 & 4 -\end{pmatrix} -\otimes -\examplemtrx &= -\begin{pmatrix} -1\examplemtrx & 2\examplemtrx \\ -3\examplemtrx & 4\examplemtrx -\end{pmatrix} -=\notag \\ -&= -\left(\begin{array}{c c c c | c c c c} -5 & 6 & 7 & 8 & 10 & 12 & 14 & 16 \\ -9 & 10 & 11 & 12 & 18 & 20 & 22 & 24 \\ -13 & 14 & 15 & 16 & 26 & 28 & 30 & 32 \\ -\hline -15 & 18 & 21 & 24 & 20 & 24 & 28 & 32 \\ -27 & 30 & 33 & 36 & 36 & 40 & 44 & 48 \\ -39 & 42 & 45 & 48 & 52 & 56 & 60 & 64 -\end{array}\right) -\end{align} -\end{example} - -Заметим, что для определения тензорного произведения матриц достаточно определить операцию умножения на элементах исходных матриц. -Также отметим, что произведение Кронекера не является коммутативным. -При этом всегда существуют две матрицы перестоновок $P$ и $Q$ такие, что $A \otimes B = P(B \otimes A)Q$. -Это свойство потребуется нам в дальнейшем. - Теперь перейдём к графам. Сперва дадим классическое определение тензорного произведения двух неориентированных графов. @@ -221,11 +166,11 @@ \section{Алгоритм} Идея алгоритма основана на обобщении пересечения двух конечных автоматов до пересечения рекурсивного автомата, построенного по грамматике, со входным графом. Пересечение двух конечных автоматов --- тензорное произведение соответствующих графов. -Пересечение языков коммутативно, тензорное произведение нет, но, как было сказано в разделе~\ref{section2}, существует решение этой проблемы. +Пересечение языков коммутативно, тензорное произведение нет, но, как было сказано в замечании~\ref{note:KronIsNotCommutative}, существует решение этой проблемы. Будем рассматривать два конечных автомата: одни получан из входного графа, второй из грамматики. Можно найти их пересечение, вычислив тензорное произведение матриц смежности соответствующих графов. -Однако, одной такой итерации не достаточно для решения исходной задачи. За первую итерацию мы найдём только те пути, которые выводятся в граммтике за одни шаг. После этого необходимо добавить соответствующие рёбра во входной граф и повторить операцию: так мы найдём пути, выводимые за два шага. Данные действия надо повторять до тех пор, пока не перестанут находиться новые пары достижимых вершин. +Однако, одной такой итерации не достаточно для решения исходной задачи. За первую итерацию мы найдём только те пути, которые выводятся в грамматике за одни шаг. После этого необходимо добавить соответствующие рёбра во входной граф и повторить операцию: так мы найдём пути, выводимые за два шага. Данные действия надо повторять до тех пор, пока не перестанут находиться новые пары достижимых вершин. Псевдокод, описывающий данные действия, представлен в листинге~\ref{lst:algo1}. \begin{algorithm} @@ -276,9 +221,9 @@ \section{Алгоритм} Во время итерации по ячейкам матрицы транзитивного замыкания алгоритм сначала проверяет наличие ребра в данной ячейке, а затем --- принадлежность стартовой и конечной вершин ребра к стартовому и конечному состоянию входного рекурсивного автомата. При удовлетворении этих условий алгоритм добавляет нетерминал (или нетерминалы), соответствующие стартовой и конечной вершинам ребра, в ячейку матрицы $M_2$, полученной с благодаря функции $getCoordinates(i,j)$. -Представленный алгоритм не требует преобразования граммтики в ОНФХ, более того, рекурсивный автомат может быть минимизирован. Однако, результатом тензорного рпоизведения является матрица существенно б\'{о}льшего размера, чем в алгоритме, основанном на матричном рпоизведении. кроме этого, необходимо искать транзитивное замыкание этой матрицы. +Представленный алгоритм не требует преобразования грамматики в ОНФХ, более того, рекурсивный автомат может быть минимизирован. Однако, результатом тензорного рпоизведения является матрица существенно б\'{о}льшего размера, чем в алгоритме, основанном на матричном рпоизведении. кроме этого, необходимо искать транзитивное замыкание этой матрицы. -Ещё одним важным свойством представленного алгоритма является его оптимальность при обработке регулярных запросов. Так как по контекстно свободной граммтике мы не можем поределить, задаёт ли она регулярный язык, то при добавлении в язык запросов возмодности задавать контекстно-свобдные ограничения, возникает проблема: мы не можем в общем случае отличить регулярный запрос от контекстно-свободного. Следовательно, мы вынуждены применять наиболее общий механизм выполнения заросов, что может приводить к существенным накладным расходам при выполнении регулярного запроса. Данный же алгоритм не выполнит лишних действий, так как сразу выполнит классическое пересечение двух автоматов и получит результат. +Ещё одним важным свойством представленного алгоритма является его оптимальность при обработке регулярных запросов. Так как по контекстно свободной грамматике мы не можем поределить, задаёт ли она регулярный язык, то при добавлении в язык запросов возмодности задавать контекстно-свобдные ограничения, возникает проблема: мы не можем в общем случае отличить регулярный запрос от контекстно-свободного. Следовательно, мы вынуждены применять наиболее общий механизм выполнения заросов, что может приводить к существенным накладным расходам при выполнении регулярного запроса. Данный же алгоритм не выполнит лишних действий, так как сразу выполнит классическое пересечение двух автоматов и получит результат. \section{Примеры} @@ -801,7 +746,7 @@ \section{Примеры} То есть желательно получить как можно более компактное описание контекстно-свободного языка. Для примера возьмём в качестве КС языка язык Дика на одном типе скобок и опишем его двумя различными грамматиками. -Первая граммтика классическая: +Первая грамматика классическая: $$ G_1 = \langle \{a,\ b\}, \{ S \}, \{S \to a \ S \ b \ S \mid \varepsilon \} \rangle $$ diff --git a/tex/figures/graph/graph3.tex b/tex/figures/graph/graph3.tex index c40c5fb..780b751 100644 --- a/tex/figures/graph/graph3.tex +++ b/tex/figures/graph/graph3.tex @@ -11,10 +11,10 @@ \node[state] (q_2) at (T60.apex) {$2$}; \node[state] (q_3) [right=1.5cm of q_2] {$3$}; \path[->] - (q_0) edge[left] node {a} (q_1) - (q_1) edge[above] node {a} (q_2) - (q_2) edge[below] node {a} (q_0) - (q_2) edge[bend left = 20, above] node {a} (q_3) - (q_2) edge[bend left = 60, above] node {b} (q_3) - (q_3) edge[bend left, below] node {b} (q_2); + (q_0) edge[left] node {$\{a\}$} (q_1) + (q_1) edge[above] node {$\{a\}$} (q_2) + (q_2) edge[below] node {$\{a\}$} (q_0) + (q_2) edge[bend left = 15, above] node {$\{a\}$} (q_3) + (q_2) edge[bend left = 65, above] node {$\{b\}$} (q_3) + (q_3) edge[bend left, below] node {$\{b\}$} (q_2); \end{tikzpicture} \ No newline at end of file diff --git a/tex/figures/graph/graph5.tex b/tex/figures/graph/graph5.tex index c2036c7..75fa0fd 100644 --- a/tex/figures/graph/graph5.tex +++ b/tex/figures/graph/graph5.tex @@ -14,11 +14,11 @@ (q_0) edge[loop below] node {} () edge node {} (q_1) edge[bend right] node {} (q_2) - edge[bend right = 60] node {} (q_3) + edge[bend right = 55] node {} (q_3) (q_1) edge[loop above] node {} () edge[bend right] node {} (q_0) edge node {} (q_2) - edge[bend left = 50, above] node {} (q_3) + edge[bend left = 55, above] node {} (q_3) (q_2) edge[loop below] node {} () edge[bend right] node {} (q_1) edge node {} (q_0) diff --git a/tex/figures/graph/path0.tex b/tex/figures/graph/path0.tex index 75c6e51..0d7b638 100644 --- a/tex/figures/graph/path0.tex +++ b/tex/figures/graph/path0.tex @@ -1,6 +1,6 @@ \begin{tikzpicture}[on grid, auto] - \node[state] (v_1) {$v_1$}; - \node[state] (v_n) [right=2.0cm of v_1] {$v_n$}; + \node[state] (v_0) {$v_0$}; + \node[state] (v_n) [right=2.0cm of v_0] {$v_n$}; \path[->] - (v_1) edge [out=45] node {$\pi$} (v_n); + (v_0) edge [out=45] node {$\pi$} (v_n); \end{tikzpicture} \ No newline at end of file