人工智能实验指导书.docx

上传人:b****7 文档编号:9077862 上传时间:2023-02-03 格式:DOCX 页数:34 大小:34.14KB
下载 相关 举报
人工智能实验指导书.docx_第1页
第1页 / 共34页
人工智能实验指导书.docx_第2页
第2页 / 共34页
人工智能实验指导书.docx_第3页
第3页 / 共34页
人工智能实验指导书.docx_第4页
第4页 / 共34页
人工智能实验指导书.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

人工智能实验指导书.docx

《人工智能实验指导书.docx》由会员分享,可在线阅读,更多相关《人工智能实验指导书.docx(34页珍藏版)》请在冰豆网上搜索。

人工智能实验指导书.docx

人工智能实验指导书

 

人工智能实验指导书

软件工程教研室

 

辽宁工业大学

2008年9月

目录

实验一Prolog初识1

实验二数据结构与列表4

实验三经典问题举例12

实验四专家系统16

实验五五子棋游戏22

 

实验一Prolog初识

一、实验目的

1、熟悉AmziProlog运行环境;

2、掌握PROLOG语言中常量、变量的表示方法;

3、掌握利用PROLOG进行事实库、规则库的编写方法;

4、掌握利用PROLOG中的谓词assert和retract进行数据管理。

二、相关知识

1、Prolog简介

Prolog在英语中的意思就是ProgramminginLogic(逻辑编程)。

它是建立在逻辑学的理论基础之上的,最初是运用于自然语言的研究领域。

然而现在它被广泛的应用在人工智能的研究中,它可以用来建造专家系统、自然语言理解、智能知识库等。

同时它对一些通常的应用程序的编写也很有帮助。

使用它能够比其他的语言更快速地开发程序,因为它的编程方法更象是使用逻辑的语言来描述程序。

本门课程实验程序将在AmziProlog上实现。

2、AmziProlog的使用

1)在桌面上为AmziProlog建一快捷方式,执行文件为d:

\AmziProlog\bin\wideW.exe。

2)在d盘建一prologxx(xx为学号后两位)文件夹,用以保存同学们自己的程序。

3)编辑AmziProlog程序:

执行桌面上AmziProlog快捷方式,在AmziProlog集成环境中新建(或打开)一Prolog程序,并保存到d:

\prologxx文件夹中。

4)运行程序:

选择菜单项Listener—Start(打开“解释器”),之后选择菜单Listener—Consult,在打开窗口中打开保存过的文件,然后就可以在“解释器”的“?

-”提示符后输入要查询的问题了。

5)如需修改程序,应先关闭“解释器”,修改完程序并保存后,再执行4)步进入。

三、实验内容及步骤

新建一文件:

like.pro,保存至d:

\prologxx

在该文件中建立如下事实数据库:

like(ellen,tennis).

like(john,football).

like(tom,baseball).

like(eric,swimming).

like(mark,tennis).

like(tom,tennis).

注:

谓词名(如:

like)和常量(如:

mark)用小写字母,每条语句以点‘.’结束。

请进入解释器询问吧。

查询1:

?

-like(mark,tennis).{查询的目标(goal)}

yes.{有某个事实与目标匹配,查询成功,回显'yes.'}

查询2:

?

-like(mark,football).

no.{没有与目标匹配的事实,查询失败,回显'no.'}

查询3:

?

-like(X,tennis).{X为变量(大写),匹配中X与ellen被绑定}

X=ellen{按回车键}

yes.{表示还有答案}

如果用户输入分号(;),Prolog就开始寻找其他的答案。

首先它必须释放(unbinds)变量X。

然后从上一次成功的位置的下一条子句开始继续搜索。

这个过程叫做回溯(backtracking)。

?

-like(X,tennis).

X=ellen;

X=mark;

X=tom;

no{表示没有答案了}

查询4:

?

-like(X,tennis),!

.

X=ellen;

no

截断谓词cut,prolog内部谓词,使用符号!

来表示。

cut能够有效地抑制其左边的子目标与其父目标的回溯,而它右边的目标则不受影响,如下面查询:

?

-like(X,tennis),!

like(tom,Y),

查询5:

让我们来控制一下输出吧,退出解释器,在数据库中加入如下规则,并保存。

do:

-like(X,tennis),write(X),tab

(2),write('liketennis.').

重新进入解释器。

?

-do.

ellenliketennis.

yes

注:

:

-即为←。

谓词之间的逗号表示‘与’的关系。

write()为Prolog实现输出内部谓词,每次输出一项内容。

tab

(2)Prolog内部谓词,实现输出两个空格。

