最近用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版本的。
来源:oschina
链接:https://my.oschina.net/u/4267017/blog/4314168