zoukankan      html  css  js  c++  java
  • Learn Prolog Now 翻译

    证明搜索

     上一节我们已经学习了合一,本节我们继续学习Prolog是如何通过搜索知识库去决定输入的查询是否能够满足。我们将会学习证明搜索,并通过简单的一个例子去涵盖这个基础的概念。

     假设我们有如下的知识库:

    f(a).
    f(b).
    
    g(a).
    g(b).
     
    h(b).
    
    k(X) :- f(X), g(X), h(X).

     如果我们查询:

     ?- k(Y).

     这个查询的结果十分明显,即k(b),但是Prolog是如何将其求解出的了?让我们继续看。

     Prolog读入整个知识库,然后尝试将查询k(Y)和知识库中的事实或者规则头部进行合一。搜索知识库是自上而下的,并在第一个可能合一的位置,找到对应的信息。这个例子只是有一种

    可能:k(Y)和规则,k(X) :- f(X), g(X), h(X) 的头部合一。

     当Prolog将查询中的变量和事实或者规则中的变量合一时,会生成一个新的变量(比如_G34)去代表共享值,所以原始的查询转换为:

     k(_G34)

     并且Prolog知识库中的规则转换为:

     k(_G34) :- f(_G34), g(_G34), h(_G34).

     现在是什么情况了?查询说:“我想要找到符合属性k的人”。规则说:“如果要找到符合属性k的人,那么这个人也必须符合属性f,g和h”。所以如果Prolog找到符合属性k,g和h的信

    息,那么就能满足原始的查询。所以Prolog使用下面的目标去替代原始查询:

     f(_G34), g(_G34), h(_G34).

     如果使用图形演示,会使得这个过程更加形象,如下:

     

     在盒子中的都是查询或者目标。具体地讲,我们的原始目标是证明k(Y),所以它出现在最顶层的盒子中。当我们将k(Y)和数据库中的规则头部合一时,_G34作为分享值的新中间变量,

    被赋值给X,Y,所以我们有了新的目标:f(_G34), g(_G34), h(_G34),出现在第二个盒子中。

     现在,无论是否存在一系列的子目标需要证明,Prolog都会通过自左向右的顺序,尝试一个一个的去满足。在最左侧的目标是f(_G34),即“想找到一个满足属性f的信息”。Prolog尝

    试搜索自上而下搜索知识库。第一个找到能够和查询合一的是事实,f(a)。这会满足目标f(_G34),并且剩余另外两个目标。现在,当我们将f(_G34)和f(a)合一,_G34会被初始化为a,

    而且这个初始化会将目标列表中所有的_G34都替换为a,所以剩余的目标列表看上去是这样的:

     g(a), h(a)

     当前的证明搜索图形如下:

     

     但是g(a)是知识库中的事实,所以剩余目标列表中的第一个目标已经满足了,所以我们还剩下:

      h(a)

     证明搜索的图形如下:

     

     但是无法再证明h(a),最后一个目标。因为关于属性h,我们通过知识库能够知道的唯一事实是,h(b),它无法和目标h(a)合一。

     

     所以,接下来会发生什么?Prolog会承认犯了错误,并且检查是否在对目标进行合一时,有其他可能的值。通过上面图形展示的路径,Prolog会回到可以有合一替代的节点。

    现在,在知识库中没有其他可以和g(a)合一的选择了,但是存在其他与f(_G34)合一的方式。存在多种合一可能的节点被称为选择节点。Prolog会保持对选择节点的追踪,所以

    当它发现一种选择是错误的时候,能够回到选择节点并且尝试其他的路径。这个过程被称为回溯,它是Prolog证明搜索的基础。

     那么继续我们的例子,Prolog回溯到选择节点。这个节点在上面图形中是下面的目标列表:

     f(_G34), g(_G34), h(_G34).

     Prolog必须重新开始工作,他必须尝试重新满足第一个目标。在知识库中,通过将事实f(b)和f(_G34)合一,可以满足目标。这个合一会将_G34初始化为b,所以剩余的目标列

    表是:

     g(b), h(b).

     g(b)也是知识库中事实,也能够被满足,所以剩余:

     h(b).

     而且,这个也是知识库中的事实,所以这个目标也满足了。现在Prolog的目标列表已经为空。这意味着原始查询所需要的每一个目的都满足了,所以原始查询是能够成功的,并且,

    Prolog也发现了为了达成目标而并且进行的初始化,即将变量Y初始化为b。

     

     考虑当我们输入“;”查询是否有其他解决方案也很有趣:

     这会强制Prolog进行回溯,去搜索是否有其他可能。但是上面的例子没有其他解决方案了,因为知识库中没有其他可能再去将h(b),g(b),f(_G34)或者k(Y)进行合一,所以Prolog

    会回答false。另一方面,如果存在另外包含了k的规则,Prolog会按照我们之前描述的方式继续尝试,即在知识库中自上而下的搜索,从左自右地满足目标列表,如果有失败就回溯到

    选择节点。

     让我们看看整体的搜索过程,如下图:

     

     这个图形是树的形式,事实上,这是我们第一个关于搜索树的例子。这种树的非叶子节点是为了满足证明搜索不同步骤的当前目标列表,树的边保存了为了满足当前目标而对知识库

    中的事实或者规则进行合一的变量初始化信息(注意,当前目标是指目标列表的第一个即最左边的目标),叶子如果还包含没有被满足的目标,那么就是Prolog失败的点(错误的路径,

    没有解决方案存在);叶子如果不包含任何的目标,就是一种可能的解决方案。从根节点到成功的叶子节点的路径,会给出为了满足原始目标而必须进行的变量初始化的值的全部信息。

     接下来我们看另外一个例子,假设我们有如下的知识库:

    loves(vincent, mia).
    loves(marcellus, mia).
    
    jealous(A, B) :- loves(A, C), loves(B, C).

     如果我们查询:

     ?- jealous(X, Y).

     对应的搜索树如下:

     

     在知识库中只有一种针对jealous(X, Y)的合一方式,即使用如下的规则:

     jealous(A, B) :- loves(A, C), loves(B, C).

     所以我们的目标列表变成了如下:

     loves(_G5, _G6), loves(_G7, _G6).

     现在,我们需要在知识库中针对loves(_G5, _G6)进行合一。有两种方式可以做到(事实1和事实2),所以这也是一个选择节点。这两种情况,都是导致目标列表剩余loves(_G7, mia),

    这个目标也可以通过知识库中的两个事实满足。最后所有的叶子节点都没有不能满足的目标,所以意味着一种有四种满足原始查询的解决方案。通过路径上的变量初始化信息,可以得出

    如下的四种解决方案:

     1. X = _G5 = vincent; Y = _G7 = vincent

     2. X = _G5 = vincent; Y = _G7 = marcellus

     3. X = _G5 = marcellus; Y = _G7 = marcellus

     4, X = _G5 = marcellus; Y = _G7 = vincent

     请仔细分析上面的例子,并确保能够完全理解。

  • 相关阅读:
    python 学习笔记 数值型(1)
    python 学习笔记 标识符和变量(3)
    python 学习笔记 字符串(2)
    jsp+servlet+javaBean+Dao
    面试被问到岗时间,是越快越好吗?
    有赞多平台推广接入与测试
    HTTPS 加密、证书、签名与握手
    开发到底要不要自己做测试?
    我也曾找不到工作
    世界第三大浏览器正在消亡
  • 原文地址:https://www.cnblogs.com/seaman-h-zhang/p/4615097.html
Copyright © 2011-2022 走看看