查询6:

让我们调用debug来观察一下查询的过程。

?

-debug.

?

?

-do.{进入debug窗口,用creep逐步追踪}

注:

Prolog的目标有四个端口用来控制运行的流程,每个端口的功能如下:

call(调用)开始使用目标搜寻子句。

exit(退出)目标匹配成功,在成功的子句上作记号,并绑定变量。

redo(重试)试图重新满足目标,首先释放变量,并从上次的记号开始搜索。

fail(失败)表示再找不到更多的满足目标的子句了。

查询7:

前面这个查询只输出一个查询结果,让我们再来修改一下刚加入的规则do。

其中nl表示换行,fail强制回溯,直到失败为止。

do:

-like(X,tennis),write(X),tab

(2),write('liketennis.'),nl,.fail.

 

?

-do.

ellenliketennis

markliketennis

tomliketennis

no

?

-debug.{再debug看看吧}

?

?

-do.

查询8:

动态数据库管理。

?

-listing(like).{listing(谓词名)列出所有该名谓词}

?

-assert((like(ellen,football)).{assert或assertz在所有like谓词后动态加入新谓词}

?

-listing(like).

?

-asserta((like(ellen,swimming)).{在所有like谓词前动态加入新谓词}

?

-listing(like).

?

-retract(like(ellen,football)).{删除动态加入的新谓词}

?

-listing(like).

注:

assert只动态地将谓词加入到内存数据库中,并未加入到为件中

四、思考题

1、试分析Prolog的推理方式(正向/逆向)。

2、试分析Prolog推理时,目标与子句的匹配顺序。

实验二数据结构与列表

一、实验目的

1.了解PROLOG中数据结构和列表的设计与使用。

2.了解PROLOG中利用列表实现递归方法。

二、实验内容及步骤

1、数据结构

除了前面实验用到的事实、查询以及规则中的简单的数据结构外,Prolog还可以通过把这些简单的数据组合起来,生成复杂的数据类型,我们称之为结构。

结构由结构名和一定数量的参数组成,结构的参数可以是简单的数据类型或者是另一个结构。

如:

结构名(参数1,参数2,...)

例如,下面的结构描述了物品的颜色、大小以及数量。

object(apple,red,small,1).

我们可以把结构用作谓词的参数,我们定义一个谓词locat:

******************struct.pro*********************

locat(object(apple,red,small,1),kitchen).

locat(object(cabbage,green,small,1),kitchen).

locat(object(radish,red,small,1),kitchen).

locat(object(table,blue,big,1),kitchen).

locat(object(chair,blue,small,6),kitchen).

locat(object(computer,while,small,2),office).

locat(object(book,various,small,many),office).

对于这段描述我们可以进行如下询问:

?

-locat(X,kitchen).

X=object(apple,red,small,1);

X=object(cabbage,green,small,1);

X=object(radish,red,small,1);

X=object(table,blue,big,1);

X=object(chair,blue,small,6);

no

Prolog变量是没有数据类型之分的,所以它可以很容易的绑定为结构,如同它绑定为原

子一样。

事实上,原子就是没有参数的最简单的结构。

我们还可以让变量绑定为结构中的某些参数,如下面的询问可以找出厨房中所有红色的东西。

?

-locat(object(X,red,S,W),kitchen).

X=apple

S=small

W=1;

X=radish

S=small

W=1;

no

如果不关心大小和数量,可以使用下面的询问,其中变量‘_’是匿名变量。

?

-locat(object(X,red,_,_),kitchen).

X=apple;

X=radish;

no

让我们添加如下谓词,使得只有在物品所在的房间且物品较轻的才能被拿起。

here(kitchen).

cantake(Thing):

-

here(Room),

locat(object(Thing,_,small,_),Room).

看一看如下查询的结果吧。

?

-cantake(apple).

?

-cantake(table).

?

-cantake(book).

同时,也可以把不能拿取某物品的原因说得更详细一些,例如添加如下规则:

cantake(Thing):

-

here(Room),

locat(object(Thing,_,big,_),Room),

write('The'),write(Thing),

write('istoobigtocarry.'),nl,fail.

cantake(Thing):

-

here(Room),

not(locat(object(Thing,_,_,_),Room)),

write('Thereisno'),write(Thing),write('here.'),nl,fail.

下面来试试功能。

?

-cantake(table).

?

-cantake(book).

?

-cantakes(desk).

结构可以任意的嵌套,例如:

locat(object(desk,color(brown),size(large),amount

(1)),office).

下面是针对它的一条查询。

?

-locat(object(X,_,size(large),_),office).

2.列表

为了能够更好地表达一组数据,简化程序,Prolog引入了列表这种数据结构。

列表是一组项目的集合,此项目可以是Prolog的任何数据类型,包括结构和列表。

列表的元素由方括号括起来,

项目中间使用逗号分隔。

例如下面的列表列出了厨房中的物品。

[apple,cabbage,radish,table]

我们可以使用列表来代替多个子句。

例如:

locate(apple,kitchen).

locate(cabbage,kitchen).

locate(radish,kitchen).

locate(table,kitchen).

可表示成:

****************list1.pro****************

loclist([apple,cabbage,radish,table],kitchen).

当某个列表中没有项目时我们称之为空表,使用“[]”表示。

也可以使用nil来表示。

下面

的句子表示hall中没有东西。

loclist([],hall)

变量也可以与列表联合,就像它与其他的数据结构联合一样。

假如数据库中有了上面的子句

,就可以进行如下的询问。

?

-loclist(X,kitchen).

X=[[apple,cabbage,radish,table]

?

-[_,X,_]=[apples,cabbage,radish].

X=cabbage

Prolog提供了两个特性,可以方便的实现对列表元素的访问。

首先,Prolog提供了把表头项目与列表剩下部分分离的方法。

其次,Prolog强大的递归功能可以方便地访问除去表头项目后的列表。

首先,列表的一般形式为:

[X|Y]

使用此列表可以与任意的列表匹配,匹配成功后,X绑定为列表的第一个项目的值,我们称之为表头(head)。

而Y则绑定为剩下的列表,我们称之为表尾(tail)。

下面我们看几个把表头项目与列表剩下部分分离例子:

?

-[a|[b,c,d]]=[a,b,c,d].{等号两边的列表是等价的}

yes

?

-[a|b,c,d]=[a,b,c,d].{在“|”之后只能是一个列表,而不能是多个项目。

}

no

注意:

表尾一定是列表,而表头则是一个项目,即可以是表,也可以是其他的任何数据结构。

下面是其它的一些列表的例子。

?

-[H|T]=[apple,cabbage,radish,table].

H=apple

T=[cabbage,radish,table]

?

-[H|T]=[a,b,c,d,e].

H=a

T=[b,c,d,e]

?

-[H|T]=[a,b].

H=a

T=[b]

?

-[H|T]=[a,[b,c,d]].{这个例子中的第一层列表有两个项目a和[b,c,d]。

}

H=a

T=[[b,c,d]]

?

-[H|T]=[a].{列表中只有一个项目的情况}

H=a

T=[]

?

-[H|T]=[].{空表不能与[H|T]匹配,因为它没有表头。

}

no

注意:

最后这个匹配失败非常重要,在递归过程中经常使用它作为边界检测。

即只要表不

为空,那么它就能与[X|Y]匹配,当表为空时,就不能匹配,表示已经到达边界条件。

我们还可以在第二个项目后面使用“|”,事实上,“|”前面的都是项目,后面的是一个表。

?

-[One,Two|T]=[a,b,c,d].

One=a

Two=b

T=[c,d]

表可以看作是表头项目与表尾列表组合而成。

而表尾列表又是由同样的方式组成的。

所以

表的定义本质上是递归定义。

我们来看看下面的例子。

?

-[a|[b|[c|[d|[]]]]]=[a,b,c,d].

Yes

?

-X=[a,b,c,d],write(X),nl,display(X),nl.{内部谓词display以递归的方式显示列表}

[a,b,c,d]

.(a,.(b,.(c,.d(,[]))))

?

-X=[a,b,[c,d],e],write(X),nl,display(X),nl.

[a,b,[c,d],e]

.(a,.(b,.(.(c,.(d,[])),.(e,[]))))

3.用递归处理列表

首先我们来编写谓词member,它能够判断某个项目是否在列表中。

***************List2.pro****************

member(H,[H|T]).

member(X,[H|T]):

-member(X,T).

第一个子句是递归的边界条件,即如果H表示的项目是列表的表头则匹配成功,递归过程结束。

第二个子句表示:

如果X表示的项目不是列表的表头,则让X与列表的的表尾匹配。

把上面的两个子句放入一prolog文件中,让我们来询问一下吧。

?

-member(apple,[apple,cabbage,radish]).

yes

?

-member(cabbage,[apple,cabbage,radish]).

yes

?

-member(banana,[apple,cabbage,radish]).

no

?

-debug.{请观察一下单步运行的结果吧}

?

?

-member(b,[a,b,c]).

如果询问的第一参数是变量,member/2可以把列表中所有的项目找出来。

?

-member(X,[apple,broccoli,crackers]).

X=apple;

X=broccoli;

X=crackers;

No

打印表中元素的例子:

****************list3.pro***************

write_a_list([]).

write_a_list([H|T]):

-write(H),nl,write_a_list(T).

?

-write_a_list([1,2,3]).

我们再来编写能够把两个列表连接成一个列表的谓词append/3。

**************list4.pro***************

append([],X,X).

append([H|L1],L2,[H|L3]):

-append(L1,L2,L3).

?

-append([a,b,c],[d,e,f],New).{第一个参数和第二个参数连接的表为第三个参数}

New=[a,b,c,d,e,f]

和member/2一样,append/3还有别的使用方法。

下面这个例子显示了append/3是如何把一

个表分解的。

?

-append(X,Y,[a,b,c]).

X=[]

Y=[a,b,c];

X=[a]

Y=[b,c];

X=[a,b]

Y=[c];

X=[a,b,c]

Y=[];

no

3.使用列表

现在有了能够处理列表的谓词,我们可以完成一个小游戏。

在厨房、书房等处分别有一些物品,并可以向这些地方添加物品。

******************list5.pro**********************

loclist([apple,cabbage,radish,table],kitchen).

loclist([desk,computer,book],office).

loclist([flashlight,envelope],desk).

loclist([stamp,key],envelope).

loclist(['washingmachine'],cellar).

loclist([nani],'washingmachine').

member(H,[H|T]).

member(X,[H|T]):

-member(X,T).

location(X,Y):

-loclist(List,Y),member(X,List).{判断X物品是否在Y中}

append([],X,X).

append([H|L1],L2,[H|L3]):

-append(L1,L2,L3).

add_thing(New,Container,NewList):

-

loclist(OldList,Container),

append([New],OldList,NewList).{向Container中添加新物品New,形成新列表NewList}

put_thing(Thing,Place):

-

retract(loclist(OldList,Place)),

asserta(loclist([Thing|List],Place)).{动态修改数据库}

我们可以进行询问了。

?

-add_thing(plum,kitchen,X).

X=[plum,apple,broccoli,crackers]

当然,也可以直接使用[Head|Tail]这种列表结构来编写add_thing/3。

add_thing2(NewThing,Container,NewList):

-

loc_list(OldList,Container),

NewList=[NewThing|OldList].

它和前面的add_thing/3功能相同。

?

-add_thing2(plum,kitchen,X).

X=[plum,apple,broccoli,crackers]

我们还可以对add_thing2/3进行简化,不是用显式的联合,而改为在子句头部的隐式联合。

add_thing3(NewTh,Container,[NewTh|OldList]):

-

loclist(OldList,Container).

它同样能完成我们的任务。

?

-add_thing3(plum,kitchen,X).

X=[plum,apple,broccoli,crackers]

下面的put_thing/2,能够直接修改动态数据库,请自己研究一下。

三、思考题

1、Prolog变量是否有数据类型之分。

2、Prolog中的变量和常量是如何区分的。

 

实验三经典问题举例

一、实验目的

1、理解PROLOG编制递归程序的方法:

边界条件与递归部分的设计;

2、加深理解人工智能中通过搜索解决问题的方法;

3、熟悉分析、运用递归方法解决问题。

二、实验内容及步骤

(一)Hanoi塔问题:

如上图,目的是把左边的所有盘子移到右边的杆子上。

一次只能移动一个盘子,可以使用中间的杆子作为临时存放盘子的地方。

在移动的过程中,小盘子必须放在大盘子之上。

分析:

用递归来解决这个问题。

如果只有一个盘子,直接移过去就行了,这是递归的边界条件。

如果要移动N个盘子,就要分三步走:

1、把N-1个盘子移动到中间的杆子上(把右边的杆子作为临时存放盘子的位置)

2、把最后一个盘子直接移到右边的杆子上。

3、最后把中间杆子上的盘子移到右边的杆子上(把左边的杆子作为临时存放盘子的位置)。

上面第一、三步用到了递归。

我们看到,通过递归把N个盘子的问题变成了两个N-1个盘子的问题。

如此下去,最后就变成了2个一个盘子的问题了,这也就是说问题被解决了。

1)Hanoi塔的Prolog代码:

hanoi(N):

-move(N,left,middle,right).

move(1,A,_,C):

-inform(A,C),!

.{!

为cut操作,截断进一步搜索}

move(N,A,B,C):

-N1isN-1,

move(N1,A,C,B),inform(A,C),

move(N1,B,A,C).

inform(Lo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 动态背景

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1