程序验证(二):SAT问题

程序验证(二):SAT问题

概念:Satisfiability Problem

SAT问题:给定一个命题公式FF,决定是否存在一个解释II使得IFI\models F.
3SAT问题是首个被确定的NP完全问题。
大多数重要逻辑问题可以归约为SAT:

  • 永真性
  • 蕴含
  • 等价性

SAT求解能力的发展:
关键:将搜索与推理结合以提高效率

CNF详解

SAT求解器的输入一般是CNF,这里为便于讨论,引入关于CNF的集合表示。

集合表示

一个公式(formula)可以视为子句(clause)的集合:
C1...CnC_1\wedge ... \wedge C_n
可以表示为:
{C1,...,Cn}\{C_1 , ... , C_n \}
同样,子句可以视为文字(literal)的集合:
(PQ)(Q¬P)(P\vee Q)\wedge (Q\to \neg P)
可以表示为:
{{P,Q},{¬Q,¬P}}\{\{P,Q\},\{\neg Q,\neg P\}\}
一些通用的表示方法:

  • 公式 formula: FF
  • 子句 clause: CC
  • 变量 variable: P,Q,R,...P, Q, R, ...

一些方便的表达方式:

  • Ci{PF}C_i\{P\mapsto F\}: 在子句CiC_i中使用FF替代PP
  • Ci[P]C_i[P]: 变量PP在子句CiC_i中是不取非的,也就是Ci={...,P,...}C_i = \{... , P , ...\}
  • Ci[¬P]C_i[\neg P]: 变量PPCiC_i中是取非的,也就是Ci={...,¬P,...}C_i = \{... , \neg P , ...\}

在这种符号体系下,会有以下命题成立(有点绕,需要多看几遍):
FF表示公式,CC表示子句,基于CNF公式的集合表示,有:

  • CiCjC_i\vee C_j: union of CiC_i and CjC_j, CiCjC_i\cup C_j
  • FiFjF_i\wedge F_j: union of FiF_i and FjF_j, FiFjF_i\cup F_j

归结(resolution)

只有一条规则:
C1[P] C2[¬P]C1{P}C2{¬P}\frac{C_1[P]~C_2[\neg P]}{C_1\{P\mapsto \bot\}\vee C_2\{\neg P\mapsto \bot\}}
给定两个具有相同变量PP,但是对于PP取非情况不同的两个子句,那么:

  • 如果PP为真,那么C2C_2中的其它文字必然为真
  • 如果PP为假,那么C1C_1中的其它文字必然为假
  • 因此,可以在两个子句中都移除PP,也就是归结
  • C1{P}C2{¬P}C_1\{P\mapsto \bot\}\vee C_2\{\neg P\mapsto\bot\}叫做归结式(resolvent)
    这个归结式可以作为一个合取子句加入到原公式,这样得到的新公式与原公式等价。
    而如果C1{p}C2{¬P}==C_1\{p\mapsto \bot\}\vee C_2\{\neg P\mapsto\bot\}=\bot\vee\bot=\bot
  • 那么C1C2C_1\wedge C_2是不可满足的
  • 任何包括{C1,C2}\{C_1,C_2\}在内的CNF都是不可满足的
    举例:
    ABCA\vee B\vee C¬ABD\neg A\vee B\vee D的归结子句是BCDB\vee C\vee D

归结法求解SAT

归结算法

在这里插入图片描述

  • FF'是所有归结式的集合
  • 每一轮迭代,更新FF以包含以产生的归结式
  • 每一轮迭代,计算所有可能的归结式
  • 在更新后的FF上重复归结过程
  • 终止条件:1.出现\bot归结式 2.无法再更新FF(此时所有的可归结的子句都已经被归结了)
    举例:
    (PQ)(PR)(QR)¬R(P\vee Q)\wedge (P\to R)\wedge (Q\to R)\wedge \neg R
步骤 子句 备注
1 pQp\wedge Q -
2 ¬PR\neg P\vee R -
3 ¬QR\neg Q\vee R -
4 ¬R\neg R -
5 QRQ\vee R 1&2
6 RR 3&5
7 \bot 4&6

归结算法的评价

解决较大规模问题的效率低下

基于搜索的方法

大致思路:从一个空的解释(interpretation)出发,每次扩展一个变量的取值

部分解释

在实现策略上更加灵活
如果II是一个部分解释,文字\ell可以为truetrue, falsefalse, undefundef:

  • truetrue(satisfied): II\models \ell
  • falsefalse(conflicting): I⊭I\not\models\ell
  • undefundef: var()∉Ivar(\ell)\not\in I
    给定一个子句CC和解释II
  • C is truetrue under II iff ICI\models C
  • C is falsefalse under II iff I⊭CI\not\models C
  • C is unitunit under II iff C=C,I⊭CC=C' \vee \ell, I\not\models C', \ell is undefundef
  • Otherwise it is undefundef
iff: if and only if,当且仅当
unit: 单元,一个新引入的概念

举例:
I={P11,P20,P41}I=\{P_1\mapsto 1,P_2\mapsto 0,P_4\mapsto 1\},那么有:

  • P1P3¬P4P_1\vee P_3\vee\neg P_4 is truetrue
  • ¬P1P2\neg P_1\vee P_2 is falsefalse
  • ¬P1¬P4P3\neg P_1\vee\neg P_4 \vee P_3 is unitunit
  • ¬P1P3P5\neg P_1\vee P_3 \vee P_5 is undefundef

