Sharp SAT — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 7: Строка 7:
  
 
== Доказательство ==
 
== Доказательство ==
Для доказательства будем строить вероятностную программу Verifier, которая хочет проверить, верно ли, что заданная формула фи имеет ровно к удовлетворяющих наборов. Программа Verifier может совершить не больше полинома от длины входа шагов, а также может обращаться к программе Prover, которая пытается любым возможным способом убедить нас (т.е. Verifier) в верности рассматриваемого утверждения.
+
Для доказательства будем строить вероятностную программу <tex>Verifier</tex>, которая хочет проверить, верно ли, что заданная формула <tex>\varphi</tex> имеет ровно <tex>k</tex> удовлетворяющих наборов. Программа <tex>Verifier</tex> может совершить не больше полинома от длины входа действий, а также может обращаться к программе <tex>Prover</tex>, которая пытается любым возможным способом убедить <tex>Verifier</tex> в верности рассматриваемого утверждения.
  
Далее в программе Verifier будем писать "проверим ...", что означает проверку соответствующего условия, и, при ложности, программа Verifier будет сразу завершаться и возвращать false, т.к. Prover нас обманывает, а значит, нет правильного доказательства проверяемого утверждения.
+
Далее в программе <tex>Verifier</tex> будем писать "проверим ...", что означает проверку соответствующего условия, и, при ложности, <tex>Verifier</tex> будет сразу завершаться и возвращать <tex>false</tex>, т.к. <tex>Prover</tex> её обманывает, а значит, нет правильного доказательства проверяемого утверждения.
  
Программа Verifier будет выполнять следующие шаги.
+
<tex>Verifier</tex> будет выполнять следующие шаги.
  
 
Шаг 0.
 
Шаг 0.
  
Пусть формула <tex>\varphi</tex> каким либо образом записана. Пусть формула фи имеет n переменных и степень d. Сделаем следующие замены и получим формулу <tex>A(x_1, x_2, ..., x_n)</tex>:
+
Пусть формула <tex>\varphi</tex> каким либо образом записана. Пусть формула <tex>\varphi</tex> имеет <tex>n</tex> переменных и степень <tex>d</tex>. Сделаем следующие замены и получим формулу <tex>A(x_1, x_2, ..., x_n)</tex>:
 
# <tex>x \land y \to x \cdot y</tex>
 
# <tex>x \land y \to x \cdot y</tex>
 
# <tex> \lnot x \to 1 - x</tex>
 
# <tex> \lnot x \to 1 - x</tex>
Строка 23: Строка 23:
 
Итак, надо проверить следующее арифметическое уравнение: <tex>\sum_{x_1 = 0}^{1}\sum_{x_2 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n) = k</tex>.
 
Итак, надо проверить следующее арифметическое уравнение: <tex>\sum_{x_1 = 0}^{1}\sum_{x_2 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n) = k</tex>.
  
А надо ли отправлять получившуюся А Proverу, или может он видит input и сам сделает такое преобразование?
+
Попросим <tex>Prover</tex> прислать <tex>Verifier</tex>'у простое число <tex>p > max(2^n, k_p)</tex> и сертификат о его простоте.
 +
Проверим простоту <tex>p</tex> по сертификату, и условие <tex>p > max(2^n, k_p)</tex>. Константу <tex>k_p</tex> определим позднее.
  
Попросим программу Prover прислать нам простое число p > max(2^n, p_k) и сертификат о его простоте.
+
Будем проверять уравнение по модулю <tex>p</tex>.
Проверим простоту p по сертификату, и условие p > max(2^n, p_k). Константу p_k определим позднее.
 
 
 
Будем проверять уравнение по модулю p.
 
  
 
Пусть <tex>A_0(x_1) = \sum_{x_2 = 0}^{1}\sum_{x_3 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n)</tex>.
 
Пусть <tex>A_0(x_1) = \sum_{x_2 = 0}^{1}\sum_{x_3 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n)</tex>.
  
Попросим программу Prover прислать нам формулу A_0(x_1). Её размер???.
+
Попросим <tex>Prover</tex> прислать <tex>Verifier</tex>'у формулу <tex>A_0(x_1)</tex>. Её размер???.
Проверим следующее утверждение: A0(0) + A0(1) = k.
+
Проверим следующее утверждение: <tex>A_0(0) + A_0(1) = k</tex>.
  
 
Шаг 1.
 
