对于这个例子:http://pastebin.com/QyebfD1p z3和cvc4返回"未知"由于检查 - 坐。两者对原因都不是很冗长,有没有办法让z3对它的执行更加冗长?
答案 0 :(得分:2)
您的脚本使用策略
s = Then('simplify','smt').solver()
这种策略应用Z3简化器,然后执行"通用" Z3中提供SMT求解器。对于非线性算法,此解算器不完整。它基于以下组合:Simplex,Interval Arithmetic和Grobner Basis。该模块的一大缺点是它无法找到包含无理数的模型/解决方案。将来,我们将使用Z3中提供的新的非线性求解器替换此模块。
对于非线性算法,我们通常建议在Z3中使用nlsat求解器。这是一个完整的过程,通常对不可满足和可满足的实例非常有效。您可以在this article中找到有关nlsat的更多信息。 要使用nlsat,我们必须使用
s = Tactic('qfnra-nlsat').solver()
不幸的是,nlsat会陷入你的榜样。它会在计算过程中产生非常大的多项式计算Subresultants。
Z3还有另一个处理非线性算法的引擎。该引擎将问题减少到了SAT。它仅对具有a + b sqrt(2)
形式的解决方案的可满足问题有效,其中a
和b
是有理数。使用此引擎,我们可以在很短的时间内解决您的问题。我将结果附在帖子的末尾。要使用此引擎,我们必须使用
s = Then('simplify', 'nla2bv', 'smt').solver()
编辑此外,策略nla2bv
将有理数a
和b
编码为一对位向量。默认情况下,它使用大小为4的位向量。但是,可以使用选项nlsat_bv_size
指定此值。这不是一个全局选项,而是提供给策略nla2bv
的选项。因此,nla2bv
只能找到a + b sqrt(2)
形式的解决方案,其中a
和b
可以使用少量位进行编码。如果一个可满足的问题没有这种形式的解决方案,这种策略将失败并返回unknown
。
结束编辑
您的示例还表明,我们必须改进nlsat,并使其作为模型/解决方案查找过程更有效。 当试图表明问题没有解决方案时,当前版本卡住了。 我们意识到这些限制,并正在制定新的程序来解决这些问题。
BTW,在Python前端,Z3以十进制表示法显示模型/解决方案。但是,一切都是精确计算的。获得解决方案的精确表示。我们可以使用方法sexpr()
。例如,我将循环更改为
for d in m.decls():
print "%s = %s = %s" % (d.name(), m[d], m[d].sexpr())
在新循环中,我以十进制表示法显示结果,并以内部精确表示。 (root-obj (+ (* 2 (^ x 2)) (* 12 x) (- 7)) 2)
的含义是多项式2*x^2 + 12x - 7
的第二个根。
修改强>
Z3提供combinators来创建非平凡的求解器。在上面的示例中,我们使用Then
来执行不同策略的顺序组合。我们也可以使用OrElse
来尝试不同的策略。和TryFor(t, ms)
在t
毫秒内尝试战术ms
,如果问题无法在给定时间内解决,则会失败。这些组合器可用于创建使用不同策略来解决问题的策略。
结束编辑
sat
Presenting results
traversing model...
s_2_p_p = 0.5355339059? = (root-obj (+ (* 2 (^ x 2)) (* 12 x) (- 7)) 2)
s_1_p_p = 0 = 0.0
s_init_p_p = 0.2928932188? = (root-obj (+ (* 2 (^ x 2)) (* (- 4) x) 1) 1)
s_2_p = 0.7071067811? = (root-obj (+ (* 2 (^ x 2)) (- 1)) 2)
s_1_p = 0 = 0.0
s_init_p = 0.2928932188? = (root-obj (+ (* 2 (^ x 2)) (* (- 4) x) 1) 1)
epsilon = 0 = 0.0
p_b2_s2_s_sink = 0.9142135623? = (root-obj (+ (* 4 (^ x 2)) (* 4 x) (- 7)) 2)
p_b2_s2_s_target = 0.0857864376? = (root-obj (+ (* 4 (^ x 2)) (* (- 12) x) 1) 1)
p_b2_s2_s_2 = 0 = 0.0
p_b2_s2_s_1 = 0 = 0.0
p_a2_s2_s_sink = 0 = 0.0
p_a2_s2_s_target = 0.8284271247? = (root-obj (+ (^ x 2) (* 4 x) (- 4)) 2)
p_a2_s2_s_2 = 0.1715728752? = (root-obj (+ (^ x 2) (* (- 6) x) 1) 1)
p_a2_s2_s_1 = 0 = 0.0
sigma_s2_b2 = 1 = 1.0
sigma_s2_a2 = 0 = 0.0
p_b1_s1_s_sink = 1 = 1.0
p_b1_s1_s_target = 0 = 0.0
p_b1_s1_s_2 = 0 = 0.0
p_b1_s1_s_1 = 0 = 0.0
p_a1_s1_s_sink = 1 = 1.0
p_a1_s1_s_target = 0 = 0.0
p_a1_s1_s_2 = 0 = 0.0
p_a1_s1_s_1 = 0 = 0.0
sigma_s1_b1 = 0 = 0.0
sigma_s1_a1 = 1 = 1.0
p_sinit_sink = 0.7071067811? = (root-obj (+ (* 2 (^ x 2)) (- 1)) 2)
p_sinit_target = 0.2928932188? = (root-obj (+ (* 2 (^ x 2)) (* (- 4) x) 1) 1)
p_sinit_2 = 0 = 0.0
p_sinit_1 = 0 = 0.0
s_sink = 0 = 0.0
s_target = 1 = 1.0
s_2 = 0.0857864376? = (root-obj (+ (* 4 (^ x 2)) (* (- 12) x) 1) 1)
s_1 = 0 = 0.0
s_init = 0.2928932188? = (root-obj (+ (* 2 (^ x 2)) (* (- 4) x) 1) 1)
修改强> 您可以使用策略
解决评论中的问题s = Then('simplify', 'nlsat').solver()
这种策略将在几秒钟内解决问题,并在帖子结束时产生解决方案。如上所述,nlsat
已完成,但可能需要很长时间。
您的问题是当前版本的Z3可以自动决定/解决的问题。我们可以将不同的策略与OrElse
和TryFor
结合使用,以使其更加稳定。例如:
s = OrElse(TryFor(Then('simplify', 'nla2bv', 'smt', 'fail-if-undecided'), 1000),
TryFor(Then('simplify', 'nlsat'), 1000),
TryFor(Then('simplify', 'nla2bv', 'smt', 'fail-if-undecided'), 10000),
Then('simplify', 'nlsat')).solver()
上面的策略尝试nla2bv
方法1秒,然后nlsat
1秒,然后nla2bv
10秒,最后nlsat
没有超时。< / p>
我知道这不是一个理想的解决方案,但是这样的变化可能是有用的解决方法,直到非线性算法的下一个求解器准备就绪。此外,在我们调用nlsat
之前,Z3还有许多其他策略可用于简化/预处理问题。
结束编辑
s_init = 15/32
s_1 = 7/16
s_2 = 1/2
s_target = 1
s_sink = 0
p_sinit_1 = 1/2
p_sinit_2 = 1/4
p_sinit_target = 1/8
p_sinit_sink = 1/8
sigma_s1_a1 = 1/2
sigma_s1_b1 = 1/2
p_a1_s1_s_1 = 1/2
p_a1_s1_s_2 = 1/4
p_a1_s1_s_target = 1/8
p_a1_s1_s_sink = 1/8
p_b1_s1_s_1 = 1/2
p_b1_s1_s_2 = 1/4
p_b1_s1_s_target = 1/16
p_b1_s1_s_sink = 3/16
sigma_s2_a2 = 1/2
sigma_s2_b2 = 1/2
p_a2_s2_s_1 = 1/2
p_a2_s2_s_2 = 1/4
p_a2_s2_s_target = 11/64
p_a2_s2_s_sink = 5/64
p_b2_s2_s_1 = 3/4
p_b2_s2_s_2 = 1/32
p_b2_s2_s_target = 9/64
p_b2_s2_s_sink = 5/64
epsilon = 1/4
s_init_p = 1649/3520
s_1_p = 797/1760
s_2_p = 103/220
s_init_p_p = 1809/3904
s_1_p_p = 813/1952
s_2_p_p = 127/244
编辑2 你的问题正处于Z3在合理的时间内可以做的事情的边缘。非线性实数算术是可判定的,但是非常昂贵。关于调试/跟踪Z3中发生的事情。以下是一些可能性:
我们可以使用以下命令启用详细消息:set_option("verbose", 10)
。
数字是详细级别:0 ==&#34;没有消息&#34;和更高的数字==&#34;更多消息&#34;。
编译Z3并支持跟踪。有关详细信息,请参阅this post。
使用命令open_log("z3.log")
创建Python程序调用的Z3 API的日志。应在任何其他Z3 API调用之前调用此命令。然后使用z3
内的gdb
可执行文件执行日志。
因此,您将能够停止执行并找到Z3卡在哪里。 nlsat
解算器通常会卡在两个不同的位置:
计算子顾问(程序psc_chain
将在堆栈上),
用代数系数隔离多项式的根(过程isolate_roots
将在堆栈上)。
在我们用更有效的new one替换旧的代数数字包之后,问题2将很快修复。不幸的是,似乎你的问题陷入了subresultant步骤。
另一个评论:虽然nla2bv
对您的原始基准有效,但您的新基准不太可能有a + b sqrt(2)
形式的解决方案a
和b
有理数。因此,使用nla2bv
只是开销。策略nlsat
假定问题出现在CNF中。因此,对于pastebin.com/QRCUQE10
,我们必须在调用tseitin-cnf
之前调用nlsat
。另一个选择是使用&#34; big&#34;策略qfnra-nlsat
。它在调用nlsat
之前调用许多预处理步骤。但是,其中一些步骤可能会使一些问题难以解决。
END EDIT 2