关于Informed Search

所谓Informed Search,就是带有智慧决策的搜索,就像它的名字一样,它是informed,消息灵通的,它能根据最新情况而重新选择搜索。Informed Search也可以叫Heuristic Search,启发式搜索。正如上一篇提到的机器人、汽车导航、打魔兽,这些都是运用了Heuristic的搜索。

 

何为Heuristic?Heuristic应该算一条引导你进入最佳选择的规则,它决定了状态空间中一个状态的质量,引导你每次都选择质量最好(或较好)的状态,一步步走向最佳方案。

Heuristic就是一种度量,它通过一个估价函数来表示。

f(n) = g(n) + h(n)

其中h(n)就是heuristic函数,g(n)是cost估算函数。g(n)表示从初始节点到当前节点所需的开销(例如可以用路径的长度/权来表示),而h(n)表示从当前节点到目标节点还剩的差距(有多种表示方法,比如可以用当前状态与目标状态Conflicts的个数来表示),g(n)和h(n)两者共同决定了f(n),即一个状态的质量/估价。有时为了区分g(n)和h(n)的权重,也可以在前面加上常系数,即表示为

f(n)=α*g(n) +β*h(n)

 

 

下面来介绍几种Informed Search算法

 

  1. 1.     Best-First SearchBEST-FS

这个应该算Informed Search中最基本的方法,基本思想如下

有一个OPEN List和一个CLOSED List,CLOSED List就是一个普通的队列,里面存放所有访问过的节点(也就是说这些节点不会被再次访问了),而OPEN List是一个优先队列,里面存放所有已访问过的节点的后继节点(即待访问的节点),OPEN List根据节点的f(n)值调整为最小堆。

(1)将初始节点插入OPEN List中

 当OPEN List非空时

(2)从OPEN List出堆,放入CLOSED List中,如果该节点即为目标节点则算法结束(backtracking路径)

(3)扩展该节点的所有后继节点

对每一个后继节点,若后继节点不在CLOSED中,则把它插入OPEN List中

 

注意,这里同样每次扩展后继节点插入OPEN List前,要将后继节点的parent指针指向当前节点。每次节点插入OPEN List后,堆会根据f(n)值进行一次调整操作。

 

之前介绍过的Uniform-Cost Search(UCS)其实可以算Best-First Search的一种特例,其中f(n)=g(n),g(n)为到达当前节点的路径长度。Breadth-First Search(BFS)也是它的一个特例,其中f(n)=h(n),h(n)为距离目标节点的深度。Best-First Search可视为多种估价函数的组合搜索。

 

  1. 2.     Beam Search

这个算法其实是Best-First Search的一个变体而已,由于Best-First Search算法中,每个节点的所有未曾出现过的后继节点都要被放入OPEN list中,随着深度的增加,空间开销势必会呈指数级膨胀。为了减少空间的开销,Beam Search限制了OPEN List的大小,它只保存好一些质量比较好的节点(f(n)值比较低的),而抛弃那些f(n)值较高的不太可能会是最佳方案的节点。这样做虽然大大提高了空间效率,但势必会有潜在的最佳方案由于当前f(n)值不理想而被丢弃了。所以说Beam Search算法是不完全的(Best-First Search是complete的),一般适用于大规模并且空间不充足的系统中。

 

  1. 3.     A* SearchA-star Search

A*算法是对Best-First Search的改良,Best-First Search虽然是完全的,但势必不是最优的。我们可以这样想,Best-First算法中,每次扩展出的后继节点只要不在CLOSED List中(也就是未被访问过),就不管三七二十一的就加到OPEN List中去了,这样势必会造成OPEN List上的冗余,可能会有两个完全相同的节点,也可能节点状态相同但f(n)值不同,这样出堆时就会出现重复访问。A*对此改良的思想如下

(1)将初始节点插入OPEN List中

 当OPEN List非空时

(2)从OPEN List出堆,放入CLOSED List中,如果该节点即为目标节点则算法结束(backtracking路径)

(3)扩展该节点的所有后继节点

     对每一个后继节点

         if后继节点在CLOSED List中,则抛弃它,continue

         else if后继节点在OPEN List中

               if后继节点的g(n)值比出现在OPEN List上的那个节点的g(n)值好

                 则用后继节点替换掉原来出现在OPEN List上的那个节点

         else

           把后继节点加到OPEN List中

 