Шаг 1.
  
Пусть r_1 = random(p). Отправим r_1 программе Prover.
+
Пусть <tex>r_1 = random(p)</tex>. Отправим <tex>r_1</tex> программе <tex>Prover</tex>.
  
 
Пусть <tex>A_1(x_2) = \sum_{x_3 = 0}^{1}\sum_{x_4 = 0}^{1}...\sum_{x_n = 0}^{1} A(r_1, x_2, ..., x_n)</tex>.
 
Пусть <tex>A_1(x_2) = \sum_{x_3 = 0}^{1}\sum_{x_4 = 0}^{1}...\sum_{x_n = 0}^{1} A(r_1, x_2, ..., x_n)</tex>.
  
Попросим программу Prover прислать нам формулу A_1(x_2).
+
Попросим <tex>Prover</tex> прислать <tex>Verifier</tex>'у формулу <tex>A_1(x_2)</tex>.
Проверим следующее утверждение: A_1(0) + A_1(1) = A_0(r_1).
+
Проверим следующее утверждение: <tex>A_1(0) + A_1(1) = A_0(r_1)</tex>.
  
 
Шаг 2.
 
Шаг 2.
Строка 48: Строка 46:
 
...
 
...
  
Шаг n.
+
Шаг <tex>n</tex>.
  
Пусть r_n = random(p). Отправим r_n программе Prover.
+
Пусть <tex>r_n = random(p)</tex>. Отправим <tex>r_n</tex> программе <tex>Prover</tex>.
  
 
Пусть <tex>A_n() = A(r_1, r_2, ..., r_n)</tex>.
 
Пусть <tex>A_n() = A(r_1, r_2, ..., r_n)</tex>.
  
Попросим программу Prover прислать нам значение A_n().
+
Попросим программу Prover прислать <tex>Verifier</tex>'у значение <tex>A_n()</tex>.
Проверим следующее утверждение: A_n() = A_n-1(r_n).  
+
Проверим следующее утверждение: <tex>A_n() = A_{n-1}(r_n)</tex>.
А также сами подставим r_1, r_2, ..., r_n в А(x_1, x_2, ..., x_n) и проверим правильность присланного значения A_n().
+
А также сами подставим <tex>r_1, r_2, ..., r_n</tex> в <tex>A(x_1, x_2, ..., x_n)</tex> и проверим правильность присланного значения <tex>A_n()</tex>.
  
Возвращаем true.
+
Возвращаем <tex>true</tex>.
  
  
Итак, остается доказать, что написанный Verifier - корректный Verifier для языка #SAT. То есть, нужно доказать:
+
Итак, остается доказать, что написанный <tex>Verifier</tex> - корректный <tex>Verifier</tex> для языка <tex>\#SAT</tex>. То есть, нужно доказать:
# Построенный Verifier - вероятностная машина Тьюринга, совершающая не более полинома от длинны входа действий.
+
# Построенный <tex>Verifier</tex> - вероятностная машина Тьюринга, совершающая не более полинома от длинны входа действий.
 
# <tex><\varphi, k> \in \#SAT \Rightarrow \exists P : P(VP(x)) \ge 2/3</tex>.
 
# <tex><\varphi, k> \in \#SAT \Rightarrow \exists P : P(VP(x)) \ge 2/3</tex>.
 
# <tex><\varphi, k> \notin \#SAT \Rightarrow \forall P : P(VP(x)) \le 1/3</tex>.
 
# <tex><\varphi, k> \notin \#SAT \Rightarrow \forall P : P(VP(x)) \le 1/3</tex>.
  
 
Доказательство:
 
Доказательство:
# Из программы Verifier видно, что она работает за O(n * |input|) = O(poly(|input|)).
+
# Из программы <tex>Verifier</tex> видно, что она работает за <tex>O(n \cdot |input|) = O(poly(|input|))</tex>.
# Если фи имеет ровно k удовлетворяющих наборов, то существует программа Prover, такая что P(VP(x)) = 1. Такой Prover:
+
# Если <tex>\varphi</tex> имеет ровно <tex>k</tex> удовлетворяющих наборов, то существует программа <tex>Prover</tex>, такая что <tex>P(VP(x)) = 1</tex>. Такая программа:
## Присылает, например, первое простое число большее 2^n и сертификат.
+
## Присылает, например, первое простое число большее <tex>max(2^n, k_p)</tex> и сертификат.
## Считает сумму A_0(x_1) и присылает формулу.
+
## Считает сумму <tex>A_0(x_1)</tex> и присылает формулу.
## Получает r_1.
+
## Получает <tex>r_1</tex>.
## Считает сумму A_1(x_2) и присылает формулу.
+
## Считает сумму <tex>A_1(x_2)</tex> и присылает формулу.
 
