最近用python實現了真值表,經過有點兒曲折,剛開始沒考慮優先級,直到前天才發現這個問題(離散數學沒學好啊),用棧改了一下。話說python就是強,把列表類型當棧用,直接調用列表的pop()和append()非常方便,廢話少說上代碼(命令行版)。
- 首先是導入外部庫和定義函數
#導入正則表達式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])
- 其次是運算部分
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])
- 利用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)
- 根據真值表獲得主范式
#返回一個小項 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))
- 主函數如下
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版本的。