命题逻辑中真值表方法的应用

实验目的及要求:

【实验目的】

通过编程掌握命题逻辑中的联结词、真值表、主范式等概念,进一步能用他们来解决实际问题。

【实验要求】

1. 从键盘输入一串符号,判断这串符号是否是合式公式(否定、合取、析取、蕴涵和等价联结词可以分别用“-”“*”“+”“->”"<->"代替)

2. 分别给出两个命题变项pq运用否定、合取、析取、蕴涵和等价的真值表。

3. 从键盘输入含三个及以上命题变项的命题公式,输出其主析取范式。

供参考的命题公式:①编程预测比赛名次,A,B,C,D四人参加百米赛跑,观众甲、乙、丙预测比赛的名次为:甲说: C第一,B第二;乙说: C第二,D第三;丙说: A第二,D第四;比赛结束后发现甲、乙、丙每人的预测都只对一半,试问实际名次如何(假定没有并列者)?②编程判断以下推理是否正确:若今天不是星期六,明天就不是星期一。明天是星期一,所以,今天是星期六。

实验原理及内容:填写格式:宋体,五号,行距最小值18

【实验原理】(列出相关知识点)

这次实验是关于命题逻辑的实验。命题逻辑是研究命题之间关系的学科,其中命题是指能够判断真假的陈述。在命题逻辑中,有许多概念和符号,如否定、合取、析取、蕴含、等价等。这些符号和概念可以用来表示命题之间的关系和逻辑含义。

在本次实验中,我们使用Python编写了两个程序,分别实现了命题公式的语法检查和主析取范式的计算。其中,命题公式的语法检查是指检查输入的命题公式是否符合命题逻辑的语法规范,而主析取范式是指将一个命题公式转换为一组合取范式的形式,其中每个合取式均为不可再分的极小项,且每个极小项均为一个命题变项或其否定。

具体来说,命题公式的语法检查程序通过遍历输入的符号串,检查其中的每个字符是否属于规定的字符集,如命题变项、否定、合取、析取、蕴含、等价、左括号和右括号等,同时还需要对括号的使用进行检查,确保括号的匹配正确。主析取范式的计算程序则使用了Python中的符号计算库Sympy,将输入的命题公式转换为Sympy中的表达式对象,然后调用库函数to_dnf()将表达式对象转换为主析取范式。最后,将计算结果转换为字符串形式,并对其中的变量名和符号进行替换和调整,得到最终的主析取范式字符串。

以下为所用到的知识点:

以下是联结词、真值表、主范式的相关知识点:

1、联结词

联结词是在逻辑表达式中用于连接或者修饰命题的符号,例如“非”、“合取”、“析取”、“蕴含”等。

常见的联结词包括:非(not)、合取(and)、析取(or)、条件(if-then或者implication)、双条件(if and only if或者biconditional)等。

2、真值表

真值表是一个表格,用来表示给定命题变量和联结词的组合下,逻辑表达式的真值。

真值表中列出了所有可能的命题变量取值组合以及对应的逻辑表达式的真值。

3、主范式

主范式是在布尔代数中用于将逻辑表达式转化为一种标准形式的方法。

常见的主范式包括:合取范式(conjunctive normal formCNF)和析取范式(disjunctive normal formDNF)。

合取范式是将逻辑表达式转化为若干个子句(即若干个合取式),每个子句由一个或多个命题变量或者它们的否定构成,并且所有子句使用析取运算符连接。

析取范式是将逻辑表达式转化为若干个项(即若干个析取式),每个项由一个或多个命题变量或者它们的否定构成,并且所有项使用合取运算符连接。

4、合式公式

合式公式是指由命题变项、联结词和括号组成的符号串,其中命题变项是指代表命题的变量,联结词是用来连接命题变项的逻辑符号,括号用来分组表示命题间的逻辑关系。

合式公式的一个重要性质是能够被赋予真值,即对于公式中的每一个命题变项,都可以确定它们的真值(真或假),然后根据公式中的联结词和括号进行逐步推导,最终得出整个公式的真值。

判断一个符号串是否为合式公式,需要满足以下两个条件:

1、符号串中只包含命题变项、联结词和括号,且联结词和括号使用正确。

2、符号串中的每一个命题变项都能够被确定其真值,即符号串具有明确的真值

5、主析取范式

主析取范式(DNF)是命题逻辑中的一种重要范式,也是逻辑表达式的一种重要形式。它表示为多个项的析取,每个项是多个命题变项的合取,即将一个逻辑表达式表示为若干个命题变项的合取式之和的形式。

主析取范式的构造过程是将原命题公式通过逻辑等价关系变换为一个或多个命题变项的合取式的析取,即将原命题公式转化为若干个单独的命题变项或其否定式的析取。因此,主析取范式在逻辑表达式的简化和化简、推理等方面具有重要的作用。

