为什么Z3的 S表达式和字符串不一样?

前端开发 2026-07-08
>>> conclusion
Implies(And(Not(Exists(z, R(z, e3))),  
            Not(Exists(z, R(z, e2)))),  
        And(Not(B(e3)), Not(B(e2))))  
>>> conclusion.sexpr()  
'(let ((a!1 (and (not (exists ((z Ent)) (R z e3)))\\n                (not (exists ((z Ent)) (R z e2))))))\\n  (=\> a!1 (and (not (B e3)) (not (B e2)))))'

如你所见,字符串形式(__str__)中的变量 conclusionImplies 开头,而 sexpr 形式以 let 开头。

为什么它们不同?字符串形式和S-expr形式在什么时候会不同?

我在参考文献中也找不到线索。

不仅是我,这份演示文稿 也指出了 Z3 sexprstring 之间的差异,但并未解释清楚。

解决方案

当你执行

print(conclusion)

Z3正在输出表达式的内部表示。它是表达式的基于Python的数据类型表示。你看到的只是Python层对表达式的呈现。

当你执行

print(conclusion.sexpr())

z3将表达式打印为 SMT-Lib格式。SMT-Lib是所有符合规范的SMT求解器都接受的标准表示,与之相比,你看到的AST完全是z3特定的表示。

所以,它们打印出来的结果不同,原因是第一种情况下你得到的是z3的内部特定AST,便于在Python中操作z3表达式;而在后者你得到的是所有求解器都能理解的标准表示;这是一种完全不同的语言。

关于使用 let

z3尝试通过共享来最小化输出,正如你所猜测的,这些表达式很快就会变得非常大。如果你不想看到这种效果,只需执行:

set_option("pp.min_alias_size", 1000000)
set_option("pp.max_depth",      1000000)

在打印之前,输出应该大致是扁平的(除非它真的非常深。你可以调整这些数字来适应你对美化输出的偏好。)

完整运行示例

你没有给出完整的脚本,所以我重新创建了一个看起来差不多的。如下代码按原样工作:

from z3 import *

z  = Int('z')
e2 = Int('e2')
e3 = Int('e3')
B = Function('B', IntSort(), BoolSort())
R = Function('R', IntSort(), IntSort(), BoolSort())

conclusion = Implies(And(Not(Exists(z, R(z, e3))),
                         Not(Exists(z, R(z, e2)))),
                     And(Not(B(e3)), Not(B(e2))))

set_option("pp.min_alias_size", 1000000)
set_option("pp.max_depth",      1000000)

print(conclusion.sexpr())

把上面的内容放到一个名为 a.py 的文件中并运行它,我得到:

$ python a.py
(=> (and (not (exists ((z Int)) (R z e3))) (not (exists ((z Int)) (R z e2))))
    (and (not (B e3)) (not (B e2))))
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章