广州大学人工智能原理-实验三-推理系统

广州大学学生实验报告

开课学院及实验室: 计算机科学与网络工程学院电子信息楼416   2023年12月21日

学院

计算机科学与网络工程学院

年级/专业/班

*****

姓名

****

学号

****

实验课程名称

人工智能原理实验

成绩

实验项目名称

推理系统

指导老师

****

实验三  推理系统

  • 实验目的

本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。

  1. 掌握人工智能中涉及的相关概念、算法;
  2. 熟悉人工智能中的知识表示方法;
  3. 掌握问题表示、求解及编程实现;
  4. 理解谓词逻辑、子句消解的原理和应用;
  5. 理解谓词逻辑、子句消解、产生式系统的结构原理与实际应用;
  6. 掌握词逻辑、子句消解、产生式规则表示及规则库组建的实现方法;
  7. 熟悉和掌握产生式系统的运行机制,掌握基于规则推理的基本方法。

二、基本要求

  1. 实验前,复习《人工智能》课程中的有关内容。
  2. 准备好实验数据。
  3. 编程要独立完成,程序应加适当的注释。
  4. 完成实验报告。

三、实验软件

使用C或C++(Visual studio或其它开发环境)(不限制语言使用)。

四、实验内容:

【产生式推理系统的算法原理】

以动物识别系统为例,用选定的编程语言建造规则库和综合数据库,开发能进行正确的正向推理,即从已知事实出发,通过规则库求得结论。推理过程是:

  • 规则集中的规则前件与事实库中的事实进行匹配,得匹配的规则集合。
  • 从匹配规则集合中选择一条规则作为使用规则。
  • 执行使用规则的后件,将该使用规则的后件送入事实库中。
  • 重复这个过程直至达到目标。

 1 动物分类规则集

      (1)若某动物有奶,则它是哺乳动物。

      (2)若某动物有毛发,则它是哺乳动物。

      (3)若某动物有羽毛,则它是鸟。

      (4)若某动物会飞且生蛋,则它是鸟。

      (5)若某动物是哺乳动物且有爪且有犬齿且目盯前方,则它是食肉动物。

      (6)若某动物是哺乳动物且吃肉,则它是食肉动物。

      (7)若某动物是哺乳动物且有蹄,则它是有蹄动物。

      (8)若某动物是有蹄动物且反刍食物,则它是偶蹄动物。

      (9)若某动物是食肉动物且黄褐色且有黑色条纹,则它是老虎。

      (10)若某动物是食肉动物且黄褐色且有黑色斑点,则它是金钱豹。

      (11)若某动物是有蹄动物且长腿且长脖子且黄褐色且有暗斑点,则它是长颈鹿。

      (12)若某动物是有蹄动物且白色且有黑色条纹,则它是斑马。

      (13)若某动物是鸟且不会飞且长腿且长脖子且黑白色,则它是驼鸟。

      (14)若某动物是鸟且不会飞且会游泳且黑白色,则它是企鹅。

      (15)若某动物是鸟且善飞且不怕风浪,则它是海燕。

下面是该规则集所形成的(部分)推理网络:

                           图1  动物识别系统部分推理网络

2 问题描述

 由上述动物识别规则组成规则库,推理机采用正向推理算法或反向推理算法,实现对动物的查询。

如给出初始事实:

F1:某动物有毛发

F2:吃肉

F3:黄褐色

F4:有黑色条纹

目标条件为:该动物是什么?

3 规则库扩充 (选做)

    在上述规则集(Ⅰ)基础上增加以下规则集(Ⅱ)

(1)兔子:有毛发,有奶,善跳跃,唇裂;

(2)猫:有毛发,有奶,善捕鼠,脚有肉垫;

(3)犀牛:有毛发,有奶,鼻子上有角,褐色,皮糙肉后,皮糙肉厚,有蹄;

(4)熊猫:有毛发,有奶,黑眼圈,四肢短小;

(5)鹦鹉:鸟类,上嘴鹰钩,会模仿人说话;

(6)鸭子:鸟类,腿短,嘴扁平,善潜水游泳;

