Z3中的增量输入和断言集

Z3中的增量输入和断言集,z3,smt,theorem-proving,Z3,Smt,Theorem Proving,我有一个运行Z3版本4.8.8-64位的程序,带有增量输入:该程序启动Z3一次,对Z3执行多轮输入输出,然后停止Z3。出于性能原因,在没有增量输入的情况下运行Z3不是一个选项 每一轮,程序将一些(assert…语句输入Z3,将(check sat)输入Z3,然后从Z3获得(check sat)的输出 我有两轮输入输出:第一轮输入如z3.sat: (declare-fun f () Int) (declare-fun n () Int) (assert (< 1 n)) (assert (&

我有一个运行Z3版本4.8.8-64位的程序,带有增量输入:该程序启动Z3一次,对Z3执行多轮输入输出,然后停止Z3。出于性能原因,在没有增量输入的情况下运行Z3不是一个选项

每一轮,程序将一些
(assert…
语句输入Z3,将
(check sat)
输入Z3,然后从Z3获得
(check sat)
的输出

我有两轮输入输出:第一轮输入如
z3.sat

(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
这意味着:如果
f
是大于或等于
2
的偶数
Int
,则存在
alpha
,其中
alpha=f/2

我假设使用增量输入运行Z3类似于将两轮输入,
Z3.sat
Z3.unsat
连接到一个输入中,如
Z3。组合的

(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(pop 1)
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
(pop 1)
所以Z3似乎需要
(push 1)
(pop 1)
语句来忘记以前的断言集,所以我在
Z3.sat
Z3.unsat
的开头和结尾添加了这些语句,并重新连接
z3.pushpop.sat
z3.pushpop.unsat
以获得
z3.pushpop.combined

  • z3.pushpop.sat
    (push 1)
    (declare-fun f () Int)
    (declare-fun n () Int)
    (assert (< 1 n))
    (assert (<= 2 f))
    (assert (= (+ (+ 1 f) 1) (+ n n)))
    (assert (not false))
    (check-sat)
    (pop 1)
    
  • z3.pushpop.composed
    (push 1)
    (declare-fun f () Int)
    (declare-fun n () Int)
    (assert (< 1 n))
    (assert (<= 2 f))
    (assert (= (+ (+ 1 f) 1) (+ n n)))
    (assert (not false))
    (check-sat)
    (pop 1)
    (push 1)
    (declare-fun f () Int)
    (declare-fun n () Int)
    (assert (< 1 n))
    (assert (<= 2 f))
    (assert (= (+ (+ 1 f) 1) (+ n n)))
    (assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
    (check-sat)
    (pop 1)
    

为什么
z3-smt2 z3.pushpop.unsat
输出
unknown

增量模式迫使z3使用不同的理论子解算器,如中的一位开发人员所解释。这些“增量模式”子滤波器通常不如“常规”子滤波器有效,或者至少可能表现不同。据我所知,只要SMT程序包含push pop作用域或多个check SAT,Z3就会切换到增量模式


您最初说不使用增量模式不是一个选项,但至少您的文件
z3.pushpop.combined
看起来很容易拆分。另一个选择可能是在这两者之间重置Z3(我认为SMT命令
(reset)
),而不是使用push-pop块。然而,如果我上面所说的是正确的,这不会阻止Z3保持在非增量模式。你可以考虑在Z3的问题跟踪器上通过“问题发布”询问开发者。

增量模式迫使Z3使用不同的理论子解决方案,如开发人员所解释的。这些“增量模式”子滤波器通常不如“常规”子滤波器有效,或者至少可能表现不同。据我所知,只要SMT程序包含push pop作用域或多个check SAT,Z3就会切换到增量模式


您最初说不使用增量模式不是一个选项,但至少您的文件
z3.pushpop.combined
看起来很容易拆分。另一个选择可能是在这两者之间重置Z3(我认为SMT命令
(reset)
),而不是使用push-pop块。然而,如果我上面所说的是正确的,这不会阻止Z3保持在非增量模式。你可以考虑在Z3的问题跟踪器上通过一个“问题问题”来询问开发者。

正如Malter所提到的,PU/POP的存在触发了Z3中的“弱”求解器。(这有很多技术原因,但我同意从最终用户的角度来看,行为的改变是不幸的,可能会让人相当困惑。)

但是有一些命令可以让您不必求助于
push
pop
就可以做您想做的事情。只需插入以下内容即可:

(reset)
当你想“启动”一个新的会话时,这将确保它能正常工作。也就是说,放下
按钮
/
弹出按钮
,连接时,在两者之间插入一个
(重置)

稍微好一点的方法 虽然上述方法可以奏效,但通常您只想忘记断言,而不想忘记定义。也就是说,您希望“记住”环境中有一个
f
和一个
n
。如果这是您的用例,则将以下内容放在脚本的顶部:

(set-option :global-declarations true)
当您想“切换”到新问题时,发布:

(reset-assertions)
这样,您就不必每次都“重复”声明。也就是说,您的整个交互应该如下所示:

(set-option :global-declarations true)

(declare-fun f () Int)
(declare-fun n () Int)

(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)

(reset-assertions)

(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
参考
所有这些都记录在官方文件中。参见第44页第3.9节了解
全局声明的描述,参见第59页第4.2.2节了解
(重置断言)
,如Malte所述,pus/pop的存在会触发z3中的“较弱”解算器。(这有很多技术原因,但我同意从最终用户的角度来看,行为的改变是不幸的,可能会让人相当困惑。)

但是有一些命令可以让您不必求助于
push
pop
就可以做您想做的事情。只需插入以下内容即可:

(reset)
当你想“启动”一个新的会话时,这将确保它能正常工作。也就是说,放下
按钮
/
弹出按钮
,连接时,在两者之间插入一个
(重置)

稍微好一点的方法 虽然上述方法可以奏效,但通常您只想忘记断言,而不想忘记定义。也就是说,您希望“记住”环境中有一个
f
和一个
n
。如果这是您的用例,则将以下内容放在脚本的顶部:

(set-option :global-declarations true)
当您想“切换”到新问题时,发布:

(reset-assertions)
这样,您就不必每次都“重复”声明。也就是说,您的整个交互应该如下所示:

(set-option :global-declarations true)

(declare-fun f () Int)
(declare-fun n () Int)

(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)

(reset-assertions)

(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
参考
所有这些都记录在官方文件中。参见第44页第3.9节了解
全局声明的描述,参见第59页第4.2.2节了解
(重置断言)的描述