📌 摘要

在人工智能学习过程中,产生式系统是最直观的知识表示与推理方法之一。本实验以动物疾病诊断为应用场景,结合正向推理与反向推理,设计并实现了一个基于规则的智能系统。通过 Python 与 PySide2 的 GUI 界面开发,不仅完成了规则库与事实库的搭建,还实现了用户交互式的疾病诊断。本文将详细介绍实验原理、设计思路、实现步骤与心得体会,帮助读者快速理解产生式系统的运行机制。


📝 正文

一、实验背景

产生式系统是一类典型的基于规则的知识表示与推理系统。在人工智能中,它广泛应用于分类、诊断与预测。本实验旨在通过实际编程,掌握正向推理和反向推理的机制,并尝试将其应用于动物疾病诊断问题。


二、实验目的

  • 熟悉一阶谓词逻辑和产生式表示方法

  • 掌握产生式系统的运行机制

  • 理解正向推理与反向推理的算法思想

  • 通过编程实现一个小型的智能诊断系统


三、实验原理

1. 正向推理

从初始已知事实出发,根据匹配规则不断推导新事实,直到得出结论或规则无法扩展。
基本过程:

  1. 初始化数据库 DATA

  2. 选择与 DATA 匹配的规则

  3. 将推理结果加入 DATA

  4. 重复直到得出结论

2. 反向推理

从目标假设出发,反向搜索支撑该假设的证据。若证据均能在事实库中找到,则假设成立。
基本过程:

  1. 假设目标 G

  2. 检查 G 是否在事实库

  3. 若不在,则寻找能推出 G 的规则,并对左部条件递归验证

  4. 若存在成功匹配,则假设成立


四、实验流程图

正向推理流程图:

反向推理流程图:

五、实验内容与实现

1. 数据库设计

存储动物疾病(如心脏病、肾脏病、犬瘟、细小等)、个体特征及规则。

个体名称:

所有特征:

规则库:

2. 规则库建立

规则形式采用条件 → 结论,例如:

异常举动 + 精神不振 + 流涕发烧  →  传染病
传染病 + 似肠胃炎 + cpv阳性  →  细小

3. 正向推理流程

(1)确定初始事实,输入一系列结论。

(2)匹配规则:产生式系统会将初始事实与产生式规则进行匹配,找到与初始事实相关的规则。

(3)执行规则:如果找到了与初始事实相关的规则,产生式系统会执行该规则。

(4)生成新事实

(5)重复匹配和执行:产生式系统会将新的事实作为初始事实,继续匹配和执行规则,直到无法再生成新的事实为止。

(6)输出结果:最终,产生式系统会输出所有生成的事实,即推断出的结论,例如,该人是成年人。

总的来说,产生式系统正向推理的过程就是根据已知的事实,通过匹配和执行规则,推断出新的结论,不断重复这个过程,直到无法再生成新的结论为止。

反向推理:

综合数据库存储初始已知事实,控制系统将其与已有知识进行匹配,被触发的知识,将其结论作为新的事实添加到综合数据库中。重复上述过程,用更新过的综合数据库中的事实再与知识库中另一条知识匹配,将其结论更新至综合数据库中,直到没有可匹配的新知识和不再有新的事实加入到综合数据库中为止。根据最终的综合数据库得到结论,判断是否得到疾病名称,是则返回疾病名称,否则提示该系统中未找到匹配对象。

4. 反向推理流程
  • 输入目标疾病

  • 检查数据库与规则库

  • 逐层回溯验证

  • 最终给出推理是否成功

5. GUI 界面实现

使用 PySide2 开发交互界面,支持:

  • 输入特征进行正向推理

  • 输入目标进行反向推理

  • 动态展示规则与数据库内容

  • 添加新规则


五、实验结果

正向推理案例

输入:异常举动 + 精神不振 + 流涕发烧 + 似肠胃炎 + cpv阳性
推理过程:

  • 得到结论“传染病”

  • 进一步推理得出“细小”

反向推理案例

目标:犬瘟

  • 若输入特征满足规则 → 推理成功

  • 若不满足 → 返回失败并提示缺失特征


六、实验总结与心得

这是人工智能课程的第一个从理论走向实践的实验。通过亲手搭建规则库并实现正向与反向推理,我对产生式系统的运行机制有了深刻理解。

  • 正向推理:思路清晰,易于实现

  • 反向推理:更具挑战,需要递归思考

  • GUI开发:通过 PySide2 首次尝试交互界面设计,加深了实践能力

总体而言,本实验让我在理论与实践之间搭建了桥梁,提升了动手能力,也为后续更复杂的人工智能实验奠定了基础。


七、实验代码

