记录一下万恶的信息论课程设计

在疯狂的考试周里,信息论老师美美地安排了课程设计并要求在考试前一天完成,于是乎,在这周我面临了三门考试+一个课程设计,这样的生活不要太充实…不过既然要做,那肯定要有所收获,不然我白通宵了5555

一、题目要求

课程目的:利用编程语言实现霍夫曼、费诺、香农编码
1、编码要求:

  • 霍夫曼编码:实现任意Q符号的N重序列信源的最优R进制编码,这里:
    8 ≤ Q ≤ 15 ; 2 ≤ R ≤ 5 ; 1 ≤ N ≤ 3 8≤Q≤15;2≤R≤5;1≤N≤3 8Q15;2R51N3
  • 费诺、香农编码:实现任意Q符号信源的二进制编码,这里:
    Q ≥ 10 Q≥10 Q10

二、pyQt5操作指南

非常简单!!

  • 使用pip install pyqt5直接安装,安装好以后在Project Interpreter中可以看到安装好的包:
    在这里插入图片描述
  • 设置pyqt5 designer,这一步很关键,因为你可以直接像画流程图一样设计你的现实界面,而且可以直接到处相应的代码而不需要自己敲!
    首先在Tools选项中选择Exrternal Tools,pyqt5 designer需要我们自己添加在这里插入图片描述
    Name自己随便设,在Program一栏中选择designer.exe路径,Woring directory填上$ProjectFileDir$,用来指向当前文件所在路径。
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ee4d2fcb5bff42b4a9dde7d29f06b618.png
    以上都设置好了以后,就可以直接通过下图方式打开pyqt5 desginer。
    在这里插入图片描述
    pyqt5 designer的界面是这样的,每次想创建一个新的界面直接创建一个新的Main Window就可以了。
    其他更有趣的操作大家还是亲手体验一下吧~
    在这里插入图片描述

三、设计思路

我参考了其他大佬的思路,用pyQt5实现可视化操作界面(最难的也在这里,其实pyQt5很好实现的,如果时间充裕的话只要有耐心就能够搞定!!)

1、开发环境与工具

  • 编辑工具:Pycharm 2020.1.5 x64
  • 编译工具:Python 3.8
  • 界面工具:PyQt5 Designer

2、一些代码参考

