人工智能实验报告 华北电力大学 刘丽Word格式.docx
《人工智能实验报告 华北电力大学 刘丽Word格式.docx》由会员分享,可在线阅读,更多相关《人工智能实验报告 华北电力大学 刘丽Word格式.docx(10页珍藏版)》请在冰豆网上搜索。
七、所附实验输出的结果或数据
设计性实验报告应含的主要内容:
一、设计要求
二、选择的方案
三、所用仪器、设备
六、结论(依据“设计要求”)
*封面左侧印痕处装订
1.熟悉PROLOG的运行环境,进行prolog的基本编程练习。
了解PROLOG语言中常量、变量的表示方法。
PROLOG的简单程序结构,掌握分析问题、询问解释技巧;
进行事实库、规则库的编写,并在此基础上进行简单的询问。
具体实验课上相关内容,练习例1到例6的内容。
2.图搜索问题求解。
任选以下实际应用题目:
爱因斯坦的超级问题、字谜问题、汉诺塔问题、八数码问题、八皇后问题、过河问题等,选两个。
要求实验报告中包括:
程序及其注释和说明、console表单中的程序运行结果。
PC机和trincprolog编译软件
PROLOG语言是一种以逻辑推理为基础的逻辑型程序设计语言,是一种陈述性语言而不是过程性语言。
PROLOG语言能够自动实现模式匹配和回溯、具备递归技术,而且语法简明,可以简化复杂问题求解。
熟悉环境Trinc-Prolog,用来编译各个逻辑新非常强的问题,从中选择汉诺塔和过河问题进行解决。
在PROLOG中,常用的结构形式有:
(1)函子(分量1,分量2,……,分量n)
(2)表:
Prolog语言中最常用的数据结构,由一些有序分量组成,长度可任意
含有3个分量a,b,c的表可写成[a,b,c],如用函数的方式可写成·
(a·
(b·
(c[])))。
其中符号“.”是表的函子
(3)表达式
PROLOG语言提供了各种运算,如算术、比较运算等
运算可以是中缀形式,简明直观,符合人们的习惯
算术表达式X+Y-Z中,“+”、“-”便是运算符,该表达式如用函数结构形式来表示就是-(+(XY)Z)
表示对象间的因果关系、蕴含关系或对应关系
格式:
head:
-body
head是谓词的定义部分,与事实一样,也包括谓词名和谓词的参数说明
:
-连接符,一般可以读作‘如果’
body一个或多个目标,与查询相同
bird(X):
-annimal(X),has(X,feather).
grandfather(X,Y):
-father(X,Z),father(Z,Y).
规则中的谓词也可以无参数:
run:
-start,step1(X),step2(X),end.
Prolog的查询工作靠模式匹配完成
查询的模板叫做目标(goal)
如果有某个事实与目标匹配,那么查询成功,解释器会回显‘yes.’
如果没有匹配的事实,查询失败,解释器回显'
no.‘
Prolog的模式匹配工作叫做联合(unification),以下三个条件是使联合成功的必要条件
目标谓词名与数据库中的某个谓词名相同
这两个谓词的参数数目相同
所有的参数也相同
在查询目标中还可以使用Prolog的变量
这种变量和其他语言中的不同,叫它逻辑变量更合适
变量可以代替目标中的一些参数
变量给联合操作带来了新的意义。
以前联合操作只有在谓词名和参数都相同时才能成功。
但是引入了变量之后,变量可以和任何的条目匹配
当联合成功之后,变量的值将和它所匹配的条目的值相同。
这叫做变量的绑定(binding)。
当带变量的目标成功的和数据库中的事实匹配之后,Prolog将返回变量绑定的值
当Prolog试图与某一个目标匹配时,例如:
location/2,它就在数据库中搜寻所有用location/2定义的子句,当找到一条与目标匹配时,它就为这条子句作上记号。
当用户需要更多的答案时,它就从那条作了记号的子句开始向下查询
我们来看一个例子:
用户询问:
location(X,kitchen).
Prolog找到数据库中的第一条location/2子句,并与目标比较
用户输入回车,Prolog开始寻找其他的答案
首先它必须释放(unbinds)变量X。
然后从上一次成功的位置的下一条子句开始继续搜索。
这个过程叫做回溯(backtracking)
在本例中就是第三条子句
子句#3location(flashlight,desk).
匹配失败,直到第六条子句时匹配又成功
Prolog的目标有四个端口用来控制运行的流程
调用(call)
退出(exit)
重试(redo)
失败(fail)
一开始使用Call端口进入目标,如果匹配成功就到了exit端口,如果失败就到了fail端口,如果用户输入回车,则又从redo端口进入目标
每个端口的功能如下:
call开始使用目标搜寻子句
exit目标匹配成功,在成功的子句上作记号,并绑定变量
redo试图重新满足目标,首先释放变量,并从上次的记号开始搜索
fail表示再找不到更多的满足目标的子句了
-?
-location(X,kitchen).
用startstep观察
程序第一次执行,与第一个事实匹配,输出,回车换行,number=1,不匹配,引起回溯
与第二个事实匹配,输出,回车换行,number=2,不匹配,引起回溯
与第三个事实匹配,输出,回车换行,number=3,匹配,最后一个语句成功,程序段结束
?
-print2.(观察结果)
表是有若干元素的有序序列,表中元素也可以为表
表最大的特点是长度不固定,在程序运行中可以动态的变化
PROLOG中采用一对方括号[]把表元素括起来,每个元素间用逗号或空格分开
谓词append是递归定义的
在Prolog中,当某个谓词的目标中包含了此谓词本身时,Prolog将进行递归调用
递归技术在表处理中特别有用,几乎所有的表处理程序都用到递归,但在一般程序中,使用递归要谨慎,或尽量不用,因为递归很容易导致堆栈溢出
到目前为止,我们都一直在使用Prolog内建的回溯功能。
使用此功能可以方便地写出结构紧凑的谓词来
并不是所有的回溯都是必须的,这时我们需要能够人工地控制回溯过程
Prolog提供了完成此功能的谓词,叫做cut,使用符号!
来表示
Cut能够有效地剔除一些多余的搜索。
如果在cut处产生回溯,它会自动地失败,而不去进行其它的选择
若将“!
”插在子句体内作为一个子目标,它总是立即成功
2.若“!
”位于子句体的最后,则它就阻止对它所在字句的头谓词的所有子句的回溯访问,而让回溯跳过该头谓词,去访问前一个子目标
3.若“!
”位于其他位置,则当其后发生回溯且回溯到“!
”处时,就在此失败,并且“!
”还使它所在子句的头谓词整个失败
cut不符合纯逻辑学,是出于实用的考虑,过多地使用cut将降低程序的易读性和易维护性。
它就像是其它语言中的goto语句
当能够确信在谓词中的某一点只有一个答案,或者没有答案时,使用cut可以提高程序的效率,另外,如果在某种情况下想让某个谓词强制失败,而不让它去寻找更多的答案时,使用cut也是个不错的选择
五、求解的问题与程序
如果要移动N个盘子,就要分三步走:
把N-1个盘子移动到中间的杆子上(把中间的杆子作为临时存放盘子的位置)
把最后一个盘子直接移到右边的杆子上
最后把中间杆子上的盘子移到右边的杆子上(把左边的杆子作为临时存放盘子的位置)
对于汉诺塔问题,实现的代码如下:
hanoi(N):
-move(N,left,middle,right).
move(1,A,_,C):
-inform(A,C),!
.
move(N,A,B,C):
-N1isN-1,move(N1,A,C,B),inform(A,C),move(N1,B,A,C).
inform(Loc1,Loc2):
-nl,
write('
Moveadiskfrom'
-Loc1-'
to'
-Loc2).
运行结果如下:
输入:
-hanoi(4).后得出
Moveadiskfrom-left-to-middle
Moveadiskfrom-left-to-right
Moveadiskfrom-middle-to-right
Moveadiskfrom-right-to-left
Moveadiskfrom-right-to-middle
Moveadiskfrom-middle-to-left
Moveadiskfrom-middle-to–right
对于过河问题实现的代码如下:
move(1,0).%表示船上有一位牧师,没有野人。
move(0,1).
move(0,2).
move(2,0).
move(1,1).
%判断移动后两岸状态是否合法
legal((X,Y,_)):
-%X为左岸状态,Y为右岸状态。
_取0或1,0代表左岸,1代表右岸
legal1(X),%分别判断两岸的状态是否合法。
legal1(Y).
legal1((X,Y)):
-
X=:
=0,Y>
=0,!
.%牧师人数为0,野人的人数大于0,合法。
Y=:
=0,X>
.%野人人数为0,牧师的人数大于0,合法。
X>
=Y,X>
=0.%牧师数大于或等于野人数,且都大于0,合法。
%update谓词能够完成把合理的移动作用的某个状态上,从而到达新的状态。
update((X,Y,0),Move,Statu1):
-%船在左岸时
(A,B)=X,
(C,D)=Y,
(E,F)=Move,
C1isC+E,
D1isD+F,
A1isA-E,
B1isB-F,
Statu1=((A1,B1),(C1,D1),1).
update((X,Y,1),Move,Statu1):
-%船在右岸时
(A,B)=X,
C1isC-E,
D1isD-F,
A1isA+E,
B1isB+F,
Statu1=((A1,B1),(C1,D1),0).
%有了以上的三个谓词move,update,legal我们就可以很容易的做出判断两个合法的状态相邻的谓词。
connect(Statu,Statu1):
move(X,Y),
update(Statu,(X,Y),Statu1),
legal(Statu1).
%判断对象X是表的成员
member(X,[X|Tail]).
member(X,[Head|Tail]):
-member(X,Tail).
%再使用深度搜索方法就可以找到答案了。
由查找的目标状态X:
((0,0),(3,3),1),开始向前查找直到与查找前的初始状态Y:
((3,3),(0,0),0)相匹配,查找结束。
findroad(X,X,L,L).%递归的边界条件。
findroad(X,Y,L,L1):
-%L为储存的路径表。
connect(X,Z),
not(member(Z,L)),%当前状态Z不在已经储存的路径表中。
findroad(Z,Y,[Z|L],L1).
运行结果:
-findroad(((0,0),(3,3),1),((3,3),(0,0),0),[((0,0),(3,3),1)],L).
L=[((3,3),(0,0),0),
((2,2),(1,1),1),
((3,2),(0,1),0),
((3,0),(0,3),1),
((3,1),(0,2),0),
((1,1),(2,2),1),
((2,2),(1,1),0),
((0,2),(3,1),1),
((0,3),(3,0),0),
((0,1),(3,2),1),
((0,2),(3,1),0),
((0,0),(3,3),1),
((0,1),(3,2),0),
(0,0),(3,3),1]
六、结论
Prolog:
ProgramminginLogic(逻辑编程)
建立在逻辑学的理论基础之上的,最初是运用于自然语言的研究领域
现在被广泛的应用在人工智能的研究中
prolog不是很高深的语言
比较起其他的一些程序语言,例如c、basic等等语言,prolog是更加容易理解的语言
prolog程序没有特定的运行顺序,其运行顺序是由电脑决定的,而不是编程序的人
从这个意义上来说,prolog程序不是真正意义上的程序
所谓程序就是按照一定的步骤运行的计算机指令
prolog程序的运行步骤不由人来决定。
它更像一种描述型的语言,用特定的方法描述一个问题,然后由电脑自动找到这个问题的答案
极端的例子:
只需要把某个数学题目告诉它,它就会自动的找到答案,而不像使用其他的语言一样,必须人工的编制出某种算法
prolog程序中没有if、when、case、for这样的控制流程语句
程序的运行方式有电脑自己决定,当然就用不到这些控制流程的语句了
通常情况下,程序员不需要了解程序的运行过程,只需要注重程序的描述是否全面
prolog也提供了一些控制流程的方法,这些方法和其他语言中的方法有很大的区别
prolog程序和数据高度统一
在prolog程序中,是很难分清楚哪些是程序,哪些是数据的
prolog中的所有东西都有相同的形式,也就是说数据就是程序,程序就是数.