使用 Z3 查找特定 CHC 系统的 'guess solution' 的反例?
Use Z3 to find counterexamples for a 'guess solution' to a particular CHC system?
假设我有以下 CHC 系统(I(x) 是一个未知谓词):
(x = 0) -> I(x)
(x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
I(x) /\ (x >= 5) -> x = 5
现在假设我猜测 I(x) 的解为 x < 2(实际上是错误的猜测)。我可以为 Z3Py 编写代码来 (i) 检查它是否是一个有效的解决方案,并且 (ii) 如果它不正确,找到一个反例,即一个满足 x < 2 但至少不满足上述 3 个方程式之一的值? (例如:x = 1,不满足第二个方程是反例吗?)
当然可以。进行这种推理的方法是断言所有约束的合取是否定,并询问 z3 是否可以满足它。如果否定返回可满足,那么你就有了一个反例。如果是unsat
,那你就知道你的不变量很好
这是一种以通用方式对这个想法进行编码的方法,由约束生成器和猜测的不变量参数化:
from z3 import *
def Check(mkConstraints, I):
s = Solver()
# Add the negation of the conjunction of constraints
s.add(Not(mkConstraints(I)))
r = s.check()
if r == sat:
print("Not a valid invariant. Counter-example:")
print(s.model())
elif r == unsat:
print("Invariant is valid")
else:
print("Solver said: %s" % r)
鉴于此,我们可以在函数中编写您的特定案例:
def System(I):
x, xp = Ints('x xp')
# (x = 0) -> I(x)
c1 = Implies(x == 0, I(x))
# (x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
c2 = Implies(And(x < 5, I(x), xp == x+1), I(xp))
# I(x) /\ (x >= 5) -> x = 5
c3 = Implies(And(I(x), x >= 5), x == 5)
return And(c1, c2, c3)
现在可以查询了:
Check(System, lambda x: x < 2)
以上打印:
Not a valid invariant. Counter-example:
[xp = 2, x = 1]
表明 x=1
违反了约束条件。 (您可以编写代码,以便它也准确地告诉您违反了哪个约束,但我离题了。)
如果您提供有效的解决方案会怎样?让我们看看:
Check(System, lambda x: x <= 5)
这会打印:
Invariant is valid
请注意,我们不需要任何量词,因为顶级变量在 z3 中充当存在项,我们需要做的就是查找是否存在违反约束的赋值。
假设我有以下 CHC 系统(I(x) 是一个未知谓词):
(x = 0) -> I(x)
(x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
I(x) /\ (x >= 5) -> x = 5
现在假设我猜测 I(x) 的解为 x < 2(实际上是错误的猜测)。我可以为 Z3Py 编写代码来 (i) 检查它是否是一个有效的解决方案,并且 (ii) 如果它不正确,找到一个反例,即一个满足 x < 2 但至少不满足上述 3 个方程式之一的值? (例如:x = 1,不满足第二个方程是反例吗?)
当然可以。进行这种推理的方法是断言所有约束的合取是否定,并询问 z3 是否可以满足它。如果否定返回可满足,那么你就有了一个反例。如果是unsat
,那你就知道你的不变量很好
这是一种以通用方式对这个想法进行编码的方法,由约束生成器和猜测的不变量参数化:
from z3 import *
def Check(mkConstraints, I):
s = Solver()
# Add the negation of the conjunction of constraints
s.add(Not(mkConstraints(I)))
r = s.check()
if r == sat:
print("Not a valid invariant. Counter-example:")
print(s.model())
elif r == unsat:
print("Invariant is valid")
else:
print("Solver said: %s" % r)
鉴于此,我们可以在函数中编写您的特定案例:
def System(I):
x, xp = Ints('x xp')
# (x = 0) -> I(x)
c1 = Implies(x == 0, I(x))
# (x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
c2 = Implies(And(x < 5, I(x), xp == x+1), I(xp))
# I(x) /\ (x >= 5) -> x = 5
c3 = Implies(And(I(x), x >= 5), x == 5)
return And(c1, c2, c3)
现在可以查询了:
Check(System, lambda x: x < 2)
以上打印:
Not a valid invariant. Counter-example:
[xp = 2, x = 1]
表明 x=1
违反了约束条件。 (您可以编写代码,以便它也准确地告诉您违反了哪个约束,但我离题了。)
如果您提供有效的解决方案会怎样?让我们看看:
Check(System, lambda x: x <= 5)
这会打印:
Invariant is valid
请注意,我们不需要任何量词,因为顶级变量在 z3 中充当存在项,我们需要做的就是查找是否存在违反约束的赋值。