離散數學——python實現真值表和打印主范式


最近用python實現了真值表,經過有點兒曲折,剛開始沒考慮優先級,直到前天才發現這個問題(離散數學沒學好啊),用棧改了一下。話說python就是強,把列表類型當棧用,直接調用列表的pop()和append()非常方便,廢話少說上代碼(命令行版)。

  1. 首先是導入外部庫和定義函數
    #導入正則表達式re庫,用來從字符串中提取信息
    import re
    #prettytable庫幫我們打印出漂亮的表格
    from prettytable import PrettyTable
    
    #過濾掉(
    def filter_brackets(string):
        p=re.compile(r'[(]+(.*)')
        return(p.findall(string)[0])
    
    #判斷格式是否合理,並返回真值表的列名
    def to_show(string):
        #利用patten提取括號中的內容
        patten=re.compile(r'[(](.*?)[)]')
        contents_in_brackets=patten.findall(string)
        #contents_in_brackets中的元素存在'('的現象,故對所有元素進行遍歷過濾掉這些括號
        for i in range(len(contents_in_brackets)):
            if contents_in_brackets[i].startswith('('):
                contents_in_brackets[i]=filter_brackets(contents_in_brackets[i])
        
        #利用sp提取命題變元,n為命題變元的個數
        sp=re.compile('[a-zA-Z]')
        simple_exp=sp.findall(string)
    
        l=simple_exp+contents_in_brackets
        #l去重得到l1
        l1=[]
        for i in l:
            if i not in l1:
                l1.append(i)
        l1.append(string)
        l1.sort(key=len)
        #第一項是要展示的部分,第二項是命題變元(有重復)
        return([l1,simple_exp])

     

  2. 其次是運算部分
    def get_prioty(operator):
        #if operator=='(' or operator==')'
        p=-1
        if operator=='(':
            p=6
        elif operator=='!':
            p=5
        elif operator=='&':
            p=4
        elif operator=='#':
            p=3
        elif operator=='|':
            p=2
        elif operator=='>':
            p=1
        elif operator=='=':
            p=0
        return(p)
    
    #兩命題變元運算
    def cal(a,operator,b=-1):
        if operator == '!':
            boo = not a
        elif operator == '&':
            boo = a and b
        elif operator == '|':
            boo = a or b
        #異或
        elif operator == '#':
            boo = (a and (not b)) or ((b and (not a)))
        #條件(注意順序是反的)
        elif operator == '>':
            boo = (not b) or a
        #等值
        elif operator == '=':
            boo = ((not a) and (not b)) or (a and b)
        else:
            print("there is no such operator")
            return(None)
        if(boo):
            return(1)
        else:
            return(0)
    
    #對傳入的字符串進行運算(傳入的字符串無括號),且
    def cal_str(Str,dic):
        i=0
        #s0為數字棧
        s0=[]
        #s1為運算符棧
        s1=[]
        while i<len(Str) or len(s1)!=0:
            if i<len(Str):
                c=Str[i]
            else:
                c=''
            if c.isalpha():
                s0.append(dic[c])
                i=i+1
            else:
                if len(s1)==0 or (c!=')' and s1[-1]=='(') or get_prioty(c)>=get_prioty(s1[-1]):
                    s1.append(c)
                    i=i+1
                    continue
    
                if  c==')' and s1[-1]=='(':
                    s1.pop()
                    i=i+1
                    continue
                
                if (i>=len(Str) and len(s1)!=0) or (c==')' and s1[-1]!='(') or get_prioty(c)<=get_prioty(s1[-1]):
                    opt=s1.pop()
                    if opt!='!':
                        result=cal(s0.pop(),opt,s0.pop())
                    elif opt=='!':
                        result=cal(s0.pop(),opt)
                    s0.append(result)
        return(s0[0])

     

  3. 利用bin()函數得到相應元素個數的全部真值賦值,經過一頓操作使用zip()函數將命題變元與其真值(0或1)綁定起來,遍歷所有的真值賦值情況,計算每種真值情況下的各個表達式的值,得到真值表
    #產生真值序列(字典形式)的列表
    def gen_truth_list(elems):
        num=len(elems)
        tl=[]
        for i in range(2**num):
            st=bin(i)[2:].zfill(num)
            truth_list=list(map(lambda j:int(j),list(st)))
            #append:將字典以整體形式加到列表中
            tl.append(dict(zip(elems,truth_list)))
        return(tl)
    
    def gen_all_line(truth_list,header):
        #產生真值表數據
        all_line=[]
        for line_truth in truth_list:
            per_line=[]
            for exp in header:
                truth=cal_str(exp,line_truth)
                per_line.append(truth)
            all_line.append(per_line)
        return(all_line)

     

  4. 根據真值表獲得主范式
    #返回一個小項
    def get_minterm(term):
        if len(term)!=0:
            return('('+'&'.join(term)+')')
        else:
            return('')
    
    #返回一個大項
    def get_maxterm(term):
        if len(term)!=0:
            return('('+'|'.join(term)+')')
        else:
            return('')
    
    def get_dnf(header,elems):
        truth_list=gen_truth_list(elems)
        minterms=[]
        all_line=gen_all_line(truth_list,header)
        #遍歷每一行
        for line_id in range(2**len(elems)):
            #term為包含某小項中各命題變元正確形式的列表
            term=[]
            #如果該行的真值賦值使得表達式為1
            if all_line[line_id][-1]==1:
                #遍歷該行對應的真值賦值
                for t in truth_list[line_id]:
                    if truth_list[line_id][t]==1:
                        term.append(t)
                    else:
                        term.append('!'+t)
            #表達式為1才能加入小項列表
            minterm=get_minterm(term)  
            if minterm!='':
                minterms.append(minterm)
        return('|'.join(minterms))
    
    def get_cnf(header,elems):
        truth_list=gen_truth_list(elems)
        maxterms=[]
        all_line=gen_all_line(truth_list,header)
        #遍歷每一行
        for line_id in range(2**len(elems)):
            term=[]
            #如果該行的真值賦值使得表達式為0
            if all_line[line_id][-1]==0:
                #遍歷該行對應的真值賦值
                for t in truth_list[line_id]:
                    if truth_list[line_id][t]==0:
                        term.append(t)
                    else:
                        term.append('!'+t)
            #表達式為1才能加入小項列表
            maxterm=get_maxterm(term)  
            if maxterm!='':
                maxterms.append(maxterm)
        return('&'.join(maxterms))

     

  5. 主函數如下
    if __name__=="__main__":
            #獲取字符串
        string=input('input:')
        
        header=to_show(string)[0]
        elem=to_show(string)[1]
        elems=[]
        for i in elem:
            if i not in elems:
                elems.append(i)
        truth_list=gen_truth_list(elems)
        
        all_line=[]
        for line_truth in truth_list:
            per_line=[]
            for exp in header:
                truth=cal_str(exp,line_truth)
                per_line.append(truth)
            all_line.append(per_line)
        
        truth_table=PrettyTable(header)
        for line in all_line:
            truth_table.add_row(line)
        
        print('The truth table of this formula is printed below:')
        print(truth_table)
        
        continue_or_not=input('Show "principal disjunctive normal form" \n or  "principal conjunctive normal form"? [y/n]\n')
        #繼續輸出主范式
        if continue_or_not=='y':
            print('pdnf(主析取范式): '+get_dnf(header,elems))
            print('pcnf(主合取范式): '+get_cnf(header,elems))
        

    第一次寫技術博客,有點兒激動,先寫到這,過兩天給出一個GUI版本的。


免責聲明!

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



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