1 问题描述

布尔可满足性问题是给定一个合取范式(CNF),即一系列析取形式的子句(clause)的合取式,问是否存在一组赋值使得整个式子为真。给出满足条件的赋值(说明是satisfied的),或者证明不存在这样的赋值(说明是unsatisfied的)。显然如果要整个CNF为真,则需要每个子句都为真。而对于每个子句内部是析取,所以需要至少有一项为真子句才能为真。

2 不完备算法

一类SAT求解算法是不完备(incomplete) 的,即对于给出的CNF算法只能证明可满足,或者算法只能证明不可满足,没办法对于可满足和不可满足的输入都证出。

2.1 Local Search

初始时随机给出一组赋值,然后带进去看看是否满足,如果有冲突,那就翻转变量取值,再冲突就再在里面翻转,并规定一个最大循环次数。

Local Search无法证明一个CNF是不满足的,能找到赋值的CNF显然就是满足的,但是没找到赋值的CNF也未必就是不满足的。

2.2 其它不完备算法

还有Genetic Algorithm、Simulated Annealing等,老师也没讲应该也用的不多,这里就记个名字吧。

3 完备算法

另一类SAT求解算法是完备(complete) 的,即给出任何CNF,都能证明它是满足的还是不满足的。

3.1 完备算法基本策略

完备算法中涉及两个基本策略(Basic Rules),在完备算法中重点使用了这些策略。

3.1.1 纯字母(Pure Literals)

如果CNF中某个字母xix_ixi​的所有出现都是同一种形式,即要么都是xix_ixi​,要么都是¬xi\neg x_i¬xi​,则说字母xix_ixi​是纯的。

这条规则意在说明如果CNF里发现了纯字母,所有带纯字母的子句都可以直接从CNF里删掉,因为可以直接让这个纯字母导出"真"而不会引起冲突,然后这些带纯字母的子句自然就都是"真"了。

例如:
φ=(¬x1∨¬x2)∧(x1∨¬x2)∧(x2∨x3)∧(x1∨x3)\varphi = (\neg x_1 \vee \neg x_2) \wedge (x_1 \vee \neg x_2) \wedge (x_2 \vee x_3) \wedge (x_1 \vee x_3) φ=(¬x1​∨¬x2​)∧(x1​∨¬x2​)∧(x2​∨x3​)∧(x1​∨x3​)

这个CNF里x3x_3x3​就是纯字母,所以包含它的后两个子句可以直接删除,化简下来
φ=(¬x1∨¬x2)∧(x1∨¬x2)\varphi = (\neg x_1 \vee \neg x_2) \wedge (x_1 \vee \neg x_2) φ=(¬x1​∨¬x2​)∧(x1​∨¬x2​)

然后¬x2\neg x_2¬x2​又是纯字母,这两个子句又可以直接删掉,那么整个CNF就是可满足的了,知x3=¬x2=⊤x_3=\neg x_2=\topx3​=¬x2​=⊤即可让整个CNF为真。

3.1.2 单元子句传播(Unit Propagation)

这个是在尝试赋值的过程中的一个规则。如果一个子句里面,其它字母都导出"假",只剩一个字母了,这个子句叫单元子句(unit clause),这时候这个字母就必须设置为"真"了,不然就会产生冲突。

而"传播"是在说这样的过程是一步步递进的,因为刚刚给一个字母指派为"真"了,又可能会导致其它子句成为单元子句,那么就可以继续应用这条规则。

例如:
φ=(x1∨¬x2∨¬x3)∧(¬x1∨¬x3∨x4)∧(¬x1∨¬x2∨x4)\varphi = (x_1 \vee \neg x_2 \vee \neg x_3) \wedge (\neg x_1 \vee \neg x_3 \vee x_4) \wedge (\neg x_1 \vee \neg x_2 \vee x_4) φ=(x1​∨¬x2​∨¬x3​)∧(¬x1​∨¬x3​∨x4​)∧(¬x1​∨¬x2​∨x4​)

