動物識別專家系統課程設計



title: 動物識別專家系統課程設計
date: 2017-12-23 18:44:13
tags:
categories: python


設計一個可以識別7種動物的專家系統,可以根據前提推導出結論,如果只有部分前提,詢問提示。
RD.txt是規則庫,一行一條,每條空格分隔,前面是前提,最后一個是結論。
用PyQt5設計界面

RD.txt


有毛發 哺乳動物
有奶 哺乳動物
有羽毛 鳥
會飛 下蛋 鳥
吃肉 食肉動物
有犬齒 有爪 眼盯前方 食肉動物
哺乳動物 有蹄 有蹄類動物
哺乳動物 嚼反芻動物 有蹄類動物
哺乳動物 食肉動物 黃褐色 暗斑點 金錢豹
哺乳動物 食肉動物 黃褐色 黑色條紋 虎
有蹄類動物 長脖子 長腿 暗斑點 長頸鹿
有蹄類動物 黑色條紋 斑馬
鳥 長脖子 長腿 黑白二色 不飛 鴕鳥
鳥 會游泳 不飛 黑白二色 企鵝
鳥 善飛 信天翁

主要文件,包含界面
main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
import sys


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.setGeometry(100, 200, 623, 300)
        self.groupBox = QtWidgets.QGroupBox(Form)
        self.groupBox.setGeometry(QtCore.QRect(10, -20, 600, 311))
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.label = QtWidgets.QLabel(self.groupBox)
        self.label.setGeometry(QtCore.QRect(30, 40, 61, 18))
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setGeometry(QtCore.QRect(470, 40, 101, 18))
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.pushButton = QtWidgets.QPushButton(self.groupBox)
        self.pushButton.setGeometry(QtCore.QRect(230, 35, 88, 27))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_2.setGeometry(QtCore.QRect(475, 190, 88, 27))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_2.clicked.connect(self.btn2_click)
        self.pushButton_3 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_3.setGeometry(QtCore.QRect(475, 240, 88, 27))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_3.clicked.connect(QtCore.QCoreApplication.instance().quit)
        self.pushButton_4 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_4.setGeometry(475, 140, 88, 27)
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_4.clicked.connect(self.topological)
        self.textEdit = QtWidgets.QTextEdit(self.groupBox)
        self.textEdit.setGeometry(QtCore.QRect(20, 80, 80, 211))
        self.textEdit.setObjectName("textEdit")
        self.textEdit_2 = QtWidgets.QTextEdit(self.groupBox)
        self.textEdit_2.setGeometry(QtCore.QRect(110, 80, 331, 211))
        self.textEdit_2.setObjectName("textEdit_2")
        self.textEdit_2.setReadOnly(True)
        self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
        self.lineEdit.move(460, 90)
        self.lineEdit.setReadOnly(True)
        self.pushButton.clicked.connect(self.go)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def btn2_click(self):
        if self.pushButton_2.text() != "確定輸入":
            self.pushButton_2.setText("確定輸入")
        else:
            self.pushButton_2.setText("修改知識庫")

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "動物識別專家系統"))
        self.label.setText(_translate("Form", "輸入事實"))
        self.label_2.setText(_translate("Form", "顯示推理結果"))
        self.pushButton.setText(_translate("Form", "進行推理"))
        self.pushButton_2.setText(_translate("Form", "修改知識庫"))
        self.pushButton_3.setText(_translate("Form", "退出程序"))
        self.pushButton_4.setText(_translate("From", "整理知識庫"))

    # 將知識庫做拓撲排序
    def topological(self):
        Q = []
        P = []
        ans = ""  # 排序后的結果
        for line in open('RD.txt'):
            line = line.strip('\n')
            if line == '':
                continue
            line = line.split(' ')
            Q.append(line[line.__len__() - 1])
            del (line[line.__len__() - 1])
            P.append(line)

        # 計算入度
        inn = []
        for i in P:
            sum = 0
            for x in i:
                if Q.count(x) > 0:  # 能找到,那么
                    sum += Q.count(x)
            inn.append(sum)

        while (1):
            x = 0
            if inn.count(-1) == inn.__len__():
                break
            for i in inn:
                if i == 0:
                    str = ' '.join(P[x])
                    # print("%s %s" %(str, Q[x]))
                    ans = ans + str + " " + Q[x] + "\n"  # 寫入結果
                    # print("%s -- %s" %(P[x],Q[x]))
                    inn[x] = -1
                    # 更新入度
                    y = 0
                    for j in P:
                        if j.count(Q[x]) == 1:
                            inn[y] -= 1
                        y += 1
                x += 1
        print(ans)

        # 將結果寫入文件
        fw = open('RD.txt', 'w', buffering=1)
        fw.write(ans)
        fw.flush()
        fw.close()

    # 進行推理
    def go(self, flag=True):
        # 將產生式規則放入規則庫中
        # if P then Q
        # 讀取產生式文件
        self.Q = []
        self.P = []
        fo = open('RD.txt', 'r', encoding='utf-8')
        for line in fo:
            line = line.strip('\n')
            if line == '':
                continue
            line = line.split(' ')
            self.Q.append(line[line.__len__() - 1])
            del (line[line.__len__() - 1])
            self.P.append(line)
        fo.close()
        print("go按鈕按下")
        self.lines = self.textEdit.toPlainText()
        self.lines = self.lines.split('\n')  # 分割成組
        self.DB = set(self.lines)
        print(self.DB)
        self.str = ""
        print(self.str)
        flag = True
        temp = ""
        for x in self.P:  # 對於每條產生式規則
            if ListInSet(x, self.DB):  # 如果所有前提條件都在規則庫中
                self.DB.add(self.Q[self.P.index(x)])
                temp = self.Q[self.P.index(x)]
                flag = False  # 至少能推出一個結論
                # print("%s --> %s" %(x, self.Q[self.P.index(x)]))
                self.str += "%s --> %s\n" % (x, self.Q[self.P.index(x)])

        if flag:  # 一個結論都推不出
            print("一個結論都推不出")
            for x in self.P:  # 對於每條產生式
                if ListOneInSet(x, self.DB):  # 事實是否滿足部分前提
                    flag1 = False       # 默認提問時否認前提
                    for i in x:  # 對於前提中所有元素
                        if i not in self.DB:  # 對於不滿足的那部分
                            btn = s.quest("是否" + i)
                            if btn == QtWidgets.QMessageBox.Ok:
                                self.textEdit.setText(self.textEdit.toPlainText() + "\n" + i)  # 確定則增加到textEdit
                                self.DB.add(i)  # 確定則增加到規則庫中
                                flag1 = True    # 肯定前提
                                # self.go(self)
                    if flag1:  # 如果肯定前提,則重新推導
                        self.go()
                        return

        self.textEdit_2.setPlainText(self.str)
        print("----------------------")
        print(self.str)
        if flag:
            btn = s.alert("啥也推不出來!!!")
            # if btn == QtWidgets.QMessageBox.Ok:  # 點擊確定
            #     self.textEdit.setText(self.textEdit.toPlainText() + "\n確定")
        else:
            self.lineEdit.setText(temp)


