基于产生式系统的小型专家系统–动物识别

一、产生式系统

  1. 产生式系统简介

产生式系统是指一组产生式相互配合,协同作用,以求得问题的解。产生式系统一般由3个基本部分组成,分别为规则库、综合数据库和推理机。

规则库又称之为知识库,是某领域知识用规则形式表示的集合,集合中包含问题初始状态以及转换为目标状态所需的所有变化规则。

综合数据库又称事实库,是用来存放当前与求解问题有关的各种信息的数据集合。包括问题的初始状态信息、目标状态信息以及在问题求解过程中产生的临时信息。

推理机又称控制系统,由一组程序组成,用来控制和协调规则库与综合数据库的运行,决定了问题的椎理方式和控制策略。

产生式系统的基本结构

产生式系统问题求解步骤一般如下:


(1)初始化综合数据库(事实库)。
(2)检测规则库中是否有与事实库相匹配的规则,若有,则执行(3),否则执行(4)。
(3)更新综合数据库,即添加步骤(2)所检测到与综合数据库匹配的规则,并将所有规则做标记。
(4)验证综合数据库是否包含解,若有,则终止求解过程,否则转(2)。
(5)若规则库中不再提供更多的所需信息,则问题求解失败,否则更新综数据库,转(2)。
  1. 产生式系统的推理方式

(1)正向推理

正向推理又称之为数据驱动式推理,从已知的事实出发,通过规则库求出结论。基本推理过程如下:

第1步,用数据库中的事实与可用规则集中所有规则的前件进行匹配,得到匹配的规则集合。
第2步,使用冲突解决算法,从匹配规则集合中选择一条规则作为启用规则。
第3步,执行启用规则的后件,将该启用规则的后件送入综合数据库或对综合数据库进行必要的修改。
第4步,重复这个过程,直到达到目标或者无可匹配规则为止。

(3)逆向推理

逆向推理也称之为目标驱动方式推理,它从目标出发,反向使用规则,求得已知事实。其推理过程如下:

第1步,用规则库中的规则后件与目标事实进行匹配,得到匹配的规则集合。
第2步,使用冲突解决算法,从匹配规则集合中选择一条规则作为启用规则。
第3步,将启用规则的前件作为子目标。
第4步,重复这个过程,直至各子目标均为已知事实为止。

(3)双向推理

双向推理是一种既自顶向下又自底向上的推理。推理从两个方向同时进行,直至某个中间界面上双方向结果相符便成功结束。不难想象,这种双向推理较正向或反向推理形成的推理网络小,从而推理效率更高。

二、产生式系统举例

1.动物识别系统

该系统可以识别老虎、金钱豹、斑马、长颈鹿、企鹅、信天翁这6种动物。
其规则库包含如下15条规则:
r1: IF 该动物有毛发 THEN 该动物是哺乳动物
r2: IF 该动物有奶 THEN 该动物是哺乳动物
r3: IF 该动物有羽毛 THEN 该动物是鸟
r4: IF 该动物会飞 AND 会下蛋 THEN 该动物是鸟
r5: IF 该动物吃肉 THEN 该动物是食肉动物
r6: IF 该动物有犬齿 AND 有爪 AND 眼盯前方 THEN 该动物是食肉动物
r7: IF 该动物是哺乳动物 AND 有蹄 THEN 该动物是有蹄类动物
r8: IF 该动物是哺乳动物 AND 是嚼反刍动物 THEN 该动物是有蹄类动物
r9: IF 该动物是哺乳动物 AND 是食肉动物 AND 是黄褐色 AND 身上有暗斑点 THEN 该动物是金钱豹
r10: IF 该动物是哺乳动物 AND 是食肉动物 AND 是黄褐色 AND 身上有黑色条纹 THEN 该动物是虎
r11: IF 该动物是有蹄类动物 AND 有长脖子 AND 有长腿 AND 身上有暗斑点 THEN 该动物是长颈鹿
r12: IF 动物是有蹄类动物 AND 身上有黑色条纹 THEN 该动物是斑马
r13: IF 该动物是鸟 AND 有长脖子 AND 有长腿 AND 不会飞 AND 有黑白二色 THEN 该动物是鸵鸟
r14: IF 该动物是鸟 AND 会游泳 AND 不会飞 AND 有黑白二色 THEN 该动物是企鹅
r15:IF 该动物是鸟AND善飞 THEN 该动物是信天翁