## ...
 
## ...
Ввиду того, что Prover все делает хорошо и нигде не ошибается, то Verifier дойдет до конца программы и вернет true.
+
Ввиду того, что <tex>Prover</tex> все делает хорошо и нигде не ошибается, то <tex>Verifier</tex> дойдет до конца программы и вернет <tex>true</tex>.
  
# Пусть фи имеет не k удовлетворяющих наборов. Тогда для того, что бы Verifier вернул true, необходимо Prover'у посылать такие A_i, чтобы выполнялись все проверяемые условия. Посмотрим на то, что он может послать:
+
# Пусть <tex>\varphi</tex> имеет не <tex>k</tex> удовлетворяющих наборов. Тогда для того, что бы <tex>Verifier</tex> вернул <tex>true</tex>, необходимо <tex>Prover</tex>'у посылать такие <tex>A_i</tex>, чтобы выполнялись все проверяемые условия. Посмотрим на то, что он может послать:
  
 
Шаг 0.
 
Шаг 0.
  
Так как фи имеет не k удовлетворяющих наборов, то Prover не может послать правильное А_0 - не выполнится условие A0(0) + A0(1) = k. Поэтому он посылает не А_0, а некое A~_0.
+
Так как <tex>\varphi</tex> имеет не <tex>k</tex> удовлетворяющих наборов, то <tex>Prover</tex> не может послать правильное <tex>A_0</tex> – не выполнится условие <tex>A_0(0) + A_0(1) = k</tex>. Поэтому он посылает не <tex>A_0</tex>, а некое <tex>\tilde{A}_0</tex>.
  
 
Шаг 1.
 
Шаг 1.
  
Во первых, отметим, что ситуация А_0(r_1) == A_~0(r_1) происходит с вероятностью меньшей либо равной d / p для некоторого случайно выбранного r_1, что следует из [[Лемма_Шварца-Зиппеля|леммы Шварца-Зиппеля]]. То есть, с вероятностью большей либо равной 1 - d / p : А_0(r_1) != A_~0(r_1) и, ввиду того, что должно выполняться условие A_1(0) + A_1(1) = A_0(r_1), получаем, что A_1 тоже будет не правильное, т.е. некоторое A~_1.
+
Во первых, отметим, что ситуация <tex>A_0(r_1) = \tilde{A}_0(r_1)</tex> происходит с вероятностью меньшей либо равной <tex>d / p</tex> для некоторого случайно выбранного <tex>r_1</tex>, что следует из [[Лемма_Шварца-Зиппеля|леммы Шварца-Зиппеля]]. То есть, с вероятностью большей либо равной <tex>1 - d / p : A_0(r_1) != \tilde{A}_0(r_1)</tex> и, ввиду того, что должно выполняться условие <tex>A_1(0) + A_1(1) = A_0(r_1)</tex>, получаем, что <tex>A_1</tex> тоже будет не правильное, т.е. некоторое <tex>\tilde{A}_1</tex>.
  
 
...
 
...
  
Шаг n.
+
Шаг <tex>n</tex>.
  
С вероятностью 1 - d / p А_n-1(r_n) != A_~n-1(r_n) и потому Verifier получает не A_n, а A~_n.
+
С вероятностью <tex>1 - d / p : A_{n-1}(r_n) != \tilde{A}_{n-1}(r_n)</tex> и потому <tex>Verifier</tex> получит не <tex>A_n</tex>, а <tex>\tilde{A}_n</tex>.
  
Из этого процесса заметим, что с вероятностью большей либо равной (1 - d / p) ^ n мы дойдем до последнего шага и будем имееть А~_n вместо A_n. Так как на шаге n Verifier вычисляет A_n и проверяет значение, то Verifier вернет false.  
+
Из этого процесса заметим, что с вероятностью большей либо равной <tex>(1 - d / p) ^ n</tex> мы дойдем до последнего шага и будем имееть <tex>\tilde{A}_n</tex> вместо <tex>A_n</tex>. Так как на шаге <tex>n</tex> <tex>Verifier</tex> вычисляет <tex>A_n</tex> и проверяет значение, то <tex>Verifier</tex> вернет <tex>false</tex>.  
  