# 判斷list中至少有一個在集合set中
def ListOneInSet(li, se):
    for i in li:
        if i in se:
            return True
    return False


# 判斷list中所有元素是否都在集合set中
def ListInSet(li, se):
    for i in li:
        if i not in se:
            return False
    return True


class SecondWindow(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(SecondWindow, self).__init__(parent)
        self.setWindowTitle("修改知識庫")
        self.setGeometry(725, 200, 300, 300)
        self.textEdit = QtWidgets.QTextEdit(self)
        self.textEdit.setGeometry(8, 2, 284, 286)


    # 警告沒有推導結果
    def alert(self, info):
        QtWidgets.QMessageBox.move(self, 200, 200)
        QtWidgets.QMessageBox.information(self, "Information", self.tr(info))

    # 詢問補充事實
    def quest(self, info):
        # 如果推理為空,需要詢問用戶是否要添加已知條件
        QtWidgets.QMessageBox.move(self, 200, 200)
        button = QtWidgets.QMessageBox.question(self, "Question",
                                                self.tr(info),
                                                QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
                                                QtWidgets.QMessageBox.Cancel)
        return button

    def handle_click(self):
        if not self.isVisible():
            # 讀取文件放到多行文本框中
            str = ""
            fo = open('RD.txt', 'r', encoding='utf-8')
            for line in fo:
                line = line.strip('\n')
                if line == '':
                    continue
                str = str + line + "\n"
            fo.close()
            self.textEdit.setText(str)
            self.show()
        else:
            # 輸出文本框內容
            self.str = self.textEdit.toPlainText()
            print(self.str)

            # 將文本框內容寫入文件
            self.fw = open('RD.txt', 'w')
            self.fw.write(self.str)
            self.fw.close()  # 關閉文件
            self.close()  # 關閉窗口

    def handle_close(self):
        self.close()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    widget = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(widget)
    widget.show()
    s = SecondWindow()
    ui.pushButton_2.clicked.connect(s.handle_click)
    sys.exit(app.exec_())

linux下開發,在Windows下運行可能需要將open函數的encoding設定為gbk


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM