【问题标题】:Z3: finding all satisfying modelsZ3:找到所有满意的模型
【发布时间】:2012-11-03 22:15:02
【问题描述】:

我正在尝试使用 Z3(Microsoft Research 开发的 SMT 求解器)检索某些一阶理论的所有可能模型。这是一个最小的工作示例:

(declare-const f Bool)
(assert (or (= f true) (= f false)))

在这个命题案例中,有两个令人满意的分配:f->truef->false。因为 Z3(以及一般的 SMT 求解器)只会尝试找到一个令人满意的模型,所以不可能直接找到所有解决方案。 Here 找到了一个好用的命令,叫(next-sat),不过好像最新版的Z3已经不支持了。这对我来说有点不幸,总的来说我认为该命令非常有用。还有其他方法吗?

【问题讨论】:

    标签: z3 smt theorem-proving


    【解决方案1】:

    实现此目的的一种方法是使用其中一个 API 以及模型生成功能。然后,您可以使用从一个可满足性检查生成的模型来添加约束,以防止以前的模型值被用于后续可满足性检查,直到没有更多令人满意的分配。当然,您必须使用有限排序(或有一些约束来确保这一点),但如果您不想找到所有可能的模型(即,在生成一堆后停止),您也可以将其与无限排序一起使用.

    这是一个使用 z3py 的示例(链接到 z3py 脚本:http://rise4fun.com/Z3Py/a6MC):

    a = Int('a')
    b = Int('b')
    
    s = Solver()
    s.add(1 <= a)
    s.add(a <= 20)
    s.add(1 <= b)
    s.add(b <= 20)
    s.add(a >= 2*b)
    
    while s.check() == sat:
      print s.model()
      s.add(Or(a != s.model()[a], b != s.model()[b])) # prevent next model from using the same assignment as a previous model
    

    一般来说,使用所有涉及的常量的析取应该可以工作(例如,ab 这里)。这将枚举满足a &gt;= 2bab(在120 之间)的所有整数赋值。例如,如果我们将ab 限制在15 之间,则输出为:

    [b = 1, a = 2]
    [b = 2, a = 4]
    [b = 1, a = 3]
    [b = 2, a = 5]
    [b = 1, a = 4]
    [b = 1, a = 5]
    

    【讨论】:

    • 另外,请参阅此答案:stackoverflow.com/questions/11867611/…
    • Z3 是否是有状态的,它会从中断的地方继续进行此类搜索?似乎每次都重新开始是很浪费的,因为(直觉上)所有的工作都完全相同,除了最后。
    • @GManNickG 对于我使用此方法的示例,看起来确实是有状态的,因为在初始模型之后找到接下来的几个模型更快。以下是具有 58 个模型的特定案例的运行时间列表(以毫秒为单位):8942 801 1663 5 599 320 450 2 2 3 1 5 1377 36 5 738 162 105 1639 3 5 16 2041 27 475 953 562 746 45 151 18 4206 3416 9 850 120 3 4 12 615 593 1219 449 154 987 3 10 1365 16 438 792 1686 743 46 5 8 412 126。请注意,第一个绝对是最长的,但其他的随机性更大(可能取决于问题和求解器的幸运程度)。
    • @GManNickG 是的,只要您使用相同的 Solver 对象,它就会保留所有学习的子句。您可以使用 push 和 pop 有选择地忘记学习的子句回到上次推送(删除约束的唯一方法是弹回之前的推送)。
    【解决方案2】:

    基于 Taylors 答案的更通用的解决方案是使用

    while s.check() == z3.sat:  
        solution = "False"
        m = s.model()
        for i in m:
            solution = f"Or(({i} != {m[i]}), {solution})"
        f2 = eval(solution)
        s.add(f2)
    

    这允许两个以上的变量。

    【讨论】:

    • 这个解决方案可能效率很低,从字符串/eval 等返回。此外,它阻止解决方案的方式也不是最佳的。请参阅stackoverflow.com/a/70656700/936310 以获得更好的方法。
    猜你喜欢
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 2016-02-16
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    相关资源
    最近更新 更多