AI(人工智能:一种现代的方法)学习之:CSP(Constraint Satisfaction Problems) 约束满足问题:回溯法——前向检查(过滤法)、弧相容检查、 变量排序

参考

加州大学伯克利分校的 AI 公开课

CSP 和传统的搜索算法的不同

在这里插入图片描述

  • 传统搜索算法将 state 看做一个黑盒子,因为在构建搜索树的过程中,如何定义每个 state 其实是定义一个自己设计的数据结构;goal test 方法也是自己设计的,比如针对路径搜索问题,我们的 goal test是负责检验在 fringe 包含的节点中被扩展的那个是否是目标节点。通过定义这种功能构成了我们的 goal test 函数。
  • 但是在 CSP 问题中,state 和 domain 都是提前定义好的,constrain set (约束集合)相当于一个规则清单。

地图着色问题

  • 相邻的区域不能同色
    在这里插入图片描述
  • 变量:这些需要被着色的地区组成的集合
  • 值域:三种不同的颜色组成的集合
  • 约束:
    • 隐式约束:WA ≠ \neq = NT
    • 显式约束:所有符合约束条件的 (WA, NT) 着色的集合
    • 显式约束和隐式约束的不同在于,虽然本质上的意义一样,但是显式约束相当于一个穷举清单,可以更直观。
      在这里插入图片描述

N-Queens 问题

  • 每个 Queen 会攻击处在横、竖、对角方向的 queen,因此我们想让任意两个 queen 不处在同一条横线,竖线或者斜线上。
    在这里插入图片描述

  • 变量:所有格子的位置 X i , j X_{i,j} Xi,j

  • 值域:格子上是否有 queen { 0 , 1 } \{0,1\} {0,1}

  • 约束:
    在这里插入图片描述

    • ∀ i , j , k   ( X i , j , X i , k ) ∈ { ( 0 , 0 ) , ( 0 , 1 ) , ( 1 , 0 ) } \forall i,j,k ~(X_{i,j}, X_{i,k})\in \{(0,0), (0,1), (1,0)\} i,j,k (Xi,j,Xi,k){(0,0),(0,1),(1,0)} 代表 i i i 相同的两个格子(变量)他们的组合只能是 一个有 queue,一个没有 queue
    • 第二个约束条件指的是:在 j j j 相同的一列上,只能有一个 queue
    • 第三个约束条件:在以 i , j i,j i,j 为参考点和其右下到左上方向上所有的点只能有一个 queue
    • 第四个条件:左下到右上的对角线上只能有一个 queue
  • 但是只有这四个约束条件是不够的,因为这个时候如果把所有的变量都置 0 也是符合条件的,因此还需要一个额外的限制:
    在这里插入图片描述

  • 即所有的 variable 的值相加要等于 queue 的个数

为什么要用 CSP 来解决某些问题

  • 如果着色问题使用 BFS 来解决,那么会形成如下一颗树:
    在这里插入图片描述
  • 根节点是空,这时候 WA=red, WA=green, WA=blue 分别当做第一层的子节点,然后以此扩展出一颗树,所有的可能的解必须等到 search tree 的最后一层才能得到,因此对于BFS 来说搜索到最后一层是灾难,空间复杂度太高。
  • 对于深度优先搜索也是一样的,可能的解只有可能出现在最后一层,而在此之前如果没有任何约束,则会构建整棵树,而树上的很多节点其实是根本不符合解的要求,但是由于没有任何限制,树还是会把所有的情况都排列出来。例如:WA=red,NT=red,SA=red;但这种着色方法显然是错的。
    在这里插入图片描述

回溯法

  • 针对深度优先遍历:

    • 每个步骤只考虑单个 variable 的赋值
    • 在深度搜索的时候如果已经出现了不能够相容的条件,则没有必要在继续探索下去,也就是说在上面那个明显的错误例子中,当给 NT=red 的时候,这个子树就不应该再进行扩展了,也就是说 NT=red 这个节点变成了一个 “死结点”。 而对应的,那些被扩展了的没有问题的节点称为 “活结点”。每次回溯都会回溯到上一个 “活结点”。
  • 对深度优先遍历进行上面两个限制的改进,称为回溯法。

  • 回溯法通常使用 递归 方式实现。
    在这里插入图片描述

  • 按照这种方式进行着色:
    在这里插入图片描述

    • 发现当这个绿色的块确定了之后,绿色右边的块没有合适的填充色可以选择了。因此要回溯:
      在这里插入图片描述
    • 回溯一步,把上一个色块改成绿色,发现还是不行,继续回溯:
      在这里插入图片描述
  • 按照这种方式直到成功:
    在这里插入图片描述

