基于产生式系统方法实现动物识别系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lidengdengter/article/details/90462624

1   产生式系统用来描述若干个不同的以一个基本概念为基础的系统。这个基本概念就是产生式规则或产生式条件和操作对象的概念。

2   在产生式系统中,论域的知识分为两部份:

     (1)事实:用于表示静态知识,如事物、事件和它们之间的关系;

     (2)规则:用于表示推理过程和行为

3   一个产生式系统由三个部分组成,如图所示:

     (1)综合数据库:用来存放与求解问题有关的数据以及推理过程环境的当前状态的描述。

     (2)产生式规则库:主要存放问题求解中的规则。

     (3)控制策略:其作用是说明下一步应该选用什么规则,也就是说如何应用规则。


规则库:

规则号 前提 结论
r1 该动物有毛发 是哺乳动物
r2 该动物有奶

是哺乳动物

r3 该动物有羽毛

是鸟

r4 该动物会飞   AND  会下蛋 是鸟
r5 该动物吃肉

是食肉动物

r6

该动物有犬齿  AND  有爪  AND  眼盯前方

是食肉动物
r7

该动物是哺乳动物  AND  有蹄 

是蹄类动物

r8

 该动物是哺乳动物  AND  是反刍动物 

是蹄类动物

r9

该动物是哺乳动物   AND  是食肉动物 AND  是黄褐色  AND  身上有暗斑点

是金钱豹
r10

该动物是哺乳动物   AND  是食肉动物  AND  是黄褐色  AND  身上有黑色条纹

是虎
r11

该动物是蹄类动物   AND  有长脖子  AND  有长腿  AND  身上有暗斑点

是长颈鹿  
r12 该动物是蹄类动物  AND  身上有黑色条纹

是斑马

r13

该动物是鸟   AND  有长脖子  AND  有长腿 AND  不会飞  AND  有黑白二色

是鸵鸟

r14

该动物是鸟  AND 会游泳 AND 不会飞  AND  有黑白二色

是企鹅    
r15 该动物是鸟   AND  善飞

是信天翁


1、知识表示

将规则中的动物特征前提事实和动物结论分别以features.txt和animals.txt存入,将规则库写入ruleBase.txt中。 


2、状态空间


3、程序清单

test1.h 

#include<bits/stdc++.h>
using namespace std;
const int MAX_SIZE=50;

struct Node{  				//特征类 
	int id; 				//编号
	char name[MAX_SIZE];  	//名称 
};

struct Statu{ 		//状态类 
	int statu; 		//0未使用 1使用过一次 2没有使用但不影响 
	int id; 
}; //可替换修改

struct Fact{ 				//数据库 
	int st_num; 			//初始事实数
	int now_num; 			//当前事实数,不断更新加入中间结论
	int neFlag; 			//条件不足置1 
	Statu data[MAX_SIZE]; 	//特征数组 
};  

struct Rule{  			//规则库 
	int result; 		//最终结论
	int data_num; 		//前提个数
	int id_set[10]; 	//前提编号数组 
	int matched;  		//是否已匹配成功  0 1
}rule[MAX_SIZE]; 		//规则库 

Node goal[20];			//目标动物
Node data[MAX_SIZE];	//特征数据
Fact indata;  			//输入数据 
int rule_num=0; 		//规则条数
int data_num=24; 		//特征数

test1.cpp

#include<bits/stdc++.h>
#include "test1.h"
using namespace std;

void readFeature(){ //读取特征库 
	FILE *fp;
	if((fp=fopen("features.txt","r"))==NULL){
		printf("Cant open features.txt!\n");
		exit(0);
	}
	
	int i=0;
	while((fscanf(fp,"%d %s",&data[i].id,&data[i].name))!=EOF) i++; //读入
	
	fclose(fp); 
}

