Классы L, NL, coNL. NL-полнота задачи о достижимости — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Теорема Иммермана)
(Теорема Иммермана)
Строка 106: Строка 106:
 
Для каждого из них перебираются все ребра, в него входящие.
 
Для каждого из них перебираются все ребра, в него входящие.
 
Затем перечисляются все вершины из <tex>R_i</tex> и, если начало нашего ребра было перечислено, то <tex>v \in R_{i + 1}</tex>.
 
Затем перечисляются все вершины из <tex>R_i</tex> и, если начало нашего ребра было перечислено, то <tex>v \in R_{i + 1}</tex>.
Алгоритм использует <tex>O(\log |G|)</tex> памяти, так необходимо хранить лишь <tex>v</tex>, <tex>u</tex>, <tex>r</tex> и еще поочередно значения полученные в результате вызова <code>Enum</code>.
+
Алгоритм использует <tex>O(\log |G|)</tex> памяти, так необходимо хранить лишь <tex>v</tex>, <tex>u</tex>, <tex>r</tex> и еще поочередно значения полученные в результате вызова '''Enum'''.
  
Теперь напишем алгоритм, который будет недетерминированно решать задачу '''STNONCON''' на логарифмической памяти.
+
Теперь напишем алгоритм, который будет недетерминированно решать задачу '''NCONN''' на логарифмической памяти.
 
Он будет состоять из двух частей: вычисление <tex>r_{n-1}</tex> и перечисление всех вершин из <tex>R_{n - 1}</tex>.
 
Он будет состоять из двух частей: вычисление <tex>r_{n-1}</tex> и перечисление всех вершин из <tex>R_{n - 1}</tex>.
Вычисление <tex>r_{n-1}</tex> происходит путем вызова <code>Next</code> (n - 1) раз, при этом каждый раз в качестве <tex>r_i</tex> подставляется новое полученное значение.
+
Вычисление <tex>r_{n-1}</tex> происходит путем вызова '''Next''' <tex>n - 1</tex> раз, при этом каждый раз в качестве <tex>r_i</tex> подставляется новое полученное значение.
  
<code>
+
 
   NONCON(G, s, t)
+
   '''NCONN'''(<tex>G, s, t</tex>)
     r<sub>n</sub> := 1                              //''r<sub>0</sub> = 1''
+
     <tex>r_n = 1</tex>                             //<tex>r_0 = 1</tex>
     '''for''' i = 0..(n - 2) '''do'''                //''вычисляем r<sub>n-1</sub>''
+
     '''for''' <tex>i = 0..n - 2</tex> '''do'''                //вычисляем <tex>r_{n-1}</tex>
       r<sub>n</sub> := Next(s, i, r<sub>n</sub>, G)
+
       <tex>r_n = </tex> '''Next'''(<tex>s, i, r_n, G</tex>)
     '''if''' t '''in''' Enum(s, n - 1, r<sub>n</sub>, G) '''then'''   //''перечисляем вершины из R<sub>n-1</sub>, если t была перечислена, то t достижима и выдаем REJECT, иначе ACCEPT''
+
     '''if''' (<tex>t1</tex> '''in''' '''Enum'''(<tex>s, n - 1, r_n, G</tex>))   //перечисляем вершины из <tex>R_{n-1}</tex>, если <tex>t</tex> была перечислена, то <tex>t</tex> достижима и выдаем '''reject''', иначе '''accept'''
       '''REJECT'''
+
       '''reject'''
 
     '''else'''
 
     '''else'''
       '''ACCEPT'''
+
       '''accept'''
 
</code>
 
</code>
  

Версия 17:30, 13 мая 2012

Определение:
Класс [math]L[/math] — множество языков, разрешимых на детерминированной машине Тьюринга с использованием [math]O(\log n)[/math] дополнительной памяти для входа длиной [math]n[/math]. [math]L = DSPACE(O(\log n))[/math]


Определение:
Класс [math]NL[/math] — множество языков, разрешимых на недетерминированной машине Тьюринга с использованием [math]O(\log n)[/math] дополнительной памяти для входа длиной [math]n[/math]. [math]NL = NSPACE(O(\log n))[/math]


Определение:
Класс [math]coNL[/math] — множество языков, дополнение до которых принадлежит [math]NL[/math].


Теорема:
[math]L \in NL \in P.[/math]
Доказательство:
[math]\triangleright[/math]

1. Детерминированная машина Тьюринга есть частный случай недетерминированной, поэтому [math]L \in NL[/math].

2. Число конфигураций машины, использующей [math]O(\log n)[/math] памяти не превышает [math]2^{O(\log n)} = n^{O(1)} = poly(n)[/math], а, следовательно, машина завершает свою работу за [math]O(poly(n))[/math] времени. Следовательно, [math]NL \in P.[/math]
[math]\triangleleft[/math]

NL-полнота

