草稿
布尔可满足性(SAT)
判断是否存在某个真值赋值让布尔公式为真,并区分“寻找赋值”和“检查一个赋值”。
引子问题:让规则为真
想象一个警报不是由电路图控制,而是由一条写下来的规则控制。四个开关 x1、x2、x3、x4 各自只能取 0 或 1。这条规则是一个布尔公式(Boolean formula):
phi = (x1 AND NOT x2 AND (x3 OR x4)) OR (x2 AND x4)
判定问题是:
是否存在某个开关设置,让
phi求值为 true?
赋值(assignment)字符串按 x1 x2 x3 x4 的顺序写。比如 1010 表示 x1=1、x2=0、x3=1、x4=0。
一个有名字的布尔开关
变量或变量的否定
phi 内部较小的表达式
组合真值的规则
第一个朴素想法:逐行尝试
最直接的方法是列出真值表(truth table),然后一行一行测试。
四个变量给出 16 个格式正确的行。表格展示其中一些代表行。
x1=1、x2=0 且 x3=1 让三段左侧子公式为真。
一个拒绝行只说明这一行失败,不是不可满足证明。
这个四变量例子只有 16 行,所以暴力搜索看起来不痛。但表格是搜索空间,不是证书。
x1=1、x2=0 且 x3=1 让三段左侧子公式为真。
x2=1 且 x4=1 让右侧子公式为真,因此根 OR 为真。
这个赋值失败,但 1010 和 0101 说明公式仍然可满足。
痛点:每加一个变量就翻倍
每增加一个变量,可能赋值数都会翻倍:
像 0000 这样的 false 行,只证明 0000 失败。它不能证明不存在满足赋值(satisfying assignment)。
检查一个证书只求值一次 phi;盲目搜索可能一行接一行地求值。
暴力表中的所有行
检查 bit,求值公式树,读取根节点
更大公式也有同样的翻倍形状
| n | 2^n | 一次检查标签 |
|---|---|---|
| 4 | 16 | O(|phi| + n) |
| 8 | 256 | O(|phi| + n) |
| 12 | 4,096 | O(|phi| + n) |
| 20 | 1,048,576 | O(|phi| + n) |
| 30 | 1,073,741,824 | O(|phi| + n) |
核心发明:一个赋值可以当证书
现在把两个任务分开:
- 搜索问:是否存在某个满足赋值?
- 验证接收一个候选赋值,然后检查它。
如果有人交给我们 1010,我们不必重新扫描整张表。我们先验证字符串是否给每个变量正好一位,再求值公式树,最后看根节点是否为 true。
如果 phi 变为真,则实例是 Yes。如果这一行失败,只说明这个证书失败。
证书(certificate)是一条被声称的 Yes 见证。它成功时能证明答案是 Yes,但它本身不是“找到自己”的方法。
验证器先检查证书格式,再自底向上求值公式出现位置,最后读取根节点。
已存储的值逐步增加:每个父节点只在子节点已知之后存储。
| 步骤 | 工作 | 状态 |
|---|---|---|
| 验证通过 | 赋值为每个公式变量恰好提供一位 | 当前 |
| x1-left: VAR | x1: x1=1 -> 1 | 等待 |
| x2-left: VAR | x2: x2=0 -> 0 | 等待 |
| not-x2-left: NOT | NOT x2: x2-left=0 -> 1 | 等待 |
| x3-left: VAR | x3: x3=1 -> 1 | 等待 |
| x4-left: VAR | x4: x4=0 -> 0 | 等待 |
| or-x3-x4: OR | x3 OR x4: x3-left=1, x4-left=0 -> 1 | 等待 |
| and-left: AND | x1 AND NOT x2 AND (x3 OR x4): x1-left=1, not-x2-left=1, or-x3-x4=1 -> 1 | 等待 |
| x2-right: VAR | x2: x2=0 -> 0 | 等待 |
| x4-right: VAR | x4: x4=0 -> 0 | 等待 |
| and-right: AND | x2 AND x4: x2-right=0, x4-right=0 -> 0 | 等待 |
| or-root: OR | (x1 AND NOT x2 AND (x3 OR x4)) OR (x2 AND x4): and-left=1, and-right=0 -> 1 | 等待 |
| 读取根节点结果 | 根公式为真,因此验证器接受这个证书 | 等待 |
SAT 的形式化定义
布尔公式由变量(variable)、文字(literal)和 AND、OR、NOT 这样的运算符(operator)构成。满足赋值是让整个公式为 true 的赋值。
设 $\varphi$ 是一个含变量 $x_1,\dots,x_n$ 的布尔公式。设 $a \in \{0,1\}^n$ 是一个赋值,$\varphi(a)$ 表示在该赋值下公式的真值。
换成普通话说:如果至少有一种真值设置让整个表达式为真,这个公式就是可满足的。
由变量和运算符构成的布尔公式
每个变量对应一位
整个表达式求值为 true
验证器实现
验证器(verifier)的职责比求解器窄:
function verifySat(phi, certificate) {
if (!hasOneBitPerVariable(phi, certificate)) return false;
const assignment = readAssignmentBits(phi, certificate);
const rootValue = evaluateFormulaTree(phi.root, assignment);
return rootValue === true;
}
对于格式正确的赋值:
像 101 或 1020 这样的格式错误字符串,会在公式求值前被拒绝。它们不是“求值为 false 的普通行”。
| 节点 | 读取输入 | 存储输出 |
|---|---|---|
| x1-left | x1=1 | x1 = 1 |
| x2-left | x2=0 | x2 = 0 |
| not-x2-left | x2-left=0 | NOT x2 = 1 |
| x3-left | x3=1 | x3 = 1 |
| x4-left | x4=0 | x4 = 0 |
| or-x3-x4 | x3-left=1, x4-left=0 | x3 OR x4 = 1 |
| and-left | x1-left=1, not-x2-left=1, or-x3-x4=1 | x1 AND NOT x2 AND (x3 OR x4) = 1 |
| x2-right | x2=0 | x2 = 0 |
| x4-right | x4=0 | x4 = 0 |
| and-right | x2-right=0, x4-right=0 | x2 AND x4 = 0 |
| or-root | and-left=1, and-right=0 | (x1 AND NOT x2 AND (x3 OR x4)) OR (x2 AND x4) = 1 |
| 读取根节点 | root=1 | accept |
子公式不变量
求值器自底向上走表达式树:
validation -> x1-left -> x2-left -> not-x2-left -> x3-left -> x4-left -> or-x3-x4 -> and-left -> x2-right -> x4-right -> and-right -> or-root -> final。
不变量:
每求值完一个子公式,已存储的每个值都等于该子公式在当前赋值下的真实真值。
这就是为什么检查很直接。验证器不会猜父节点的值;它先算子节点,再应用父节点运算符。
复杂度
证书为每个变量提供一位:
在这个例子里,公式大小统计变量出现位置和运算符节点。按照本页使用的 n 元 AND / OR 约定,|\varphi| = 11:六个变量出现位置加五个运算符节点。
一次验证会检查赋值格式、求值一次公式树、读取根节点:
盲目搜索可能对每个赋值都重复一次公式检查:
每个变量一位
六个变量出现位置加五个运算符节点
可能对每个赋值重复公式求值
这证明了 SAT in NP:Yes 实例有一个每变量一位的证书,而且验证器关于公式大小以多项式时间运行。
主张边界
SAT 也因为 NP-complete 而有名,但本页不证明困难性或完备性。那条证明路线需要归约、CNF 和 3SAT 等范式,以及更多证明工具。
这个小例子、满足行 1010、验证器追踪,只证明成员关系这一侧:候选赋值可以被高效检查。
| 主张 | 处理方式 | 原因 |
|---|---|---|
| SAT 属于 NP | 本页证明 | 赋值长度为 n;验证器运行时间为 O(|phi| + n) |
| SAT 是 NP-hard 或 NP-complete | 作为后续背景命名 | 证明需要归约,而不是一个固定例子的追踪 |
| SAT 已经表示 CNF 或 3SAT | 后续节点 | 本页使用任意带括号的公式 |
常见混淆
每个修正都把失败行、格式错误行、验证器和后续归约分开。
`0000` 让 phi 为假,所以也许 phi 不可满足。
修正: 失败行只排除这个赋值。不可满足意味着每个格式正确的行都失败。
验证器会自动找到满足赋值。
SAT 一定已经表示 CNF 子句列表。
太短或含非 bit 的字符串仍可当作 false 来计算。
| x1 | psi | 原因 |
|---|---|---|
| 0 | false | x1 为假,因此左侧文字失败。 |
| 1 | false | NOT x1 为假,因此右侧文字失败。 |
图谱连接
p-vs-np 提供证书和验证器的语言。circuit-sat 在门电路上问同一种“是否存在满足赋值”的问题。SAT 是它的公式版本:对象现在是一棵布尔表达式树。
后续节点可以解释电路如何变成公式或约束、为什么 CNF 重要、3SAT 如何进入归约证明。这些是未来节点,不是理解本页的隐藏前置条件。
证书与验证器
电路上的同类赋值问题
公式版本,已实现节点
后续范式节点
练习
区分满足、拒绝、格式错误,以及“已证明/后续再证明”的主张。
选择一个答案来检查。
选择一个答案来检查。
选择一个答案来检查。
选择一个答案来检查。
选择一个答案来检查。
- 对赋值
1010,哪个子公式最先让它看起来有希望? - 为什么
0000不能证明phi不可满足? - 为什么
101应该在任何公式树求值前停止? - 本页证明了哪条主张:
SAT in NP、SAT is NP-hard,还是两者都证明了?
图谱连接 : 布尔可满足性(SAT)