(1)霍夫曼编码

    def Hoffman_Coding(self):

        Q,N,R,sp = self.Read_Input()
        if Q == 0 and N == 0 and R == 0 and sp == 0:
            self.ui_error.show()
            return 0
        all_sym = self.Get_All_Symbol(Q,N,R,sp)      # all nodes
        if R == 2:
            hoffman_tree = self.Hoffman_Tree_Generate_2(Q,N,sp,all_sym)
            hoffman_code = self.Coding_2(all_sym,hoffman_tree)
            outcome = ''
            for i in range(len(all_sym)):
                outcome = outcome + str(round(all_sym[i].P,6)) + '    ' + hoffman_code[i] + '    ' +'\n'
            # print(outcome)
            self.ui.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(N,R,sp,all_sym,hoffman_code)
        elif R == 3:
            hoffman_tree = self.Hoffman_Tree_Generate_3(Q,N,sp,all_sym)
            hoffman_code = self.Coding_3(all_sym, hoffman_tree)
            outcome = ''
            for i in range(len(all_sym)):
                outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
            self.ui.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)
        elif R == 4:
            hoffman_tree = self.Hoffman_Tree_Generate_4(Q,N,sp,all_sym)
            hoffman_code = self.Coding_4(all_sym, hoffman_tree)
            outcome = ''
            for i in range(len(all_sym)):
                outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
            self.ui.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)
        elif R == 5:
            hoffman_tree = self.Hoffman_Tree_Generate_5(Q,N,sp,all_sym)
            hoffman_code = self.Coding_5(all_sym, hoffman_tree)
            outcome = ''
            for i in range(len(all_sym)):
                outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
            self.ui.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)


    def Hoffman_Tree_Generate_2(self,Q,N,sp,all_sym):
        queue = all_sym[:]
        while len(queue) > 1:
            queue.sort(key=lambda item:item.P)
            node_child1 = queue.pop(0)
            node_child2 = queue.pop(0)
            node_father = Node_2(node_child1.P + node_child2.P)
            node_father.child1 = node_child1
            node_father.child2 = node_child2
            node_child1.father = node_father
            node_child2.father = node_father
            queue.append(node_father)
        queue[0].father = None
        return queue[0]

    def Hoffman_Tree_Generate_3(self,Q,N,sp,all_sym):
        queue = all_sym[:]
        while len(queue) > 1:
            queue.sort(key=lambda item:item.P)
            node_child1 = queue.pop(0)
            node_child2 = queue.pop(0)
            node_child3 = queue.pop(0)
            node_father = Node_3(node_child1.P + node_child2.P + node_child3.P)
            node_father.child1 = node_child1
            node_father.child2 = node_child2
            node_father.child3 = node_child3
            node_child1.father = node_father
            node_child2.father = node_father
            node_child3.father = node_father
            queue.append(node_father)
        queue[0].father = None
        return queue[0]

    def Hoffman_Tree_Generate_4(self,Q,N,sp,all_sym):
        queue = all_sym[:]
        while len(queue) > 1:
            queue.sort(key=lambda item:item.P)
            node_child1 = queue.pop(0)
            node_child2 = queue.pop(0)
            node_child3 = queue.pop(0)
            node_child4 = queue.pop(0)
            node_father = Node_4(node_child1.P + node_child2.P + node_child3.P + node_child4.P)
            node_father.child1 = node_child1
            node_father.child2 = node_child2
            node_father.child3 = node_child3
            node_father.child4 = node_child4
            node_child1.father = node_father
            node_child2.father = node_father
            node_child3.father = node_father
            node_child4.father = node_father
            queue.append(node_father)
        queue[0].father = None
        return queue[0]

    def Hoffman_Tree_Generate_5(self,Q,N,sp,all_sym):
        queue = all_sym[:]
        while len(queue) > 1:
            queue.sort(key=lambda item:item.P)
            node_child1 = queue.pop(0)
            node_child2 = queue.pop(0)
            node_child3 = queue.pop(0)
            node_child4 = queue.pop(0)
            node_child5 = queue.pop(0)
            node_father = Node_5(node_child1.P + node_child2.P + node_child3.P + node_child4.P + node_child5.P)
            node_father.child1 = node_child1
            node_father.child2 = node_child2
            node_father.child3 = node_child3
            node_father.child4 = node_child4
            node_father.child5 = node_child5
            node_child1.father = node_father
            node_child2.father = node_father
            node_child3.father = node_father
            node_child4.father = node_father
            node_child5.father = node_father
            queue.append(node_father)
        queue[0].father = None
        return queue[0]


    def Coding_2(self,all_sym,root):
        codes = ['']*len(all_sym)
        for i in range(len(all_sym)):
            node_tem = all_sym[i]
            while node_tem != root:
                if node_tem.check_num_of_child() == 1:
                    codes[i] = '0' + codes[i]
                else:
                    codes[i] = '1' + codes[i]
                node_tem = node_tem.father
        print(codes)
        return codes


    def Coding_3(self, all_sym, root):
        codes = ['']*len(all_sym)
        for i in range(len(all_sym)):
            node_tem = all_sym[i]
            while node_tem != root:
                if node_tem.check_num_of_child() == 1:
                    codes[i] = '0' + codes[i]
                elif node_tem.check_num_of_child() == 2:
                    codes[i] = '1' + codes[i]
                else:
                    codes[i] = '2' + codes[i]
                node_tem = node_tem.father
        print(codes)
        return codes

    def Coding_4(self, all_sym, root):
        codes = ['']*len(all_sym)
        for i in range(len(all_sym)):
            node_tem = all_sym[i]
            while node_tem != root:
                if node_tem.check_num_of_child() == 1:
                    codes[i] = '0' + codes[i]
                elif node_tem.check_num_of_child() == 2:
                    codes[i] = '1' + codes[i]
                elif node_tem.check_num_of_child() == 3:
                    codes[i] = '2' + codes[i]
                else:
                    codes[i] = '3' + codes[i]
                node_tem = node_tem.father
        print(codes)
        return codes

    def Coding_5(self, all_sym, root):
        codes = ['']*len(all_sym)
        for i in range(len(all_sym)):
            node_tem = all_sym[i]
            while node_tem != root:
                if node_tem.check_num_of_child() == 1:
                    codes[i] = '0' + codes[i]
                elif node_tem.check_num_of_child() == 2:
                    codes[i] = '1' + codes[i]
                elif node_tem.check_num_of_child() == 3:
                    codes[i] = '2' + codes[i]
                elif node_tem.check_num_of_child() == 4:
                    codes[i] = '3' + codes[i]
                else:
                    codes[i] = '4' + codes[i]
                node_tem = node_tem.father
        print(codes)
        return codes

    def Get_All_Symbol(self,Q,N,R,sp):
        all_sym = []
        symbol_sequence = []
        nodes = []
        for i in range(N):
            symbol_sequence.append(0)
        for i in range(pow(Q,N)):
            j = N-1
            P = sp[symbol_sequence[0]]
            for k in range(N):
                if k != 0:
                    P *= sp[symbol_sequence[k]]
            if R == 2:
                all_sym.append(Node_2(P))
            elif R == 3:
                all_sym.append(Node_3(P))
            elif R == 4:
                all_sym.append(Node_4(P))
            elif R == 5:
                all_sym.append(Node_5(P))

            while symbol_sequence[j] == Q-1:
                symbol_sequence[j] = 0
                j -= 1
                if j == -1:
                    # print(len(all_sym))
                    if( int((Q - R)/(R - 1))!=(Q - R)/(R - 1) ):
                        Q_expand = int((Q - R)/(R - 1)+1)*(R - 1)+R
                        for i in range(Q_expand - Q):
                            if R == 2:
                                all_sym.append(Node_2(0))
                            elif R == 3:
                                all_sym.append(Node_3(0))
                            elif R == 4:
                                all_sym.append(Node_4(0))
                            elif R == 5:
                                all_sym.append(Node_5(0))
                    return all_sym
            symbol_sequence[j] += 1

    def Read_Input(self):

        Q = int(self.ui.lineEdit_5.text()) # num of symbol
        N = int(self.ui.lineEdit_6.text())# num of sequence
        R = int(self.ui.lineEdit_7.text())  # num of radix


        text = self.ui.textEdit.toPlainText()

        sp = self.Get_Symbol_Probability(text)  # symbol probability

        if Q<8 or Q>15 or N<1 or N>3 or R<2 or R>5 or len(sp)!=Q or sum(sp) < 0.99999:
            print('!!')
            # self.ui_error.show()
            # print(sum(sp))
            return 0,0,0,0
        else:
            # print(Q,N,R,sp)
            return Q,N,R,sp

    def Str_Find_HH(self,str):  # HH:huan hang '\n'
        n = len(str)
        pos = list()
        for i in range(n):
            if str[i] == '\n':
                pos.append(i)
        # print(pos)
        return pos

    def Get_Symbol_Probability(self,str):
        n = len(str)
        pos = self.Str_Find_HH(str)
        sp = list()
        n_pos = len(pos)
        for i in range(n_pos):
            if i == 0:
                sp.append(float(str[0:pos[i]]))
            else:
                sp.append(float(str[pos[i - 1] + 1:pos[i]]))
        # print(sp)
        return sp


    def Calculate_Performance_Index(self,N,R,sp,all_sym,codes):
        HU = 0
        l_avr = 0
        for i in range(len(sp)):
            HU += -sp[i]*math.log2(sp[i])
        for i in range(len(all_sym)):
            l_avr += all_sym[i].P*len(codes[i])
        effi = HU*N/l_avr/math.log2(R)

        self.ui.lineEdit_2.setText(str(round(HU,5)))
        self.ui.lineEdit_3.setText(str(round(l_avr,2)))
        self.ui.lineEdit_4.setText(str(round(effi*100,4))+'%')