Определение:
Язык [math]X[/math]называют [math]NL[/math]-полным, если [math]X \in NL[/math] и [math]\forall Y : Y \in NL, Y \leq_L X[/math].


Теорема:
Задача существования пути между двумя заданными вершинами в данном графе NL-полна.
Доказательство:
[math]\triangleright[/math]

Задача [math]\text{CONN} = \{\langle G, s, t \rangle[/math] : в графе G [math]\exists [/math] путь из s в t[math]\}[/math].

Докажем, что CONN[math] \in[/math] NL. Для доказательства необходимо предъявить алгоритм для недетерминированной машины Тьюринга, который использует конечное число переменных, каждая из которых занимает [math] O(\log n) [/math] памяти, где [math] n [/math] - размер входа для задачи и за время порядка [math] O(poly(n)) [/math] решает эту задачу.

Алгоритм

1. Начиная с вершины [math] s [/math] недетерминированно переходим в одну из вершин, смежных с ней. (Очевидно, для этого необходимо конечное число переменных)

2. Проверяем, правда ли, что текущая вершина совпадает с [math] t [/math]. Если это так, возвращает TRUE.

3. Отдельно считаем количество пройденных вершин. Как только это число превышает количество вершин в графе, возвращаем FALSE, так как посетили некоторую вершину дважды.

Таким образом в каждый момент алгоритму достаточно хранить текущую вершину, количество посещенных вершин, финальную вершину [math] t [/math] и некоторое число вспомогательных переменных, для совершения переходов. Все эти переменные принимают значения не более, чем максимальный номер вершины, то есть как раз занимают [math] O(\log n) [/math] памяти.

Теперь докажем, что любая задача из класса NL сводится к задаче CONN с использованием не более чем логарифмической памяти.

Необходимо по данной задаче из NL построить тройку [math] \langle G, s, t \rangle [/math], решение задачи CONN для которой будет эквивалентно решению данной задачи.

Любая машина Тьюринга, которая принимает некоторый язык L из NL, использует не более чем логарифмическое количество ячеек на рабочей ленте, и таким образом возможных мгновенных описаний этой машины Тьюринга [math] O(poly(n)) [/math]. Каждому возможному мгновенному описанию машины Тьюринга будет соответствовать некоторая вершина в [math] G [/math], а каждому переходу из этого описания в другое (которых в недетерминированной машине Тьюринга конечное число) — ребро в графе [math] G [/math]. За вершину [math] s [/math] принимается вершина, соответствующая начальному состоянию машины, а из каждой вершины, соответствующей некоторому допускающему состоянию, добавляется переход в выделенную вершину [math] t [/math].

Очевидно, что для любого слова из языка L, то есть принимаемого данной машиной Тьюринга, будет существовать путь из [math] s [/math] в [math] t [/math] в построенном графе [math] G [/math]. А если для некоторого слова не из L в [math] G [/math] существует путь из [math] s [/math] в [math] t [/math], то он соответствует некоторой корректной последовательности переходов в изначальной машине, таким образом слово должно было приниматься этой недетерминированной машиной.

Такое построение графа [math] G [/math] по данной машине Тьюринга можно выполнить с использованием конечного числа переменных, которые будут перебирать всевозможные мгновенные состояния машины (их [math] O(poly(n)) [/math], потому переменная, перебирающая его занимает [math] O(\log n) [/math] памяти), переходы из него и проверка возможности перехода.
[math]\triangleleft[/math]


Теорема Иммермана

Теорема:
[math]NL = coNL.[/math]
Доказательство:
[math]\triangleright[/math]

Решим задачу [math]\text{NCONN} = \{\langle G, s, t \rangle[/math] : в графе G нет пути из s в t[math]\}[/math]. Очевидно, что этот язык является дополнением языка CONN. Чтобы показать, что NCONN [math]\in[/math] NL, придумаем недетерминированый алгоритм, использующий [math]O(\log |G|)[/math] памяти, который проверяет, достижима ли вершина t из s.

Определим [math]R_i[/math] = {[math]v:[/math] существует путь из [math]s[/math] в [math]v[/math] длиной [math]\leq i[/math]}. Другими словами это множество всех вершин, достижимых из [math]s[/math] не более чем за [math]i[/math] шагов. Обозначим [math]|R_i|[/math] за [math]r_i[/math]. Если [math]t \notin R_{n-1}[/math], где [math]n = |V|[/math], то не существует путь из [math]s[/math] в [math]t[/math] в графе [math]G[/math], то есть [math]\langle G, s, t \rangle \in [/math] NCONN.

<tr><td>[math]\triangleleft[/math]</td></tr> </table> </td></tr><tr><td>[math]\triangleleft[/math]</td></tr> </table>
Лемма:
Можно построить недетерминированный алгоритм, который будет допускать [math]r_i[/math] и при этом будет перечислять все вершины из [math]R_i[/math] на [math]O(\log |G|)[/math] памяти.
Доказательство:
[math]\triangleright[/math]