Так как мы хотим сделать вероятность возврата false большую либо равную 2/3, то выберем k_p так, чтобы (1 - d / k_p) ^ n >= 2/3.  
+
Так как мы хотим сделать вероятность возврата <tex>false</tex> большую либо равную <tex>2/3</tex>, то выберем <tex>k_p</tex> так, чтобы <tex>(1 - d / k_p) ^ n \ge 2/3</tex>.  
  
 
Утверждение доказано.
 
Утверждение доказано.

Версия 18:45, 22 апреля 2010

Определение

[math]\#SAT = \{ \lt \varphi, k\gt | \varphi[/math] имеет [math]k[/math] удовлетворяющих наборов [math]\}[/math]

Утверждение

[math]\#SAT \in IP[/math]

Доказательство

Для доказательства будем строить вероятностную программу [math]Verifier[/math], которая хочет проверить, верно ли, что заданная формула [math]\varphi[/math] имеет ровно [math]k[/math] удовлетворяющих наборов. Программа [math]Verifier[/math] может совершить не больше полинома от длины входа действий, а также может обращаться к программе [math]Prover[/math], которая пытается любым возможным способом убедить [math]Verifier[/math] в верности рассматриваемого утверждения.

Далее в программе [math]Verifier[/math] будем писать "проверим ...", что означает проверку соответствующего условия, и, при ложности, [math]Verifier[/math] будет сразу завершаться и возвращать [math]false[/math], т.к. [math]Prover[/math] её обманывает, а значит, нет правильного доказательства проверяемого утверждения.

[math]Verifier[/math] будет выполнять следующие шаги.

Шаг 0.

Пусть формула [math]\varphi[/math] каким либо образом записана. Пусть формула [math]\varphi[/math] имеет [math]n[/math] переменных и степень [math]d[/math]. Сделаем следующие замены и получим формулу [math]A(x_1, x_2, ..., x_n)[/math]:

  1. [math]x \land y \to x \cdot y[/math]
  2. [math] \lnot x \to 1 - x[/math]
  3. [math] x \lor y \to x + y - x \cdot y = 1 - (1 - x) \cdot (1 - y)[/math]

Заметим, что длина формулы возрастет не больше, чем в константу раз.

Итак, надо проверить следующее арифметическое уравнение: [math]\sum_{x_1 = 0}^{1}\sum_{x_2 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n) = k[/math].

Попросим [math]Prover[/math] прислать [math]Verifier[/math]'у простое число [math]p \gt max(2^n, k_p)[/math] и сертификат о его простоте. Проверим простоту [math]p[/math] по сертификату, и условие [math]p \gt max(2^n, k_p)[/math]. Константу [math]k_p[/math] определим позднее.

Будем проверять уравнение по модулю [math]p[/math].

Пусть [math]A_0(x_1) = \sum_{x_2 = 0}^{1}\sum_{x_3 = 0}^{1}...\sum_{x_n = 0}^{1} A(x_1, x_2, ..., x_n)[/math].

Попросим [math]Prover[/math] прислать [math]Verifier[/math]'у формулу [math]A_0(x_1)[/math]. Её размер???. Проверим следующее утверждение: [math]A_0(0) + A_0(1) = k[/math].

Шаг 1.

Пусть [math]r_1 = random(p)[/math]. Отправим [math]r_1[/math] программе [math]Prover[/math].

Пусть [math]A_1(x_2) = \sum_{x_3 = 0}^{1}\sum_{x_4 = 0}^{1}...\sum_{x_n = 0}^{1} A(r_1, x_2, ..., x_n)[/math].

Попросим [math]Prover[/math] прислать [math]Verifier[/math]'у формулу [math]A_1(x_2)[/math]. Проверим следующее утверждение: [math]A_1(0) + A_1(1) = A_0(r_1)[/math].

Шаг 2.

...

Шаг [math]n[/math].

Пусть [math]r_n = random(p)[/math]. Отправим [math]r_n[/math] программе [math]Prover[/math].

