私はZ3を使用して、有界モデルチェッカーを構築しています。完全性テストを実装しようとすると、奇妙なパフォーマンスの問題が発生します。完全性テストでは、すべてのパスに各状態が最大で1回含まれていることをすべての状態で確認する必要があります。この特性を満たすパスがまだある場合、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)
私のコンピューターでは、これにより次の実行時間が発生します(パスの長さによって異なります)。
- 3:0.057秒
- 4:0.561秒
- 5:42.602秒
- 6:> 15m(中止)
Intからサイズ64のビットベクトルに切り替えると、パフォーマンスは少し向上しますが、それでも指数関数的に見えます。
- 3:0.035秒
- 4:0.053秒
- 5:0.061秒
- 6:0.106秒
- 7:0.467秒
- 8:1.809s
- 9:2分49.074秒
不思議なことに、長さが10の場合、2m34.197秒しかかかりません。小さいサイズのビットベクトルに切り替えると、パフォーマンスは少し向上しますが、それでも指数関数的です。
だから私の質問は:これは予想されることですか?この「ループのない」制約を定式化するためのより良い方法はありますか?