Filtering 过滤法 (forward checking)

  • 过滤法是将 还没有进行赋值的候选变量 进行适当排除。

  • 简单的过滤是通过 前向检查的方式来进行的

  • 对着色问题来说,过滤法通过下面步骤来实现:

    • 所有要上色的块中都包含着整个 domain 的所有值,这些值目前都是可选的
    • 但经过对当前的块上色之后,所有和他相连的块的 domain 中就需要去掉当前选定的颜色
    • 按照这个步骤进行下去当某个块中的 domain 为空,则证明无法完成整个着色任务,因此前面的步骤中一定发生了错误,因此需要向前回溯。
  • 一开始所有的色块中都未被分配颜色,所有每个色块的 domain 中都包含所有的颜色

在这里插入图片描述

  • 对第一个色块分配蓝色,那么相邻的两个色块 domain 中的蓝色就要被删掉

在这里插入图片描述

  • 第二个色块从剩下的 domain 的值中选一个作为当前色块的值

在这里插入图片描述

  • 同样进行。。。

在这里插入图片描述

  • 再两步之后,发现有一个格子里面的 可选 domain 空了,因此当前的绿色块成为了 dead node (死结点)因此不得不回溯

在这里插入图片描述

  • 回溯到上一个 活结点

在这里插入图片描述在这里插入图片描述

  • 再前进,发现又产生了死结点,还是不行。

在这里插入图片描述

  • 再回溯

在这里插入图片描述

  • 再前进

在这里插入图片描述

  • 重复上述步骤直到成功

在这里插入图片描述

  • 前向检查 forward checking 会帮助避免一些未来可能出现的错误,但是它不能够保证未来的过程中不发生错误而回溯。

弧相容(arc consistency)

弧的定义
  • 在下面这样一个无向图中,A, B, C, D 是 4 个 variable;那么 (A,B), (B,C), (C,D), (B,D) 之间是存在无向边连接的。

在这里插入图片描述

  • 对于每一个无向边,都可以看成是两个方向相反的有向边;而每个单独的有向边都可以看成一个 arc(弧);用定义每个 variable 为 X i X_{i} Xi,从 X i X_i Xi 指向 X j X_j Xj 的弧表示为 X i → X j X_i \rightarrow X_j XiXj,其中 X j X_j Xj 称为 头部 variable (head variable) X i X_i Xi 称为 尾部 variable (tail variable)
    在这里插入图片描述
弧相容的定义与实现
  • 最开始将整个约束图(上面包含 A,B,C,D 的图)中所有的弧存入一个队列 Q Q Q

  • 按照下面的方式检查每一个弧 X i → X j X_i \rightarrow X_j XiXj,检查完毕的弧就从 Q Q Q 中移除:

    • 对于 tail variable X i X_i Xi domain 中的每一个值 v v v至少head variable X j X_j Xj 中存在一个 w w w 不违反 X i , X j X_i, X_j Xi,Xj 之间的 任何约束。如果 head variable 中无法找到符合条件的 w w w 那么 v v v 需要从 X i X_i Xi 中删除
  • 如果在检查弧 X i → X j X_i \rightarrow X_j XiXj 的过程中, X i X_i Xi 中的某个值 v v v 被删除了,那么所有指向 X i X_i Xi 的弧 X k → X i X_k \rightarrow X_i XkXi 会被重新加入 Q Q Q 中(如果已经在 Q Q Q 中,则无需重复加入)。

  • 这样重新将 X k → X i X_k \rightarrow X_i XkXi 加入 Q Q Q 的方式是因为 X i X_i Xi 被更新了,需要重新检查一遍。

  • 这里借用知乎的文章举个例子好理解:

  • 这个例子中 WA, Q 已经着色,{NT, SA, NSW, V} 等待被着色,所以弧相容的检测发生在 {NT, SA, NSW, V} 之间。
    在这里插入图片描述
