Теорема Левина — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м (rollbackEdits.php mass rollback)
 
(не показано 14 промежуточных версий 4 участников)
Строка 1: Строка 1:
По одному из определений [[Класс NP|<tex>NP</tex> языка]], язык <tex>L</tex> принадлежит <tex>NP</tex>, если существует такая функция <tex>R(x, y) \in \tilde{P}</tex> — <tex>NP</tex>-отношение для языка <tex>L</tex> (<tex>NP</tex>-relation), что: <tex>x \in L \Leftrightarrow \exists y</tex> — такой сертификат для <tex>x</tex>, что: <tex>|y| \le poly(|x|)</tex> и <tex>R(x, y) = 1</tex>. Таким образом, для проверки принадлежности некоторого слова <tex>NP</tex> языку <tex>L</tex> с <tex>NP</tex>-отношением <tex>R</tex> необходимо предъявить соответствующий сертификат. Так как для любого слова из языка существует подтверждающий сертификат, то существует программа <tex>g(x)</tex>, которая для слов из языка возвращает нужный сертификат. А для слов не из языка никаких гарантий на возвращаемое значение функции нет, и потому она может либо вернуть неправильный сертификат, либо вообще зависнуть.
+
{{Теорема
 +
|author=Левин
 +
|statement=
 +
Для любого языка <tex>L \in \Sigma_1</tex> и соответствующего ему (из определения <tex>\Sigma_1</tex>) отношения <tex>R</tex> существует «оптимальная» (работающая «не сильно дольше», чем любая другая) программа <tex>p</tex>, сопоставляющая словам из <tex>L</tex> их сертификаты, то есть:
 +
# <tex>x \in L \Leftrightarrow R(x, p(x)) = 1</tex>;
 +
# для любой другой программы <tex>q</tex>, для которой верно <tex>x \in L \Leftrightarrow R(x, q(x)) = 1</tex>, найдутся такие константа <tex>c</tex> и полином <tex>r</tex>, что для любого <tex>x</tex> выполняется: <tex>T(p, x) \le c \cdot T(q, x) + r(|x|)</tex>.
 +
|proof=
 +
Построим «оптимальную» программу <tex>p(x)</tex>.
  
Встает вопрос о возможности построения «оптимальной» программы для заранее заданного <tex>NP</tex> языка <tex>L</tex> и <tex>NP</tex>-отношения для этого языка <tex>R</tex>, которая будет находить сертификат для слова. Оптимальность программы в данном случае означает, что время ее работы для слов из языка не сильно хуже, чем у любой другой программы, правильно находящей сертификат для слов из языка.
+
Пронумеруем все программы <tex>\lbrace p_i \rbrace_{i=1}^\infty</tex>. Подадим им на вход слово <tex>x</tex> и будем исполнять по одной инструкции в следующем порядке: на шаге с номером <tex>j</tex> запустим программу <tex>p_k</tex>, где <tex>k</tex> таково, что <tex>j</tex> делится на <tex>2^{k-1}</tex> и не делится на <tex>2^{k}</tex>. Таким образом, программа <tex>p_k</tex> будет исполняться на каждом <tex>2^k</tex>-м шаге начиная с <tex>2^{k-1}</tex>-го. Следовательно, если <tex>p_k</tex> завершит работу за <tex>T(p_k, x)</tex> инструкций, то к этому времени нами будет сделано <tex>2^{k-1} + (T(P_k, x) - 1) \cdot 2^k</tex> шагов.
  
== Формулировка теоремы Левина об оптимальной <tex>NP</tex> программе ==
+
Как только <tex>p_k</tex>, выдав некоторое значение, завершит работу, будем на соответствующих шагах запускать проверку сертификата слова <tex>x</tex>, используя вывод <tex>p_k</tex> в качестве сертификата. Если результат проверки положителен, искомый сертификат найден, иначе продолжим работу, ничего не делая на тех шагах, когда должна была исполняться <tex>p_k</tex>.
Для любого языка <tex>L \in NP</tex> и функции <tex>R</tex> (<tex>NP</tex>-отношения для <tex>L</tex>) существует такая программа <tex>f</tex>, что:
 
#<tex>\forall x \in L</tex> выполнено <tex>R(x, f(x)) = 1</tex>;
 
#<tex>\forall g</tex> — такой программы, что <tex>\forall x \in L: R(x, g(x)) = 1</tex> выполнено <tex>\forall x \in L: T(f, x) \le C_g \cdot (T(g, x) + poly(|x|))</tex>, где <tex>T(f, x)</tex> время работы программы <tex>f</tex> на входе <tex>x</tex>.
 
  
Заметим, что <tex>C_g</tex> не зависит от слова <tex>x</tex>, т.е. константа от <tex>x</tex>.
+
Таким образом, если некоторая программа <tex>q = p_m</tex> генерирует верные сертификаты, то наша программа <tex>p</tex> завершит работу не более, чем за <tex>2^{m-1} + (T(p_m,x) + T(R, \langle x,p_m(x) \rangle) - 1) \cdot 2^m</tex> шагов. <tex>R \in P</tex> и <tex>|y| \le poly(|x|)</tex> из определения <tex>\Sigma_1</tex>, значит это равно <tex>2^{m-1} + (T(p_m,x) + poly(|x|)) \cdot 2^m = 2^m \cdot T(q,x) + poly(|x|)</tex>.
 +
}}
  
== Доказательство ==
+
== См. также ==
Для доказательства теоремы будем строить оптимальную <tex>NP</tex> программу <tex>f</tex> для некоторого <tex>NP</tex> языка <tex>L</tex> и <tex>NP</tex> отношения <tex>R(x, y)</tex> для него.
+
*[[Класс P]]
 +
*[[Классы_NP_и_Σ₁]]
  
