一个子句的其余文字均为假、只剩一个未赋值文字时,
将这个文字置真。
重复传播,直到没有新赋值或发现冲突。
取
取
传播没有发现冲突,不等于已经找到模型。
Algorithm 1 DPLL
1:function DPLL(
2:
3:if
4:return Unsat
5:if
6:return
7:
8:for all
9:
10:
11:
12:if
13:return
14:return Unsat
两支都失败才判 UNSAT。
完备不代表多项式时间。
伪代码的辅助过程未展开,不能独立运行。
02
记录传播原因,用归结解释一次失败。
若
因此,归结式是原有子句的逻辑后果:
保存这个原因,才能在冲突后反向解释
后续分析使用这里记录的传播原因。
@k 表示决策层;第 从冲突子句
① 消去
② 消去
03
让学习子句决定回跳位置和下一次传播。
保留第
回跳层取除唯一当前层文字外的最大层;单位子句回到根层
保留
继续搜索,可得到满足全部原始子句的模型:
Algorithm 2 CDCL
Input: CNF formula
Output: A model of
1:Initialize(
2:while true do
3:
4:if
5:if
6:return Unsat
7:
8:Backtrack(
9:AddClause(
10:Enqueue(
11:else if AllAssigned() then
12:return Assignment()
13:else
14:Decide(ChooseLiteral())
04
在保持逻辑依据的前提下,减少搜索与传播成本。
一个监视文字
标准回溯无需把监视位置恢复到历史位置。
参与近期冲突会提高活跃度。
用衰减逐步降低旧事件影响。
优先选择活跃的未赋值变量。
记录变量上一次使用的取值。
再次选择变量时复用该取值。
重启后也可继续利用这一状态。
撤销非根层赋值,回到根层
保留学习子句,以及活跃度、相位等启发式状态。
下一轮从新的决策顺序继续搜索。
无限重复短搜索不能保证终止;重启需要保证搜索进展。
保留学习子句可复用推理,也会增加存储和传播开销。
本例学习时,
删除已蕴含的学习子句,不改变原公式的模型集合。
删除子句中的文字会加强约束。例如:
本例
将
为什么
完整推导与阅读路线见 SAT 求解专题。
从传播队列与监视列表,走向搜索控制、公式简化和效果评估。
配套笔记:预处理、内处理与模型恢复 · 搜索策略
用一个排班问题串起约束编码、假设查询、核心缩减与证据检查。
配套笔记:增量 SAT 与建模实践 · 结果验证
[1] A. Darwiche, K. Pipatsrisawat. Complete Algorithms.
Handbook of Satisfiability, 2nd ed., 2021, pp. 101–132.
DOI
[2] J. Marques-Silva, I. Lynce, S. Malik.
Conflict-Driven Clause Learning SAT Solvers.
同书,2021, pp. 133–182. DOI
[3] N. Eén, N. Sörensson. An Extensible SAT-solver.
SAT 2003 会议论文集,2004, pp. 502–518.
出版版本 · 扩展稿 v1.2
前置知识:布尔逻辑、集合与递归。参考文献使用 2021 年第二版 Handbook of Satisfiability 与 MiniSat 扩展稿;完整推导见配套知识笔记。
先理解完整搜索,再用同一个例子串起冲突分析、学习子句和回跳。最后概括实现与启发式;完整实现算例在第二篇展开。页眉可跳转至各章,两种比例使用相同页序。
文字是变量或其否定,子句是文字的析取,CNF 是子句的合取。求解器可以返回部分模型,但必须保证它能补全为满足原公式的赋值。来源:[1] §3.2。 空合取为真,空析取为假。在递归搜索中,冲突针对当前部分赋值;只有排除所有分支或在根层证明冲突,才能判断原公式 UNSAT。来源:[1] pp. 101–102。
这里固定从左到右的一种传播顺序。也可以先由最后一个单位子句得到 c=0,最终同样会冲突,但最先报告的冲突子句可能不同。未赋值是实现状态,不是布尔逻辑中的第三种真值。来源:[1] §3.5.2。
这个四子句例子说明单位传播不是完整的 SAT 判定方法。需要分支搜索或者更强的推理。来源:[1] pp. 103, 115–116;公式与分支分析可直接逐项核对。
初始调用 DPLL(F, 空赋值)。PropagateToFixpoint 在当前分支内传播,直到没有新赋值或发现冲突;Condition 与 Extend 分别生成该分支的剩余公式与赋值副本。空子句表示冲突,空公式表示全部子句已经满足。返回部分模型表示 SAT,返回 UNSAT 表示该分支无解。伪代码中的辅助过程尚未展开,不能独立运行。来源:[1] §3.5。 每个递归分支独立维护剩余公式与赋值。成功时未赋值变量可任意补全;空赋值也可能是合法返回值,因此不能按布尔真假判断模型。资源限制导致的提前退出应报告未完成。来源:[1] §3.5。
A 和 B 是不含被归结变量的剩余文字析取。加入逻辑后果保留所有模型,但不能随意删除原有前提;DP 变量消除需要处理相应正负子句对。归结的这一含义将在冲突分析中具体出现。来源:[1] §§3.2.1, 3.3.1。
下一次决策前必须传播到无新赋值且无冲突;发生冲突时可立即停止。蕴含图中的多条入边共同表达一个原因子句,不能把每一条边误读成独立的逻辑蕴含。来源:[2] pp. 135–140。
该例子使用 8 个变量、6 个子句。u 的决定使 C6 满足,但与接下来的冲突无关,便于展示跳过无关决策层。每次决定之后先完成传播,再进行下一个决定。 处理 d 时先将 e、f 加入传播队列,随后检查 C5,就能产生这里的轨迹。其他合法传播次序可能先得到 f=0,并在 C4 上报冲突。我们不把一种轨迹当成唯一轨迹。
节点表示已经为真的赋值,@ 后的数字表示决策层,边旁的 C 编号标记原因子句。e 的两个前提 b、d 需要共同成立;同样,冲突节点的两条 C5 入边共同表示 e=f=1 使 C5 的两个文字都为假。当前层从 c 到冲突的路径都经过 d;因此 d 是 1-UIP,c 是更早的 UIP。图由 Mermaid 围栏生成,变量与正文例子一一对应;与冲突无关的 u 不画入图中。 定义中的图限制在当前决策层,低层 b 的赋值作为固定上下文。沿同一当前层归结链继续追到更早的 UIP,低层文字集合可能扩大,回跳层不会因此更低;这有固定推导方式的条件,不能推广到任意子句最小化后的结果。来源:[2] pp. 143–145。
从冲突子句开始,沿 trail 逆序取当前层传播变量,用其原因子句归结。每一步都保留“当前公式蕴含所得子句”这个不变量。这里 e 与 d 仍同属当前层。 重复的 ¬d 只保留一次。L 中只有 ¬d 来自当前第 3 层,¬b 来自第 1 层,因此达到了标准 1-UIP 停止条件。不要继续消去 d 再声称仍是 first UIP。
标准断言式回跳取其他文字最大层,不是简单退一层,也不是把某个任意 UIP 的层当作回跳目标。u 虽然无关,也作为 trail 后缀的一部分撤销;回跳不会保留不连续的高层赋值。来源:[2] pp. 143–144。 此时的断言赋值是 d=0,不是直接翻转原决策 c。随后才由 C2 传播 c=0。给出的完整模型逐项满足六个原始子句;它也满足新子句。学习没有把原本的模型排除掉。
伪代码中的辅助过程没有展开,不是可独立运行的程序。C 为冲突子句,None 表示没有冲突;空子句仍属于冲突。AnalyzeFirstUIP 显式返回学习子句 L、回跳层 j 和断言文字 l。Initialize 初始化公式、赋值轨迹和根层传播队列;Enqueue 的第二个参数是原因子句;Decide 合并新建决策层与记录无原因的决策赋值。返回模型表示 SAT,返回 UNSAT 表示无解。省略重启、子句删除和预处理。传播必须发生在下一次决策之前。根层冲突不依赖分支假设,可以推出 UNSAT;外部验证需要另行输出证明记录。来源:[2] §4.2;[3] §4.5。
长度至少为 2 的子句使用两个监视位置,单位子句单独处理。替代项可以为真或未赋值,不限于未赋值。正确实现依赖传播队列和 watch list 的维护;不能把“找不到替代”一概当作单位传播。来源:[2] pp. 149–151;[3] §§3, 4.3。
左侧概括 VSIDS 类方法,不把一种实现的计数规则当作唯一标准。活跃度选择变量,相位保存选择倾向的真值;两者都影响搜索路线,不负责证明学习子句正确。来源:[2] pp. 148–149。
重启重新选择路径,但学习子句仍约束后续搜索。正确答案的可靠性与最终终止是两个不同问题;完备性的论证取决于重启、删除以及搜索进展的具体条件。这里不把任意重启策略都称为完备。来源:[1] §3.6.4.5;[2] p. 148;[3] §4.7。
本页讨论保留原始公式时删除冗余学习子句,不讨论预处理中的等可满足变换。删除子句可以失去搜索进展信息,不能由模型集合不变直接推出任意删除策略都终止。锁定的原因子句涉及实现中的引用有效性。来源:[2] pp. 148–151;[3] §§4.5, 4.7。 这里在子句的所有文字均已赋值时计算 LBD,τ 指这一次轨迹。LBD 是不同决策层的数量,不是文字数量,也不是子句永久不变的语法属性;不同求解器可在后续使用中更新评分。低 LBD 是经验启发式,不能保证任意子句都更有用。来源:[2] pp. 144–146, 148–149。
反例完整赋值为 (a,b,c,d,e,f,u,v)=(0,0,1,1,0,1,1,0),满足六个原始子句及 L,却不满足 L'。实际子句最小化通过原因追溯或归结证明文字冗余;这与删除整条冗余学习子句不同。来源:[2] pp. 144–146;反例由本页公式直接核对。
第一部分回到两个分支覆盖所有赋值;第二部分回到原因子句、唯一当前层文字和其他文字最大层;第三部分区分正确性、终止和经验性能。可请听众用本例完整解释学习与回跳。
本篇建立 DPLL 到 CDCL 的算法主线,实现部分只介绍机制与正确性条件。第二篇展开实现成本和优化算例,第三篇连接应用约束与可信结果;更完整的定义和推导保留在知识笔记中。
[1]、[2] 按 2021 年第二版的出版页码定位;不要与 2009 年第一版的章节页码混用。 演讲备注中的 [3] 按 extended version 1.2 的章节定位。会议名称中的 2003 与论文集的出版年 2004 不同。扩展稿为 23 页,不能把其中页序直接当作出版页码。原始读书报告:https://github.com/sj-shijin/assets/tree/main/Handbook%20of%20SAT 。