(2)费诺编码

 def Feno_Coding(self):
        Q, sp = self.Read_Input()

        if Q == 0 and sp == 0:
            QMessageBox.warning(self, "Error", "Invalid input. Please check your input.")
            return
        sp_node = []
        print(Q)
        self.feno_code = [''] * len(sp)
        sp.sort(reverse=True)

        for i in range(len(sp)):
            sp_node.append(Node(sp[i], i))
        self.Coding(sp_node)
        # print(self.feno_code)
        outcome = ''
        for i in range(len(sp)):
            outcome = outcome + str(sp[i]) + '    ' + self.feno_code[i] + '    ' + '\n'
        self.ui.textEdit_2.setPlainText(outcome)
        self.Calculate_Performance_Index(sp, self.feno_code)


    def Coding(self, sp_node):
        if len(sp_node) == 1:
            return
        findPos = 0
        diff_c = 1
        sum1 = 0
        sum2 = 0
        left_flag = 0  # 0 means left bigger than right

        for i in range(len(sp_node) - 1):
            for j in range(i + 1):
                sum1 += sp_node[j].P
            for k in range(i + 1, len(sp_node)):
                sum2 += sp_node[k].P
            if abs(sum1 - sum2) < diff_c:
                diff_c = abs(sum1 - sum2)
                if sum1 < sum2:
                    left_flag = 1
                else:
                    left_flag = 0
                findPos = i
            sum1 = 0
            sum2 = 0

        for i in range(len(sp_node)):
            if left_flag:
                if i <= findPos:
                    self.feno_code[sp_node[i].pos] += '1'
                else:
                    self.feno_code[sp_node[i].pos] += '0'
            else:
                if i <= findPos:
                    self.feno_code[sp_node[i].pos] += '0'
                else:
                    self.feno_code[sp_node[i].pos] += '1'

        left = []
        right = []
        for i in range(findPos + 1):
            left.append(sp_node[i])
        for i in range(findPos + 1, len(sp_node)):
            right.append(sp_node[i])

        self.Coding(left)
        self.Coding(right)


    def Read_Input(self):

        Q = int(self.ui.lineEdit.text())  # num of symbol

        text = self.ui.textEdit.toPlainText()
        sp = self.Get_Symbol_Probability(text)  # symbol probability
        if Q < 10 or len(sp) != Q or sum(sp) < 0.99999:
            print('!!')
            # self.ui_error.show()
            # print(sum(sp))
            return 0, 0, 0, 0
        else:
            # print(Q,N,R,sp)
            return Q, sp


    def Str_Find_HH(self, str):  # HH:huan hang '\n'
        n = len(str)
        pos = list()
        for i in range(n):
            if str[i] == '\n':
                pos.append(i)
        #pos.append(i)
        #print(pos)
        return pos


    def Get_Symbol_Probability(self, str):
        n = len(str)
        pos = self.Str_Find_HH(str)
        sp = list()
        n_pos = len(pos)
        #print(n_pos)
        for i in range(n_pos):
            if i == 0:
                sp.append(float(str[0:pos[i]]))
            else:
                sp.append(float(str[pos[i - 1] + 1:pos[i]]))
        print(sp)
        return sp


    def Calculate_Performance_Index(self, sp, codes):
        HU = 0
        l_avr = 0
        for i in range(len(sp)):
            HU += -sp[i] * math.log2(sp[i])
        for i in range(len(sp)):
            l_avr += sp[i] * len(codes[i])
        effi = HU / l_avr / math.log2(2)
        print(effi)
        self.ui.lineEdit_2.setText(str(round(HU, 5)))
        self.ui.lineEdit_3.setText(str(round(l_avr, 2)))
        self.ui.lineEdit_4.setText(str(round(effi * 100, 4)) + '%')