Занумеруем все программы <tex>g_1, g_2, ... , g_n, ...</tex> сначала по длине программы, а в случае равенства длин — лексикографически.
+
[[Категория: Теория сложности]]
 
 
Будем запускать <tex>g_i</tex> каждый раз на один шаг и запоминать полученное состояние запущенной программы. Запускать будем в следующем порядке: 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, 5 и так далее. Заметим, что мы запускаем программу <tex>g_i</tex> каждый <tex>2^i</tex>-й раз, а потому, если программа <tex>g_i(x)</tex> завершается за <tex>k</tex> шагов, то <tex>f</tex> совершит не больше <tex>2^i \cdot k</tex> шагов до момента завершения <tex>g_i</tex> на входе <tex>x</tex> в программе <tex>f</tex>.
 
 
 
После того, как программа <tex>g_i</tex> остановилась, на её месте будем запускать программу <tex>R(x, y)</tex>, где <tex>y</tex> - значение, которое вернула <tex>g_i(x)</tex>. Причем <tex>f</tex> совершит не больше <tex>2^i \cdot poly(|x + y|)</tex> шагов до завершения программы <tex>R(x, y)</tex>, так как <tex>R \in \tilde{P}</tex> и она запускается каждый <tex>2^i</tex>-й раз. Если <tex>R(x, y)</tex> вернула <tex>true</tex>, то возвратим <tex>y</tex>, так как <tex>y</tex> — нужный сертификат для <tex>x</tex>, а если <tex>false</tex>, то ничего на этом месте больше запускать не будем.
 
 
 
Осталось доказать, что данная программа действительно удовлетворяет пунктам 1 и 2 теоремы Левина.
 
#Так как программа <tex>f</tex> возвращает только те <tex>y</tex>, для которых <tex>R(x, y) = 1</tex>, то <tex>R(x, f(x)) = 0</tex> получиться не может. Покажем, что и зависнуть на словах из языка <tex>f</tex> не может. Как выше уже упоминалось, если слово принадлежит языку <tex>L</tex>, то для него есть сертификат, а значит есть и программа <tex>g</tex>, которая, например, просто этот сертификат возвращает. Так как все программы рано или поздно будут занумерованы, то и <tex>g</tex> будет занумерована, а следовательно и запущена. После остановки <tex>g</tex> и проверки правильности <tex>y</tex> программа <tex>f</tex> вернет его.
 
#Если программа <tex>g(x)</tex> правильно находит сертификаты для слов из языка и завершается за <tex>k</tex> шагов для некоторого слова <tex>x</tex> из <tex>L</tex>, то программа <tex>f</tex> завершится не более, чем за <tex>2^i \cdot (k + poly(|x + y|))</tex> шагов для этого же слова. Заметим, что <tex>2^i \cdot (k + poly(|x + y|))=2^i \cdot (k + poly(|x|))</tex>, так как <tex>y</tex> — сертификат для <tex>x</tex> и потому <tex>|y| \le poly(|x|)</tex>.
 
 
 
Теорема доказана.
 

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

Теорема (Левин):
Для любого языка [math]L \in \Sigma_1[/math] и соответствующего ему (из определения [math]\Sigma_1[/math]) отношения [math]R[/math] существует «оптимальная» (работающая «не сильно дольше», чем любая другая) программа [math]p[/math], сопоставляющая словам из [math]L[/math] их сертификаты, то есть:
  1. [math]x \in L \Leftrightarrow R(x, p(x)) = 1[/math];
  2. для любой другой программы [math]q[/math], для которой верно [math]x \in L \Leftrightarrow R(x, q(x)) = 1[/math], найдутся такие константа [math]c[/math] и полином [math]r[/math], что для любого [math]x[/math] выполняется: [math]T(p, x) \le c \cdot T(q, x) + r(|x|)[/math].
Доказательство:
[math]\triangleright[/math]

Построим «оптимальную» программу [math]p(x)[/math].

Пронумеруем все программы [math]\lbrace p_i \rbrace_{i=1}^\infty[/math]. Подадим им на вход слово [math]x[/math] и будем исполнять по одной инструкции в следующем порядке: на шаге с номером [math]j[/math] запустим программу [math]p_k[/math], где [math]k[/math] таково, что [math]j[/math] делится на [math]2^{k-1}[/math] и не делится на [math]2^{k}[/math]. Таким образом, программа [math]p_k[/math] будет исполняться на каждом [math]2^k[/math]-м шаге начиная с [math]2^{k-1}[/math]-го. Следовательно, если [math]p_k[/math] завершит работу за [math]T(p_k, x)[/math] инструкций, то к этому времени нами будет сделано [math]2^{k-1} + (T(P_k, x) - 1) \cdot 2^k[/math] шагов.

Как только [math]p_k[/math], выдав некоторое значение, завершит работу, будем на соответствующих шагах запускать проверку сертификата слова [math]x[/math], используя вывод [math]p_k[/math] в качестве сертификата. Если результат проверки положителен, искомый сертификат найден, иначе — продолжим работу, ничего не делая на тех шагах, когда должна была исполняться [math]p_k[/math].

Таким образом, если некоторая программа [math]q = p_m[/math] генерирует верные сертификаты, то наша программа [math]p[/math] завершит работу не более, чем за [math]2^{m-1} + (T(p_m,x) + T(R, \langle x,p_m(x) \rangle) - 1) \cdot 2^m[/math] шагов. [math]R \in P[/math] и [math]|y| \le poly(|x|)[/math] из определения [math]\Sigma_1[/math], значит это равно [math]2^{m-1} + (T(p_m,x) + poly(|x|)) \cdot 2^m = 2^m \cdot T(q,x) + poly(|x|)[/math].
[math]\triangleleft[/math]

См. также