这主要是一个逻辑问题我猜...
我使用这个smtlib公式:
(declare-fun a () Bool)
(declare-fun b () Bool)
(declare-fun c () Bool)
(declare-fun d () Bool)
(assert (xor (and a (xor b c)) d))
这个结构的一个术语(至少在我看来):
XOR
| |
AND d
| |
a XOR
| |
b c
我的猜测:resultSet看起来像这样:
{ab, ac, d}
但它使用scala ^ z3 ctx.checkAndGetAllModels():
{ab, d, ac, ad, abcd}
为什么广告和abcd在那里? 是否有可能只获得我期望的结果?
答案 0 :(得分:3)
使用Scala(不带Z3)来表明实际上有更多的约束解决方案:
val tf = Seq(true, false)
val allValid =
for(a <- tf; b <- tf; c <- tf; d <- tf;
if((a && (b ^ c)) ^ d)) yield (
(if(a) "a" else "") + (if(b) "b" else "") +
(if(c) "c" else "") + (if(d) "d" else ""))
allValid.mkString("{ ", ", ", " }")
打印:
{ abcd, ab, ac, ad, bcd, bd, cd, d }
所以除非我遗漏了什么,问题是,为什么不找到所有解决方案?现在这是答案。 (剧透警告:“getAllModels”并没有真正获得所有模型。)首先,让我们再现你观察到的内容:
import z3.scala._
val ctx = new Z3Context("MODEL" -> true)
val a = ctx.mkFreshConst("a", ctx.mkBoolSort)
val b = ctx.mkFreshConst("b", ctx.mkBoolSort)
val c = ctx.mkFreshConst("c", ctx.mkBoolSort)
val d = ctx.mkFreshConst("d", ctx.mkBoolSort)
val cstr0 = ctx.mkXor(b, c)
val cstr1 = ctx.mkAnd(a, cstr0)
val cstr2 = ctx.mkXor(cstr1, d)
ctx.assertCnstr(cstr2)
现在,如果我跑:ctx.checkAndGetAllModels.foreach(println(_))
,我得到:
d!3 -> false
a!0 -> true
c!2 -> false
b!1 -> true
d!3 -> true // this model is problematic
a!0 -> false
d!3 -> false
a!0 -> true
c!2 -> true
b!1 -> false
d!3 -> true
a!0 -> true
c!2 -> false
b!1 -> false
d!3 -> true
a!0 -> true
c!2 -> true
b!1 -> true
现在,问题是第二个模型是不完整的模型。 Z3可以返回它,因为无论b
和c
的值是什么,约束都会得到满足(b
和c
不关心变量)。 checkAndGetAllModels
的当前实现只是否定了模型以防止重复;在这种情况下,它会要求另一个模型(not (and d (not a)))
成立。这将阻止返回具有这两个值的所有其他模型。从某种意义上说,不完整的模型实际上代表了四个有效的,完整的模型。
顺便说一下,如果你使用带有findAll
函数的ScalaZ3的DSL,会发生什么情况,所有模型都将完成,当它们不完整时(以及之前)用于计算下一个)。在DSL的上下文中,我们可以这样做,因为我们知道公式中出现的变量集。在这种情况下,很难猜测模型应该如何完成。一种选择是让ScalaZ3记住使用了哪些变量。一个更好的解决方案是Z3可以选择始终返回无关变量的值,或者只是列出模型中的所有不关心变量。