Пусть [math]A_n() = A(r_1, r_2, ..., r_n)[/math].

Попросим программу Prover прислать [math]Verifier[/math]'у значение [math]A_n()[/math]. Проверим следующее утверждение: [math]A_n() = A_{n-1}(r_n)[/math]. А также сами подставим [math]r_1, r_2, ..., r_n[/math] в [math]A(x_1, x_2, ..., x_n)[/math] и проверим правильность присланного значения [math]A_n()[/math].

Возвращаем [math]true[/math].


Итак, остается доказать, что написанный [math]Verifier[/math] - корректный [math]Verifier[/math] для языка [math]\#SAT[/math]. То есть, нужно доказать:

  1. Построенный [math]Verifier[/math] - вероятностная машина Тьюринга, совершающая не более полинома от длинны входа действий.
  2. [math]\lt \varphi, k\gt \in \#SAT \Rightarrow \exists P : P(VP(x)) \ge 2/3[/math].
  3. [math]\lt \varphi, k\gt \notin \#SAT \Rightarrow \forall P : P(VP(x)) \le 1/3[/math].

Доказательство:

  1. Из программы [math]Verifier[/math] видно, что она работает за [math]O(n \cdot |input|) = O(poly(|input|))[/math].
  2. Если [math]\varphi[/math] имеет ровно [math]k[/math] удовлетворяющих наборов, то существует программа [math]Prover[/math], такая что [math]P(VP(x)) = 1[/math]. Такая программа:
    1. Присылает, например, первое простое число большее [math]max(2^n, k_p)[/math] и сертификат.
    2. Считает сумму [math]A_0(x_1)[/math] и присылает формулу.
    3. Получает [math]r_1[/math].
    4. Считает сумму [math]A_1(x_2)[/math] и присылает формулу.
    5. ...

Ввиду того, что [math]Prover[/math] все делает хорошо и нигде не ошибается, то [math]Verifier[/math] дойдет до конца программы и вернет [math]true[/math].

  1. Пусть [math]\varphi[/math] имеет не [math]k[/math] удовлетворяющих наборов. Тогда для того, что бы [math]Verifier[/math] вернул [math]true[/math], необходимо [math]Prover[/math]'у посылать такие [math]A_i[/math], чтобы выполнялись все проверяемые условия. Посмотрим на то, что он может послать:

Шаг 0.

Так как [math]\varphi[/math] имеет не [math]k[/math] удовлетворяющих наборов, то [math]Prover[/math] не может послать правильное [math]A_0[/math] – не выполнится условие [math]A_0(0) + A_0(1) = k[/math]. Поэтому он посылает не [math]A_0[/math], а некое [math]\tilde{A}_0[/math].

Шаг 1.

Во первых, отметим, что ситуация [math]A_0(r_1) = \tilde{A}_0(r_1)[/math] происходит с вероятностью меньшей либо равной [math]d / p[/math] для некоторого случайно выбранного [math]r_1[/math], что следует из леммы Шварца-Зиппеля. То есть, с вероятностью большей либо равной [math]1 - d / p : A_0(r_1) != \tilde{A}_0(r_1)[/math] и, ввиду того, что должно выполняться условие [math]A_1(0) + A_1(1) = A_0(r_1)[/math], получаем, что [math]A_1[/math] тоже будет не правильное, т.е. некоторое [math]\tilde{A}_1[/math].

...

Шаг [math]n[/math].

С вероятностью [math]1 - d / p : A_{n-1}(r_n) != \tilde{A}_{n-1}(r_n)[/math] и потому [math]Verifier[/math] получит не [math]A_n[/math], а [math]\tilde{A}_n[/math].

Из этого процесса заметим, что с вероятностью большей либо равной [math](1 - d / p) ^ n[/math] мы дойдем до последнего шага и будем имееть [math]\tilde{A}_n[/math] вместо [math]A_n[/math]. Так как на шаге [math]n[/math] [math]Verifier[/math] вычисляет [math]A_n[/math] и проверяет значение, то [math]Verifier[/math] вернет [math]false[/math].

Так как мы хотим сделать вероятность возврата [math]false[/math] большую либо равную [math]2/3[/math], то выберем [math]k_p[/math] так, чтобы [math](1 - d / k_p) ^ n \ge 2/3[/math].

Утверждение доказано.