弧相容的明显效果
  • 还是自下而上的着色,配合 forward checking 来缩小与当前色块相关的还没有进行分配的块的 domain
  • 如果 只使用 forward checking 会发生下面这种情况:
  • 走到下图所示的这一步,左上角和右下角 的两个色块的 domain 都只剩一个绿色,因此其实这个策略已经失败了,但是在只采用 forward checking 的回溯算法中,不会顾及这一些,他只会按部就班地采用 forward checking 下去直到 死结点 (下面第二张图)才会回溯。
    在这里插入图片描述
  • 所以他会一直走到如下状态的时候(左上角块的 domain 空了)才会意识到出问题了。但是从上一张图到下图中失败的情况过程中的那些步骤都是浪费的计算步骤。
    在这里插入图片描述
  • 如果结合使用弧相容的方式,就不会出现上述问题

在这里插入图片描述

  • 在为第二个块分配了 红色 之后,由于 弧相容 策略的执行,使得 左上和右下 的节点在这一步已经解决了可能发生的冲突问题,所以在后面也不会遇到冗余计算的问题。
  • 注意下面的两步:
    在这里插入图片描述
    在这里插入图片描述
  • 在最后一个蓝色放下的时候,剩余的所有节点都直接 domain 为空了,因此就不会继续向下探索;这就是弧相容带来的便利,如果只用 forward checking,那么必然还需要经过很多步骤才能判断剩下的路是错的,但是弧相容可以帮助我们更早的发现这个问题。

变量排序(Variable Ordering)

  • 首先强调:这个方法也是在回溯法的基础上的一种优化方式,和弧相容是并列的,也就是说在这个部分,我们单独研究变量排序如何帮助算法更高效地实现回溯算法,而不结合任何弧相容。
  • 在这个部分的实例中,我们将结合 forward checking 作为基本方法,然后加入变量排序来使得可能暴露的问题尽早的暴露。
  • 变量排序就是如何选择要赋值的变量顺序。比如还拿澳大利亚地图着色问题来看:当为最左边的版块分配了红色,那么接下来选择哪一个变量进行赋值呢?是选择与这个红色相邻的版块赋值还是选择较远的版块呢?还是说任意选择一块来赋值?Variable 就是讨论如何通过选择变量赋值的顺序来帮助提高回溯算法的效率。
    在这里插入图片描述
最小剩余 domain 排序
  • 一个常用的选择标准是:minimum remaining values ;也就是选择 domain 中包含选择最少的 variable。比如在 filtering 部分我们提过,每次我们给当前的变量赋值之后,剩下的所有版块的 domain 都会更新,那么这些板块中谁的 domain 包含的元素最少,就代表这个版块的 domain 可能最早变成 而变成 死结点 进而产生回溯操作。所以这种 minimum remaining values 的排序方法认为:既然问题迟早可能暴露,那就选择一种可以让问题尽早暴露的方式。
    在这里插入图片描述
  • 按照最小 domain 值排序的方式也叫 fail-fast 排序(快速错误排序)
  • 依然是这张图,但区别是为第二个版块分配了红色以后,直接选择了左上角的版块为他分配绿色,因为他的 domain 中的值最少:只有一个绿色。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
最小约束值排序(Least Constraining Value)
  • 上一个选择顺序的方式是 基于 variable 的,但这个最小值约束排序讨论的是在一个 variable 被选定的时候,domain 里面选哪个值比较好的问题,是 domain 中 value 层面的排序问题。
  • 例如下图中已经选择对右上角的版块进行颜色分配,但是到底分配红色还是蓝色呢?这是个问题。
    在这里插入图片描述
为什么 variable 层面上我们要去首先选择最容易错误的 variable 而在 value 层面却要选择对周围影响最小的 value 呢?
  • 因为在 CSP 问题中,无论如何都要对所有的 variable 进行值的分配,因此必须把困难的 variable 情况放在前面进行讨论,这样可以提前暴露问题,触发回溯行为,避免不必要的计算。但是对于每个 variable domain 中的值来说,并不是每个值都会用到,因此我们只需要选择最有效的 value 就可以了。就例如在上图中右上角的颜色分配中,只需要选择一个值(要么选蓝色要么选红色)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暖仔会飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值