本文的真值表转逻辑表达式没有化到最简,最简详见:
更新链接:https://blog.csdn.net/wxkhturfun/article/details/131776977?spm=1001.2014.3001.5501
前言
遇到一个问题:想把真值表转换成逻辑表达式,真值表太长,不想手算,于是写了个脚本。但是为了检验结果的正确性,顺带写了个逻辑表达式转真值表的脚本。
一. 逻辑表达式转真值表
下面的例子是expression = abc+ (a非)b(c非)
,为了方便表示,用大写字母表示取非,小写字母表示原值,则expression = abc+AbC
,在python代码中,该expression
即被记为[(1,1,1),(0,1,0)]
,这里的(1,1,1)
是按字母顺序的abc
,这里的(0,1,0)
是按字母顺序的AbC
。
此时已经可以表示了,但是如果还有字母d呢?即化简后d消失了,那么可以认为d是可有可无的x
,为了统一处理,这里用数字2
来表示x
, 则此时expression=[(1,1,1,2),(0,1,0,2)]
,以此类推!
生成的真值表存储在test.csv
文件中
import csv
def Write_csv(csv_file,data,encode='utf-8'):
with open(csv_file, 'w', encoding=encode,newline='') as file_obj:
writer = csv.writer(file_obj)
for i in data:
writer.writerow(i)
def gen_data(exp,N):
data_out = []
for i in range(2**N):
line = bin(i)
line = str(line)
line = line[2:]
line = '0'*(N-len(line)) + line
tmp_0 = 0
for data_in in exp:
tmp_1 = 1
for i in range(N):
if( data_in[i] == 2 ):
continue
elif(data_in[i] == int(line[i])):
continue
else:
tmp_1 = 0
break
tmp_0 = tmp_0 + tmp_1
if(tmp_0 != 0):
line = line + '1'
else:
line = line + '0'
data_out.append(tuple(line))
return data_out
if __name__ == "__main__":
#T = 1
#F = 0
#X = 2
#大写字母代表取非
#小写字母代表正常字母
#expression = abc + AbC
#exp = ['abc','AbC'] for N = 3
#exp = ['abcX','AbCX'] for N=4(thus include D)
#exp = [[1,2,1,2],[0,1,0,2]]
exp = [[2,2,2,2],[1,2,1,0]]
data = gen_data(exp,4)
Write_csv('test.csv',data)
二. 真值表转逻辑表达式
这里输出的表达式的含义见上一小节。
需要注意的是两个极端例子:
- 如果真值表恒为1,则输出结果为
[2,2,2,2]
(即真值表对应的输出结果永真时,其输入可为任意值) - 如果真值表恒为0,则输出结果为
[]
import csv
#input:csv file
#out1:元素个数
#out2:把结果为1的值读进data
def Read_csv_True(csv_file,encode='utf-8'):
data = []
column = 0
with open(csv_file, 'r', encoding=encode) as file_obj:
reader = csv.reader(file_obj)
for row in reader:
element = row[-1]
if(0 == int(element)):
continue
tmp = row[:-1]
for i in range(len(tmp)):
tmp[i] = int(tmp[i])
data.append(tmp)
column = len(row)-1
return column,data
def get_Exp(data,N):
if(len(data) == 0):
return []
for n in range(N):
for i in range(len(data)-1):
for j in range(i,len(data)):
if (j == len(data)):
#因为有del(data[j]),所以要判断溢出
break
tmp = []
cnt = 0
for k in range(N):
if(data[i][k] == data[j][k]):
tmp.append(data[i][k])
else:
cnt += 1
tmp.append(2)
if(cnt == 1):
data[i] = tmp
del(data[j])
if __name__ == "__main__":
#N指字母个数
N,data = Read_csv_True('test.csv','utf-8')
print(N)
get_Exp(data,N)
print(data)
三.后记
本人试了几个结果,发现没有问题,如果有问题,可以@我。
另外,真值表转逻辑表达那个脚本本意就是想化简的,所以具有一定的化简功能,我感觉是化到最简了(尚未进行严格的数学证明!)。(后发现不是最简)
补充,关于代码逻辑:
起先我是画了一个韦恩图,试图找到可以合并的两项的表达式有什么联系,然后发现:
可以合并的两项必然有一条边重合,也就是说在韦恩图中,如果两个最小区域(即不包含其他区域的区域)可以合并,那么至少有一条边是共有的。没有共有边或只有共有的顶点的两个最小区域不能合并。
(注:不知道有没有严格的数学证明,有的话可以在评论给我提示一下)
按这个思路来,有4项的项合并后,变为3项,那么就可以先把所有可以合并的4项给合并成3项,再合并成2项,直至不能合并!
按照这个思路,如果不能合并,那么必不存在共有边,即得到的逻辑表达式是最简的(想法没错,但是代码并没有化到最简)