假设到了某一步已经设置¬x2=¬x3=⊥\neg x_2 = \neg x_3 = \bot¬x2​=¬x3​=⊥,那么第一个子句就成了单元子句,所以必须有x1=⊤x_1 = \topx1​=⊤,这又导致后面两个子句成了单元子句,所以必须有x4=⊤x_4=\topx4​=⊤,这时候发现整个CNF是可满足的,知x1=x4=⊤x_1=x_4=\topx1​=x4​=⊤即可让整个CNF为真。

当然,也可能会导致其它子句出现冲突,这时候就要根据具体的SAT求解算法的策略来回退了。

例如,对上面的例子,修改末尾的x4x_4x4​变成¬x4\neg x_4¬x4​:
φ=(x1∨¬x2∨¬x3)∧(¬x1∨¬x3∨x4)∧(¬x1∨¬x2∨¬x4)\varphi = (x_1 \vee \neg x_2 \vee \neg x_3) \wedge (\neg x_1 \vee \neg x_3 \vee x_4) \wedge (\neg x_1 \vee \neg x_2 \vee \neg x_4) φ=(x1​∨¬x2​∨¬x3​)∧(¬x1​∨¬x3​∨x4​)∧(¬x1​∨¬x2​∨¬x4​)

还是设置¬x2=¬x3=⊥\neg x_2 = \neg x_3 = \bot¬x2​=¬x3​=⊥,然后知x1=⊤x_1=\topx1​=⊤,再执行一次单元子句传播,发现剩下两个单元子句既要x4=⊤x_4=\topx4​=⊤又要¬x4=⊤\neg x_4=\top¬x4​=⊤,这就发生冲突了。

3.2 消解法(Resolution)

该方法关注于将CNF里的某些子句消解成新子句,利用
(x∨α)∧(¬x∨β)⊢(α∨β)(x \vee \alpha) \wedge (\neg x \vee \beta) \vdash (\alpha \vee \beta) (x∨α)∧(¬x∨β)⊢(α∨β)

如果CNF中同时出现了形如(x∨α)(x \vee \alpha)(x∨α)和(¬x∨β)(\neg x \vee \beta)(¬x∨β)的子句,就把它们替换成(α∨β)(\alpha \vee \beta)(α∨β)。

当消解出⊥\bot⊥子句时,说明原公式是不可满足的,如:
(x1∨x2)∧(¬x1∨x3)∧(¬x2)∧(¬x3)⊢(x2∨x3)∧(¬x2)∧(¬x3)⊢(x3∨⊥)∧(¬x3)⊢(x3)∧(¬x3)⊢⊥\begin{aligned} & (x_1 \vee x_2) \wedge (\neg x_1 \vee x_3) \wedge (\neg x_2) \wedge (\neg x_3) \\ \vdash & (x_2 \vee x_3) \wedge (\neg x_2) \wedge (\neg x_3) \\ \vdash & (x_3 \vee \bot) \wedge (\neg x_3) \\ \vdash & (x_3) \wedge (\neg x_3) \\ \vdash & \bot \end{aligned} ⊢⊢⊢⊢​(x1​∨x2​)∧(¬x1​∨x3​)∧(¬x2​)∧(¬x3​)(x2​∨x3​)∧(¬x2​)∧(¬x3​)(x3​∨⊥)∧(¬x3​)(x3​)∧(¬x3​)⊥​

是不可满足的。

