\documentclass[12pt,fleqn,a4paper]{book}
% 
% Packages used:
%
\usepackage[koi8-r]{inputenc}
\usepackage[russian,english]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{amsthm}
%
% Common customization:
%
\input defs
%
% The document
%
\begin{document}
\selectlanguage{russian}
%
% Lecture title
%
\lecture{4}{Сложность недетерминированных вычислений по памяти}{Д. Ицыксон}

\section{Определения недетерминированной машины Тьюринга
и ее сложности по памяти}

\begin{enumerate}
\item
\emph{Недетерминированная} машина Тьюринга отличается от детерминированной тем,
что функция перехода $\delta(q,c)$ по состоянию $q$ и символу $c$
выдает теперь \emph{множество} троек
$\{ (q_1, c_1, d_1), (q_2, c_2, d_2),\ldots \}$, где $q_i$ --- состояние,
$c_i$ --- символ, а $d_i$ --- направление движения. Таким образом, из каждой
конфигурации есть много способов перейти в следующую. Образуется целое дерево 
вычислений. Соответственно, машина принимает слово тогда и только тогда, когда
есть ветвь вычислений, приводящая к принимающему состоянию. Время работы ---
длина максимальной ветви. Память --- максимальная память по всем ветвям.

\item
\emph{Недетерминированная} машина Тьюринга --- это обыкновенная 
детерминированная машина с
дополнительной лентой (подсказкой), которая доступна только для чтения
(readonly). Такая машина
принимает слово $x$, 
если существует подсказка, при которой машина, получая на 
дополнительную
ленту эту подсказку, а на вход --- $x$, останавливается
в принимающем состоянии. Время работы --- максимум
по всем подсказкам. Для памяти тоже самое, только для рабочих лент.
Память на дополнительной ленте не учитываем --- ведь подсказку
мы не обязаны даже читать полностью, а писать туда вообще не
разрешается (неформально, подсказка соответствует недетерминированному
выбору между $(q_i,c_i,d_i)$ на каждом шаге --- т.е. количество символов
в ней соответствует времени, а не памяти). Оказывается, существенно
то, как разрешается считывать символы с ленты подсказки:
\begin{enumerate}
\item \emph{offline}-модель: подсказку можно читать, как любую ленту;
\item \emph{online}-модель: подсказку можно читать только слева направо. 
\end{enumerate}
Обозначим соответствующие классы языков $\NSPACE_\mathrm{off}(f(n))$
и\linebreak$\NSPACE_\mathrm{on}(f(n))$ соответственно.
\end{enumerate}

Очевидно, что определение 1 эквивалентно online-модели.

Offline непригодна для измерений, так как она по памяти экспоненциально сильнее
online.

