1.产生式系统介绍
总数据库
存放求解过程中各种当前信息的数据结构
产生式规则
规则库,存放与求解问题有关的某个领域知识的规则之集合及其交换规则
控制策略
推理机构,控制产生式系统的运行,决定问题求解过程的推理线路
2.动物识别系统属性选择
编号依次为(0~31)
毛发 产乳 羽毛 飞行 产蛋 吃肉
爪子 利齿 前视 蹄 反刍 黄褐色
深色斑点 黑色条纹 长腿 长颈 白色 不会飞 黑白相杂 游水 善飞
鸟类动物 哺乳动物 食肉动物
有蹄动物 猎豹 老虎 长颈鹿 斑马 鸵鸟 企鹅 海燕
3.规则建立
0->22 1->22 2->21
3+4->21 22+5->23 22+6+7+8->23
22+9->24 22+10->24 23+11+12->25
23+11+13->26
24+14+15+11+12->27
24+16+13->28
21+17+15+14+18->29
21+17+19+18->30
21+20->31
属性及规则划分
L类(只出现在产生式左边且可推出中间属性的属性)
LR类(在产生式左右两边都出现且是过渡的属性)
R类(只在产生式右边出现的且是目标的属性)
属性 规则
L类 0,1,2,3,4 0->22 1->22 2->21 3+4->21
LR类 23,24 22+5->23 22+9->24 22+6+7+8->23 22+10->24
R类 25,26,27,28,29,30,31 23+11+12->25 23+11+13->26 24+14+15+11+12->27 24+16+13->28 21+17+15+14+18->29 21+17+18+19->30
4.算法描述
第一步:依据L类属性及其规则第一次扩充输入属性集合
第二步:依据LR类属性及其规则第二次扩充属性集合
第三步:依据R类规则及上述属性集合求出R类集合,若R类集合为空,则不能识别动物,
若有唯一值,则可以唯一确定动物,
若有多个值,则结论冲突,输入非法
5.算法实现
数据结构:
输入属性集合 get[24],其长度为length
目标事实个数:targetNum
目标事实确认集合:target1[7]
产生式规则,二维数组produce[15][6]
6.程序结构
reshape()刷新屏幕
getPro()输入属性编号
new1Num()第一次扩充
new2Num()第二次扩充
Search()查找目标
output()输出结论
7.源代码(完整)
//简单动物识别系统源代码实现 人工智能及其应用 研究生用书 2.7节例题
//语言:C,行界面形式
//日期:2011.10.29
//作者:唐裕凤 E201102057
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//事实编号数据,最多为24个
int get[24]={-1};
int length=0;//get数组长度
int targetNum=0;//目标事实个数
//动物目标编号
int target[7]={25,26,27,28,29,30,31};
//动物是否被确认
int target1[7]={0};
//产生式规则,用二维数组表示
int produce[15][6]={0,-1,-1,-1,-1,22,1,-1,-1,-1,-1,22,2,-1,-1,-1,-1,21,3,4,-1,-1,-1,21,22,5,-1,-1,-1,23,22,6,7,8,-1,23,22,9,-1,-1,-1,24,22,10,-1,-1,-1,24,23,11,12,-1,-1,25,
23,11,13,-1,-1,26,24,14,15,11,12,27,24,16,13,-1,-1,28,21,17,15,14,18,29,21,17,19,18,-1,30,21,20,-1,-1,-1,31};
void reshape(void)//刷新全局变量函数
{
int i=0;
for(i=0;i<24;i++)
get[i]=-1;
length=0;
for(i=0;i<7;i++)
target1[i]=0;
targetNum=0;
}
void init1(void)//显示事实列表
{
printf("/********************************************************************/\n");
printf("/* 动物识别系统 /\n");
printf("/* 姓名:唐裕凤 学号:E201102057 专业:计算机应用技术 */\n");
printf("/********************************************************************/\n");
printf("\n\n\n以下是可供选择的动武属性:\n");
printf("0 毛发 1 产乳 2 羽毛 3 飞行 4 产蛋 5 吃肉\n");
printf("6 爪子 7 利齿 8 前视 9 蹄 10 反刍 11 黄褐色\n");
printf("12 深色斑点 13 黑色条纹 14 长腿 15 长颈 16 白色 17 不会飞\n");
printf("18 黑白相杂 19 游水 20 善飞 21 鸟类动物 22 哺乳动物 23 食肉动物\n");
printf("24 有蹄动物\n");
}
void init2(void)//可以得出的动物名称
{
printf("\n\n\n下面是可以得出的动物名称:\n");
printf("25 猎豹 26 老虎 27 长颈鹿 28 斑马\n");
printf("29 鸵鸟 30 企鹅 31 海燕\n");
}
void output()//输出所有的产生式
{
int i=0,j=0,k=0;
printf("\n\n\n下面是15条产生式规则\n\n");
for(i=0;i<15;i++)
{
for(j=0;j<5;j++)
if(produce[i][j]==-1)
break;
else
{
printf("%d",produce[i][j]);
k=j+1;
if(produce[i][k]!=-1&&k!=5)
printf("+");
}
printf("->%d\n",produce[i][5]);
}
}
//输入事实编号数据,以-1结束,最多为24个
void getPro()
{
printf("\n\n\n请输入选择的条件,以-1结束");
int temp,i=0;
do
{
scanf("%d",&temp);
if(temp<-1||temp>24)
{
printf("\n该输入非法,请重新输入\n");
continue;
}
get[i++]=temp;
}while(temp!=-1);
length=i;
}
void outputGet()
{
for(int i=0;i<length-1;i++)
printf("%d\t",get[i]);
printf("\n");
}
//计算事实个数,即get数组个数
void Length(int get[])
{
int i=0;
while(get[i]!=-1)
{
i++;
}
length=i;
}
//是否用到规则0
int find0(void)
{
int i=0;
for(;i<length;i++)
if(get[i]==0) return 1;
return 0;
}
//是否用到规则1
int find1(void)
{
int i=0;
for(;i<length;i++)
if(get[i]==1) return 1;
return 0;
}
//是否用到规则2
int find2(void)
{
int i=0;
for(;i<length;i++)
if(get[i]==2) return 1;
return 0;
}
//是否用到规则3
int find3(void)
{
int i=0,flag1=0,flag2=0;
for(;i<length;i++)
if(get[i]==3) flag1=1;
else if(get[i]==4) flag2=1;
if(flag1&&flag2) return 1;
else
return 0;
}
//更新后的事实数组
void new1Num(void)
{
int m=length;
if(find0()||find1())
{
get[m]=22;
m++;
}
if(find2()||find3())
{
get[m]=21;
m++;
}
length=m;
}
//利用中间规则推导出中间数据
//是否用到规则4
int find4(void)
{
int i=0,flag1=0,flag2=0;
for(;i<length;i++)
if(get[i]==5) flag1=1;
else if(get[i]==22) flag2=1;
if(flag1&&flag2) return 1;
else
return 0;
}
//是否用到规则5
int find5(void)
{
int i=0,flag1=0,flag2=0,flag3=0,flag4=0;
for(;i<length;i++)
switch(get[i])
{
case 6:flag1=1;break;
case 7:flag2=1;break;
case 8:flag3=1;break;
case 22:flag4=1;break;
default:break;
}
if(flag1&&flag2&&flag3&&flag4) return 1;
else
return 0;
}
//是否用到规则6
int find6(void)
{
int i=0,flag1=0,flag2=0;
for(;i<length;i++)
if(get[i]==9) flag1=1;
else if(get[i]==22) flag2=1;
if(flag1&&flag2) return 1;
else return 0;
}
//是否用到规则7
int find7(void)
{
int i=0,flag1=0,flag2=0;
for(;i<length;i++)
if(get[i]==10) flag1=1;
else if(get[i]==22) flag2=1;
if(flag1&&flag2) return 1;
else return 0;
}
//第二次更新事实数组get[]
void new2Num(void)
{
int m=length;
if(find4()||find5())
{
get[m]=23;
m++;
}
if(find6()||find7())
{
get[m]=21;
m++;
}
length=m;
}
//利用所有的事实数据判断最终的结论
//判断是否是猎豹25
int IsLieBao(void)
{
int i=0,flag1=0,flag2=0,flag3=0;
for(;i<length;i++)
if(get[i]==11) flag1=1;
else if(get[i]==12) flag2=1;
else if(get[i]==23) flag3=1;
if(flag1&&flag2&&flag3)
return 1;
else
return 0;
}
//判断是否是老虎
int IsLaoHu(void)
{
int i=0,flag1=0,flag2=0,flag3=0;
for(;i<length;i++)
if(get[i]==11) flag1=1;
else if(get[i]==13) flag2=1;
else if(get[i]==23) flag3=1;
if(flag1&&flag2&&flag3)
return 1;
else
return 0;
}
//判断是否是长颈鹿
int IsChangJiuLu(void)
{
int i=0,flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;
for(;i<length;i++)
if(get[i]==11) flag1=1;
else if(get[i]==12) flag2=1;
else if(get[i]==14) flag3=1;
else if(get[i]==15) flag4=1;
else if(get[i]==24) flag5=1;
if(flag1&&flag2&&flag3&&flag4&&flag5)
return 1;
else
return 0;
}
//判断是否是斑马
int IsBanMa(void)
{
int i=0,flag1=0,flag2=0,flag3=0;
for(;i<length;i++)
if(get[i]==13) flag1=1;
else if(get[i]==16) flag2=1;
else if(get[i]==24) flag3=1;
if(flag1&&flag2&&flag3)
return 1;
else
return 0;
}
//判断是否是鸵鸟
int IsTuoNiao(void)
{
int i=0,flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;
for(;i<length;i++)
if(get[i]==14) flag1=1;
else if(get[i]==15) flag2=1;
else if(get[i]==17) flag3=1;
else if(get[i]==18) flag4=1;
else if(get[i]==21) flag5=1;
if(flag1&&flag2&&flag3&&flag4&&flag5)
return 1;
else
return 0;
}
//判断是否是企鹅
int IsQiE(void)
{
int i=0,flag1=0,flag2=0,flag3=0,flag4=0;
for(;i<length;i++)
if(get[i]==17) flag1=1;
else if(get[i]==18) flag2=1;
else if(get[i]==19) flag3=1;
else if(get[i]==21) flag4=1;
if(flag1&&flag2&&flag3&&flag4)
return 1;
else
return 0;
}
//判断是否是海燕
int IsHaiYan(void)
{
int i=0,flag1=0,flag2=0;
for(;i<length;i++)
if(get[i]==20) flag1=1;
else if(get[i]==21) flag2=1;
if(flag1&&flag2)
return 1;
else
return 0;
}
//搜索过程,根据输入事实,利用前项推导结论
void Search(void)
{
if(IsLieBao()) target1[0]=1;
if(IsLaoHu()) target1[1]=1;
if(IsChangJiuLu()) target1[2]=1;
if(IsBanMa()) target1[3]=1;
if(IsTuoNiao()) target1[4]=1;
if(IsQiE()) target1[5]=1;
if(IsHaiYan()) target1[6]=1;
}
//输出结论
void output2(void)
{
int i=0;
for(i=0;i<7;i++)
if(target1[i]==1) targetNum++;
printf("\n\n\n");
switch(targetNum)
{
case 0:printf("不能判断动物的名称\n");break;
case 1:
{
printf("可以唯一确定动物的类型\n");
for(i=0;i<7;i++)
if(target1[i]==1)
switch(i)
{
case 0:printf("该动物是猎豹\n");break;
case 1:printf("该动物是老虎\n");break;
case 2:printf("该动物是长颈鹿\n");break;
case 3:printf("该动物是斑马\n");break;
case 4:printf("该动物是鸵鸟\n");break;
case 5:printf("该动物是企鹅\n");break;
case 6:printf("该动物是海燕\n");break;
default:break;
}
break;
}
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:printf("得出的是冲突的结论\n");break;
default:
break;
}
}
void main(void)
{
char ch;
init1();
init2();
output();
do{
reshape();
getPro();
printf("当前输入的事实数据:\n");
outputGet();
new1Num();
printf("事实数据第一次扩充后的结果:\n");
outputGet();
new2Num();
printf("事实数据第二次扩充后的结果:\n");
outputGet();
Search();
output2();
printf("\n\n是否继续,请输入Y or N\n");
ch=getchar();//此句为接收换行的字符
ch=getchar();
}while(ch=='Y'||ch=='y');
}