在计算机科学中,主析取范式的应用非常广泛,例如,它可以用于电路设计中的最小化、布尔运算的化简以及逻辑推理等方面。

【程序思路】

1问思路:首先,代码通过input()函数获取用户输入的符号串,将其中的否定、合取、析取、蕴涵和等价联结词分别替换成对应的符号。这个过程是通过多次调用字符串的replace()方法实现的。

接下来,代码创建一个栈,遍历输入的符号串。如果当前字符是合法的字符(包括命题变项和联结词),则将其压入栈中;如果当前字符是右括号,说明当前的子公式已经处理完毕,需要从栈中弹出这个子公式所在的所有字符,直到遇到左括号为止;如果当前字符是其他符号,说明需要将其与栈顶的联结词进行比较,如果栈顶元素的优先级比当前符号高,则需要弹出栈顶元素,直到栈顶元素优先级不高于当前符号,然后再将当前符号压入栈中。

最后,代码检查栈中是否只剩下一个命题变项,如果是则说明输入的符号串是合式公式,否则不是。

总体来说,这段代码实现了一种比较基础的算法,即通过栈来维护公式中的括号和运算符,并且使用了一些字符串替换和比较操作来实现对符号串的处理

3问思路:首先,通过input函数获取用户输入的命题公式,并使用字符串函数replace将其中的否定、合取、析取、蕴涵和等价联结词转化为Python中对应的逻辑运算符。

接着,使用sympify函数将命题公式字符串转换为Sympy中的表达式,并使用to_dnf函数将其转换为主析取范式形式。这一步需要导入sympy模块,并在代码中先定义命题变项p,q,r,s,t

由于Sympy中主析取范式的表达形式与常规形式不同,因此需要对输出结果进行一些字符串处理。具体地,先将主析取范式中的"Or""And"转化为"or""and",将"~"转化为"not ",将括号和空格去除,并将范式拆分为多个子式,每个子式都是由若干个命题变项和它们的否定运算符组成的合取式。