当消解出的公式中所有字母都是纯字母时,说明原公式是可满足的,如:
(x1∨¬x2∨¬x3)∧(¬x1∨¬x2∨¬x3)∧(x2∨x3)∧(x3∨x4)⊢(¬x2∨¬x3)∧(x2∨x3)∧(x3∨x4)⊢(¬x3∨x3)∧(x3∨x4)⊢⊤∧(x3∨x4)⊢(x3∨x4)\begin{aligned} & (x_1 \vee \neg x_2 \vee \neg x_3)\wedge (\neg x_1 \vee \neg x_2 \vee \neg x_3) \wedge (x_2 \vee x_3) \wedge (x_3 \vee x_4) \\ \vdash & (\neg x_2 \vee \neg x_3) \wedge (x_2 \vee x_3) \wedge (x_3 \vee x_4) \\ \vdash & (\neg x_3 \vee x_3) \wedge (x_3 \vee x_4) \\ \vdash & \top \wedge (x_3 \vee x_4) \\ \vdash & (x_3 \vee x_4) \end{aligned} ⊢⊢⊢⊢​(x1​∨¬x2​∨¬x3​)∧(¬x1​∨¬x2​∨¬x3​)∧(x2​∨x3​)∧(x3​∨x4​)(¬x2​∨¬x3​)∧(x2​∨x3​)∧(x3​∨x4​)(¬x3​∨x3​)∧(x3​∨x4​)⊤∧(x3​∨x4​)(x3​∨x4​)​

是可满足的,只要x3=⊤x_3=\topx3​=⊤或x4=⊤x_4=\topx4​=⊤。

3.3 Stalmarck’s Method

这个就是在搜索解空间树的时候用3.1中的基本规则进行剪枝,每次固定一个变量看其它的变量,如果出现了单元子句,则可以剪掉使解空间树矛盾的那一分支。该方法用来求解common assignments,即必须为⊤\top⊤或者必须为⊥\bot⊥的变量。

例如,对于:
φ=(a∨b)∧(¬a∨c)∧(¬b∨d)∧(¬c∨d)\varphi = (a \vee b) \wedge (\neg a \vee c) \wedge (\neg b \vee d) \wedge (\neg c \vee d) φ=(a∨b)∧(¬a∨c)∧(¬b∨d)∧(¬c∨d)

先设置a=⊥a=\bota=⊥,则发现(a∨b)(a \vee b)(a∨b)是单元子句(因此可以剪掉b=⊥b=\botb=⊥的分支),必须有b=⊤b=\topb=⊤,然后进行传播,发现(¬b∨d)(\neg b \vee d)(¬b∨d)是单元子句,因此d=⊤d=\topd=⊤,推理至此无法继续进行。

再设置对立面a=⊤a=\topa=⊤,则发现(¬a∨c)(\neg a \vee c)(¬a∨c)是单元子句,必须有c=⊤c=\topc=⊤,发现(¬c∨d)(\neg c \vee d)(¬c∨d)是单元子句,因此d=⊤d=\topd=⊤,推理至此无法继续进行。

合之,知d=⊤d=\topd=⊤是一条common assignment,将这个真值指派代入原公式,再继续应用此方法求解。

这个例子不是很好,因为这个例子里ddd是纯字母,实际上后两个子句一开始就可以直接扔掉。

3.4 Recurive Learning

Recurive Learning和Stalmarck’s Method一样也是求解common assignments的,只不过Stalmarck’s Method是固定一个变量的正反两面,而Recurive Learning则是让一个子句内的每个字母分别取⊤\top⊤。

例如,还是对于:
φ=(a∨b)∧(¬a∨c)∧(¬b∨d)∧(¬c∨d)\varphi = (a \vee b) \wedge (\neg a \vee c) \wedge (\neg b \vee d) \wedge (\neg c \vee d) φ=(a∨b)∧(¬a∨c)∧(¬b∨d)∧(¬c∨d)

取第一个子句(a∨b)(a \vee b)(a∨b),要让整个公式满足,这个子句内至少有一个字母要满足。

先设置a=⊤a=\topa=⊤,则(¬a∨c)(\neg a \vee c)(¬a∨c)是单元子句,知c=⊤c=\topc=⊤,则(¬c∨d)(\neg c \vee d)(¬c∨d)是单元子句,知d=⊤d=\topd=⊤,至此无法继续传播。