(3)香农编码

    def Shannon_Coding(self):
        Q, sp = self.Read_Input()
        if Q == 0 and sp == 0:
            self.ui_error.show()
            return

        shannon_code = [''] * len(sp)
        sp.sort(reverse=True)
        for i in range(len(sp)):
            P_acc = 0
            code = ''
            l = int(-math.log2(sp[i]) + 1)
            for j in range(i):
                P_acc += sp[j]
            while True:
                P_acc *= 2
                if P_acc >= 1:
                    code += '1'
                else:
                    code += '0'
                if len(code) == l:
                    break
                P_acc -= int(P_acc)
                if P_acc == 0:
                    if (len(code) < l):
                        code += '0' * (l - len(code))
                        break
            shannon_code[i] = code[:l]
        # print(shannon_code)

        outcome = ''
        for i in range(len(sp)):
            outcome = outcome + str(sp[i]) + '    ' + shannon_code[i] + '    ' + '\n'
        self.ui.textEdit_2.setPlainText(outcome)
        self.Calculate_Performance_Index(sp, shannon_code)


    def Read_Input(self):
        Q = int(self.ui.lineEdit.text())  # num of symbol
        text = self.ui.textEdit.toPlainText()
        sp = self.Get_Symbol_Probability(text)  # symbol probability
        if Q < 10 or len(sp) != Q or sum(sp) < 0.99999:
            # self.ui_error.show()
            # print(sum(sp))
            return 0, 0, 0, 0
        else:
            # print(Q,N,R,sp)
            return Q, sp


    def Str_Find_HH(self, str):  # HH:huan hang '\n'
        n = len(str)
        pos = list()
        for i in range(n):
            if str[i] == '\n':
                pos.append(i)
        # print(pos)
        return pos


    def Get_Symbol_Probability(self, str):
        n = len(str)
        pos = self.Str_Find_HH(str)
        sp = list()
        n_pos = len(pos)
        for i in range(n_pos):
            if i == 0:
                sp.append(float(str[0:pos[i]]))
            else:
                sp.append(float(str[pos[i - 1] + 1:pos[i]]))
        # print(sp)
        return sp


    def Calculate_Performance_Index(self, sp, codes):
        HU = 0
        l_avr = 0
        for i in range(len(sp)):
            HU += -sp[i] * math.log2(sp[i])
        for i in range(len(sp)):
            l_avr += sp[i] * len(codes[i])
        effi = HU / l_avr / math.log2(2)

        self.ui.lineEdit_2.setText(str(round(HU, 5)))
        self.ui.lineEdit_3.setText(str(round(l_avr, 2)))
        self.ui.lineEdit_4.setText(str(round(effi * 100, 4)) + '%')

