Z3 的搜索时间对公式顺序敏感吗?
Is Z3's search time sensitive to formula order?
在许多编程语言中,分支效率取决于提供子句的顺序。例如,在 Python、
if p or q :
将在 p
计算结果为真时立即分支到 if 语句,因此通常最好先提供计算量小的子句。我想知道 Z3 中的可满足性检查是否也是如此。换句话说,检查 And(P, Q)
和 And(Q, P)
之间是否有任何区别,前提是其中一个公式比另一个公式复杂得多?
是的,您指定子句的顺序可能会有所不同。然而,当谈到 Z3 时,重新排列条款可能不会有太多收获。此外,预先确定通用 "optimal order" 可能很困难(也许不值得你花时间)。
对于其他 SMT 求解器,我观察到您以极端方式描述的内容。对于某些求解器,它可以完成或破坏计算,从某种意义上说,在某些情况下,当子句以一种顺序呈现时求解器超时,但当相同的子句以不同顺序呈现时,它会迅速找到解决方案.但是,对我来说,这表明求解器设计不当。 Z3 和其他现代 SMT 求解器(如 CVC4)比旧的或不太健壮的 SMT 求解器更不容易受到此类问题的影响。
关于实际找到最佳排序,SMT 求解器的 "computationally light" 或 "more complex" 与传统计算机语言不同。真正重要的是连接中的某个子句是否可能导致冲突,或者析取中的特定子句是否可能导致解决方案。这类似于试图找到走出迷宫的出路——如果你一开始就走错了路,那么在你最终决定回到起点并采取不同的道路之前,你可能会在死胡同中花费很长时间分支。同样,现代 SMT 和 SAT 求解器具有缓解这种情况的技术。
此外,具体到 Z3,如果可以通过根据一些人类可理解的通用复杂性度量对子句进行排序来使 Z3 在现实世界的应用程序中更有效率,那么它可能已经添加为Z3 的预处理步骤。通常,对于涉及多个因素(例如 Z3 实现的细节)的复杂优化问题,您必须尝试多种方法并在与您的应用程序相关的一组测试示例中进行基准测试。
作为我上面的一些主张的一点证据,我写了这个 SMT 问题的小例子:
(declare-fun p () Int)
(declare-fun q () Int)
(declare-fun n () Int)
(assert (> p 1))
(assert (> q 1))
(assert (and (= n 18679565357) (= n (* p q))))
(check-sat)
(get-value (p q n))
(exit)
交换 and
语句中子句的顺序对我的系统影响很小(不到 1%)。如果我把它分成两个单独的断言,那么差异会更大,但要知道这种差异是否普遍存在(跨这个 class 的不同 SMT 问题)我必须 运行 一个基准套件有很多这样的问题。
在许多编程语言中,分支效率取决于提供子句的顺序。例如,在 Python、
if p or q :
将在 p
计算结果为真时立即分支到 if 语句,因此通常最好先提供计算量小的子句。我想知道 Z3 中的可满足性检查是否也是如此。换句话说,检查 And(P, Q)
和 And(Q, P)
之间是否有任何区别,前提是其中一个公式比另一个公式复杂得多?
是的,您指定子句的顺序可能会有所不同。然而,当谈到 Z3 时,重新排列条款可能不会有太多收获。此外,预先确定通用 "optimal order" 可能很困难(也许不值得你花时间)。
对于其他 SMT 求解器,我观察到您以极端方式描述的内容。对于某些求解器,它可以完成或破坏计算,从某种意义上说,在某些情况下,当子句以一种顺序呈现时求解器超时,但当相同的子句以不同顺序呈现时,它会迅速找到解决方案.但是,对我来说,这表明求解器设计不当。 Z3 和其他现代 SMT 求解器(如 CVC4)比旧的或不太健壮的 SMT 求解器更不容易受到此类问题的影响。
关于实际找到最佳排序,SMT 求解器的 "computationally light" 或 "more complex" 与传统计算机语言不同。真正重要的是连接中的某个子句是否可能导致冲突,或者析取中的特定子句是否可能导致解决方案。这类似于试图找到走出迷宫的出路——如果你一开始就走错了路,那么在你最终决定回到起点并采取不同的道路之前,你可能会在死胡同中花费很长时间分支。同样,现代 SMT 和 SAT 求解器具有缓解这种情况的技术。
此外,具体到 Z3,如果可以通过根据一些人类可理解的通用复杂性度量对子句进行排序来使 Z3 在现实世界的应用程序中更有效率,那么它可能已经添加为Z3 的预处理步骤。通常,对于涉及多个因素(例如 Z3 实现的细节)的复杂优化问题,您必须尝试多种方法并在与您的应用程序相关的一组测试示例中进行基准测试。
作为我上面的一些主张的一点证据,我写了这个 SMT 问题的小例子:
(declare-fun p () Int)
(declare-fun q () Int)
(declare-fun n () Int)
(assert (> p 1))
(assert (> q 1))
(assert (and (= n 18679565357) (= n (* p q))))
(check-sat)
(get-value (p q n))
(exit)
交换 and
语句中子句的顺序对我的系统影响很小(不到 1%)。如果我把它分成两个单独的断言,那么差异会更大,但要知道这种差异是否普遍存在(跨这个 class 的不同 SMT 问题)我必须 运行 一个基准套件有很多这样的问题。