根据以上规则库进行长颈鹿的动物识别,推理之前,给出综合数据库的事实如下:动物有暗斑,有长脖子,有长腿,有奶,有蹄。推理过程如下:

(1)根据有奶,利用规则r2推出动物是哺乳动物;

(2)根据哺乳动物和有蹄,利用规则r7推出是蹄类动物;

(3)根据蹄类动物、有暗斑、有长脖、有长腿,利用规则r11推出是长颈鹿。

2.代码实现

#include<iostream>
#include<iomanip>
using namespace std;
char *animal[]={"企鹅","信天翁","鸵鸟","斑马","长颈鹿","虎","金钱豹"};
char *feature[]={"有毛","产奶","有羽毛","会飞","会下蛋","吃肉","有犬齿","有爪","眼睛盯前方","有蹄","反刍","黄褐色","有斑点",
        //0 1 2 3 4 5 6 7 8 9 10 11 12
        "有黑色条纹","长脖","长腿","不会飞","会游泳","黑白两色","善飞","哺乳类","鸟类","肉食类","蹄类",
        //13 14 15 16 17 18 19 20 21 22 23
        "企鹅","信天翁","鸵鸟","斑马","长颈鹿","虎","金钱豹"};
//24 25 26 27 28 29 30
typedef struct //存放规则的结构体
{
    int relation[5];
    int name;
}Rule;
Rule rule[15]={
        {{0,-1},20},
        {{1,-1},20},
        {{2,-1},21},
        {{3,4,-1},21},
        {{20,5,-1},22},
        {{6,7,8,-1},22},
        {{20,9,-1},23},
        {{20,10,-1},23},
        {{20,22,11,12,-1},30},
        {{20,22,11,13,-1},29},
        {{23,14,15,12,-1},28},
        {{23,13,-1},27},
        {{21,14,15,16,-1},26},
        {{21,17,18,16,-1},24},
        {{21,19,-1},25}};
int flag[23]={0};//标记各个特征是否选择
int IsAnimal(int a);
int inference();
void input();
void menu();
void menu()
{
    int i=0;
    for(i=0;i<24;i++)
    {
        if(i%4==0&&i!=0)
        {
            cout<<endl;
        }
        printf("%-3d.%-15s",i,feature[i]);
        //%s ,它的原理其实也是通过字符串首地址输出字符串,printf("%s ", s); 传给它的其实是s所保存的字符串的地址
    }
}
void input()
{
    int ti=0;
    for(int i=0;i<24;i++)
    {
        flag[i]=0;
    }
    while(ti!=-1)
    {
        cout<<"\n 输入选择(-1 结束):";
        cin>> ti;
        if(ti>=0&&ti<=23)
            flag[ti]=1;
        else if(ti!=-1)
        {
            cout<<"输入错误!请输入 0~23 之间的数字!"<< endl; //notanimal=25
            cin.clear();//清除流错误错误标
            cin.sync(); 清空输入缓冲区
        }
    }
}
int IsAnimal(int a)
{
    if(a>=24&&a<=30)
        return 1;
    else
        return 0;
}
int inference()//正向推理
{
    int ti;
    int i,j;
    int tres;
    cout<<endl;
    for(i=0;i<15;i++)
    {
        j=0;
        ti=rule[i].relation[j];
        while(ti!=-1) //-1 作为结束
        {
            if(flag[ti]==0)
                break;
            j++;
            ti=rule[i].relation[j];
        }
        if(ti==-1)//ti==-1 代表规则满足
        {
            tres=rule[i].name;
            flag[tres]=1;
            printf("运用了规则%d : ",i+1);
            j=0;
            while(rule[i].relation[j]!=-1)
            {
                cout<<feature[rule[i].relation[j]]<<" ";
                j++;
            }
            cout<<"====> "<<feature[tres]<<endl;
            if(IsAnimal(tres))
            {
                return 1;
            }
        }
    }
    if(i==15)
    {
        cout<<"没有这种动物";
    }
    return -1;
}
int main()
{
    char q;
    while(q!='n')
    {
        menu();
        input();
        inference();
        cout<<"\n 继续?(Y/N)"<<endl;
        cin>>q;
        system("cls");
    }
}

3.结果显示

三、总结

产生式系统具备自然性、模块性、清晰性、有效性的特点,但是也存在着效率低,不便于表示结构性知识、难以拓展、控制饱和的问题等缺点。在现实中,对于专家系统的选取,应当结合实际情况进行,选择最适用性高并且效率高的系统。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年6月21日
下一篇 2023年6月21日

相关推荐