(4)界面显示程序

这个py文件就是pyqt5 designer中导出的代码
在这里插入图片描述

(5)具体操作

这里可能有点绕,拿霍夫曼编码界面举例,pyqt5 designer会自动生成一个ui文件,也就是这里的huffman.ui文件,然后用pyqt5 desginer导出一个py文件,即huffman_ui.py,它将操作可视化界面的具体设置放在了里面,比如设置了哪些元素(如放了一个文本框,放了一个标签,放了一个按钮,界面大小是多大等等),最后huffman.py会调用huffman_ui.py,在这个文件中,会实例化我们创建的Main Window,代码如下:

class Mywindow(QtWidgets.QMainWindow):

    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = Huffman_MainWindow()
        self.ui.setupUi(self)

并对里面的元素做一些具体的操作,比如实现按钮点击跳转(self.ui.PushButton.clicked.connect(相应的函数))、读取输入框中的内容(self.ui.lineEdit.text(),要注意我设置的输入框是lineEdit格式,可能还有textEdit等等的格式,不同格式读取输入内容的方式不同)、将输出内容显示在界面对应的文本框中(self.ui.lineEdit.text(xx))在这里这个函数就是对应的霍夫曼编码,霍夫曼编码的相关代码也会放在这个文件中。
在这里插入图片描述

四、界面展示

根据自己的喜好去设计界面,最后跑通代码是一件很有成就感的事情哦,所以大家加油吧~
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值