(7)鹰:鸟类,上嘴鹰钩,有爪,吃肉;

(8)鸭子:有羽毛,卵生,善游泳,嘴扁平,腿短;

(9)鹅:有羽毛,卵生,善潜水游泳,白色或黑色,颈长,嘴大,腿长,颈部有肉只凸起;

(10)鸦:有羽毛,卵生,黑色,嘴大;

(11)鹰:有羽毛,卵生,有爪,吃肉,上嘴鹰钩;

(12)鹦鹉:有羽毛,卵生,上嘴鹰钩,能模仿人说话;

(13)青蛙:卵生,生活在水中,生活在陆地,有皮肤呼吸,用肺呼吸,皮肤光滑,吃昆虫,会变色;

(14)蝾螈:卵生,生活在水中,生活在陆地,有皮肤呼吸,用肺呼吸,吃昆虫,皮肤粗糙,四肢扁,背部黑色;

(15)蟾蜍:卵生,生活在水中,生活在陆地,有皮肤呼吸,用肺呼吸,吃昆虫,皮肤粗糙;

(16)比目鱼:用鳃呼吸,身体有鳍,生活在海洋中,身体扁平,两眼在头部同侧;

(17)鲫鱼:用鳃呼吸,身体有鳍,生活在淡水中,身体扁平,头高尾部窄;

(18)蛇:生活在陆地,用肺呼吸,胎生,身体有鳞或甲,身体圆而细长,吃小动物;

(19)壁虎:生活在陆地,用肺呼吸,胎生,身体有鳞或甲,有四肢,尾巴细长易断,吃昆虫;

(20)乌龟:生活在陆地,用肺呼吸,胎生,身体有鳞或甲,身体圆而扁,有坚硬的壳;

(21)玳瑁:生活在陆地,用肺呼吸,胎生,身体有鳞或甲,壳为黄褐色,皮肤光滑,有黑斑;

(22)鳄鱼:生活在陆地,用肺呼吸,胎生,身体有鳞或甲,有四肢,善游泳,皮硬黑褐色。

要求在动物分类规则集(Ⅰ)的基础上添加上述22条知识,共构成29种动物的知识库系统,对原有动物分类系统进行扩充和修改。

五、学生实验报告要求

1 以产生式推理模式为基础,实现动物分类系统,推理方法采用正向推理或反向推理;

2 要求表示规则的语言必须能体现出规则前提和结论的对应关系,必须能体现出前提和结论中的逻辑关系;

3 要求能对规则库进行动态地增加、删除和修改操作(选做);

4要求有用户交互,如界面等输入要查询的初始事实、推理方法、推理中用到的规则和结论。

算法设计过程

规则集

正向推理过程

