Part A: 基本命题逻辑
这个模块、我们学习如何用z3来解决基本命题逻辑的问题
命题的声明:
我们可以在声明两个布尔类型的命题,当然,这两个命题有两种取值true 或者是false,声明命题P和Q如下:
P = Bool('P')
Q = Bool('Q')
或者,我们可以用简短的写法:
P, Q = Bools('P Q')
用连接词来创建命题:
Z3支持连接词:/\(And), \/(Or), ~(Not), ->(Implies)等等。我们可以通过写lisp风格的抽象语法树来创建命题。比如,这个析取:
P \/ Q (在Z3中连接词\/写成 Or)在AST写法如下:
F = Or(P, Q)
Solve 的使用:
Example A-1: z3中最简单的用法就是直接把命题用z3来写,并通过调用solve()函数来检查可满足性,这个solve()函数将创建一个solver实例来检验命题的可满足性,并且如果命题可满足的话输出一个模型,代码如下:
F = Or(P, Q)
solve(F)
通过以上的调用,z3的输出可能是这样的:
[P=True, Q=False]
这个模型是命题P,Q让命题F可满足的一个结果。很显然,这只是几个可能的模型的其中一个。
Example A-2: 不是所有命题都是可满足的,比如下面这个命题:
F = And(P, Not(P))
solve(F)
Z3 会输出:
no solution
这表明命题F是不可满足的,就是说,不管P的取值是什么,命题F都不可能成立。
获取更多的解法:
再看看Example A-1的例题:
F = Or(P, Q)
solve(F)
默认情况下,Z3只输出真值表的第一行:
P Q P\/Q
-----------------
t t t
t f t
f t t
f f f
总之,我们用Z3来检验命题的可满足性,输出一行已经是足够的。但是如果我们想要输出几行怎么办呢?这里有个技巧: 当我们得到一个答案时,我们对这个答案进行否定,并与原命题结合,然后再检查它的可满足性。对于上面的例子:
F = Or(P, Q) # 命题F
solve(F) #输出一个结果
F = And(F, Not(And(P, Not(Q)))) # 对答案进行否定(Not)、然后与原命题F结合(And)
solve(F)
F = And(F, Not(And(Not(P), Q))) # 对答案进行否定(Not)、然后与原命题F结合(And)
solve(F)
F = And(F, Not(And(P, Q))) # 对答案进行否定(Not)、然后与原命题F结合(And)
solve(F)
输出会包括三种可能的解法:
[P = True, Q = False]
[P = False, Q = True]
[P = True, Q = True]
no solution
Exercise 1:
Question: (P /\ Q) \/ R
P, Q, R =Bools('P Q R') # Exercise1
F = Or((And(P, Q)), R)
solve(F)
Exercise 1-2 :
Question:P \/ ( Q \/ R )
P, Q, R = Bools('P Q R') # exercise1-2
F = Or(P, Or(Q, R))
solve(F)
Exercise 1-3:
Question: (P \/ Q) /\ (Q /\ R) /\ (P /\ ~R) P, Q, R = Bools('P Q R') # exercise1-3 S = And(P, Not(R)) M = And(Q, R) N = Or(P, Q) F = And(N, And(M, S)) solve(F)
输出:no solution
Exercise 1-4 :
Question: (P /\ ~S /\ R) /\ (R /\ ( ~P \/ (S /\ ~Q)))
P, Q, R, S = Bools('P Q R S') # left A = And(Not(S), R) B = And(P, A) # right C = And(S, Not(Q)) D = Or(Not(P), C) E = And(R, D) # left and right F = And(B, E) solve(F)
输出: no solution
Exercise 1-4 :
Question:输出所有的结果 (P /\ Q) \/ R
#中科大软院-形式化方法笔记-可私信交流