利用真值表法求取主析取范式及主合取范式
程序结构
├─ code
│ ├─logical_operation
│ │ ├─__init__.py
│ │ ├─Algorithm.py
│ │ └─operator.py
│ └─main.py
- code:主程序文件夹
- logical_operation:定义与逻辑运算有关的符号及运算法则
- __ init __.py:用于将文件夹变为一个python模块
- Algorithm.py:定义逻辑运算符的运算法则
- operator.py:定义逻辑运算符符号
- main.py:主程序
- logical_operation:定义与逻辑运算有关的符号及运算法则
__ init __.py
__all__ = ['operator', 'Algorithm']
表示将logical_operation模块中的operator.py、Algorithm.py对外暴露
operator.py
def _not_(value):
"""
定义否定联结词
"""
# 判断传入值是否为0/1
if value not in [0, 1]:
return -1
# 返回否定式
return 1 if value == 0 else 0
def _conjunction_(value1, value2):
"""
定义合取联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return value1 & value2
def _disjunctive_(value1, value2):
"""
定义析取联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return value1 | value2
def _implied_(value1, value2):
"""
定义蕴涵联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return 0 if (value1 == 1 and value2 == 0) else 1
def _equivalent_(value1, value2):
"""
定义等价联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return 1 if (value1 == value2) else 0
def get_result(operator, *values):
# 若联结词未定义,抛出异常
if operator not in ['!', '&', '|', '>', '-']:
return -1
# 判断操作数数目是否正确
if len(values) == 0:
return -1
if (operator == '!') and (len(values) >= 2):
return -1
if (operator in ['&', '|', '>', '-']) and (len(values) != 2):
return -1
# 进行运算
res = -1
if operator == '!':
res = _not_(values[0])
elif operator == '&':
res = _conjunction_(values[0], values[1])
elif operator == '|':
res = _disjunctive_(values[0], values[1])
elif operator == '>':
res = _implied_(values[0], values[1])
elif operator == '-':
res = _equivalent_(values[0], values[1])
return res
分别定义否定联结词、合取联结词、析取联结词、蕴涵联结词和等价联结词的运算规则(这几个联结词的定义见离散数据教科书),并定义一个供外界调用的函数get_result,参数为operator和values,其中operator为联结词符号(!代表否定联结词、&代表合取联结词、|代表析取联结词、>代表蕴涵联结词、-代表等价联结词),values代表操作数(其中!为单目运算符,有一个操作数,其它符号有两个操作数)。
Algorithm.py
该函数借鉴四则运算符,利用“栈”定义了逻辑运算符的运算法则。
"""
通过 栈 定义 逻辑运算
"""
from logical_operation import operator
# 定义符号优先级
prority_dict = {"!": 1, "&": 2, "|": 3, ">": 4, "-": 5} # 1代表最高的优先级
# 定义数字栈和符号栈
num_stack, ope_stack = [], []
# 将 出栈运算 步骤封装
def temp():
ope = ope_stack.pop()
# 一元运算符
if ope == '!':
v = num_stack.pop()
res = operator.get_result(ope, v)
# 二元运算符
else:
v2 = num_stack.pop()
v1 = num_stack.pop()
res = operator.get_result(ope, v1, v2)
num_stack.append(res)
def algorithm(expression):
for str in expression:
# 若是数字,则直接加入数字栈((!1&1)|(1&!1))>0
if str in '01':
num_stack.append(int(str))
continue
# 若是符号,则判断入栈还是运算
if (str in prority_dict.keys()) | (str in '()'):
# 若符号栈为空、栈顶符号为‘(’、当前符号为‘(’,则直接入栈
if (len(ope_stack) == 0) or (ope_stack[-1] == '(') or (str == '('):
ope_stack.append(str)
continue
if str == ')':
while ope_stack[-1] != '(':
temp()
ope_stack.pop()
continue
# 若当前符号优先级小于等于栈顶符号优先级,则进行运算
# 直至栈为空,或者当前符号优先级大于栈顶符号优先级
while prority_dict[str] > prority_dict[ope_stack[-1]]:
temp()
# 若栈已经为空、或栈顶符号为‘(’,则直接退出循环
if (len(ope_stack) == 0) or (ope_stack[-1] == '('):
break
ope_stack.append(str)
continue
# 表达式遍历完成,检查符号栈中是否还有符号
if len(ope_stack) == 0:
return num_stack[-1]
else:
while len(ope_stack) != 0:
temp()
return num_stack[-1]
这一部分主要是对数据结构中“栈”的应用,没有别的需要注意的地方。
main.py
import logical_operation.Algorithm as al
import pandas as pd
import sys
if __name__ == '__main__':
exp = input("请输入表达式: ")
# 指定变量
var_name = ['p', 'q', 'r']
result = list()
# 生成0/1
for i in range(2 ** len(var_name)):
bin_list = list(str(bin(i))[2:].zfill(len(var_name)))
# 将变量替换为01
expt = exp
for j in range(len(var_name)):
expt = expt.replace(var_name[j], bin_list[j])
res = al.algorithm(expt)
if res == -1:
print("error!!!")
sys.exit(0)
bin_list.append(res)
result.append(bin_list)
var_name.append(exp)
result2 = pd.DataFrame(result, columns=var_name, index=None)
M_list = list()
m_list = list()
for i in range(len(result)):
if result[i][len(var_name)-1] == 0:
M_list.append(f"M{i}")
else:
m_list.append(f"m{i}")
print(f"主合取范式为:{ '^'.join(M_list) }")
print(f"主析取范式为:{ 'v'.join(m_list) }")
print(result2)
下面用一个例子来解释上述代码——p|q|!r:
-
表达式只能使用var_name中指定的变量
-
真值表的行数等于2变量数2^{变量数}2变量数,如下图,三个变量的真值表有23=82^3=823=8行
-
可见p、q、r对应的值即为python对应的下标的二进制(例如当python对应下标为5时,二进制为101,即p=1,q=0,r=1),因此可以根据下标生成p、q、r的值(以i=3为例)
- bin(i) = 0b11 ------> bin()函数生成0b开头的二进制
- str(bin(i)) = str(0b11) = “0b11” ------> 将二进制转换为字符串
- str(bin(i))[2:].zfill(len(v)) = “0b11”[2:].zfill(3) = “11”.zfill(3) = “011” ------> 从第三位取出字符串的值,并在前面填充0,使其长度达到3
- list(str(bin(i))[2:].zfill(len(v))) = list(“011”) = [“0”, “1”, “1”]
-
将输入表达式中的p、q、r替换为对应的0、1值
- 输入表达式为“p|q|!r”,则替换为“0|1|!1”
-
通过logical_operation模块的Algorithm方法计算值
- logical_operation.Algorithm(“0|1|!1”) = 1
-
将结果并入前面的列表
- 得到[“0”, “1”, “1”, 1]
-
循环结束后,可得到列表
-
[ ["0", "0", "0", 1], ["0", "0", "1", 0], ["0", "1", "0", 1], ["0", "1", "1", 1], ["1", "0", "0", 1], ["1", "0", "1", 1], ["1", "1", "0", 1], ["1", "1", "1", 1], ]
-
-
将表达式并入变量名列表,可得到
-
["p", "q", "r", "p|q|!r"]
-
-
得到最终真值表
-
直接根据真值表得到主析取范式和主合取范式(具体方法见离散数学教材)
- 主合取范式为:M1
- 主析取范式为:m0vm2vm3vm4vm5vm6vm7
python对应下标 | p | q | r | p|q|!r |
---|---|---|---|---|
0 | 0 | 0 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
2 | 0 | 1 | 0 | 1 |
3 | 0 | 1 | 1 | 1 |
4 | 1 | 0 | 0 | 1 |
5 | 1 | 0 | 1 | 1 |
6 | 1 | 1 | 0 | 1 |
7 | 1 | 1 | 1 | 1 |
最终代码
__ init __.py:
__all__ = ['operator', 'Algorithm']
operator.py:
def _not_(value):
"""
定义否定联结词
"""
# 判断传入值是否为0/1
if value not in [0, 1]:
return -1
# 返回否定式
return 1 if value == 0 else 0
def _conjunction_(value1, value2):
"""
定义合取联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return value1 & value2
def _disjunctive_(value1, value2):
"""
定义析取联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return value1 | value2
def _implied_(value1, value2):
"""
定义蕴涵联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return 0 if (value1 == 1 and value2 == 0) else 1
def _equivalent_(value1, value2):
"""
定义等价联结词
"""
# 判断是否为0/1
if (value1 not in [0, 1]) | (value2 not in [0, 1]):
return -1
return 1 if (value1 == value2) else 0
def get_result(operator, *values):
# 若联结词未定义,抛出异常
if operator not in ['!', '&', '|', '>', '-']:
return -1
# 判断操作数数目是否正确
if len(values) == 0:
return -1
if (operator == '!') and (len(values) >= 2):
return -1
if (operator in ['&', '|', '>', '-']) and (len(values) != 2):
return -1
# 进行运算
res = -1
if operator == '!':
res = _not_(values[0])
elif operator == '&':
res = _conjunction_(values[0], values[1])
elif operator == '|':
res = _disjunctive_(values[0], values[1])
elif operator == '>':
res = _implied_(values[0], values[1])
elif operator == '-':
res = _equivalent_(values[0], values[1])
return res
Algorithm.py:
"""
通过 栈 定义 逻辑运算
"""
from logical_operation import operator
# 定义符号优先级
prority_dict = {"!": 1, "&": 2, "|": 3, ">": 4, "-": 5} # 1代表最高的优先级
# 定义数字栈和符号栈
num_stack, ope_stack = [], []
# 将 出栈运算 步骤封装
def temp():
ope = ope_stack.pop()
# 一元运算符
if ope == '!':
v = num_stack.pop()
res = operator.get_result(ope, v)
# 二元运算符
else:
v2 = num_stack.pop()
v1 = num_stack.pop()
res = operator.get_result(ope, v1, v2)
num_stack.append(res)
def algorithm(expression):
for str in expression:
# 若是数字,则直接加入数字栈((!1&1)|(1&!1))>0
if str in '01':
num_stack.append(int(str))
continue
# 若是符号,则判断入栈还是运算
if (str in prority_dict.keys()) | (str in '()'):
# 若符号栈为空、栈顶符号为‘(’、当前符号为‘(’,则直接入栈
if (len(ope_stack) == 0) or (ope_stack[-1] == '(') or (str == '('):
ope_stack.append(str)
continue
if str == ')':
while ope_stack[-1] != '(':
temp()
ope_stack.pop()
continue
# 若当前符号优先级小于等于栈顶符号优先级,则进行运算
# 直至栈为空,或者当前符号优先级大于栈顶符号优先级
while prority_dict[str] > prority_dict[ope_stack[-1]]:
temp()
# 若栈已经为空、或栈顶符号为‘(’,则直接退出循环
if (len(ope_stack) == 0) or (ope_stack[-1] == '('):
break
ope_stack.append(str)
continue
# 表达式遍历完成,检查符号栈中是否还有符号
if len(ope_stack) == 0:
return num_stack[-1]
else:
while len(ope_stack) != 0:
temp()
return num_stack[-1]
main.py:
import logical_operation.Algorithm as al
import pandas as pd
import sys
if __name__ == '__main__':
exp = input("请输入表达式: ")
# 指定变量
var_name = ['p', 'q', 'r']
result = list()
# 生成0/1
for i in range(2 ** len(var_name)):
bin_list = list(str(bin(i))[2:].zfill(len(var_name)))
# 将变量替换为01
expt = exp
for j in range(len(var_name)):
expt = expt.replace(var_name[j], bin_list[j])
res = al.algorithm(expt)
if res == -1:
print("error!!!")
sys.exit(0)
bin_list.append(res)
result.append(bin_list)
var_name.append(exp)
result2 = pd.DataFrame(result, columns=var_name, index=None)
M_list = list()
m_list = list()
for i in range(len(result)):
if result[i][len(var_name)-1] == 0:
M_list.append(f"M{i}")
else:
m_list.append(f"m{i}")
print(f"主合取范式为:{ '^'.join(M_list) }")
print(f"主析取范式为:{ 'v'.join(m_list) }")
print(result2)
最后
上述代码仅供参考,其还有可以改进的地方,例如,可以将生成真值表的代码进一步封装为函数。