// 进行正向推理
    while (q.size()) {
        string s = q.front();
        q.pop();

        // 查找出度
        vector<string> ver = outDegree[s];
        for (auto next : ver) {
            //入度的数目加1
            currentInDegree[next].push_back(s);
            vector<string> inDegree2 = currentInDegree[next];
            for (auto ver : preCondition[next]) {
                if (inDegree2.size() >= ver.size()) {
                    int equals = 0;

                    // 入度可能重复出现了两次 要去重
                    sort(inDegree2.begin(), inDegree2.end());
                    for (int i = 0; i < (int)ver.size(); i++) {
                        for (int j = 0; j < (int)inDegree2.size(); j++) {
                            if (j > 0 && inDegree2[j] == inDegree2[j - 1]) continue; // 跳过重复的
                            if (ver[i] == inDegree2[j]) {
                                equals++;
                            }
                        }
                    }
                    // 入度足够, 能够推导出下一步
                    if (equals >= (int)ver.size()) {
                        q.push(next);
                        // 出度为0, 是最终结果
                        if (outDegree[next].size() == 0) {
                            ans.insert(next);
                        }
                        break;
                    }
                }
            }
        }

实验运行结果 :

实验选做

实验完整代码

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <iomanip>
#include <algorithm>
#include <string>
using namespace std;
map<string, vector<string>> inDegree;
map<string, vector<string>> outDegree;
map<string, vector<vector<string>>> preCondition;
set<string> st;
map<string, int> getNum;
map<int, string> getString;
int maxWordLength = 0;

/*
* 初始化 : 入度, 出度, 前提条件(多个入度推导出下一步)
*/
void init()
{

    vector<vector<string>> ver = {
        {"有奶", "哺乳动物"},
        {"有毛发", "哺乳动物"},
        {"有羽毛", "鸟"},
        {"会飞", "生蛋", "鸟"},
        {"哺乳动物", "有爪", "有犬齿", "目盯前方", "食肉动物"},
        {"哺乳动物","吃肉","食肉动物"},
        {"哺乳动物", "有蹄", "有蹄动物"},
        {"有蹄动物", "反刍食物", "偶蹄动物"},
        {"食肉动物", "黄褐色", "黑色条纹", "老虎"},
        {"食肉动物", "黄褐色", "黑色斑点","金钱豹"},
        {"有蹄动物", "长腿", "长脖子", "黄褐色", "暗斑点", "长颈鹿"},
        {"有蹄动物", "白色", "黑色条纹", "斑马"},
        {"鸟", "不会飞", "长腿", "长脖子", "黑白色", "驼鸟"},
        {"鸟", "不会飞", "会游泳", "黑白色", "企鹅"},
        {"鸟", "善飞", "不怕风浪", "海燕"},

        // 选做
        {"有毛发", "有奶", "善跳跃", "唇裂", "兔子"},
        {"有毛发", "有奶", "善捕鼠", "脚有肉垫", "猫"},
        {"有毛发", "有奶", "鼻子上有角", "褐色", "皮糙肉后", "皮糙肉厚", "有蹄", "犀牛"},
        {"有毛发", "有奶", "黑眼圈", "四肢短小", "熊猫"},
        {"鸟类", "上嘴鹰钩", "会模仿人说话", "鹦鹉"},
        {"鸟类", "腿短", "嘴扁平", "善潜水游泳", "鸭子"},
        {"鸟类", "上嘴鹰钩", "有爪", "吃肉", "鹰"},
        {"有羽毛", "卵生", "善游泳", "嘴扁平", "腿短", "鸭子"},
        {"有羽毛", "卵生", "善潜水游泳", "白色或黑色", "颈长", "嘴大", "腿长", "颈部有肉只凸起", "鹅"},
        {"有羽毛", "卵生", "黑色", "嘴大", "鸦"},
        {"有羽毛", "卵生", "有爪", "吃肉", "上嘴鹰钩", "鹰"},
        {"有羽毛", "卵生", "上嘴鹰钩", "能模仿人说话", "鹦鹉"},
        {"卵生", "生活在水中", "生活在陆地", "有皮肤呼吸", "用肺呼吸", "皮肤光滑", "吃昆虫", "会变色", "青蛙"},
        {"卵生", "生活在水中", "生活在陆地", "有皮肤呼吸", "用肺呼吸", "吃昆虫", "皮肤粗糙", "四肢扁", "背部黑色", "蝾螈"},
        {"卵生", "生活在水中", "生活在陆地", "有皮肤呼吸", "用肺呼吸", "吃昆虫", "皮肤粗糙", "蟾蜍"},
        {"用鳃呼吸", "身体有鳍", "生活在海洋中", "身体扁平", "两眼在头部同侧", "比目鱼"},
        {"用鳃呼吸", "身体有鳍", "生活在淡水中", "身体扁平", "头高尾部窄", "鲫鱼"},
        {"生活在陆地", "用肺呼吸", "胎生", "身体有鳞或甲", "身体圆而细长", "吃小动物", "蛇"},
        {"生活在陆地", "用肺呼吸", "胎生", "身体有鳞或甲", "有四肢", "尾巴细长易断", "吃昆虫", "壁虎"},
        {"生活在陆地", "用肺呼吸", "胎生", "身体有鳞或甲", "身体圆而扁", "有坚硬的壳", "乌龟"},
        {"生活在陆地", "用肺呼吸", "胎生", "身体有鳞或甲", "壳为黄褐色", "皮肤光滑", "有黑斑", "玳瑁"},
        {"生活在陆地", "用肺呼吸", "胎生", "身体有鳞或甲", "有四肢", "善游泳", "皮硬黑褐色", "鳄鱼"}

    };

    int n = ver.size();
    for (int i = 0; i < n; i++) {
        int m = ver[i].size();
        string ed = ver[i][m - 1];
        vector<string> pre;
        st.insert(ver[i][m - 1]);
        maxWordLength = max(maxWordLength, (int)ver[i][m - 1].size());
        for (int j = 0; j < m - 1; j++) {
            st.insert(ver[i][j]);
            inDegree[ed].push_back(ver[i][j]);
            outDegree[ver[i][j]].push_back(ed);
            pre.push_back(ver[i][j]);
            maxWordLength = max(maxWordLength, (int)ver[i][j].size()); 
        }

        preCondition[ed].push_back(pre);
    }

    cout << "规则集合" << endl;
    for (auto [s, matrix] : preCondition) {
        for (auto ver : matrix) {
            cout << s << ":";
            for (auto s : ver) {
                cout << s << ' ';
            }
            cout << endl;
        }
    }
    cout << endl;
    cout << "入度" << endl;
    // 输出inDegree
    for (auto [s, ver] : inDegree) {
        cout << s << ":";
        for (auto s2 : ver) {
            cout << s2 << ' ';
        }
        cout << endl;
    }
    cout << endl;
    cout << "出度" << endl;
    for (auto [s, ver] : inDegree) {
        cout << s << ":";
        for (auto s2 : ver) {
            cout << s2 << ' ';
        }
        cout << endl;
    }

    // 单词与数字之间的映射
    int idx = 1;
    for (auto s : st) {
        getNum[s] = idx;
        getString[idx] = s;
        idx++;
    }
}
int main()
{
    // 初始化
    init();

    cout << endl; 
    for (auto [idx, s] : getString) {
        string idx2 = to_string(idx);
        string s2 = idx2 + "." + s;
        cout << std::left << std::setw(maxWordLength + 1) << s2<< "\t";
        if (idx % 6 == 0) {
            cout << endl;
        }
    }
    cout << "\n输入初始事实, 输入0结束" << endl;
    int idx;
    cin >> idx;
    queue<string> q;
    while (idx != 0) {
        q.push(getString[idx]);
        cin >> idx;
    }

    map<string, vector<string>> currentInDegree; // 当前的入度信息, 如果入度达到一定数目, 那么可以推导出来
    set<string> ans; // 出度为0的string 是答案
    // 进行正向推理
    while (q.size()) {
        string s = q.front();
        q.pop();

        // 查找出度
        vector<string> ver = outDegree[s];
        for (auto next : ver) {
            //入度的数目加1
            currentInDegree[next].push_back(s);
            vector<string> inDegree2 = currentInDegree[next];
            for (auto ver : preCondition[next]) {
                if (inDegree2.size() >= ver.size()) {
                    int equals = 0;

                    // 入度可能重复出现了两次 要去重
                    sort(inDegree2.begin(), inDegree2.end());
                    for (int i = 0; i < (int)ver.size(); i++) {
                        for (int j = 0; j < (int)inDegree2.size(); j++) {
                            if (j > 0 && inDegree2[j] == inDegree2[j - 1]) continue; // 跳过重复的
                            if (ver[i] == inDegree2[j]) {
                                equals++;
                            }
                        }
                    }
                    // 入度足够, 能够推导出下一步
                    if (equals >= (int)ver.size()) {
                        q.push(next);
                        // 出度为0, 是最终结果
                        if (outDegree[next].size() == 0) {
                            ans.insert(next);
                        }
                        break;
                    }
                }
            }
        }

    }

    if (ans.size() == 0) {
        cout << "无法推理出该动物" << endl;
    }
    else {
        cout << "经过推理, 该动物可能是" << ":";
        for (auto s : ans) {
            cout << s << ", ";
        }
        cout << endl;
    }

    return 0;
}


// 91 92 57 18 0 =>兔子

  • 17
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值