一般问题
我已经多次注意到push-pop
已经弹出的范围似乎会影响check-sat
后续范围中的 a 所需的时间。
也就是说,假设一个程序具有多个(可能是任意嵌套的)push-pop 作用域,每个作用域都包含一个 check-sat 命令。此外,假设第二个 check-sat 需要 10 秒,而第一个只需要 0.1 秒。
...
(push)
(assert (not P))
(check-sat) ; Could be sat, unsat or unknown
(pop)
...
(push)
(assert (not Q))
(check-sat) ; Could be sat, unsat or unknown
(pop)
注释完第一个 push-pop 范围后,第二个 check-sat 只需要 1s。这是为什么?
AFAIK,如果使用推弹范围,Z3 会切换到增量求解器。他们为什么会这样表现有(概念上的)原因吗?
曾经有人告诉我,Z3 按重要性为符号分配属性,这会影响证明搜索(在证明搜索期间,符号的重要性也会发生变化)。这可能是原因吗?是否可以重置重要性(在范围之间)?
这可能是一个错误吗?我发现这篇文章Leonardo 提到了一个似乎相关的错误(不过,他的回答来自 2012 年)。
具体实例
不幸的是,我只有相当长的(自动生成的)SMTLib 文件来说明该行为,您可以在此 gist中找到其中一个文件。它使用量词和未解释的函数,但既不使用mbqi
数组也不使用位向量。该示例由 148 个嵌套的 push-pop 作用域和 89 个 check-sat 组成,Z3 4.3.2 大约需要 8s 来处理它。最后一次检查(以 为前缀echo
)耗时最长。
我随机评论了几个 push-pop 作用域(一次一个,永远不会是最后一个,确保你没有评论符号声明),并且在大多数情况下,整体运行时间下降到不到 1 秒。也就是说,最后一次检查坐的速度要快得多。
为了提供更多详细信息,我将运行 Z3 与所有范围(慢,8 秒)与运行 Z3 进行比较,其中标记的范围[XXX]
已被注释(快速,0.3 秒)。结果可以在这个差异中看到(左慢,右快)。
diff 表明所有检查-sat 的行为都相同(我通过回显“unsat”来伪造评论过的一个),从中我得出结论,评论范围会影响证明搜索,但不会影响其最终结果。
我还试图从获得的统计数据的差异中找出一些意义,但我对如何正确解释统计数据知之甚少。以下是我能理解的一些统计数据:
grobner
(383 vs 36)和nonlinear-horner
(342 vs 25),所以看起来较慢的运行执行更多与算术相关的操作。注释范围确实即将进行非线性算术(许多其他算法也是如此),但是注释范围中的特定证明应该是“微不足道的”,它本质上表明x != 0
对于x
已0 < x
明确假设的一个。memory
(40 vs 7),我解释为表明Z3在程序的慢版本中探索了更大的搜索空间quant-instantiations
(43k vs 51k),这让我感到惊讶,因为明显更快的运行仍然触发了更多的量词实例化。