最后,将每个子式中的命题变项和它们的否定运算符转化为"""~",并将子式用""连接起来,形成整个命题公式的主析取范式。

最终,使用print函数输出计算结果。

实验数据与结果分析:(含运行结果截屏)

【实验结果】

1问实验结果:

2问实验结果:

p

¬p

q

¬q

pq

pq

p→q

1

0

1

0

1

1

1

1

0

0

1

0

1

0

0

1

1

0

0

1

1

0

1

0

1

0

0

1

3问实验结果:

实际应用:①编程预测比赛名次,A,B,C,D四人参加百米赛跑,观众甲、乙、丙预测比赛的名次为:甲说: C第一,B第二;乙说: C第二,D第三;丙说: A第二,D第四;比赛结束后发现甲、乙、丙每人的预测都只对一半,试问实际名次如何(假定没有并列者)?②编程判断以下推理是否正确:若今天不是星期六,明天就不是星期一。明天是星期一,所以,今天是星期六。

【结果分析】

实际应用题分析一:

本题需要用到逻辑推理,根据观众的预测信息,反推出比赛的实际名次。设 ABC的实际名次为 abcd,根据甲、乙、丙的预测可以得出以下等式:

c = a

b = d

a = b or a = c or a = d

d = a or d = b or d = c

同时,题目又告诉我们每个观众只对一半预测正确,因此需要考虑排除预测错误的情况。我们可以将实际名次的所有可能情况列出来,然后依次验证每个可能情况是否符合观众的预测。

最后,比赛的实际名次为CB,A,D.

实际应用题分析二:

根据题目中的前提,如果今天不是星期六,那么明天就不是星期一,可以表示为:
如果今天不是星期六,那么明天是星期日、星期一、星期二、星期三、星期四、星期五。但是根据题目的结论,如果明天是星期一,那么今天一定是星期六,这是错误的。因为如果今天是星期五,那么根据前提,明天既可以是星期六(不违背前提),也可以是星期日(也不违背前提),因此推理的结论不正确。

实验小结:(包括问题和解决方法、心得体会、意见与建议等)

在这个实验中,我学习了命题逻辑的相关知识,包括命题、联结词、真值表、主析取范式等。通过编写代码,我深入了解了命题逻辑中的概念和运算,并且更加熟练地掌握了Python编程语言。

在编写代码的过程中,我遇到了一些问题,例如代码逻辑错误、语法错误等。在调试代码的过程中,我通过不断查找资料、理解知识点、分析问题原因等方法,最终成功地解决了这些问题。通过这个过程,我发现了自己在命题逻辑和Python编程中的不足之处,也学会了如何查找和解决问题。

通过这次实验,我不仅学会了命题逻辑和Python编程,还发现了自己的不足和需要进一步提高的方面。我认为,应该实践与理论相结合,这样不仅可以让我更好地掌握这些知识,而且在将来的学习和工作中有所帮助。同时,我会更多的上机实验,加强自己的编程能力和理论运用能力。

实验源代码清单:(带注释)

1问代码:

#通过input函数获取用户输入的符号串,并且依次用replace函数将输入串中的否定、合取、析取、蕴涵和等价联结词分别替换为对应的符号。

input_str = input("请输入符号串:")

input_str = input_str.replace("-", "¬")

input_str = input_str.replace("*", "")

input_str = input_str.replace("+", "")

input_str = input_str.replace("->", "")

input_str = input_str.replace("<->", "↔")

#定义一个栈stack,用于存放操作符和命题变项。

stack = []

#逐个处理输入符号串中的字符。如果当前字符是合法的字符(包括命题变项和联结词),则将其压入栈中;如果当前字符是右括号,说明当前的子公式已经处理完毕,需要从栈中弹出这个子公式所在的所有字符,直到遇到左括号为止;如果当前字符是其他符号,说明需要将其与栈顶的联结词进行比较,如果栈顶元素的优先级比当前符号高,则需要弹出栈顶元素,直到栈顶元素优先级不高于当前符号,然后再将当前符号压入栈中。

for c in input_str:

    if c in ["¬", "", "", "", "↔", "(", "p", "q", "r", "s", "t"]:

        stack.append(c)

    elif c == ")":

        if stack[-1] in ["p", "q", "r", "s", "t"]:

            stack.pop()

            stack.pop()

            if stack and stack[-1] == "¬":

                stack.pop()

        else:

            while stack and stack[-1] != "(":

                stack.pop()

            if stack:

                stack.pop()

    else:

        while stack and stack[-1] in ["¬", "", "", "", "↔"]:

            stack.pop()

        stack.append("p")

if len(stack) == 1 and stack[0] in ["p", "q", "r", "s", "t"]:

    print("是合式公式")

else:

    print("不是合式公式")

3问代码:

from sympy import *

定义命题变项
p, q, r, s, t = symbols(&apos;p q r s t&apos;)

输入命题公式
input_str = input("请输入命题公式:")
将命题公式转换为否定、合取、析取和命题变项的组合形式
input_str = input_str.replace("-", "not ")
input_str = input_str.replace("*", " and ")
input_str = input_str.replace("+", " or ")
input_str = input_str.replace("->", " <= ")
input_str = input_str.replace("<->", " == ")
将命题公式转换为主析取范式
expr = sympify(input_str)
expr = to_dnf(expr)
expr_str = str(expr)
expr_str = expr_str.replace("Or", "or")
expr_str = expr_str.replace("And", "and")
expr_str = expr_str.replace("~", "not ")
expr_str = expr_str.replace("(", "")
expr_str = expr_str.replace(")", "")
expr_str = expr_str.replace(" ", "")
expr_list = expr_str.split("or")
for i, item in enumerate(expr_list):
    item_list = item.split("and")
    for j, sub_item in enumerate(item_list):
        if sub_item == "Not(p)":
            item_list[j] = "~p"
        elif sub_item == "Not(q)":
            item_list[j] = "~q"
        elif sub_item == "Not(r)":
            item_list[j] = "~r"
        elif sub_item == "Not(s)":
            item_list[j] = "~s"
        elif sub_item == "Not(t)":
            item_list[j] = "~t"
    item_str = "
".join(item_list)
    expr_list[i] = item_str
result = " 
 ".join(expr_list)
result = result.replace("q", "q
rs")
result = result.replace("r", "q
rs")
result = result.replace("s", "q
rs")
print("
主析取范式为:", result)

实际应用代码:

一:

import itertools

# 枚举实际名次的所有可能情况

for a, b, c, d in itertools.permutations(range(1, 5)):

    # 验证甲的预测是否正确

    if c == a and b == d:

        # 验证乙的预测是否正确

        if c == 2 and d == 3:

            # 验证丙的预测是否正确

            if a == 2 and d == 4:

                print(f"实际名次为:{c}{d}{b}{a}")

                break

二:

today = ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

tomorrow = {"Sunday": "Monday", "Monday": "Tuesday", "Tuesday": "Wednesday", "Wednesday": "Thursday", "Thursday": "Friday", "Friday": "Saturday", "Saturday": "Sunday"}

if "Monday" == tomorrow[today[5]]:

    if "Saturday" != today[5]:

        print("推理错误")

    else:

        print("推理正确")

else:

    print("推理错误")

猜你喜欢

转载自blog.csdn.net/m0_65168503/article/details/131143682