我正在使用Z3来构建有界模型检查器。在尝试实现完整性测试时,我遇到了一个奇怪的性能问题。完整性测试必须确保每个路径最多包含一次状态的所有状态。如果仍然存在满足此属性的路径,则Z3快速得到答案,但是在考虑了所有路径的情况下,Z3似乎呈指数级缓慢。
我已将测试用例减少到以下内容:
; Set the problem size (length of path)
(define-fun sz () Int 5)
; Used to define valid states
(define-fun limit ((s Int)) Bool
(and (>= s 0)
(<= s sz)))
; Constructs a path of a given length
(define-fun path-of-len ((path (Array Int Int)) (len Int)) Bool
(forall ((i Int))
(=> (and (>= i 0)
(< i len))
(limit (select path i)))))
; Asserts that a given path only contains unique states
(define-fun loop-free ((path (Array Int Int)) (len Int)) Bool
(forall ((i Int) (j Int))
(=> (and (>= i 0)
(>= j 0)
(< i len)
(< j len)
(not (= i j)))
(not (= (select path i) (select path j))))))
; Construct a unique path of a given length
(define-fun path ((path (Array Int Int)) (len Int)) Bool
(and (path-of-len path len)
(loop-free path len)))
; Declare a concrete path
(declare-const tpath (Array Int Int))
; Assert that the path is loop free
(assert (path tpath (+ sz 2)))
(check-sat)
在我的计算机上,这会导致以下运行时间(取决于路径长度):
如果我从Int切换到64位的位向量,性能会好一点,但仍然看似指数:
奇怪的是,长度为10只需要2m34.197s。 如果我切换到较小尺寸的位向量,性能会好一点,但仍然呈指数级。
所以我的问题是:这是预期的吗?是否有更好的方法来制定这种“无循环”约束?
答案 0 :(得分:1)
你的公式基本上编码了“鸽子洞”问题。
您有sz+1
个洞(值0,1,...,sz)和sz+2
鸽子(阵列单元格(select tpath 0)
,...,(select tpath (+ sz 1))
)。
你首先量词是说每只鸽子应该放在其中一个洞里。
第二个是说两只不同的鸽子不应该在同一个洞里。
“鸽子洞”问题没有多项式大小分辨率证明。 因此,预计运行时间将呈指数增长。 请注意,基于分辨率,DPLL或CDCL的任何SAT求解器都会对鸽笼问题表现不佳。
使用位向量时,您可以获得更好的性能,因为Z3将它们缩减为命题逻辑,并且案例分析在该级别上更有效。
顺便说一句,您使用量词来编码参数问题。 这是一个优雅的解决方案,但它不是Z3最有效的方法。 对于Z3,一般来说,断言“扩展”量词免费问题更好。 但是,对于你问题中描述的问题,它不会产生很大的不同,因为你仍然会经历指数增长。
答案 1 :(得分:0)
就像莱昂纳多所说的那样,由于鸽笼问题本质上是指数级的,所以表现最终会变坏。你可能做的唯一事情是推迟表现糟糕的时间。既然你已经尝试了位向量,我的建议是尝试将问题转换为莱昂纳多建议的无量词问题,因为问题大小是预先定义的,并尝试使用一些策略。