同样,每次加新节点或者替换节点的时候,都要把parent指针指向它的父节点。

注:后继节点出现在OPEN List中时,也可以比较它们的f(n)值,因为节点状态相同,它们的h(n)值肯定是一样的。

 

只要空间允许,A*算法肯定是完全的,但它是否一定的最优的呢?

这取决于它是否采用了admissible heuristic(也就是它的可容性)

admissible heuristic的定义如下(摘自Wikipedia)

In computer science, a heuristic function is said to be admissible if it is no more than the lowest-cost path to the goal. In other words, a heuristic is admissible if it never overestimates the cost of reaching the goal. An admissible heuristic is also known as an optimistic heuristic.

也就是说它的h(n)(估计的从当前节点到达目标节点的cost)<= C(n)(实际的……)

这就要求heuristic函数是单调的,随着n的增大(即路径的延伸),h(n)(剩下的路径)是单调递减的,g(n)(已走的路径)是单调递增的,而整体上f(n)也是单调递增的。

这个看起来很好想象理解,但不知道如何证明(困惑中。。。。。。)

 

要让单调性也同样推出可容性,还要求任何目标节点的h(n)=0.

这个倒很好证明

对于任意两个相邻节点X和Y,h(x)<=d(x, y)+h(y)   d(x, y)为从X到Y的cost

这样,L(x)+h(x)<=L(x)+d(x, y)+h(y)=L(y)+h(y)   L(x)为到达X的路径长度

由此,对于从初始节点s到目标节点g的一条最短路径P=(s, v1, v2, …, vn, g)

h(s)<=d(s, v1)+h(v1)<=d(s, v1)+d(v1, v2)+h(v2)<=……<=L(P)+h(g)=L(P)

所以h(g)=0

 

单调性似乎是对可容性的限制,总的f(n)不能减,这有点类似于Dijkstra算法中的边权值不能为负的限制。

Dijkstra算法可以视为Best-First Search的一个例子,也可视为A* Search的一个特例,其中对于任何n,h(n)=0。

 

可以说,A*算法是采用相同估价函数情况下最优的算法,both admissible and optimal,所以它也是Informed Search中最为重要的算法。

 

  1. 4.     Iterative-Deepening A* IDA*

A*的变体,又结合了IDS(Iterative Deepening Search)的特性。不同的是,IDA*采用了某f(n)的值(而不是depth)作为limit。在一次搜索中,当发现某个节点的f(n)值超过了限制的值,方法就返回(可能没找到目标节点就backtracking)。所以为了尽可能找到目标节点,f(n)的限制值得增量(初始值和增量大小得具体考究),迭代进行A* Search(每次A*退出的条件为:f(n)值超过限制值;或已找到目标节点;或OPEN List已为空)。

 

但我真不知道IDA*有什么用处,论完全性,它显然是不完全的,论效率,它显然不如直接A* Search。因为它每一次迭代都要从初始节点开始延伸,多次迭代造成了很多节点重复访问。由于A*中本身就采用了优先队列,OPEN List每次都会选择f(n)值最小的节点出堆,所以我觉得不必去限制f(n)而进行迭代,A*完全有能力高效的找到目标节点。(仅代表个人意见)

 

  1. 5.     Simplified Memory-Bounded A* SMA*

也是A*的变体,思想同Beam Search。SMA*限制了OPEN List的大小,当OPEN List将满时,它会抛弃那些f(n)值最大(离最佳方案希望最渺茫)的节点。同样,SMA*是不完全的,潜在的最佳方案可能中途就被抛弃了。

 

  1. 6.     D*Dynamic A*

原始的D*是一种uninformed incremental search算法,后来演变成Focused D*,一种informed incremental heuristic search算法。Focused D*结合了A*的思想和原始的D*。这种算法还是蛮有用的,因为A*虽然被证明是采用相同估价函数情况下最优的算法,但现实中情况是多变的,当A*算法进行中时,需求(目标节点)或者约束(或g(n)值或h(n)值)变了,显然A*算法就存在缺陷了。所以说D*就是一种Dynamic A*,它根据最新的情况,对之前的A*进行动态调整,以寻求最佳方案。

 

