Z3Py:使用 eval 或 z3 解析表达式。parse_smt2_string

Z3Py: Parsing expressions using eval or z3.parse_smt2_string

我正在编写一个 python 程序,除其他外,它必须将大型命题公式转换为 z3 实例。例如,我的程序可以通过

创建公式 f
a = my_atomic_proposition("a") # Bool
b = my_atomic_proposition("b", operator.ge, 42) # Real: c >= 42
c = my_atomic_proposition("c") # Bool
f = my_and(a, my_or(b, my_not(c)))

应该转换成z3实例g

a = z3.Bool("a")
b = z3.Real("b")
c = z3.Bool("c")
g = z3.And(a, z3.Or(b >= 42, z3.Not(c)))

请记住,我说的是包含 100 多个术语的公式。

关注 post Z3 with string expressions 我首先尝试构建自己的解析器(Leornardo de Moura 在 post 中建议的选项 1),它只是递归地遍历我所有公式的操作数并在途中构建 z3 实例。这个选项非常慢,所以我改为尝试递归地构建更快的字符串,然后在它们上调用 eval(上面 post 中描述的选项 3)。这个解决方案要快得多,但是,当我的公式变得太大时(抛出 MemoryError),这个解决方案就不起作用了。

所以现在我要尝试第三个选项:使用 z3.parse_smt2_string 从字符串创建 z3 实例(不是我上面使用 eval 的那个,它必须有不同的句法)。我会以某种类似于 Z3_parse_smtlib_string usage issues 中的方式进行。但是,我想知道我是否可以 运行 使用 z3.parse_smt2_string 遇到类似的内存问题,就像我使用 eval 一样?从那时起,我可能会在为此付出太多努力之前寻找另一种方式。

此外,如果有人对我如何实现我的目标有其他想法(希望是更聪明的想法),我很乐意发表任何评论。谢谢你的帮助!

编辑 - 内存错误示例:

我将举例说明抛出 MemoryError 的情况:假设我有以下公式作为字符串:

f = 'z3.Or(a___0,z3.And(True,z3.Or(a___1,z3.And(True,z3.Or(a___2,z3.And(True,z3.Or(a___3,z3.And(True,z3.Or(a___4,z3.And(True,z3.Or(a___5,z3.And(True,z3.Or(a___6,z3.And(True,z3.Or(a___7,z3.And(True,z3.Or(a___8,z3.And(True,z3.Or(a___9,z3.And(True,z3.Or(a___10,z3.And(True,z3.Or(a___11,z3.And(True,z3.Or(a___12,z3.And(True,z3.Or(a___13,z3.And(True,z3.Or(a___14,z3.And(True,z3.Or(a___15,z3.And(True,z3.Or(a___16,z3.And(True,z3.Or(a___17,z3.And(True,z3.Or(a___18,z3.And(True,z3.Or(a___19,z3.And(True,z3.Or(a___20,z3.And(True,z3.Or(a___21,z3.And(True,z3.Or(a___22,z3.And(True,z3.Or(a___23,z3.And(True,z3.Or(a___24,z3.And(True,z3.Or(a___25,z3.And(True,z3.Or(a___26,z3.And(True,z3.Or(a___27,z3.And(True,z3.Or(a___28,z3.And(True,z3.Or(a___29,z3.And(True,z3.Or(a___30,z3.And(True,z3.Or(a___31,z3.And(True,z3.Or(a___32,z3.And(True,z3.Or(a___33,z3.And(True,z3.Or(a___34,z3.And(True,z3.Or(a___35,z3.And(True,z3.Or(a___36,z3.And(True,z3.Or(a___37,z3.And(True,z3.Or(a___38,z3.And(True,z3.Or(a___39,z3.And(True,z3.Or(a___40,z3.And(True,z3.Or(a___41,z3.And(True,z3.Or(a___42,z3.And(True,z3.Or(a___43,z3.And(True,z3.Or(a___44,z3.And(True,z3.Or(a___45,z3.And(True,z3.Or(a___46,z3.And(True,z3.Or(a___47,z3.And(True,z3.Or(a___48,z3.And(True,z3.Or(a___49,z3.And(True,a___50))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))'

和以下表示 f 变量的字符串列表:

variables = ['a___2', 'a___31', 'a___34', 'a___46', 'a___29', 'a___12', 'a___9', 'a___32', 'a___41', 'a___24', 'a___38', 'a___23', 'a___19', 'a___50', 'a___3', 'a___6', 'a___35', 'a___28', 'a___13', 'a___16', 'a___0', 'a___33', 'a___36', 'a___40', 'a___45', 'a___10', 'a___39', 'a___43', 'a___22', 'a___27', 'a___7', 'a___49', 'a___21', 'a___17', 'a___1', 'a___4', 'a___37', 'a___44', 'a___11', 'a___14', 'a___30', 'a___42', 'a___47', 'a___8', 'a___26', 'a___48', 'a___20', 'a___25', 'a___5', 'a___15', 'a___18']

然后我按以下方式使用 eval

# Declare z3 variables for all strings in my list 'variables'
for x in variables:
    globals()[x] = z3.Bool(x)
# Create z3 object from string 'f'
z3f = eval(f)

并收到错误:

---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-71-b7421db475e5> in <module>()
      3     globals()[x] = z3.Bool(x)
      4 # Create z3 object from string 'f'
----> 5 z3f = eval(f)

MemoryError: 

对于类似但更短的 f,上面的代码可以正常工作。例如:

f = 'z3.Or(a___0,z3.And(True,z3.Or(a___1,z3.And(True,z3.Or(a___2,z3.And(True,z3.Or(a___3,z3.And(True,z3.Or(a___4,z3.And(True,z3.Or(a___5,z3.And(True,z3.Or(a___6,z3.And(True,z3.Or(a___7,z3.And(True,z3.Or(a___8,z3.And(True,z3.Or(a___9,z3.And(True,z3.Or(a___10,z3.And(True,z3.Or(a___11,z3.And(True,z3.Or(a___12,z3.And(True,z3.Or(a___13,z3.And(True,z3.Or(a___14,z3.And(True,z3.Or(a___15,z3.And(True,z3.Or(a___16,z3.And(True,z3.Or(a___17,z3.And(True,z3.Or(a___18,z3.And(True,z3.Or(a___19,z3.And(True,z3.Or(a___20,z3.And(True,z3.Or(a___21,z3.And(True,z3.Or(a___22,z3.And(True,z3.Or(a___23,z3.And(True,z3.Or(a___24,z3.And(True,z3.Or(a___25,z3.And(True,z3.Or(a___26,z3.And(True,z3.Or(a___27,z3.And(True,z3.Or(a___28,z3.And(True,z3.Or(a___29,z3.And(True,z3.Or(a___30,z3.And(True,z3.Or(a___31,z3.And(True,z3.Or(a___32,z3.And(True,z3.Or(a___33,z3.And(True,z3.Or(a___34,z3.And(True,z3.Or(a___35,z3.And(True,z3.Or(a___36,z3.And(True,z3.Or(a___37,z3.And(True,z3.Or(a___38,z3.And(True,z3.Or(a___39,z3.And(True,a___40))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))'
variables = ['a___2', 'a___31', 'a___34', 'a___29', 'a___12', 'a___9', 'a___32', 'a___24', 'a___38', 'a___23', 'a___19', 'a___3', 'a___6', 'a___35', 'a___28', 'a___13', 'a___16', 'a___0', 'a___33', 'a___36', 'a___40', 'a___10', 'a___39', 'a___22', 'a___27', 'a___7', 'a___21', 'a___17', 'a___1', 'a___4', 'a___37', 'a___11', 'a___14', 'a___30', 'a___8', 'a___26', 'a___20', 'a___25', 'a___5', 'a___15', 'a___18']

我收到:

z3f = Or(a___0,
And(True,
   Or(a___1,
      And(True,
          Or(a___2,
             And(True,
                 Or(a___3,
                    And(True,
                        Or(a___4,
                           And(True,
                               Or(a___5,
                                  And(True,
                                    Or(a___6,
                                    And(True,
                                    Or(a___7,
                                    And(True,
                                    Or(a___8,
                                    And(True,
                                    Or(a___9,
                                    And(True,
                                    Or(..., ...)))))))))))))))))))))

感谢您添加示例 ec-m!

这实际上是 Python 方面的问题。 Python 非常保守地限制了 eval(...) 的堆栈,显然它在某些版本中只能处理 35 个作用域(如 Parser crashes for deeply nested list displays). A similar problem exists with deeply nested lambdas (see Python: nested lambdas — s_push: parser stack overflow Memory Error 中所述)。

切换到 Z3 的 parse_smt2_string 肯定可以避免此类问题,它允许更大的堆栈。