产生式系统实验报告(共26页).doc
精选优质文档-倾情为你奉上学生实验报告实验课名称:人工智能 实验项目名称:产生式系统实验 专业名称:计算机科学与技术 班级: 学号:6 学生姓名:程文迪 教师姓名:陈亮亮 2015 年 10 月 25 日实验日期: 2015 年 10 月 23 日 实验室名称: 明远2203 一 实验名称:产生式系统实验二实验目的与要求:1、确定推理方法(正向还是反向),并根据问题设计并实现一个简单的推理机(要求涉及:匹配、冲突消解)2、规则库要求至少包含15条规则(知识规则如何存储?)3、推理机和知识库必须分离4、初始事实可以任意给定,输入初始事实后能够得到推理结果5、设计合理的人机界面,解释模块提供查询规则的功能6、可以不考虑知识库管理模块7、提交实验报告8、报告中要有推理树三实验内容:本实验我设计了一个动物识别的小型专家系统,主要是根据一些观察到的事实,依据系统给出的一系列规则来进行正向推理,将逐渐的推导出结果。本次实验设计了一个简单的推理机,推理机给出的推理结果有“它是_动物”、“条件不足,不能推出它是什么动物”、“条件有冲突,没有这样的动物”或“条件不完全,但它有_的部分特征”。部分推理树如下:专心-专注-专业四、算法描述:1.表示事实和特征的知识。 在本程序中,我将动物的特征写入data.txt,将规则记入rules.txt,将动物种类记为goal.txt。通过函数void readFiles()readGoal();readCod();readRule();/reaFiles读入所有数据分别存放于goal,rule,cod自定义数组中。2. 综合数据库和规则库实现综合数据库(包括特征和目标) typedef structint xuh;/存放编号 char valu50;/存放具体内容Node;Node goal20;Node cod50;void readCod()FILE *fp;int i;if(fp=fopen("data.txt","r")=NULL)printf("cannot open datan");exit(0);i=0;while(fscanf(fp,"%d %s",&codi.xuh,&codi+.valu)!=EOF);fclose(fp);/readCodvoid readGoal()FILE *fp;int i;if(fp=fopen("goal.txt","r")=NULL)printf("cannot open goaln");exit(0);i=0;while(fscanf(fp,"%d %s",&goali.xuh,&goali+.valu)!=EOF);fclose(fp);/readGoal规则库typedef structint rslt;int codNum;/记载前提的个数int cod10;/记载前提的序号int used;/记载是否已匹配成功Nrule;Nrule rule50;void readRule()FILE *fp;int i;int tempxuh,tempcodn;char ch;if(fp=fopen("rules.txt","r")=NULL)printf("cannot open rulesn");exit(0);i=0;rulei.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);rulei.codtempcodn+=tempxuh;tempxuh=0;if(ch='=')/下一个是结论ch=fgetc(fp);while(ch<='9'&&ch>='0')tempxuh=tempxuh*10+ch-'0'ch=fgetc(fp);rulei.rslt=tempxuh;/ifelse if(ch='*')ch=fgetc(fp);rulei.codNum+;i+;ch=fgetc(fp);rulenum=i;fclose(fp);3. 规则库的匹配算法是什么?如何选用可用规则集中的规则?分别使用哪些函数实现的? 程序中的正向搜索是在void main()中调用forwardFinger实现的。正向搜索是从下向上的推理。由于建立规则库时的内在要求,即子规则必在父规则前,故进行正向推理的时候只要将规则库从前到后扫一遍看是否能由规则推出相应结果即可。如果能匹配推出结果则看该结果是否为动物,如果已经推出动物则推理成功。否则更新事实库,匹配下一个规则。代码如下:void forwardFinger()int flag;/1:工作已完成 0:还未完成int flagFit;int flagCNew;/记录本次循环有没有推出新事实int fitPart;/1:有部分符合条件int i,j,k;flag=0;flagCNew=1;while(!flag&&flagCNew=1)flagCNew=0;for(j=0;j<rulenum&&rulej.used!=1&&flag=0;j+)/一条规则if(rulej.codNum<=inpCod.curnum)/事实数不小于当前规则所要求的条件数flagFit=1;for(i=0;i<rulej.codNum&&flagFit=1;i+)fitPart=0;for(k=0;k<inpCod.curnum;k+)if(rulej.codi=inpCod.codk.xuh)fitPart=1;flagFit=fitPart;if(flagFit=1)flagCNew=1;fitOneRule(j,&flag);/有事实匹配时,就处理把结论加入事实库等事情flagFit=0;/whileif(flagCNew=0)printf("条件不足,不能推出它是什么动物");3.推理过程 本次实验采用的是正向推理的方法,是从已知事实出发,通过规则库求得结论,也称为自底向上,或称为数据驱动方式。这种推理方式是正向使用原则,即问题的初始状态作为初始数据库,在仅当数据库中的事实满足某条规则的前提时,这条规则才能够被使用。程序中采用的是基于用户按照规则点击,逐步得出结果的。正向推理的步骤:步骤1 将初始事实置入动态数据库;步骤2 用动态数据库中的事实,匹配目标条件,若目标条件满足,则推理成功,结束。 步骤3 用规则库中各规则的前件匹配动态数据库中的事实,将匹配成功的规则组成冲突集;步骤4 若冲突集为空,则运行失败,退出。步骤5 对冲突集做处理,对选择执行的各规则,将其结论加入动态数据库,或执行其动作,转步骤2。推理的流程图五 源程序:#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream.h>#include<math.h>#define MAXNUM 50typedef structint xuh;char valu50;Node;typedef structint stat;/0:还未访问 1:至少用过一次 2:没用过但不冲突int xuh;NFact;typedef structint snum;/开始时的事实数int curnum;/目前的事实数int notEnoughFlag;/当最后若所有未用过的条件支持一个结论,但条件不足时,置1NFact codMAXNUM;Fact;typedef structint rslt;int codNum;/记载前提的个数int cod10;/记载前提的序号int used;/记载是否已匹配成功Nrule;int codnum=28;int goalnum=15;int rulenum=0;Node goal20;Node cod50;Nrule rule50;Fact inpCod;void readGoal()FILE *fp;int i;if(fp=fopen("goal.txt","r")=NULL)printf("cannot open goaln");exit(0);i=0;while(fscanf(fp,"%d %s",&goali.xuh,&goali+.valu)!=EOF);fclose(fp);/readGoalvoid readRule()FILE *fp;int i;int tempxuh,tempcodn;char ch;if(fp=fopen("rules.txt","r")=NULL)printf("cannot open rulesn");exit(0);i=0;rulei.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);rulei.codtempcodn+=tempxuh;tempxuh=0;if(ch='=')/下一个是结论ch=fgetc(fp);while(ch<='9'&&ch>='0')tempxuh=tempxuh*10+ch-'0'ch=fgetc(fp);rulei.rslt=tempxuh;/ifelse if(ch='*')ch=fgetc(fp);rulei.codNum+;i+;ch=fgetc(fp);rulenum=i;fclose(fp);void readCod()FILE *fp;int i;if(fp=fopen("data.txt","r")=NULL)printf("cannot open datan");exit(0);i=0;while(fscanf(fp,"%d %s",&codi.xuh,&codi+.valu)!=EOF);fclose(fp);/readCodvoid readFiles()readGoal();readCod();readRule();/reaFilesint inputCod()int retflag=1;int temp;int i;i=0;doscanf("%d",&temp);inpCod.codi+.xuh=temp;if(temp>=codnum)printf("特征序号不能大于%d,请重新输入:n",codnum-1);fflush(stdin);/清空输入缓冲区retflag=0;while(temp!=-1&&temp<codnum);inpCod.snum=i-1;inpCod.curnum=inpCod.snum;return retflag;/inputCod()int onlyExtra(int inpCodXuh,int rslt)int i,j;int fa50;int head;int tail;int retflag;int tempstate50;/若放入队列中,则记录为1fa0=rslt;tempstaterslt=1;head=0;tail=1;retflag=0;while(head!=tail&&retflag!=1)for(j=0;j<rulenum;j+)if(rulej.rslt=fahead)for(i=0;i<rulej.codNum;i+)if(inpCod.codinpCodXuh.xuh=rulej.codi)retflag=1;elseif(tempstaterulej.codi!=1)fatail+=rulej.codi;tempstaterulej.codi=1;head+;return retflag;/onlyExtraint isContradict(int rslt)int i;int flag;flag=0;for(i=0;i<inpCod.curnum&&flag=0;i+)if(inpCod.codi.stat=0&&inpCod.codi.xuh!=rslt)if(onlyExtra(i,rslt)inpCod.codi.stat=2;flag=0;elseflag=1;return flag;/isContradict()void isAim(int rslt,int *doneflag)if(rslt>=codnum)/已推理出一个动物*doneflag=1;if(isContradict(rslt)printf("条件有冲突,没有这样的动物。n");elseprintf("它是%s。n",goalrslt-codnum.valu);/isAim()void addFact(int ruleXuh,int *doneflag)int i;int flagHave;flagHave=0;/标志此次推出的结论是否已在inpCod.cod中for(i=0;i<inpCod.curnum;i+)if(inpCod.codi.xuh=ruleruleXuh.rslt)flagHave=1;if(flagHave=0)inpCod.codinpCod.curnum.xuh=ruleruleXuh.rslt;inpCod.curnum+;isAim(ruleruleXuh.rslt,doneflag);/addFact()void fitOneRule(int ruleXuh,int *doneflag)int i,k;for(i=0;i<ruleruleXuh.codNum;i+)/作inpCod的访问标记for(k=0;k<inpCod.curnum;k+)if(ruleruleXuh.codi=inpCod.codk.xuh)inpCod.codk.stat=1;/forruleruleXuh.used=1;addFact(ruleXuh,doneflag);/fitOneRule()void countNoUseF(int *recNoUseF,int *recNoUseFNum)int i;int tempstate50;/若已经在recNoUseF中记录过,就记为1for(i=0;i<inpCod.curnum;i+)if(inpCod.codi.stat=0&&tempstateinpCod.codi.xuh!=1)recNoUseF*recNoUseFNum=inpCod.codi.xuh;+(*recNoUseFNum);tempstateinpCod.codi.xuh=1;/countNoUseF()void printLikeClouse(int tempflag,int ruleXuh,int *printRec)Node *result;int resultXuh;result=cod;resultXuh=ruleruleXuh.rslt;printRecruleruleXuh.rslt=1;if(resultXuh>27)result=goal;resultXuh-=28;if(tempflag=0)printf("条件不完全,但它有%s",resultresultXuh.valu);/elseprintf("和%s",resultresultXuh.valu);/printLikeClouse()void maybeAnimal()int i,j,k;int countLikeCurRule;int recNoUseF50,recNoUseFNum;int printRec50;/若前面已推出这个"可能结论",就置为1int tempflag;recNoUseFNum=0;countNoUseF(recNoUseF,&recNoUseFNum);tempflag=0;for(i=0;i<rulenum;i+)countLikeCurRule=0;for(j=0;j<rulei.codNum;j+)for(k=0;k<recNoUseFNum;k+)if(recNoUseFk=rulei.codj)+countLikeCurRule;if(countLikeCurRule*2>=rulei.codNum&&printRecrulei.rslt!=1)printLikeClouse(tempflag,i,printRec);tempflag=1;if(tempflag=0)printf("条件不足,不能推出它是什么动物");elseprintf("的部分特征");printf("。n");/maybeAnimal()void forwardFinger()int flag;/1:工作已完成 0:还未完成int flagFit;int flagCNew;/记录本次循环有没有推出新事实int fitPart;/1:有部分符合条件int i,j,k;flag=0;flagCNew=1;while(!flag&&flagCNew=1)flagCNew=0;for(j=0;j<rulenum&&rulej.used!=1&&flag=0;j+)/一条规则if(rulej.codNum<=inpCod.curnum)/事实数不小于当前规则所要求的条件数flagFit=1;for(i=0;i<rulej.codNum&&flagFit=1;i+)fitPart=0;for(k=0;k<inpCod.curnum;k+)if(rulej.codi=inpCod.codk.xuh)fitPart=1;flagFit=fitPart;if(flagFit=1)flagCNew=1;fitOneRule(j,&flag);/有事实匹配时,就处理把结论加入事实库等事情flagFit=0;/whileif(flagCNew=0)maybeAnimal();/当没有推出任何动物时,看是否极有可能得出一些结论/finger()void printChoice()/打印选项int i,j;j=0;for(i=0;i<codnum;i+)printf("%-2d %-14s",codi.xuh,codi.valu);j+;if(j%4=0)printf("n");printf("n");/printChoice() void init()int i;for(i=0;i<MAXNUM;i+)rulei.used=0;inpCod.notEnoughFlag=0;inpCod.codi.stat=0;void main()cout<<"*动物识别系统*"<<endl;char ch;int i=0;readFiles();doinit();if(i%3=0)printChoice();i+;printf("请输入已知的动物的特征的序号,以'-1'结束:");printf("n");while(inputCod()=0);forwardFinger();/正向推理printf("n");printf("按任意键继续,按'n'或'N'退出:");ch=getchar();ch=getchar();while(ch!='n'&&ch!='N');六运行结果与分析:七实验中遇到的问题、解决方法及体会:本次实验遇到了一些问题,首先,要做到推理机和知识库分离,经过多次尝试之后,我选择了读取外部txt文件的方法,对综合数据库及规则库进行读入;其次,我选择可正向推理,推理机具备匹配规则、识别冲突、解决等功能,正向推理,从事实出发,通过规则库匹配出结论。由于本实验规则较少,本程序没有涉及冲突解决算法,只设计了判断其是何种动物及具备某种动物特征算法,若判断冲突,则得出条件有冲突,没有这样的动物的结论。通过这次实验,对人工智能的产生式系统有了进一步的认识,特别是对正向推理有更深的了解,充分培养了我的独立解决问题的能力。由于首次设计比较生疏,加之时间较短,所以该系统还有许多不尽如人意的地方,例如界面设计不美观等,因此有待进一步改进。