from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton
from PySide2.QtWidgets import QPlainTextEdit
from PySide2.QtWidgets import QMessageBox

Names = []
Feature = []
Rules = []
dy_data = []# 综合数据库
tested_1 = []
tested_2 = []
tested2 = []
num = []
sg =[]
dydata=[]
Init=[]
InitInit=[]
mid_result = []
midresult=[]
weici1 = '1'
weici2 = '2'

class GUI():
    def __init__(self):

        self.window = QMainWindow()# 创建主窗口,定义主窗口
        self.window.resize(800, 500)# 定义初始化大小
        self.window.move(300, 310)# 启动程序的窗口位置,距离左边和上边的距离
        self.window.setWindowTitle('动物疾病产生式系统')  # 窗口标题栏名称

        self.textEdit7 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit7.setPlaceholderText("请输入系统谓词1)")
        self.textEdit7.move(230, 450)
        self.textEdit7.resize(120, 30)

        self.textEdit8 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit8.setPlaceholderText("请输入系统谓词2)")
        self.textEdit8.move(360, 450)
        self.textEdit8.resize(120, 30)

        self.textEdit = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit.setPlaceholderText("请输入已有特征信息的序号(以空格分隔)")
        self.textEdit.move(220, 50)
        self.textEdit.resize(100, 300)

        info = []
        for i in range(len(Feature)):
            s = "%d: %s " % (i + 1, Feature[i])
            info.append(s)
        self.textEdit2 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit2.setPlainText(str(info))
        self.textEdit2.move(10, 50)
        self.textEdit2.resize(200, 300)

        self.textEdit3 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit3.setPlainText('所有特征')
        self.textEdit3.move(10, 15)
        self.textEdit3.resize(120, 30)

        self.textEdit4 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit4.move(430, 50)
        self.textEdit4.resize(350, 300)

        self.button1 = QPushButton('正向推理', self.window)# 创建按钮
        self.button1.move(330, 130)# 按钮位置
        self.button1.clicked.connect(self.handle)# 将信号通过槽 slot 连到 handle. 用handle处理点击事件

        self.button2 = QPushButton('反向推理', self.window)# 创建按钮
        self.button2.move(330, 190)
        self.button2.clicked.connect(self.handle2)

        self.button3 = QPushButton('展示所有规则', self.window)# 创建按钮
        self.button3.resize(150, 100)
        self.button3.move(10, 380)
        self.button3.clicked.connect(self.display_rules)

        self.textEdit5 = QPlainTextEdit(self.window)# 创建文本编辑框
        self.textEdit5.setPlaceholderText("请输入要添加的规则")
        self.textEdit5.move(230, 380)
        self.textEdit5.resize(250, 50)

        self.button4 = QPushButton('添加规则', self.window)# 创建按钮
        self.button4.resize(100, 50)
        self.button4.move(510, 380)
        self.button4.clicked.connect(self.add_rules)

        self.button6 = QPushButton('设置系统谓词', self.window)
        self.button6.move(490, 450)
        self.button6.clicked.connect(self.set_weici)

    def set_weici(self):
        global weici1
        global weici2
        weici1 = self.textEdit7.toPlainText()
        weici2 = self.textEdit8.toPlainText()

    def display_rules(self):
        Rules = []
        with open("D:/python rgzn sy/产生式系统/rule.txt", 'r', encoding='utf8') as f3:
            for line in f3:
                line = line.split()
                Rules.append(line)
            f3.close()
        info = []
        for i in range(len(Rules)):  # 使输出有序
            s = "%d: %s " % (i + 1, Rules[i])
            info.append(s)
        QMessageBox.about(self.window, '所有规则', f'''如下:\n\n{'       '.join(info)}''')#弹出对话框

    def add_rules(self):
        info = self.textEdit5.toPlainText()
        file = open('D:/python rgzn sy/产生式系统/rule.txt', 'a')
        file.write('\n' + info)
        file.close()

    def handle(self):
        global num
        init_info = []
        info = self.textEdit.toPlainText()
        num = list(map(int, info.split()))
        for i in num:
            dy_data.append(Feature[i - 1])
            init_info.append(Feature[i - 1])
        infer = inference()
        self.textEdit4.setPlainText(f'''您初始输入的特征信息有:\n{' '.join(init_info)}
                    {'            '.join(mid_result)}\n\n您得到的答案是:\n{infer}''')

    def handle2(self):
        global num
        init_info = []
        info = self.textEdit.toPlainText()
        num = list(map(int, info.split()))
        for i in num:
            dy_data.append(Feature[i - 1])
            init_info.append(Feature[i - 1])
        infer = inference2()

        self.textEdit4.setPlainText(f'''您初始输入的特征信息有:\n{' '.join(init_info)}
            {'            '.join(mid_result)}\n\n您给的结论有在综合数据库中有以下的特征:\n{' '.join(dydata)}\n\n您的规则库是:\n{' '.join(InitInit)}\n\n您得到的答案是:\n{infer}''')