Можно построить недетерминированный алгоритм, который будет допускать [math]r_i[/math] и при этом будет перечислять все вершины из [math]R_i[/math] на [math]O(\log |G|)[/math] памяти.

   Enum([math]s, i, ri, G[/math])
   [math]counter[/math] [math]\leftarrow[/math] 0                 //количество уже найденных и выведенных элементов
   for [math]v = 1..n[/math] do              //перебираем все вершины графа
       continue or find path      //недетерминированно угадываем путь из s до v или переходим к следующей вершине
       [math]counter[/math]++
       return' [math]v[/math]                //выдаем вершину, до которой угадали путь
   if ([math]counter \geq r_i[/math])             //нашли [math]r_i[/math] вершин, допускаем, завершаем работу
       accept
   reject                  //не нашли [math]r_i[/math] вершин, не допускаем
   

Enum перебирает все вершины на логарифмической памяти и пытается угадать путь до этой вершины из [math]s[/math]. Под угадыванием пути подразумевается последовательность недетерминированных выборов следующей вершины пути из [math]s[/math] в [math]v[/math]. Для угадывания пути необходимо [math]O(\log |G|)[/math] памяти, так как необходимо лишь хранить текущую и следующую угадываемую вершины угадываемого пути. Enum является недетерминированым алгоритмом, и если существует порядок его исполнения достигающий accept, то происходит допуск.

Теперь, имея Enum, можно по индукции находить [math]r_i[/math]. Очевидно, что [math]r_0 = 1[/math], так как [math]R_0[/math] содержит единственную вершину — [math]s[/math]. Пусть известно значение [math]r_i[/math]. Напишем программу, которая на логарифмической памяти будет находить [math]r_{i + 1}[/math].


 Next([math]s, i, r_i, G[/math])
   [math]r = 1[/math]                              //[math]r_{i+1}[/math] хотя бы один, так как [math]r \in R_{i+1}[/math]
   for [math]v = 1..n[/math]; [math]v \ne s[/math] do               //перебираем все вершины графа, кроме [math]s[/math] — это кандидаты на попадание в [math]R_{i+1}[/math]
     for [math]u : (u, v) \in E[/math] do               //перебираем все ребра, входящие в [math]v[/math]
       if ([math]u[/math] in Enum([math]s, i, r_i, G[/math]))   //перечисляем все вершины из [math]R_i[/math], если [math]u[/math] одна из них, то [math]v \in R_{i+1}[/math]
         [math]r[/math]++                            //увеличиваем количество найденных вершин и переходим к рассмотрению следующего кандидата
         break 
   return [math]r[/math]


Данный алгоритм изначально учитывает [math]s[/math], а затем перебирает всех возможных кандидатов [math]v[/math] на попадание в [math]R_{i + 1}[/math]. Для каждого из них перебираются все ребра, в него входящие. Затем перечисляются все вершины из [math]R_i[/math] и, если начало нашего ребра было перечислено, то [math]v \in R_{i + 1}[/math]. Алгоритм использует [math]O(\log |G|)[/math] памяти, так необходимо хранить лишь [math]v[/math], [math]u[/math], [math]r[/math] и еще поочередно значения полученные в результате вызова Enum.

Теперь напишем алгоритм, который будет недетерминированно решать задачу NCONN на логарифмической памяти. Он будет состоять из двух частей: вычисление [math]r_{n-1}[/math] и перечисление всех вершин из [math]R_{n - 1}[/math]. Вычисление [math]r_{n-1}[/math] происходит путем вызова Next [math]n - 1[/math] раз, при этом каждый раз в качестве [math]r_i[/math] подставляется новое полученное значение.


 NCONN([math]G, s, t[/math])
   [math]r_n = 1[/math]                             //[math]r_0 = 1[/math]
   for [math]i = 0..n - 2[/math] do                //вычисляем [math]r_{n-1}[/math]
     [math]r_n = [/math] Next([math]s, i, r_n, G[/math])
   if ([math]t1[/math] in Enum([math]s, n - 1, r_n, G[/math]))   //перечисляем вершины из [math]R_{n-1}[/math], если [math]t[/math] была перечислена, то [math]t[/math] достижима и выдаем reject, иначе accept
     reject
   else
     accept

</code>

Данный алгоритм использует [math]O(\log |G|)[/math] памяти, так как для хранения [math]r_n[/math] и [math]i[/math] необходимо [math]O(\log |G|)[/math], и для вызываемых Next и Enum необходимо [math]O(\log |G|)[/math] памяти.

Таким образом показано, что STNONCONNL. Поскольку STCONNLC, то аналогичным образом STNONCONco-NLC. Получаем, что любую задачу из co-NL можно свести к задаче из NL, а значит co-NLNL.

Из соображений симметрии NLco-NL, а значит NL = co-NL.