搜索程序:一个状态机

  • 每一个状态都记录了部分解释与当前的公式
  • 状态之间的转化由转化规则决定
    程序的状态包括:
  • satsat
  • unsatunsat
  • [I]F[I] \lVert F, 这里的[I][I]是一个解释,FF是一个CNF
    初始状态:[Φ]F[\Phi]\lVert F
    结束状态:satsat, unsatunsat
    中间状态:
  • [Φ]F1[\Phi]\lVert F_1, CC: 解释为空,F=F1CF=F_1\wedge C
  • [I1,Pˉ,I2]F[I_1,\bar{P},I_2]\lVert F: 解释先置为I1I_1,然后P0P\mapsto 0, 然后解释为I2I_2

搜索规则

通俗的说,就是深度优先搜索。在某些算法中优化了回退策略。

  1. 判定规则(Decision Rule)
    [I]F[I,P]F if{P occurs in FP unassigned in I [I]\lVert F \hookrightarrow [I,P^{\circ}]\lVert F~if \begin{cases}P~occurs~in~F\\P~unassigned~in~I\end{cases}
  2. 回退规则(Backtrack Rule)
    [I1,P,I2]F[I1,Pˉ]F if{[I1,P,I2]⊭FP last decision in interp.[I_1,P^{\circ},I_2]\lVert F\hookrightarrow [I_1,\bar{P}]\lVert F~if \begin{cases}[I_1,P,I_2]\not\models F\\P~last~decision~in~interp.\end{cases}
  3. 可满足规则(Sat Rule)
    [I]Fsat if [I]F[I]\lVert F\hookrightarrow sat~if~[I]\models F
  4. 不可满足规则(Unsat Rule)
    [I]Funsat if{I⊭FNo decisions in I[I]\lVert F\hookrightarrow unsat~if \begin{cases}I\not\models F\\No~decisions~in~I\end{cases}
    以上四条规则足以构建一个基本的sat求解器
    我们可以进一步优化。比如在unitunit子句中,对于解释II与子句CC,有
  • II不满足CC
  • CC中有且只有一个文字被置为假
    那么根据归结原理,有:
  1. 单元传播规则(Unit Propagation Rule)
    [I]F,CP[I,P]F,CP[I]\lVert F, C\vee P\hookrightarrow[I,P]\lVert F,C\vee P
    [I]F,C¬P[I,Pˉ]F,C¬P[I]\lVert F,C\vee \neg P\hookrightarrow [I,\bar{P}]\lVert F,C\vee \neg P
    条件是
    I⊭C,and P undefined in II\not\models C, and~P~undefined~in~I

高级回退&子句学习

基础的回退规则比较“笨”:

  • 它总是回退到最近确定的解释
  • 它不保留子句冲突的信息
    引入回跳规则(BackJump Rule):
    [I1,P,I2]F[I1,]F,(Cl) if{[I1,P,I2]⊭FExists C s.t.:F(Cl)I1Cvar() undef. in I1var() appears in F[I_1,P^{\circ},I_2]\lVert F\hookrightarrow [I_1,\ell]\lVert F, (C\to l)~if \begin{cases}[I_1,P^{\circ},I_2]\not\models F\\ Exists~C~s.t.:F\Rightarrow (C\to l)\\ I_1\models C\\ var(\ell)~undef.~in~I_1\\ var(\ell)~appears~in~F\end{cases}
    这里ClC\to l就叫做冲突子句,我们只要避免冲突子句就可以进一步寻找解。
    那么,如何找到冲突子句呢?
    构造一个蕴含图(implication graph) G=(V,E)G=(V,E):
  • VV对于解释II中每一个判定文字都有一个节点,用这个文字的值和它的判定等级来标记(说白了就是这个文字是你所判定的第几个文字)
  • 对于每个子句C=1...nC=\ell_1\vee ... \vee\ell_n \vee \ell,其中1,...,n\ell_1, ... ,\ell_n被赋值为假,首先为\ell添加一个节点,它的判定等级就是它进入到II的顺序,然后添加边(i,)(\ell_i, \ell)EE,其中1in1\le i\le n
  • 添加一个冲突节点Λ\Lambda。对于所有标记为PP¬P\neg P的冲突变元,在EE中添加从这些节点到Λ\Lambda的边。
  • 将每条边都标记上导致这个蕴含关系的子句
    例如:
    在这里插入图片描述
    冲突图:只有一个冲突变元,且所有节点都具有通往Λ\Lambda的路径的蕴含图
    例如:
    在这里插入图片描述
    获得冲突子句:
    考虑一个冲突图GG
  1. GG中切一刀,使得:
  • 所有的判定节点在一侧(“原因”)
  • 至少一个冲突文字在另一侧(“结果”)
  1. 在“原因”一侧中,选出所有与被切割的边相连的节点KK
  2. KK中的节点即为冲突的原因
  3. 相应的文字的非生成了冲突子句
    例如:
    在这里插入图片描述
    图中,¬P5¬P2\neg P_5\vee\neg P_2¬P5P6\neg P_5\vee P_6可以作为冲突子句

DPLL & CDCL

DPLL见DPLL
CDCL即为(Conflict-Driven Clause Learning),是目前SAT求解器主要采用的方法。

展开阅读全文
©️2020 CSDN 皮肤主题: 鲸 设计师: meimeiellie 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值