void readRule(){ //读取规则库 
	FILE *fp;
	if((fp=fopen("ruleBase.txt","r"))==NULL){
		printf("Cant open ruleBase.txt!\n");
		exit(0);
	} 
	
	int i=0;
	char ch;
	rule[i].data_num=0;  
	
	int t=1;
	while((ch=fgetc(fp))!=EOF){ //文件结尾 
		int cnt=0; //规则前提个数 
		while(ch!='\n'&&ch!=EOF){ //每一条规则 
			int tmp_id=0;
			
			while(ch>='0'&&ch<='9'){ 
				tmp_id=tmp_id*10+ch-'0';
				ch=fgetc(fp);
			} 
			rule[i].id_set[cnt++]=tmp_id;
			
			tmp_id=0; //处理结论
			if(ch=='='){
				ch=fgetc(fp);
				while(ch>='0'&&ch<='9'){
					tmp_id=tmp_id*10+ch-'0';
					ch=fgetc(fp);
				}
				rule[i].result=tmp_id;
			}
			else if(ch=='&') ch=fgetc(fp);	
		}

		rule[i].data_num=cnt; //该规则前提数 
		i++;
	} 
	rule_num=i; //规则条数 

	fclose(fp);
//	for(int i=0;i<rule_num;i++){
//		for(int j=0;j<rule[i].data_num;j++){
//			printf("%s",data[rule[i].id_set[j]].name);
//			printf("%c",j==rule[i].data_num-1?'=':'&');
//		}
//		printf("%s\n",data[rule[i].result].name);
//	}
}

void readAnimal(){ //读取目标库 
	FILE *fp;
	if((fp=fopen("animals.txt","r"))==NULL){
		printf("Cant open animals.txt!\n");
		exit(0);
	}
	
	int i=0;
	while((fscanf(fp,"%d %s",&goal[i].id,&goal[i].name))!=EOF) i++; //读入
	fclose(fp); 
}

int valueInput(){ //输入是否有效 
	int tmp; //输入序号
	int cnt=0,inflag=1; //特征数,有效输入标记 
	
	do{
		scanf("%d",&tmp);
		indata.data[cnt++].id=tmp;
		if(tmp>=data_num||tmp<-1){ //越界 
			printf("特征序号只能在0-%d之间,请重新输入:\n",data_num-1);
			fflush(stdin);
			inflag=0; 
		} 
	}while(tmp!=-1&&tmp<data_num&&tmp>=0);
	
	indata.st_num=cnt-1; //输入的特征数
	indata.now_num=indata.st_num;
	
	return inflag; 
} 

int isOther(int in_id,int result){ //消解冲突 
	int queue[MAX_SIZE],vis[MAX_SIZE]; //加入队列标记 
	int head=0,tail=1;
	int flag=0;
	
	queue[0]=result; vis[result]=1;
	while(head!=tail&&flag!=1){
		for(int i=0;i<rule_num;i++)
			if(queue[head]==rule[i].result){ //结果匹配规则结论 
				for(int j=0;j<rule[i].data_num;j++)
					if(indata.data[in_id].id==rule[i].id_set[j])
						flag=1;
					else{
						if(vis[rule[i].id_set[j]]!=1){
							queue[tail++]=rule[i].id_set[j];
							vis[rule[i].id_set[j]]=1;
						}
					}
			}
		head++;
	}
	return flag;
} 

bool isContract(int result){ //是否冲突 
	for(int i=0;i<indata.now_num;i++)
		if(indata.data[i].statu==0&&indata.data[i].id!=result){ //未访问的输入特征 
			if(isOther(i,result))
				indata.data[i].statu=2;
			else
				return true;
		}
	return false;
}

void isMatch(int result,int *finish){ //匹配最终结论
	if(result >=data_num){ //已推理出动物 
		*finish=1; //任务完成 
		if(isContract(result))
			printf("条件冲突,没有这样的动物!\n");
		else
			printf("它是 %s.\n",goal[result-data_num].name); 
	} 
	
}

void addToFact(int rule_id,int *finish){ //匹配更新 
	for(int i=0;i<rule[rule_id].data_num;i++) //标记访问
		for(int k=0;k<indata.now_num;k++)
			if(indata.data[k].id==rule[rule_id].id_set[i])
				indata.data[k].statu=1;
	
	
	
	rule[rule_id].matched=1; 
	
	int vis=0;  //标记结论是否存在 
	for(int i=0;i<indata.now_num;i++)
		if(indata.data[i].id==rule[rule_id].result){  //匹配结论
			vis=1;break;
		} 
	
	if(vis==0){
		indata.data[indata.now_num].id=rule[rule_id].result;
		//printf("add the %d\n",indata.data[indata.now_num].id);
		indata.now_num++;
	}
	
	isMatch(rule[rule_id].result,finish);
}

