length() 函数返回的是无符号数,当其与int型负数比较时,结果是错误的,-1> (unsign)2;
用基于产生式系统的方法求解动物识别系统的实现。 以一个动物识别系统为例,构造产生式系统求解问题的过程,识别虎、金钱豹、斑马、长颈鹿、鸵鸟、企鹅、信天翁等七种动物的产生式系统。
在产生式系统中,论域的知识分为两部份:
(1)事实:用于表示静态知识,如事物、事件和它们之间的关系;
(2)规则:用于表示推理过程和行为一个产生式系统由三个部分组成,
如图所示:
总数据库:用来存放与求解问题有关的数据以及推理过程环境的当前状态的描述。
产生式规则库:主要存放问题求解中的规则。
(3)控制策略:其作用是说明下一步应该选用什么规则,也就是说如何应用规则。
通常从选择规则到执行操作分三步:
(1)匹配:把当前数据库和规则的条件部分相匹配。如果两者完全匹配,则把这条规则称为触发规则。
(2)冲突解决:当有一个以上的规则条件部分和当前数据库相匹配时,就需要解决首先使用哪一条规则——冲突解决。
1、专一性排序:如果某一规则的条件部分比另一条规则的条件部分所规定的情况更为专门,则这条规则有较高的优先权。
2、规则排序:如果规则编排顺序就表示了启用的优先级,则称之为排序。
3、数据排序:把规则条件部分的所有条件按优先级次序编排起来,运行时首先使用在条件部分包含较高优先级数据的规则。
4、规模排序:按规则的条件部分的规模排列优先级,优先使用被满足的条件较多的规则。5)就近排序:把最近使用的规则放在最优先的位置。
6、上下文限制:把产生式规则按他们所描述的上下文分组,也就是说按上下文对规则分组,在某种上下文条件下,只能从与其相对应的那组规则中选择可应用的规则。
7、使用次数排序:把使用频率较高的排在前面。
首先要建立规则数据库,创建规则结构体来存放一条规则,要结构体数组来表示规则数据库
typedef struct rules{//规则结构体,一个结构体表示一条规则,规则库由一组规则结构体构成
string rule[maxsize];//规则结构体,一个结构体表示一条规则,规则库由一组规则结构体构成
int symble_count=0;
string result; //存放规则的结论
int flag = 0;//用于标记规则是否已匹配过
}R;
而后建立综合数据库,综合数据库用结构体表示。内部包含string数组,用于存储状态。用栈的形式存储,int型指针top指向栈顶。每次匹配规则时从栈顶开始匹配,直到栈底,如此便可以根据最新的状态来匹配规则。
typedef struct status{//用结构体来表示总数据库 ,声明为栈形式
string sta[maxsize];
int top = -1;
}S;
先贴上所有的代码,还需说明的是:字符串匹配时本用的是KMP算法,但是事倍功半,KMP算法在此次应用里并不能提高效率,于是便将KMP改写为普通的模式匹配算法。
另外:由于是字符串的模式匹配,所以动物特征 “蹄” 与 “有蹄类动物” 是可以匹配成功的,为了防止出现这样的错误,可以将动物特征“蹄”改为“蹄子”,以区别。而在这个算法里,采用了从栈顶开始匹配的方式,避开了这类错误。
#include <stdio.h>
#include <string.h>
#include <string >
#include <algorithm>
#include <stdlib.h>
#include <iostream>
using namespace std;
#define maxsize 10
int math_symble = 0;//匹配的特征数
int mate_count = 0;//用于判断指针的top是否改变
typedef struct rules{//规则结构体,一个结构体表示一条规则,规则库由一组规则结构体构成
string rule[maxsize];//用于存放每条规则的条件,如 有羽毛、会飞
int symble_count=0;
string result; //存放规则的结论
int flag = 0;//用于标记规则是否已匹配过
}R;
R Rules[20];
typedef struct status{//用结构体来表示总数据库 ,声明为栈形式
string sta[maxsize];
int top = -1;
}S;
void inistatus(S &s){//初始化综合数据库函数
cout << "input initial statues" << endl;
string str;
while(cin >> str) {
s.sta[++s.top] = str;
}
}
void visit_sta(S s){
for(int i = s.top; i >= 0 ; i--)
cout << s.sta[i] << " ";
}
void create_rule(R *rules){
rules[0].rule[0] = "该动物有毛发";
rules[0].result = "该动物是哺乳动物";
rules[0].symble_count = 1;
rules[1].rule[0] = "该动物有奶";
rules[1].result = "该动物是哺乳动物";
rules[1].symble_count = 1;
rules[2].rule[0] = "该动物有羽毛";
rules[2].result = "该动物是鸟";
rules[2].symble_count = 1;
rules[3].rule[0] = "该动物会飞";
rules[3].rule[1] = "会下蛋";
rules[3].result = "该动物是鸟";
rules[3].symble_count = 2;
rules[4].rule[0] = "该动物吃肉";
rules[4].result = "该动物是食肉动物";
rules[4].symble_count = 1;
rules[5].rule[0] = "该动物有犬齿";
rules[5].rule[1] = "有爪";
rules[5].rule[2] = "眼盯前方";
rules[5].result = "该动物是食肉动物";
rules[5].symble_count = 3;
rules[6].rule[0] = "该动物是哺乳动物";
rules[6].rule[1] = "有蹄";
rules[6].result = "该动物是有蹄类动物";
rules[6].symble_count = 2;
rules[7].rule[0] = "该动物是哺乳动物";
rules[7].rule[1] = "是反刍动物";
rules[7].result = "该动物是有蹄类动物";
rules[7].symble_count = 2;
rules[8].rule[0] = "该动物是哺乳动物";
rules[8].rule[1] = "是食肉动物";
rules[8].rule[2] = "是黄褐色";
rules[8].rule[3] = "身上有暗斑点";
rules[8].result = "该动物是金钱豹";
rules[8].symble_count = 4;
rules[9].rule[0] = "该动物是哺乳动物";
rules[9].rule[1] = "是食肉动物";
rules[9].rule[2] = "是黄褐色";
rules[9].rule[3] = "身上有黑色条纹";
rules[9].result = "该动物是虎";
rules[9].symble_count = 4;
rules[10].rule[0] = "该动物是有蹄类动物";
rules[10].rule[1] = "有长脖子";
rules[10].rule[2] = "有长腿";
rules[10].rule[3] = "身上有暗斑点";
rules[10].result = "该动物是长颈鹿";
rules[10].symble_count = 4;
rules[11].rule[0] = "该动物是有蹄类动物";
rules[11].rule[1] = "身上有黑色条纹";
rules[11].result = "该动物是斑马";
rules[11].symble_count = 2;
rules[12].rule[0] = "该动物是鸟";
rules[12].rule[1] = "有长脖子";
rules[12].rule[2] = "有长腿";
rules[12].rule[3] = "不会飞";
rules[12].rule[4] = "有黑白二色";
rules[12].result = "该动物是鸵鸟";
rules[12].symble_count = 5;
rules[13].rule[0] = "该动物是鸟";
rules[13].rule[1] = "会游泳";
rules[13].rule[2] = "不会飞";
rules[13].rule[3] = "有黑白二色";
rules[13].result = "该动物是企鹅";
rules[13].symble_count = 4;
rules[14].rule[0] = "该动物是鸟";
rules[14].rule[1] = "善飞";
rules[14].result = "该动物是信天翁";
rules[14].symble_count = 2;
}
void visit(R rules[],int n){
cout << "rule" << n+1 << ": " << endl;
for(int i = 0 ; i < rules[n].symble_count; ++i){
cout << rules[n].rule[i] << endl;
}
cout << rules[n].result<< endl;
}
int KMP(string s1, string s2){// 函数: KMP算法 ,本欲使用KMP算法,但是匹配串不会出现子句重叠,故改为普通字符串匹配
int i = 0, j = 0,k = 0;
/*while(i < (int)s1.length() && j < (int)s2.length()){
if(j == -1 || s1[i] == s2[j]){
++i;
++j;
}
else
j = next[j];
}
cout << j <<endl;
cout << (int) s2.length() << endl;*/
while(i < (int)s1.length() && j < (int)s2.length()){
if(s1[i] != s2[j]){
++k;
i = k;
j = 0;
}
else {
++i;
++j;
}
}
//cout << i << " " << j <<endl;
if(j+1 > (int)s2.length())
return 1;
else return 0;
}
void math(S &s, R *rules,int n){//n为规则库里的第n条规则匹配
math_symble = 0;//变量清0 ;
for(int i = 0 ; i < rules[n].symble_count; ++i){
for(int j = s.top; j >= 0 ; j--){//动物特征—蹄 会与有蹄类动物匹配成功,防止与规则11,12直接匹配,匹配时从最新的特征开始匹配
if(KMP(rules[n].rule[i],s.sta[j]) == 1){
math_symble ++;
}
}
if(math_symble == rules[n].symble_count){
cout << "与规则 " << n+1 << " 匹配" << endl;
rules[n].flag = 1;
s.sta[++s.top] = rules[n].result;
//visit_sta(s);
//cout << endl;
cout << endl;
}
}
}
int main (){
create_rule(Rules);
S s;
inistatus(s);
while(true){
for(int i = 0; i < 15; ++i){
if(Rules[i].flag != 1)
math(s,Rules,i);
if(s.top > mate_count)
break;
}
if(KMP(s.sta[s.top],"信天翁") == 1 || KMP(s.sta[s.top],"长颈鹿") == 1 || KMP(s.sta[s.top],"斑马") == 1 || KMP(s.sta[s.top],"金钱豹") == 1 || KMP(s.sta[s.top],"虎") == 1 || KMP(s.sta[s.top],"企鹅") == 1 || KMP(s.sta[s.top],"鸵鸟") == 1 ){
cout << "匹配成功:" << s.sta[s.top] << endl;
break;
}
mate_count = s.top;
}
return 0;
}
控制策略:选择与总数据库最先匹配的一条规则,然后更新综合数据库,即入栈规则结论 ,然后检查是否识别出动物了,识别出则结束,否则继续
冲突:没有明显的冲突策略,规则库排序,选择最先匹配的一条即可消除冲突。从栈顶开始匹配特征,可以避免蹄 与 有蹄类动物 匹配成功。
虽然简单实现了,但测试样本过少,可能存在未发现的bug。笔者能力不足,如若有何错误请指教。