def Database(file1, file2, file3):
    with open(file1, 'r', encoding='utf8') as f1:
        for line in f1.readlines():
            line = str(line).split()
            Names.extend(line)
        f1.close()
    with open(file2, 'r', encoding='utf8') as f2:
        for line in f2.readlines():
            line = str(line).split()
            Feature.extend(line)
        f2.close()
    with open(file3, 'r', encoding='utf8') as f3:
        for line in f3:
            line = line.split()
            Rules.append(line)
        f3.close()

def inference():
    flag = 1
    while (flag):
        for i in range(len(dy_data)):
            if (dy_data[i] in Names):
                return dy_data[i]
        tested_1 = []
        for i in range(len(Rules)):
            if (Rules[i] in tested_2):  # 防止规则重复匹配
                pass
            else:
                sub = Rules[i][:-1]
                for j in sub:
                    if (j not in dy_data):
                        break
                    if (j == sub[-1]):
                        if (Rules[i][-1] not in dy_data):  # 避免匹配到的规则后件重复加入
                            dy_data.append(Rules[i][-1])
                        s = "\n匹配的规则:"
                        s += weici1
                        for g in Rules[i]:
                            if (g == Rules[i][-2]):
                                s += g
                                s += '--->'
                                s += weici2
                            else:
                                s += g
                                s += '、'
                        mid_result.append(s)
                        ss = "\n目前综合数据库信息:"
                        for g in dy_data:
                            ss += g
                            ss += '、'
                        mid_result.append(ss)
                        tested_1.append(Rules[i])
                        tested_2.append(Rules[i])
        if (tested_1 == []):
            flag = 0  # 匹配失败,查找不到
    if (mid_result == []):
        return False
    else:
        return dy_data[-1]

def inference2():
  Init.extend(dy_data)
  InitInit.extend(dy_data)
  sg.extend(dy_data)
  del Init[0]
  del InitInit[0]
  flag=1
  while(flag):
    a=1
    for i in range(len(Rules)):
        if (Rules[i][-1] in dy_data):
            a=0
            s = "\n匹配的规则:"
            for g in Rules[i]:
                if (g == Rules[i][-1]):
                    s += '<---'
                    s += weici2
                    s += g
                else:
                    s += weici1
                    s += g
                    s += '、'
            mid_result.append(s)
            del dy_data[:]
            for j in range(len(Rules[i])-1):
                if (j != -1): dy_data.append(Rules[i][j])
            ss = "\n目前综合数据库信息:"
            for g in dy_data:
                ss += str(g)
                ss += '、'
            mid_result.append(ss)
            dydata.extend(dy_data)
    if (a==1):
      flag=0

  flagflag = 1
  while (flagflag):
        tested1 = []
        for i in range(len(Rules)):
            if (Rules[i] in tested2):  # 防止规则重复匹配
                pass
            else:
                sub = Rules[i][:-1]
                for j in sub:
                    if (j not in InitInit):
                        break
                    if (j == sub[-1]):
                        if (Rules[i][-1] not in InitInit):  # 避免匹配到的规则后件重复加入
                            InitInit.append(Rules[i][-1])
                        h = "\n匹配的规则:"
                        h += weici1
                        for g in Rules[i]:
                            if (g == Rules[i][-2]):
                                h += g
                                h += '--->'
                                h += weici2
                            else:
                                h += g
                                h += '、'
                        midresult.append(h)
                        hh = "\n目前综合数据库信息:"
                        for g in InitInit:
                            hh += g
                            hh += '、'
                        midresult.append(hh)
                        tested1.append(Rules[i])
                        tested2.append(Rules[i])
        if (tested1 == []):
            flagflag = 0  # 匹配失败,查找不到
  if (midresult == []):
        return False
  else:
      if(InitInit[-1]==sg[0]):
        return True
      else:
        w="False\n"
        w+="缺少的规则有:"
        for ww in dydata:
            if (ww not in InitInit ):  # 防止规则重复匹配
               w += ww
               w += '、'
        return w

file1_path = "D:/python rgzn sy/产生式系统/name.txt"
file2_path = "D:/python rgzn sy/产生式系统/feature.txt"
file3_path = "D:/python rgzn sy/产生式系统/rule.txt"
Database(file1_path, file2_path, file3_path)
app = QApplication([])
gg = GUI()
gg.window.show()
app.exec_()

Logo

更多推荐