利用真值表法求取主析取范式及主合取范式

利用真值表法求取主析取范式及主合取范式

程序结构

├─ code
│  ├─logical_operation
│  │  ├─__init__.py
│  │  ├─Algorithm.py
│  │  └─operator.py
│  └─main.py
  • code:主程序文件夹
    • logical_operation:定义与逻辑运算有关的符号及运算法则
      • __ init __.py:用于将文件夹变为一个python模块
      • Algorithm.py:定义逻辑运算符的运算法则
      • operator.py:定义逻辑运算符符号
    • main.py:主程序

__ 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对应下标pqrp|q|!r
00001
10010
20101
30111
41001
51011
61101
71111

最终代码

__ 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)

最后

上述代码仅供参考,其还有可以改进的地方,例如,可以将生成真值表的代码进一步封装为函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值