产生式系统实验报告.doc
《产生式系统实验报告.doc》由会员分享,可在线阅读,更多相关《产生式系统实验报告.doc(21页珍藏版)》请在冰点文库上搜索。
学生实验报告
实验课名称:
人工智能
实验项目名称:
产生式系统实验
专业名称:
计算机科学与技术
班级:
2013240202
学号:
201324020226
学生姓名:
程文迪
教师姓名:
陈亮亮
2015年10月25日
实验日期:
2015年10月23日实验室名称:
明远2203
一.实验名称:
产生式系统实验
二.实验目的与要求:
1、确定推理方法(正向还是反向),并根据问题设计并实现一个简单的推理机(要求涉及:
匹配、冲突消解)
2、规则库要求至少包含15条规则(知识规则如何存储?
)
3、推理机和知识库必须分离
4、初始事实可以任意给定,输入初始事实后能够得到推理结果
5、设计合理的人机界面,解释模块提供查询规则的功能
6、可以不考虑知识库管理模块
7、提交实验报告
8、报告中要有推理树
三.实验内容:
本实验我设计了一个动物识别的小型专家系统,主要是根据一些观察到的事实,依据系统给出的一系列规则来进行正向推理,将逐渐的推导出结果。
本次实验设计了一个简单的推理机,推理机给出的推理结果有“它是__动物”、“条件不足,不能推出它是什么动物”、“条件有冲突,没有这样的动物”或“条件不完全,但它有__的部分特征”。
部分推理树如下:
四、算法描述:
1.表示事实和特征的知识。
在本程序中,我将动物的特征写入data.txt,将规则记入rules.txt,将动物种类记为goal.txt。
通过函数
voidreadFiles()
{
readGoal();
readCod();
readRule();
}//reaFiles
读入所有数据分别存放于goal[],rule[],cod[]自定义数组中。
2.综合数据库和规则库实现
综合数据库(包括特征和目标)
typedefstruct
{
intxuh;//存放编号
charvalu[50];//存放具体内容
}Node;
Nodegoal[20];
Nodecod[50];
voidreadCod()
{
FILE*fp;
inti;
if((fp=fopen("data.txt","r"))==NULL)
{
printf("cannotopendata\n");
exit(0);
}
i=0;
while((fscanf(fp,"%d%s",&cod[i].xuh,&cod[i++].valu))!
=EOF);
fclose(fp);
}//readCod
voidreadGoal()
{
FILE*fp;
inti;
if((fp=fopen("goal.txt","r"))==NULL)
{
printf("cannotopengoal\n");
exit(0);
}
i=0;
while((fscanf(fp,"%d%s",&goal[i].xuh,&goal[i++].valu))!
=EOF);
fclose(fp);
}//readGoal
规则库
typedefstruct
{
intrslt;
intcodNum;//记载前提的个数
intcod[10];//记载前提的序号
intused;//记载是否已匹配成功
}Nrule;
Nrulerule[50];
voidreadRule()
{
FILE*fp;
inti;
inttempxuh,tempcodn;
charch;
if((fp=fopen("rules.txt","r"))==NULL)
{
printf("cannotopenrules\n");
exit(0);
}
i=0;
rule[i].codNum=0;
while((ch=fgetc(fp))!
=EOF)
{
if(i==15)
i=i;
tempcodn=0;
while(ch!
='\n'&&ch!
=EOF) //每一条规则
{
tempxuh=0;
while(ch<='9'&&ch>='0')
{
tempxuh=tempxuh*10+ch-'0';//
ch=fgetc(fp);
}
rule[i].cod[tempcodn++]=tempxuh;
tempxuh=0;
if(ch=='=')//下一个是结论
{
ch=fgetc(fp);
while(ch<='9'&&ch>='0')
{
tempxuh=tempxuh*10+ch-'0';
ch=fgetc(fp);
}
rule[i].rslt=tempxuh;
}//if
elseif(ch=='*')
{
ch=fgetc(fp);
}
rule[i].codNum++;
}
i++;
ch=fgetc(fp);
}
rulenum=i;
fclose(fp);
}
3.规则库的匹配算法是什么?
如何选用可用规则集中的规则?
分别使用哪些函数实现的?
程序中的正向搜索是在voidmain()中调用forwardFinger实现的。
正向搜索是从下向上的推理。
由于建立规则库时的内在要求,即子规则必在父规则前,故进行正向推理的时候只要将规则库从前到后扫一遍看是否能由规则推出相应结果即可。
如果能匹配推出结果则看该结果是否为动物,如果已经推出动物则推理成功。
否则更新事实库,匹配下一个规则。
代码如下:
voidforwardFinger()
{
intflag;//1:
工作已完成0:
还未完成
intflagFit;
intflagCNew;//记录本次循环有没有推出新事实
intfitPart;//1:
有部分符合条件
inti,j,k;
flag=0;
flagCNew=1;
while(!
flag&&flagCNew==1)
{
flagCNew=0;
for(j=0;j=1&&flag==0;j++)//一条规则
{
if(rule[j].codNum<=inpCod.curnum)//事实数不小于当前规则所要求的条件数
{
flagFit=1;
for(i=0;i {
fitPart=0;
for(k=0;k {
if(rule[j].cod[i]==inpCod.cod[k].xuh)
{
fitPart=1;
}
}
flagFit=fitPart;
}
if(flagFit==1)
{
flagCNew=1;
fitOneRule(j,&flag);//有事实匹配时,就处理把结论加入事实库等事情
flagFit=0;
}
}
}//
}//while
if(flagCNew==0)
{
printf("条件不足,不能推出它是什么动物");
}
}
3.推理过程
本次实验采用的是正向推理的方法,是从已知事实出发,通过规则库求得结论,也称为自底向上,或称为数据驱动方式。
这种推理方式是正向使用原则,即问题的初始状态作为初始数据库,在仅当数据库中的事实满足某条规则的前提时,这条规则才能够被使用。
程序中采用的是基于用户按照规则点击,逐步得出结果的。
正向推理的步骤:
步骤1将初始事实置入动态数据库;
步骤2用动态数据库中的事实,匹配目标条件,若目标条件满足,则推理成功,结束。
步骤3用规则库中各规则的前件匹配动态数据库中的事实,将匹配成功的规则组成冲突集;
步骤4若冲突集为空,则运行失败,退出。
步骤5对冲突集做处理,对选择执行的各规则
,将其结论加入动态数据库,或执行其动作,转步骤2。
推理的流程图
五.源程序:
#include
#include
#include
#include
#include
#defineMAXNUM50
typedefstruct
{
intxuh;
charvalu[50];
}Node;
typedefstruct
{
intstat;//0:
还未访问1:
至少用过一次2:
没用过但不冲突
intxuh;
}NFact;
typedefstruct
{
intsnum;//开始时的事实数
intcurnum;//目前的事实数
intnotEnoughFlag;//当最后若所有未用过的条件支持一个结论,但条件不足时,置1
NFactcod[MAXNUM];
}Fact;
typedefstruct
{
intrslt;
intcodNum;//记载前提的个数
intcod[10];//记载前提的序号
intused;//记载是否已匹配成功
}Nrule;
intcodnum=28;
intgoalnum=15;
intrulenum=0;
Nodegoal[20];
Nodecod[50];
Nrulerule[50];
FactinpCod;
voidreadGoal()
{
FILE*fp;
inti;
if((fp=fopen("goal.txt","r"))==NULL)
{
printf("cannotopengoal\n");
exit(0);
}
i=0;
while((fscanf(fp,"%d%s",&goal[i].xuh,&goal[i++].valu))!
=EOF);
fclose(fp);
}//readGoal
voidreadRule()
{
FILE*fp;
inti;
inttempxuh,tempcodn;
charch;
if((fp=fopen("rules.txt","r"))==NULL)
{
printf("cannotopenrules\n");
exit(0);
}
i=0;
rule[i].codNum=0;
while((ch=fgetc(fp))!
=EOF)
{
if(i==15)
i=i;
tempcodn=0;
while(ch!
='\n'&&ch!
=EOF) //每一条规则
{
tempxuh=0;
while(ch<='9'&&ch>='0')
{
tempxuh=tempxuh*10+ch-'0';//
ch=fgetc(fp);
}
rule[i].cod[tempcodn++]=tempxuh;
tempxuh=0;
if(ch=='=')//下一个是结论
{
ch=fgetc(fp);
while(ch<='9'&&ch>='0')
{
tempxuh=tempxuh*10+ch-'0';
ch=fgetc(fp);
}
rule[i].rslt=tempxuh;
}//if
elseif(ch=='*')
{
ch=fgetc(fp);
}
rule[i].codNum++;
}
i++;
ch=fgetc(fp);
}
rulenum=i;
fclose(fp);
}
voidreadCod()
{
FILE*fp;
inti;
if((fp=fopen("data.txt","r"))==NULL)
{
printf("cannotopendata\n");
exit(0);
}
i=0;
while((fscanf(fp,"%d%s",&cod[i].xuh,&cod[i++].valu))!
=EOF);
fclose(fp);
}//readCod
voidreadFiles()
{
readGoal();
readCod();
readRule();
}//reaFiles
intinputCod()
{
intretflag=1;
inttemp;
inti;
i=0;
do
{
scanf("%d",&temp);
inpCod.cod[i++].xuh=temp;
if(temp>=codnum)
{
printf("特征序号不能大于%d,请重新输入:
\n",codnum-1);
fflush(stdin);//清空输入缓冲区
retflag=0;
}
}while(temp!
=-1&&temp inpCod.snum=i-1;
inpCod.curnum=inpCod.snum;
returnretflag;
}//inputCod()
intonlyExtra(intinpCodXuh,intrslt)
{
inti,j;
intfa[50];
inthead;
inttail;
intretflag;
inttempstate[50];//若放入队列中,则记录为1
fa[0]=rslt;
tempstate[rslt]=1;
head=0;
tail=1;
retflag=0;
while(head!
=tail&&retflag!
=1)
{
for(j=0;j {
if(rule[j].rslt==fa[head])
{
for(i=0;i {
if(inpCod.cod[inpCodXuh].xuh==rule[j].cod[i])
{
retflag=1;
}
else
{
if(tempstate[rule[j].cod[i]]!
=1)
{
fa[tail++]=rule[j].cod[i];
tempstate[rule[j].cod[i]]=1;
}
}
}
}
}
head++;
}
returnretflag;
}//onlyExtra
intisContradict(intrslt)
{
inti;
intflag;
flag=0;
for(i=0;i {
if(inpCod.cod[i].stat==0&&inpCod.cod[i].xuh!
=rslt)
{
if(onlyExtra(i,rslt))
{
inpCod.cod[i].stat=2;
flag=0;
}
else
{
flag=1;
}
}
}
returnflag;
}//isContradict()
voidisAim(intrslt,int*doneflag)
{
if(rslt>=codnum)//已推理出一个动物
{
*doneflag=1;
if(isContradict(rslt))
{
printf("条件有冲突,没有这样的动物。
\n");
}
else
{
printf("它是%s。
\n",goal[rslt-codnum].valu);
}
}
}//isAim()
voidaddFact(intruleXuh,int*doneflag)
{
inti;
intflagHave;
flagHave=0;//标志此次推出的结论是否已在inpCod.cod[]中
for(i=0;i {
if(inpCod.cod[i].xuh==rule[ruleXuh].rslt)
{
flagHave=1;
}
}
if(flagHave==0)
{
inpCod.cod[inpCod.curnum].xuh=rule[ruleXuh].rslt;
inpCod.curnum++;
}
isAim(rule[ruleXuh].rslt,doneflag);
}//addFact()
voidfitOneRule(intruleXuh,int*doneflag)
{
inti,k;
for(i=0;i {
for(k=0;k {
if(rule[ruleXuh].cod[i]==inpCod.cod[k].xuh)
{
inpCod.cod[k].stat=1;
}
}
}//for
rule[ruleXuh].used=1;
addFact(ruleXuh,doneflag);
}//fitOneRule()
voidcountNoUseF(int*recNoUseF,int*recNoUseFNum)
{
inti;
inttempstate[50];//若已经在recNoUseF[]中记录过,就记为1
for(i=0;i {
if(inpCod.cod[i].stat==0&&tempstate[inpCod.cod[i].xuh]!
=1)
{
recNoUseF[*recNoUseFNum]=inpCod.cod[i].xuh;
++(*recNoUseFNum);
tempstate[inpCod.cod[i].xuh]=1;
}
}
}//countNoUseF()
voidprintLikeClouse(inttempflag,intruleXuh,int*printRec)
{
Node*result;
intresultXuh;
result=cod;
resultXuh=rule[ruleXuh].rslt;
printRec[rule[ruleXuh].rslt]=1;
if(resultXuh>27)
{
result=goal;
resultXuh-=28;
}
if(tempflag==0)
{
printf("条件不完全,但它有%s",result[resultXuh].valu);//
}
else
{
printf("和%s",result[resultXuh].valu);
}
}//printLikeClouse()
voidmaybeAnimal()
{
inti,j,k;
intcountLikeCurRule;
intrecNoUseF[50],recNoUseFNum;
intprintRec[50];//若前面已推出这个"可能结论",就置为1
inttempflag;
recNoUseFNum=0;
countNoUseF(recNoUseF,&recNoUseFNum);
tempflag=0;
for(i=0;i {
countLikeCurRule=0;
for(j=0;j {
for(k=0;k {
if(recNoUseF[k]==rule[i].cod[j])
{
++countLikeCurRule;
}
}
}
if(countLikeCurRule*2>=rule[i].codNum&&printRec[rule[i].rslt]!
=1)
{
printLikeClouse(tempflag,i,printRec);
tempflag=1;
}
}
if(tempflag==0)
{
printf("条件不足,不能推出它是什么动物");
}
else
{
printf("的部分特征");
}
printf("。
\n");
}//maybeAnimal()
voidforwardFinger()
{
intflag;//1:
工作已完成0:
还未完成
intflagFit;
intflagCNew;//记录本次循环有没有推出新事实
intfitPart;//1:
有部分符合条件
inti,j,k;
flag=0;
flagCNew=1;
while(!
flag&&flagCNew==1)
{
flagCNew=0;
for(j=0;j=1&&flag==0;j++)//一条规则
{
if(rule[j].codNum<=inpCod.curnum)//事实数不小于当前规则所要求的条件数
{
flagFit=1;
for(i=0;i {
fitPart=0;
for(k=0;k {
if(rule[j].cod[i]==inpCod.cod[k].xuh)
{
fitPart=1;