我有一个关于Z3如何逐步解决问题的问题。在阅读了一些答案后,我发现了以下内容:
我做了一些比较(欢迎你问一下这些公式,它们太大而无法放在rise4fun上),但这里是我的观察:在一些公式中,包括量词,假设模式更快。在一些包含大量布尔变量(假设变量)的公式中,堆栈模式比假设模式更快。
它们是否针对特定目的实施?增量求解如何在Z3中起作用?
答案 0 :(得分:10)
是的,基本上有两种增量模式。
基于堆栈:使用push(),pop()创建一个遵循堆栈规则的本地上下文。在匹配的pop()之后删除在push()下添加的断言。此外,去除了在推动下衍生的任何引理。使用push()/ pop()模拟冻结状态并在冻结状态上添加其他约束,然后恢复到冻结状态。它的优点是可以释放在push()范围内构建的任何额外的内存开销(例如学习的lemmas)。工作假设是,推动下学习的外表不再有用。
基于假设:使用传递给check()/ check_sat()的附加假设文字,您可以(1)在假设文字上提取不可满足的核心,(2)获得局部递增性,而无需独立于假设得到的垃圾收集引理。换句话说,如果Z3学习了一个不包含任何假设文字的引理,它就不会垃圾收集它们。要有效地使用假设文字,您还必须将它们添加到公式中。因此,权衡是与假设一起使用的子句包含一些膨胀。例如,如果要在本地假设某个公式(< = x y),则添加一个子句(=> p(< = x y)),并在调用check_sat()时假设为p。请注意,原始假设是一个单位。 Z3有效地传播单位。使用假设文字的公式,它不再是搜索基础级别的单位。这会产生一些额外的开销。单位成为二元条款,二元条款成为三元条款等。
推送/弹出功能的区别适用于Z3的默认SMT引擎。这是大多数公式将使用的引擎。 Z3包含一些引擎组合。例如,对于纯位传动问题,Z3可能最终使用基于sat的引擎。基于sat的引擎的增量实现与默认引擎不同。这里使用假设文字来实现增量。您在推送范围内添加的任何断言都被声明为暗示(=> scope_literals公式)。在这样的范围内的check_sat()将不得不处理假设文字。另一方面,任何不依赖于当前范围的结果(引理)都是在pop()上收集的 not 垃圾。
在优化模式下,当您声明优化目标,或者在API上使用优化对象时,您还可以调用push / pop。同样有固定点。对于这两个功能,推/弹主要是为了方便用户。没有内部增量。原因是这两种模式使用了非超级增量的大量预处理。