广州大学学生实验报告
开课学院及实验室: 计算机科学与网络工程学院电子信息楼416 2023年12月21日
学院
计算机科学与网络工程学院
年级/专业/班
姓名
学号
实验课程名称
人工智能原理实验
成绩
实验项目名称
推理系统
指导老师
实验三 推理系统
- 实验目的
本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。
- 掌握人工智能中涉及的相关概念、算法;
- 熟悉人工智能中的知识表示方法;
- 掌握问题表示、求解及编程实现;
- 理解谓词逻辑、子句消解的原理和应用;
- 理解谓词逻辑、子句消解、产生式系统的结构原理与实际应用;
- 掌握词逻辑、子句消解、产生式规则表示及规则库组建的实现方法;
- 熟悉和掌握产生式系统的运行机制,掌握基于规则推理的基本方法。
二、基本要求
- 实验前,复习《人工智能》课程中的有关内容。
- 准备好实验数据。
- 编程要独立完成,程序应加适当的注释。
- 完成实验报告。
三、实验软件
使用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 =>兔子
版权归原作者 Eren Yeager1 所有, 如有侵权,请联系我们删除。