再设置b=⊤b=\topb=⊤,则(¬b∨d)(\neg b \vee d)(¬b∨d)是单元子句,知d=⊤d=\topd=⊤,至此无法继续传播。

合之,知d=⊤d=\topd=⊤是一条common assignment,将这个真值指派代入原公式,再继续应用此方法求解,或者3.33.4一起用也可以。

3.5 回溯法(DPLL)

DPLL就是标准的子集树回溯,在每步搜索的时候也要去应用3.1中的基本规则进行剪枝,并检查是否有发生冲突的子句,发生冲突时就立即回溯。当找到一个到叶子结点的路径时就说明这个CNF是可满足的,如果回溯完也没找到,就说明是不可满足的。

这里核心就在冲突检查上,例如,下面是DPLL搜索中的某一步:

这时是在a=⊥a=\bota=⊥这一分支上尝试¬b=⊥\neg b=\bot¬b=⊥这一分支,这使得第一个子句和第二个子句成为单元子句,所以d=e=⊤d=e=\topd=e=⊤,而这导致第三个子句为假,因此这时要立即回溯,转而搜索¬b=⊤\neg b=\top¬b=⊤这一分支。

3.6 Conflict-Driven Clause Learning

CDCL直译过来就是冲突驱动子句学习,是在DPLL基础上进行改进得到的。

当在回溯搜索过程中发生冲突时,即可从"当前的搜索路径会导致冲突"这一事实,依据路径上的变量赋值,学习出一个子句项。例如,对于:
φ=(a∨b)∧(¬b∨c∨d)∧(¬b∨e)∧(¬d∨¬e∨f)...\varphi = (a \vee b) \wedge (\neg b \vee c \vee d) \wedge (\neg b \vee e) \wedge (\neg d \vee \neg e \vee f)... φ=(a∨b)∧(¬b∨c∨d)∧(¬b∨e)∧(¬d∨¬e∨f)...

在搜索路径决策为c=⊥c=\botc=⊥且f=⊥f=\botf=⊥时,下一步尝试a=⊥a=\bota=⊥会导致(a∨b)(a \vee b)(a∨b)是单元子句,所以b=⊤b=\topb=⊤,进而导致(¬b∨e)(\neg b \vee e)(¬b∨e)是单元子句,从而e=⊤e=\tope=⊤,进而导致(¬d∨¬e∨f)(\neg d \vee \neg e \vee f)(¬d∨¬e∨f)产生冲突。

这时可以学习到(¬c∧¬f∧¬a)=⊥(\neg c\wedge \neg f \wedge \neg a) = \bot(¬c∧¬f∧¬a)=⊥,所以可以在原CNF中析取一个子句(c∨f∨a)(c \vee f \vee a)(c∨f∨a)。

CDCL的另一个特点是,发生冲突时,应当按照导致冲突的子句进行回溯,而不必按照变量的决策顺序(不必按照时间序)仅回退到上一层。

例如,某个决策顺序是c=⊥c=\botc=⊥,f=⊥f=\botf=⊥,h=⊥h=\both=⊥,i=⊥i=\boti=⊥。接下来在搜索a=⊥a=\bota=⊥时发生冲突,冲突的子句是(a∨c∨f)(a \vee c \vee f)(a∨c∨f),而在此基础上搜索a=1a=1a=1时仍然发生冲突。这时不必回退到i=⊤i=\topi=⊤,而是根据刚刚的子句(a∨c∨f)(a \vee c \vee f)(a∨c∨f),接下来去搜索c=⊤c=\topc=⊤或f=⊤f=\topf=⊤,而ccc的拓扑序在fff前面,因此接下来搜索c=⊥c=\botc=⊥且f=⊤f=\topf=⊤的情况,即直接回溯到fff这一层。