同A*一样,D*也采用了OPEN List和CLOSED List,但不同的是,A*是从初始节点向目标节点延伸,而D*是从目标节点向初始节点延伸(所以它必须知道目标节点在哪)。每次扩展后继节点时parent指针都指向父节点,所以当扩展出的节点即为初始节点时,算法结束,只需沿着初始节点的parent指针可一路正向输出最佳路径。

 

算法过程如下

当在搜索过程中,沿着最初计算出的路径前进时,发现了途中的障碍(即表示cost即将增大),那么把所有受那个障碍直接影响的后继节点重新放到OPEN List中去,并且节点标记为RAISE(表示cost增大了/ f(n)增大了 ),然后继续扩展那些节点的后继节点,如果cost不能降低,依旧把后继节点标记为RAISE并放到OPEN List中去。如此下去,就形成了RAISE的一个波浪,不断向前推进。而当某个标记为RAISE的节点被计算出能降低cost,那么将它的parent指针更新后,它的后继节点就标记为LOWER放到OPEN List中去,此后就形成了LOWER的波浪。这样的RAISE 和LOWER波浪就是D*算法的核心。当然,不受先前障碍直接或间接影响的节点当然也不会受到RAISE或LOWER波浪的波及。

 

D*的过程真的就像机器人探路一样了,它知道要去哪里,但它可见的路面信息是有限的,得根据实际的路面信息实时地重新计算最佳路径。

 

比起这样的D*,有一种更简单并更有效的实现方法,叫做D* Lite算法,它基于一种叫Lifelong Planning A*(LPA*)的思想。D* Lite貌似很神秘,本身这个算法也是近几年才提出来的,而且据说美国的“勇气号”和“机遇号”就采用了这种搜索算法。可想而知,D* Lite是多么的强大(我没有找到比较详细的资料)。

 

  1. 7.     A*算法在Bidirectional Search中的应用

在上一篇中我们提到了Bidirectional Search,我们说若首末两端只采用BFS搜索,两条路径往往是不会碰头的。因为现实情况往往复杂,所以采用A*更为有效。

 

 

思想如下

因为两端都是A* Search,所以需要的list数量当然是两倍

Start端:OPEN List S,CLOSED List SC

Goal端:OPEN List G,CLOSED List GC

(1)将初始节点放入S中,目标节点放入G中

(2)当S和G都不为空时

(3)if  S不为空

        从S中出堆一个,记为x,放入SC中

如果x就是目标节点或者它在G中,则算法成功结束

否则对于x的每一个后继节点x’

     如果x’ 不在SC中,则插入S中

(4)if  G不为空

        从G中出堆一个,记为x’,放入GC中

             如果x’ 就是初始节点或者它在S中,则算法成功结束

             否则对于x’ 的每一个后继节点x

                 如果x不在GC中,则插入G中

(5)重复(2)

(6)算法没有找到满足的路径而结束

 

注意,每个节点插入OPEN List前都要用parent指针记住父节点,当算法成功结束时,通过最后一个节点和它在另一个OPEN List上对应状态的节点,可以把两条路径拼为一条完整路径。

 

  1. 8.     TabuTaboo Search

A*算法是完全的,因为它把每一个后继节点都插入OPEN List中去了,并且每次插入都会调整为最小堆。但有些时候当情况比较简单(简单不是指状态空间个数少,而是状态空间整体上有规律可循)的话,按照A*的流程做产生大量调整堆的cost,我们有一种更为efficient的方法来处理这种简单的情况,这就是Tabu Search。

可以说Tabu Search是一种非常简单并很容易实现的算法。

只需要一个TABU List来记录已经访问过的节点(类似A*中的CLOSED List,是普通的队列)

还要有一个best指针,用来保存当前找到的质量最好的节点(最有可能产生最佳方案的节点)

算法如下

(1)将初始状态(或任意状态)放入TABU List中,best指向初始节点

(2)扩展best节点的所有后继节点,并只将不曾在TABU List上出现过的质量最好的后继节点放入TABU List上

(3)如果该后继节点比best节点质量好(f(n)值更小),则更新best指针

(4)重复(2),直到termination条件满足

同样,每个后继节点都有指向父节点的指针。

 

从上述过程很好发现,Tabu Search既节省了空间,又节省了时间。它遵循greedy思想,每次都沿着质量最好的节点延伸。比如像下图这种有规律的状态空间

 

 

 

 

 

 

Tabu Search每次都沿着最好的节点,很快就能找到最佳方案(就是到达顶峰的路径)。

 

