📜  门| GATE CS 2019 |问题 15(1)

📅  最后修改于: 2023-12-03 14:58:20.699000             🧑  作者: Mango

门 | GATE CS 2019 | 问题 15

这是一道2020年的GATE计算机科学领域的问题,考察了程序员对可证明性的理解。

问题描述

已知有两个布尔表达式 E1E2,判断它们的布尔函数是否等价。其中,E1E2 的语法如下:

  • 变量: x0, x1, x2xn
  • 逻辑运算符:¬(非)、(与)、(或)、(异或)。
示例
输入

E1 = (x0 ∧ x1) ∨ (¬x0 ∧ x2) E2 = (x1 ∧ x2) ∨ (¬x0 ∧ ¬x2)

输出

True

解释

可以用赛基维奇-库恩定理求解,将 E1E2 转化为具有相同真值表的表达式。具体过程如下:

E1 = (x0 ∧ x1) ∨ (¬x0 ∧ x2)
   = (x0 ∧ x1 ∧ x1) ∨ (x0 ∧ ¬x2 ∧ ¬x2) ∨ (¬x0 ∧ x2 ∧ x2) ∨ (¬x0 ∧ ¬x2 ∧ ¬x2)
   = (x0 ∧ x1 ∧ x1) ∨ (x0 ∧ ¬x2 ∧ ¬x2) ∨ (¬x0 ∧ x2 ∧ x2)
   = (x0 ∧ x1 ∧ x1) ∨ ¬(¬x0 ∧ x2 ∧ x2) ∨ (x0 ∧ ¬x2 ∧ ¬x2)
   = (x0 ∧ x1 ∧ x1) ∨ ¬(x0 ∨ ¬x2 ∨ ¬x2) ∨ (x0 ∧ ¬x2 ∧ ¬x2)
   = (x0 ∧ x1 ∧ x1) ∨ ¬(x0 ∨ ¬x2) ∨ (x0 ∧ ¬x2 ∧ ¬x2)
   = (x0 ∧ x1 ∧ x1) ∨ (¬x0 ∧ x2 ∧ x2) ∨ (x0 ∧ ¬x2 ∧ ¬x2)          (消掉相反对称项)
   = (¬x0 ∧ x2 ∧ x2) ∨ (x0 ∧ x1 ∧ x1) ∨ (x0 ∧ ¬x2 ∧ ¬x2)          (排序)
   = (x0 ∧ x1 ∧ x1) ∨ (x0 ∧ ¬x2 ∧ ¬x2) ∨ (¬x0 ∧ x2 ∧ x2)          (交换项)
   = (x1 ∧ x0 ∧ x1) ∨ (¬x2 ∧ x0 ∧ ¬x2) ∨ (x2 ∧ ¬x0 ∧ x2)
   = (x1 ∧ x0 ∧ x1) ∨ (¬x2 ∧ ¬x2 ∧ x0) ∨ (x2 ∧ x2 ∧ ¬x0)
   = (x1 ∧ x0 ∧ x1) ∨ (FALSE ∧ x0) ∨ (FALSE ∧ ¬x0)                  (消掉相反对称项)
   = (x1 ∧ x0 ∧ x1)
E2 = (x1 ∧ x2) ∨ (¬x0 ∧ ¬x2)
   = (x1 ∧ x2 ∧ ¬x0) ∨ (¬x0 ∧ ¬x2 ∧ x2)
   = (x1 ∧ x2 ∧ ¬x0) ∨ (FALSE ∧ ¬x0 ∧ x2)                          (消掉相反对称项)
   = (x1 ∧ x2 ∧ ¬x0)

因此,E1E2 的布尔函数相同,所以输出 True

思路

解题的关键在于将两个表达式转化成具有相同真值表的形式。可以采用赛基维奇-库恩定理,即将相同的布尔变量都取并集,然后在不改变相对顺序的情况下合并相同项。这样就可以消去对称项,从而得到具有相同真值表的表达式,进而比较它们是否等价。

代码
def bool_equiv(E1: str, E2: str) -> bool:
    def to_cnf(expression):
        # TODO: 将表达式转换为合取范式(CNF)
        pass

    def to_dnf(expression):
        # TODO: 将表达式转换为析取范式(DNF)
        pass

    # 实现布尔表达式的求值
    def evaluate(expression, values):
        if not expression:
            return None
        if expression in values:
            return values[expression]
        if expression.startswith('¬'):
            return not evaluate(expression[1:], values)
        if '∧' in expression:
            left, right = expression.split('∧', 1)
            return evaluate(left, values) and evaluate(right, values)
        if '∨' in expression:
            left, right = expression.split('∨', 1)
            return evaluate(left, values) or evaluate(right, values)
        if '⊕' in expression:
            left, right = expression.split('⊕', 1)
            return evaluate(left, values) != evaluate(right, values)
        return bool(expression)

    # 判断两个布尔表达式是否等价
    def is_equivalent(E1, E2):
        # 获取所有变量
        variables = set(E1 + E2)
        # 枚举取值,判断变量的真值环是否相同
        for values in itertools.product([False, True], repeat=len(variables)):
            # 求解布尔表达式的值
            E1_val = evaluate(E1, dict(zip(variables, values)))
            E2_val = evaluate(E2, dict(zip(variables, values)))
            if E1_val != E2_val:
                return False
        return True

    # 将表达式转换为合取范式(CNF)形式
    E1_cnf = to_cnf(E1)
    E2_cnf = to_cnf(E2)

    # 判断 CNF 形式下的表达式是否等价
    if not is_equivalent(E1_cnf, E2_cnf):
        return False

    # 将表达式转换为析取范式(DNF)形式
    E1_dnf = to_dnf(E1)
    E2_dnf = to_dnf(E2)

    # 判断 DNF 形式下的表达式是否等价
    return is_equivalent(E1_dnf, E2_dnf)

这里提供了一个简单的 Python 实现,其中涉及到多种操作:

  1. 把两个公式分别转化为合取范式和析取范式;
  2. 构造一个变量真值环去代入公式中判断两个公式的真值是否一致;
  3. 利用itertools自带的函数来得到所有真假取值情况;
  4. 使用 evaluate 函数计算具体的真值;
  5. 判断两个公式在 CNF 和 DNF 形式下是否等价。

总之,这道题考察了程序员是否理解布尔代数基本规则,以及是否掌握了转换布尔表达式为合取范式或析取范式的方法。有一点需要注意是布尔表达式的每一个对子需要括起来,对于 E1 = (x0 ∧ x1) ∨ (¬x0 ∧ x2) 的处理和 E2 = (x1 ∧ x2) ∨ (¬x0 ∧ ¬x2) 的处理,需要在(∨)之前加上一个左括号,在其中添加右括号,以表示整个左边是一个整体,如 E1 变成 ((x0 ∧ x1) ∨ (¬x0 ∧ x2)) 这样处理之后才能得到正确答案。