【算法学习笔记】6:SAT问题的一些经典求解策略相关推荐

  1. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

  2. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  3. 数据结构与算法学习笔记之 从0编号的数组

    数据结构与算法学习笔记之 从0编号的数组 前言 数组看似简单,但掌握精髓的却没有多少:他既是编程语言中的数据类型,又是最基础的数据结构: 一个小问题: 为什么数据要从0开始编号,而不是 从1开始呢? ...

  4. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  5. 算法学习笔记:对指定金额计算最少钞票数

    算法学习笔记:对指定金额计算最少钞票数 一.引出问题 财务人员给员工发工资时经常遇到这样一个问题,即根据每个人的工资额(以元作为单位)计算出各种面值的钞票的张数,且要求总张数最少.例如,某职工工资为3 ...

  6. matlab中x从0到5不含0,关于MATLAB的数学建模算法学习笔记

    关于MATLAB的数学建模算法学习笔记 目录 线性规划中应用: (3) 非线性规划: (3) 指派问题;投资问题:(0-1问题) (3) 1)应用fmincon命令语句 (3) 2)应用指令函数:bi ...

  7. 机器学习篇01:在线学习的支持向量机算法学习笔记

    在线学习的支持向量机算法学习笔记 oisvm算法实现说明 oisvm算法实现说明 % 本程序是用于实现基于在线学习的调制信号识别的程序 % % % 第一步:调制信号的生成 % 首先是7个信号:2ASK ...

  8. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

  9. l2-004 这是二叉搜索树吗?_算法学习笔记(45): 二叉搜索树

    二叉搜索树(Binary Search Tree, BST)是一种常用的数据结构,在理想情况下,它可以以 的复杂度完成一系列修改和查询,包括: 插入一个数 删除一个数 查询某数的排名(排名定义为比该数 ...

最新文章

  1. 英伟达TRTTorch
  2. nagios监控三部曲之——为什么nagios不能发送报警邮件(2)
  3. python列表的增删改查
  4. candence 16.6 win8.1 x64 破解
  5. 想要学习设计模式,你得先会看类图,一张图读懂UML
  6. 荣耀v40还会适配鸿蒙,荣耀年度旗舰V40再确认!将搭载“双芯片”:还能升级鸿蒙系统...
  7. 概率软逻辑(PSL,Probabilistic soft logic)通用(可处理中文)版本
  8. 拓端tecdat|R语言随机波动率(SV)模型、MCMC的Metropolis-Hastings算法金融应用:预测标准普尔SP500指数
  9. C语言 运算符与表达式
  10. IP地址中A类、B类、C类地址的区别
  11. [anjularjs] ui-router嵌套ui-view不刷新问题
  12. 批处理文件——多个QQ一键登录
  13. java 字符 加密_Java 字符串的加密与解密
  14. 全球及中国化妆品市场销售格局与品牌竞争状况调研报告2022版
  15. 汤逊湖一期治理接近尾声,SL-MS水质取样监测无人船助力水质监测
  16. df和du显示的磁盘空间使用情况不一致的原因及处理
  17. 网络安全 基础之 Windows漏洞复现(MS12-020)死亡蓝屏
  18. Pandas——ix vs loc vs iloc区别
  19. NNs(Neural Networks,神经网络)和Polynomial Regression(多项式回归)等价性之思考,以及深度模型可解释性原理研究与案例...
  20. 通过poi导出复杂excel既有合并行又有合并列

热门文章

  1. 《推背图》存在着什么样的秘密呢?
  2. 图片上传到服务器,存储路径和查看图片的设置
  3. 微信小程序开发入门教程(十二)
  4. 动态网站数据采集 - 去哪儿网火车票查询爬虫
  5. 转:HDFS研究----.Trash文件
  6. java号码分身_电话号码分身
  7. 如何系统掌握产品功能改进方案?
  8. Matlab求解AX=XB(手眼标定用)
  9. JVM调优系列(五)——JVM调优利器
  10. 数据库中间件Mycat诞生记1