但需注意的是,Tabu Search是属于local search范畴的,它潜在的问题是,有时该算法会陷入local optimum,而找不到global optimum,就比如下面这种状态空间

 

 

 

Tabu Search可能只找到较低的那个峰的路径,较高的那个峰的路径可能中途就被抛弃了。

 

这个过程其实就类似爬山,目标是登上最高峰,方法是从山脚下平坦的某一处,每次都选择高度上升量最大的邻接节点。这样,很可能通向最高峰的路径由于一开始坡度不大,而早早的就被抛弃了。

 

  1. 9.     Hill Climbing Search

接上述,针对与爬山类似的问题,我们又有两种算法,分别叫Hill Climbing和Gradient descent,区别是Gradient descent每次前进的步伐与坡度成正比。

 

这两种算法同样存在local optimum的问题,但可以通过改进算减轻这个问题。比如允许选择质量不是最好的邻接节点,或者随机选择邻接节点(Stochastic hill climbing),或者每隔一段时间就从初始节点重新再选一遍(Random-restart hill climbing)。

 

还存在的一个缺陷是,当状态空间的分布如同高原或者平原时,这些算法就都很难选择最好的邻接节点,可能造成选来选去路径一直在同一块区域徘徊。

 

 

  1. 10.  Simulated Annealing

在上面Hill Climbing Search的改进方法里面,我们提到了Stochastic hill climbing,就是随机选择邻接节点。我们现在要介绍的Simulated Annealing算法真的就是一个随机算法,当然随机肯定不可能是瞎随机的,也得有一定的策略的。

算法如同它的名字一样,是模仿炼铁,要使最后的成品铁质量高,那么降温的时候必然不能一下子冷冻(这样铁内部会产生很多气泡和裂纹),它需要逐渐慢慢的降温。

 

先解释一下Energy的概念,每个节点都有它当前的Energy(类似我们之前一直提到的f(n)吧,具体问题中也可以用它路径的cost表示),由于我们的目标是让它冷却,所以Energy越低代表它质量越好。这里我们需要用到随机数,还有一个概率公式

 

ΔE表示Energy的改变量,T表示当前的Temperature

 

算法流程如下

(1)初始化好Temperature

     用current指针代表当前节点,adjacent指针代表邻接节点

(2)随机选择初始节点,current=初始节点,并计算current的Energy

while(Temperature >0 )

(3)adjacent=随机选择current的一个邻接节点    (也通过随机数来选择)

(4)计算adjacent的Energy

(5)ΔE=adjacent->energy – current->energy

(6)if(ΔE<0)  //说明能量降低了,质量提高了

         current=adjacent

     else

         p=exp(-ΔE/Temperature)

         if ( p > random(0, 1) )  //跟0~1之间产生的随机数比较

             current=adjacent

(7)降低Temperature(可采用Temperature=α* Temperature,α为常系数)

 

可见上述算法中多处采用随机方法,通过循环来削弱随机带来的不良影响。如果随机方法选择的好,包括p的概率公式,选择邻接节点的随机数,温度降低的规律,这些选择得当的话,该算法能大大提高找到global optimum的概率。(具体如何选择是值得根据具体问题考究的)

 

正如Simulated Annealing是一个随机算法,所以最好是循环次数很多,因为最初一段时间的循环中邻接节点的替换是很不稳定的,因为Temperature较高,p较大,能量高的点替换能量低的点的概率也大。

如下图,左边是温度变化曲线,右图是current节点能量变化曲线,可知随着温度的迭代次数的增加,能量变化最后会趋于稳定,即最佳方案。

 

 

由图可以想象出,为了让Simulated Annealing也能找到global optimum,这代价势必会高于完全遍历一遍所有的节点。

 

关于Simulated Annealing应用的例子,引自Wikipedia

 

 

                                         

 

Example illustrating the effect of cooling schedule on the performance of simulated annealing. The problem is to rearrange the pixels of an image so as to minimize a certain potential energy function, which causes similar colours to attract at short range and repel at a slightly larger distance. The elementary moves swap two adjacent pixels. These images were obtained with a fast cooling schedule (left) and a slow cooling schedule (right), producing results similar to amorphous and crystalline solids, respectively.

 

posted @ 2012-08-27 10:29  另Ⅰ中Feel▂  阅读(1481)  评论(0编辑  收藏  举报