人工智能-基于规则的动物识别专家系统
人工智能实验二
一.题目:基于规则的动物识别专家系统
二.实验目的
1.熟悉产生式的特点,基本结构和设计思想;
2.掌握基于规则推理的基本过程和方法;
3.学会用高级程序设计语言开发基于规则的动物识别系统。
三.实验内容
动物识别专家系统是流行的专家系统实验模型,它用产生式规则来表示知识,共15条规则、可以识别七种动物,这些规则既少又简单,可以改造他们,也可以加进新的规则,还可以用来识别其他东西的新规则来取代这些规则。动物识别15条规则:
r1 毛发哺乳动物
r2 奶哺乳动物
r3 羽毛鸟
r4 会飞|下蛋鸟
r5 吃肉食肉动物
r6 犬齿|爪|眼睛盯着前方食肉动物
r7 哺乳动物|蹄有蹄类动物
r8 哺乳动物|反刍有蹄类动物
r9 哺乳动物|食肉动物|黄褐色|暗斑点金钱豹
r10 哺乳动物|食肉动物|黄褐色|黑色条纹虎
r11 有蹄类动物|长脖子|长腿|暗斑点长颈鹿
r12 有蹄类动物|黑条纹斑马
r13 鸟|不会飞|长脖子|长腿|黑白色鸵鸟
r14 鸟|不会飞|游泳|黑白色企鹅
r15 鸟|善飞信天翁
四.实验要求
1、确定推理方法(正向还是反向),并根据问题设计实现一个简单的不通用推理机(匹配、冲突消解);
2、规则库要求至少包含15条规则;
3、初始事实可以任意给定,输入初始事实后能够得到推理结果;
4、设计人机界面,解释模块提供查询规则的功能;
5、可以不考虑知识库管理模块;
6、提交实验报告,以word文档形式“学号+姓名”命名;
①报告中要有程序源代码;
②有程序运行结果截图;
③要有推理树;
④报告提交到:ftp://192.168.129.253/xstjzy/任建平/人工智能
五.实验原理
1.基于规则产生式系统结构
基于规则的产生式系统一般由规则库(知识库)、综合数据库和推理引擎(推理机)三部分组成,规则库中它的基本组成框架如下图1所示。
知识库由谓词演算事实和有关讨论主题的规则构成,综合库又称为上下文,用来暂时存储推理过程中的结论和数据。推理机是用规则进行推理的过程和行为。知识采集系统是领域专家把相关领域的知识表示成一定的形式,并输入到知识库中。解释系统通过用户输入的条件来分析被系统执行的推理结构,并将专家知识以易理解的方式并把知识解释给用户。
图1 规则产生式系统的基本结构
2. 简单动物识别产生式系统结构:
⑴知识库ANIMAL的知识库非常小,仅仅包含15条规则(一般说来,一个
产生式系统的知识库应包含≥几百条规则);
⑵解空间很小,在一个特定的动物园里,共有虎、金钱豹、长颈鹿、斑马、鸵鸟、企鹅和信天翁等7种动物;
⑶初始事实集合很小,仅仅包含30个事实,cha
⑷数据(即事实、证据、断言),知识(即浅层知识,规则)和推理都是精确的,即确定性的;
⑸知识库。
3.正向推理过程分析:
下面以一个具体的动物识别产生式系统模型来说明其原理。
初始事实集:
动物身上有暗斑点、有长脖子、有长腿、有奶、有蹄
要求解的问题是判断满足该事实集的是何种动物?
推理过程:
①首先从规则库取出第一条规则r1,将r1中的前提部分与初始事实集中的事实相比较,匹配失败;于是继续取第二条规则再试,匹配成功!将此规则的结论部分作为新事实加入到综合数据库的初始事实集中。于是初始事实集变为:
该动物身上有暗斑点、有长脖子、有长腿、有奶、有蹄、是哺乳动物。
②接着依次取r3、r4、r5、r6 与初始事实集匹配、均不成功,当执行到r7 时再次获得匹配,于是事实集中以增加一条事实:
该动物身上有暗斑点、有长脖子、有长腿、有奶、有蹄、是哺乳动物、是有蹄类动物。
③此后,当搜索到r11 时又一次匹配成功,事实集变为:
该动物身上有暗斑点、有长脖子、有长腿、有奶、有蹄、是哺乳动物、是有蹄类动物、该动物是长颈鹿。于是得到最终结论---该动物是长颈鹿。
上述问题的求解过程是一个不断地从规则库中选取可用规则与综合数据库中的已知事实进行匹配的过程,规则的每一次匹配都会使综合数据库增加新的内容,并朝着问题的解决前进了一步。这就是一个推理过程。
4.逆向推理过程分析:
初始事实集:
动物身上有暗斑点、有长脖子、有长腿、有奶、有蹄要求解的问题是判断满足该事实集的是何种动物?
推理过程:
①我们假设这个动物是长颈鹿的话,为了检验这个假设,根据规则r11,要求这个动物是长脖子,长腿,暗斑点且是有蹄类动物。
②这时数据库中已经有了长脖子,长腿,暗斑点事实,为此我们还要验证“动物是有蹄类动物”,根据规则r8要求动物反刍,且是哺乳动物,而事实库中没有反刍,根据规则r7要求动物有蹄,且是哺乳动物,事实中动物有蹄。为此我们要验证动物是哺乳动物
③我们要验证动物是哺乳动物,根据规则r2知道,要求动物有奶,事实中动物有奶,此时
各个子目标都是已知事实,所以逆向推理成功。
上述问题的求解过程是从目标的(作为假设)状态出发,朝着出事状态前进,逆向适用规则的一种方法。
六.推理树
七.具体代码如下
#include
#include
#include
#include
#define True 1
#define False 0
#define DontKnow -1
char *str[]={"chew_cud反刍动物","hooves蹄类动物","mammal哺乳动物","forward_eyes眼盯前方",
"claws有爪","pointed_teeth有犬齿","eat_meat吃肉","lay_eggs会下蛋","fly会飞", "feathers有羽毛","ungulate有蹄","carnivore食肉动物","bird鸟","give_milk能产奶",
"has_hair有毛发","fly_well善飞","black&white_color黑白色","can_swim会游泳",
"long_legs长腿","long_neck长脖子","black_stripes黑条纹","dark_spots黑斑点",
"tawny_color黄褐色","albatross信天翁","penguin企鹅","ostrich驼鸟","zebra斑马",
"giraffe长颈鹿","tiger老虎","cheetah猎豹",0};
int rulep[][6]={{22,23,12,3,0,0},{21,23,12,3,0,0},{22,19,20,11,0,0},
{21,11,0,0,0,0},{17,19,20,13,-9,0},{17,18,13,-9,0,0},{16,13,0,0,0,0}, {15,0,0,0,0,0},{14,0,0,0,0,0},{10,0,0,0,0,0},{8,7,0,0,0,0},
{7,0,0,0,0,0},{4,5,6,0,0,0},{2,3,0,0,0,0},{1,3,0,0,0,0}};
int rulec[]={30,29,28,27,26,25,24,3,3,13,13,12,12,11,11,0};
class fact
{
private:
int Number;
char Name[21];
int Active;
int Succ;
public:
fact *Next;
fact(int Num,char *L)
{
strcpy(Name,L);
Number=Num;
Active=False;
//-1 是已经推理,不符合。1 是已经推理,符合。
Succ=DontKnow; //0 是无,-1 是不知道,1 是有。
Next=NULL;
}
char *GetName()
{
char *L;
L=new char[21];
strcpy(L,Name);
return L;
}
int GetNumber()
{
return Number;
}
int GetAct()
{
return Active;
}
int GetSucc()
{
return Succ;
}
void PutAct(const int Act0,int Suc0)
{
Active=Act0;
Succ=Suc0;
}
};
fact *Fact;
class list
{
private:
int Number;
public:
list *Next;
list(int Num)
{
Number=Num;
Next=NULL;
}
int GetNumber()
{
return Number;
}
};
class rule
{
char *Name;
list *Pre;
int Conc;
public:
rule *Next;
rule(char *N,int P[],int C);
~rule();
int Query();
void GetName()
{
cout< } }; rule::~rule() { while(Pre) { L=Pre->Next; delete Pre; Pre=L; } delete Name; } rule::rule(char *N,int P[],int C) { int i; list *L; Pre=NULL; Next=NULL; Name=new char[strlen(N)+1]; strcpy(Name,N); i=0; while(P[i]!=0) { L=new list(P[i++]); L->Next=Pre; Pre=L; } Conc=C; } int rule::Query() { char c; int Tag=0; list *L; fact *F; F=Fact; L=Pre; if(L==NULL) cout<<"\nError"; while(L!=NULL) { F=Fact; for(;;) { if(abs(L->GetNumber())==F->GetNumber()) break; F=F->Next;//查找与规则前提链中前提号相同的事实 if(L->GetNumber()>0) { if((F->GetSucc())==true) {L=L->Next;continue;} if((F->GetSucc())==false) return false; }//如果事实的断言为真则判断下一个前提,为假,则表示该规则不适合else { if((F->GetSucc())==True) return False; if((F->GetSucc())==False) { L=L->Next; continue; } } cout< c=getchar();//事实断言为不知道的时候,向用户询问 flushall(); if((c=='Y')||(c=='y')) { if(L->GetNumber()>0) F->PutAct(1,True);//设置事实的断言和激活标志 if(L->GetNumber()<0) { F->PutAct(1,True); Tag=-1; return False; } } else { if(L->GetNumber()<0) F->PutAct(-1,False); else { F->PutAct(-1,False); Tag=-1; //已经推理,不符合。 return False; } } L=L->Next; } F=Fact; for(;;) { if(Conc==F->GetNumber()) break;//查找结论断言对应的事实 F=F->Next; } if(Conc<24) { F->PutAct(1,True); return False; } if(Tag!=-1) { F=Fact; for(;;) { if(Conc==F->GetNumber()) break; F=F->Next; } if(Conc<24) { F->PutAct(1,True); return False; } cout<<"\nThis aniamal is "< return True; } return False; } int main() { fact *F,*T; rule *Rule,*R; char ch[8]; int i=1; Fact=NULL; printf("请按提示选择:(Y:是N:不是ENTER:确认)\n"); while(str[i-1]) //初始化事实库,倒序排列。 { F=new fact(i,str[i-1]); F->Next=Fact; Fact=F; i++; } F=Fact; Fact=NULL; while(F) //把倒序排列正过来。 { T=F; F=F->Next; T->Next=Fact; Fact=T; } i=0; ch[0]='R'; ch[1]='U'; ch[2]='L'; ch[3]='E'; ch[4]='_'; ch[5]='a'; ch[6]='\0'; Rule=NULL; for(i=0;i<15;i++) //初始化规则库。 { R=new rule(ch,rulep[i],rulec[i]); R->Next=Rule; Rule=R; ch[5]++; } R=Rule; for(;;) { i=R->Query(); if((i==1)||(i==-1)) break; R=R->Next; if(!R) break; } if(!R) cout<<"I don't know."< cout<<"press any key to exit."< getchar(); return True; } 八.程序截图