\begin{proposition}\label{prop:expspeedup}
$\NSPACE_{\mathrm{on}}(2^{f(n)}) \subseteq \NSPACE_{\mathrm{off}}(O(f(n))$.
\end{proposition}

\begin{proof}
Пусть $L \in {\NSPACE}_{\mathrm{on}}(2^{f(n)})$, $M$ --- соответствующая
ему (online) НМТ.

Для любого слова $x$ из $L$ существует вычисление машины $M$, 
приводящее к принимающему состоянию. Запишем это принимающее вычисление
как подсказку для offline машины. В строчку: начальная конфигурация,
далее все конфигурации подряд, и, наконец, принимающая конфигурация
(конфигурация включает в себя все необходимое для описания <<состояния>>,
в котором находится машина: текущее состояние, положение \emph{всех} головок
(двоичное число!),
содержимое \emph{рабочих} лент).

Теперь осталось проверить:

\begin{enumerate}
\item Правильность синтаксиса подсказки --- память $O(1)$.

\item Первая конфигурация --- действительно начальная
(в частности, входная лента содержит $x$),
а последняя --- действительно принимающая ---
память $O(1)$.
                 
\item Следующая конфигурация правильно получается
из предыдущей:

\begin{enumerate}
\item состояние машины и положение головок изменились в соответствии
с функцией $\delta$ --- память $O(f(n))$ (на счетчик для возвращения
к нужному месту предыдущей/последующей конфигурации --- где она начинается,
мы может найти и так),
ибо положение головки ---
это число, не превосходящее $2^{f(n)}$;

\item содержимое рабочих лент изменилось в соответствии с функцией $\delta$ ---
для этого нам нужно еще и хранить и увеличивать на единицу 
счетчик сравниваемой позиции 
%либо относительное смещение одной конфигурации относительно другой 
(чтобы сравнивать \emph{одинаковые} позиции конфигураций,
а затем возвращаться к \emph{следующей} позиции
предыдущей конфигурации), снова память $O(f(n))$.
\end{enumerate}
\end{enumerate}
\end{proof}

В дальнейшим мы используем только online-модель.

\section{Факты о сложности недетерминированных вычислений по памяти}

\begin{lemma}\label{lem:reachability}
Узнать, есть ли в графе путь между двумя вершинами, можно, используя
памяти не более квадрата логарифма числа вершин,
т.е. $\lang{Reachability}\in \DSPACE(O(\log^2 n))$.
\end{lemma}

\begin{proof} Определим трехместный предикат $\mathrm{PATH}(x, y, i)$, который
означает, что есть путь из $x$ в $y$ длины не более $2^i$.
(Тогда\linebreak$\mathrm{PATH}(x, y, \lceil \log n\rceil)$ --- искомый ответ.)
Очевидно,
\[
\mathrm{PATH}(x, y, i) \iff \exists z \ ( \mathrm{PATH}(x, z, i-1) \land
\mathrm{PATH}(z, y, i-1)).
\]
Пользуясь этим соотношением, получаем следующий рекурсивный алгоритм.

Шаг рекурсии: пусть в самом конце ленты 
написано $(x, y, i)$ --- тогда, стерев эту тройку, 
перебираем все $z$; для каждого из них
\begin{itemize}
\item пишем $(x,z,i-1)$ 
%и $(z,y,i-1)$ 
в конец ленты и 
совершаем рекурсивный вызов, 
\item если этот вызов закончился
успешно, пишем в конце ленты $(z,y,i-1)$ 
и совершаем еще один рекурсивный вызов,
\item если оба рекурсивных вызова закончились успешно,
то успешно завершаем вызов.
\end{itemize}
Если же нужного $z$ не было найдено, то завершаем вызов неудачно.

Рекурсия заканчивается, когда $x=y$ --- тогда вызов успешен,
либо когда $i=0$ --- тогда надо просто проверить, что в графе есть
ребро $(x,y)$.

Ясно, что при работе $\mathrm{PATH}(x,y,\lceil\log n\rceil)$
длина записи на ленте не превосходит
$ 3 \cdot \lfloor \log n\rfloor \cdot \mbox{длину чисел}=O(\log^2 n)$.
\end{proof}

\begin{theorem}
$\NSPACE(f)\subseteq\DSPACE(f^2)$ для 
%разумной\footnote{Для классов,
%определяемых с ограничением по памяти, <<разумная>> означает
%<<space constructible>>, т.е. такая, что существует машина,
%вычисляющая (двоичное представление) $f(n)$ 
%на входе $\underbrace{1\ldots1}_n$ и затрачивающая
%на это память не более $f(n)$.} 
space constructible функции 
$f(n) = \Omega(\log n)$.
\end{theorem}

\begin{proof}

Рассмотрим граф, заданный на конфигурациях НМТ, ограниченной по памяти $f(n)$.
Нам интересно, есть ли путь из начальной конфигурации в принимающую. Воспользуемся
алгоритмом из леммы. Сколько вершин в графе? Их не более $c^{f(n)}$,
поскольку ячеек используется не более $f(n)$.
Следовательно, по лемме~\ref{lem:reachability} достаточно памяти $O(f^2)$.
(Заметим, что сам граф нам хранить не надо, так как выяснить,
можно ли перейти из конфигурации $x$ в конфигурацию $y$,
можно с памятью $O(f(n))$ --- мы это делали в утверждении~\ref{prop:expspeedup}.)
\end{proof}

\begin{definition}
\[\PSPACE=\bigcup\limits_{k\in\mathbb{N}} \DSPACE(O(n^k)).\]
\[\class{NPSPACE}=\bigcup\limits_{k\in\mathbb{N}} \NSPACE(O(n^k)).\]
\end{definition}
\begin{corollary}
$\PSPACE=\class{NPSPACE}$.
\end{corollary}

Из этого следствия вытекает также, что 
$\class{NPSPACE}=\co\class{NPSPACE}$,
но из теоремы не вытекает, что $\NSPACE(f(n))=\co\NSPACE(O(f(n)))$.
Ниже мы докажем это более тонкое утверждение.
Начнем со вспомогательной леммы.

\begin{lemma}
Размер множества вершин
некоторого графа $G=(V,E)$, достижимых из заданной вершины $x\in V$,
можно вычислить на НМТ, используя память $O(\log |V|)$.
При этом можно их все перечислить.
\end{lemma}

\begin{proof}  Обозначим $S(k)$ --- это множество вершин, до которых есть путь
из $x$ длины  не более $k$. (Тогда $|S(n)|$ --- это требуемый результат.)

Мы будем вычислять $|S(k)|$ индуктивно, используя только $|S(k-1)|$.
База индукции: $|S(0)|=1$.

Пройдемся один раз по всем вершинам $u \in V$ и подсчитаем $l$ ---
количество вершин $u \in S(k)$.  

Как мы определим, что $u \in S(k)$? А вот как: перебираем все вершины $v$
и ищем среди них такую, что $v \in S(k-1) \land (v,u) \in E$. (Заодно проверяем, что
количество $v \in S(k-1)$ равно $|S(k-1)|$; если не равно, то вычисление
оказалось неудачным.)

Вы спросите, откуда же мы узнаем, что $v \in S(k-1)$? На это у нас есть
недетерминизм машины. Чтобы это узнать, берем с ленты подсказки
одно за другим числа $w_1, w_2, \dots, w_{k-2}$, которые мы подозреваем в 
том, что они последовательные вершины на искомом пути длины $\le k-1$ (соседние вершины
в пути могут совпадать) --- проверить, что
%. Положим $w_0=x$, осталось на $i$-ом шаге
%запрашивать $w_i$, проверить, что 
$\forall i\in[0\,.\,.\,k-2]\ ((w_i, w_{i+1}) \in E \,\lor\, w_i=w_{i+1})$,
нетрудно (здесь $w_0$ обозначает $x$, а $w_{k-1}=v$).
Если хотя бы одна проверка не прошла,
то
считаем, что $v\notin S(k-1)$. Таки образом мы заново подсчитываем
количество $v\in S(k-1)$; если оно не сошлось с ожидаемым,
объявим вычисление неудачным.
%На каждом шаге нам нужно хранить только несколько чисел от $1$ до $n$,
%увеличивать, уменьшать их на $1$ и сравнивать. Логарифмической памяти на все
%хватает.
%EH: Еще ведь есть счетчики итд. Конечно, все равно хватает, но лучше замять...
\end{proof}

\begin{theorem} $\NSPACE(f(n))=\co\NSPACE(O(f(n)))$ для любой 
%разумной 
space constructible функции
$f(n) = \Omega(\log n)$.
\end{theorem}

\begin{proof}
Пусть язык $L \in \NSPACE(f(n))$ принимается НМТ $M$, ограниченной по
памяти $f(n)$. Покажем, что существует машина $\bar{M}$, ограниченная по памяти
$f(n)$, решающая язык $\bar{L}$. $\bar{M}$ запускает недетерминированный
алгоритм перечисления достижимых вершин в графе конфигураций $M$ из начальной
конфигурации и проверяет дополнительно на каждом шаге, не является ли вершина
принимающим состоянием. Если алгоритм сработал успешно (подсказка правильная),
и есть путь в принимающее состояние, то он отвергает; 
если нет пути, то принимает.
(Если подсказка была неправильная, то ветвь --- неудачная;
впрочем, это как раз и значит, что в этом случае ---
тоже отвергает.)

\begin{verbatim}
                     /\
                    /  \
                   /   /\
                  /   |  \
                 /    |   \
                /     |    \
               /      |     \
          неудача  в лемме   в лемме
          в лемме    OK,        OK,
           => 0   нашли q_Y  не нашли q_Y
                    => 0        => 1
\end{verbatim}

\end{proof}
     
\end{document}