void count_unum(int *unusef,int *u_num){ //未访问特征数 
	int vis[MAX_SIZE]; //未访问事实加组标记 
	memset(vis,0,sizeof(vis));
	
	for(int i=0;i<indata.now_num;i++){
		if(indata.data[i].statu==0&&vis[indata.data[i].id]!=1){
			unusef[*u_num]=indata.data[i].id;
			++(*u_num);
			vis[indata.data[i].id]=1;
		}
	}
		
}

void mayMatch(int tflag,int rule_id,int *getflag){ //匹配可能性结论 
	Node *res;
	int res_id;
	res=data;
	//printf("result=%d\n",rule[rule_id].result);
	res_id=rule[rule_id].result;
	getflag[rule[rule_id].result]=1;
	
	if(res_id>23){
		res=goal;
		res_id-=24;
	}
	
	if(tflag==0)
		printf("条件不完全,但它有%s",res[res_id].name);
	else
		printf("和%s",res[res_id].name);
}

void guess(){ //可能结论 
	int tflag,ecnt; //相同个数
	int unusef[MAX_SIZE],u_num=0;
	int getflag[MAX_SIZE];//若已推出这个"可能结论",就置为1
	memset(getflag,0,sizeof(getflag));
	
	count_unum(unusef,&u_num);
		
	tflag=0;
	for(int i=0;i<rule_num;i++){
		ecnt=0;
		for(int j=0;j<rule[i].data_num;j++)
			for(int k=0;k<u_num;k++)
				if(unusef[k]==rule[i].id_set[j])
					ecnt++;
		if(ecnt*2>=rule[i].data_num&&getflag[rule[i].result]!=1){
			mayMatch(tflag,i,getflag);
			tflag=1;
		}
	} 
	if(tflag==0)
		printf("条件不足,不能推出它是什么动物!\n");
	else
		printf("的部分特征.\n");
}

void forwardWork(){ //正向推理 
	int finish=0; //推理是否完成 0 1
	int factNew=1; //一次推理是否得出新事实
	int fitFlag; //1 可推理 
	int fitPart;  //1 部分符合 
	 
	while(!finish&&factNew==1){
		factNew=0;
		
		for(int i=0;i<rule_num&&rule[i].matched!=1&&finish==0;i++){  //取出一条规则 
			if(indata.now_num>=rule[i].data_num){  //现有事实数不小于当前规则条件数 
				fitFlag=1;
				for(int j=0;j<rule[i].data_num&&fitFlag==1;j++){ //比较是否匹配该规则  
					fitPart=0;
					for(int k=0;k<indata.now_num;k++)
						if(indata.data[k].id==rule[i].id_set[j])
							fitPart=1; //部分匹配 
					fitFlag=fitPart; 
				}
				
				if(fitFlag==1){ //与该规则匹配 
					//printf("匹配第%d条规则\n",i);
					factNew=1;
					addToFact(i,&finish); //更新到事实库 
					fitFlag=0;
				} 
			}
		}
	} 
	if(factNew==0) //当没有推出任何动物,看是否极有可能得出一些结论 
		guess(); 
}

main.cpp

#include<bits/stdc++.h>
#include "test1.cpp"
using namespace std;

void read(){ //读取库 
	//读取文件 
	readFeature();
	readRule();
	readAnimal();
} 

void init(){ //初始化状态值 	
	for(int i=0;i<MAX_SIZE;i++){
		rule[i].matched=0; //未匹配成功
		indata.neFlag=0;   
		indata.data[i].statu=0; //特征未访问 
	}
}

void interface(){ //界面 
	printf("\n\t******************动物识别系统******************\t\n\n\t");
	for(int i=0,j=1;i<data_num;i++,j++){
		printf("[%2d] %-12s",data[i].id,data[i].name);
		if(j%3==0) printf("\n\t");
	}
	printf("\n\t***********************************************\t\n");
}

int main(){ //处理主函数  
	read(); 
	char ch; 
	do {
		init();
		system("cls");
		interface();
		
		printf("请输入已知动物特征的序号,以-1结束:\n");
		while(valueInput()==0); //直到输入有效

		forwardWork();	//正向推理

		printf("\n按任意键继续,按'n'或'N'退出:");
		ch=getchar();ch=getchar();
	} while(ch!='n'&&ch!='N');  //结束标记
	return 0; 
}
 

猜你喜欢

转载自blog.csdn.net/lidengdengter/article/details/90462624