ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

pySMT SMT-LIB格式详解:如何解析、打印并扩展smt2文件(parser与script实战)

pySMT SMT-LIB格式详解:如何解析、打印并扩展smt2文件(parser与script实战) pySMT SMT-LIB格式详解如何解析、打印并扩展smt2文件parser与script实战【免费下载链接】pysmtpySMT: A library for SMT formulae manipulation and solving项目地址: https://gitcode.com/gh_mirrors/py/pysmtpySMT 是一个用于 SMT 公式操作与求解的 Python 库而SMT-LIB 格式即 smt2 文件正是它与各类求解器之间的通用语言。本文带你从零看懂 SMT-LIB 语法并实战演示如何用 pySMT 的smtlib模块解析、打印、扩展smt2 文件——即使你是第一次接触 SMT也能快速上手。 什么是 SMT-LIB 格式SMT-LIB 2.6 是一套基于LISP 风格 S 表达式的文本标准几乎所有 SMT 求解器Z3、CVC5、MathSAT、Yices 等都支持它。一个典型的 smt2 文件由若干命令组成pySMT 自带的示例见 examples/smtlib.py就是一个很好的入门样本(set-logic QF_LIA) (declare-fun p () Int) (declare-fun q () Int) (declare-fun x () Bool) (define-fun .def_1 () Bool (! (and x y) :cost 1)) (assert ( x ( p q))) (check-sat) (push) (assert ( y ( q p))) (check-sat) (pop)核心命令速查表命令作用(set-logic ...)声明逻辑如QF_LIA、QF_BV(declare-fun x () Int)声明变量 / 函数(define-fun f (...) ...)定义可复用的函数(assert expr)添加断言约束(check-sat)请求求解返回sat/unsat(get-model)输出满足约束的模型(push)/(pop)增量求解的断言上下文类似栈(! expr :key value)注解为表达式附加元信息理解这张表后任何 smt2 文件对你来说都只是一堆带括号的命令。⚡ pySMT 解析 smt2 的三层 APIpySMT 把 SMT-LIB 处理封装在 pysmt/smtlib/ 模块中按粒度由浅入深分三层你的需求推荐 API所在位置读文件直接拿到公式read_smtlib(fname)pysmt/shortcuts.py拿到可迭代的命令序列SmtLibParser.get_script()pysmt/smtlib/parser/parser.py逐条处理原始命令流get_command_generator()同上最省事的方式只需一行from pysmt.shortcuts import read_smtlib f read_smtlib(demo.smt2) # 自动取脚本中最后一条断言对应的公式 print(f)注意pySMT 读取时还会透明支持.bz2压缩文件解析器内置了open_帮助函数这对处理大量基准测试集非常方便。如果追求极致解析速度还可设置环境变量PYSMT_CYTHONtrue让解析器自动走 Cython 加速路径见 pysmt/smtlib/parser/init.py。 从 smt2 到 Python 公式parser 实战想更精细地控制解析过程可以直接使用SmtLibParserfrom pysmt.smtlib.parser import SmtLibParser parser SmtLibParser() script parser.get_script_fname(demo.smt2) # 内部走 Tokenizer → 命令表 → SmtLibScript for cmd in script: print(cmd.name) # set-logic / declare-fun / assert ... f script.get_last_formula() # 考虑 push/pop 后的最终公式解析管线可以概括为三步Tokenizer按 LISP 规则把文本切成 token支持交互模式逐字符读取见 parser.py 中的Tokenizer类SmtLibParser查内部命令表self.commands把每条命令解析成SmtLibCommand对象表达式则交给get_expression递归构造 pySMT 的FNodeSmtLibScript把命令序列收集成脚本对象见 pysmt/smtlib/script.py并提供实用工具script.contains_command(check-sat)—— 检查某命令是否存在script.count_command_occurrences(assert)—— 统计出现次数script.filter_by_command_name(declare-fun)—— 筛选某类命令script.get_strict_formula()—— 假设只有一份公式的严格模式遇到push/pop或多次check-sat会抛异常script.get_last_formula()—— 常规模式返回脚本执行完后的最终公式。怎么选大多数基准文件是一堆断言 一次check-sat两个方法结果相同增量脚本则必须用get_last_formula()。️ 如何把公式打印回 SMT-LIB 格式反序列化同样简单pySMT 的打印器 pysmt/smtlib/printers.py 中的SmtPrinter通过树遍历把FNode还原成 SMT-LIB 语法import sys script.serialize(sys.stdout, daggifyTrue) # 输出 smt2 文本其中daggify参数控制输出形态daggifyTrueDAG 模式把重复子表达式提取为.def_0、.def_1… 等define-fun文件更短、求解器更快daggifyFalse树模式每次展开完整表达式可读性更好。单个公式也可以直接f.serialize()得到 SMT-LIB 字符串。整个读入 → 变换 → 输出闭环正是 SMT-LIB/parse_and_print.py 基准脚本在做的事。️ 注解annotationssmt2 里的隐藏信息SMT-LIB 标准允许用!给表达式附加元数据例如示例中的(! (and x y) :cost 1)。pySMT 用 pysmt/smtlib/annotations.py 中的Annotations统一管理这些注解ann script.annotations print(ann.all_annotated_formulae(cost)) # 列出所有带 :cost 的公式这是做模型检查、加权约束等自定义格式时的推荐扩展方式——不破坏 SMT-LIB 兼容性的同时传递额外语义。 进阶扩展解析器支持自定义 smt2 命令如果你的输入文件包含 pySMT 不认识的命令比如模型检查领域的(init ...)、(trans ...)标准解析器会抛出UnknownSmtLibCommandError。此时只需继承SmtLibParser并注册新命令from pysmt.smtlib.parser import SmtLibParser class TSSmtLibParser(SmtLibParser): def __init__(self, envNone, interactiveFalse): SmtLibParser.__init__(self, env, interactive) self.commands[init] self._cmd_init # 注册新命令 self.commands[trans] self._cmd_trans del self.commands[check-sat] # 删除不适用的命令 self.interpreted[next] self._operator_adapter(self._next_var) # 注册新算子完整示例含符号迁移系统的(init)、(trans)、(next)处理在 examples/smtlib.py 中可以完整阅读对应的回归测试是 pysmt/test/smtlib/test_parser_extensibility.py。扩展三要点新命令注册进self.commands处理函数接收 token 流、调用self.get_expression(tokens)取表达式新算子注册进self.interpreted_operator_adapter帮你处理变参不需要的命令直接del遇到时会显式报错而不是静默忽略。 真实的 smt2 基准文件在哪里想练手项目仓库自带了一个小型基准测试库按逻辑分类存放了大量.smt2.bz2文件pysmt/test/smtlib/fuzzed/覆盖QF_BV、QF_LIA、QF_UFLRA等 20 个逻辑的 fuzzing 测试集pysmt/test/smtlib/omt/多目标优化OMT扩展格式样例如clique.smt2、shortpath.smt2pysmt/test/smtlib/small_set/各逻辑的精挑小样例如QF_LIA/prp-20-46.smt2.bz2。批量处理这些文件可以参考 SMT-LIB/parse_all.py——它用multiprocessing并行解析整个目录并输出耗时统计是非常实用的模板脚本。另外pySMT 还支持HR 格式Human-Readable更接近数学书写习惯的表达式由 pysmt/parsing.py 负责解析可与 SMT-LIB 格式互补使用。✅ 快速总结三步搞定 smt2读一行read_smtlib()拿公式或SmtLibParser().get_script_fname()拿完整命令流写script.serialize(stream, daggifyTrue)或formula.serialize()还原成 smt2扩继承SmtLibParser往commands/interpreted表里注册你的自定义命令与算子。想亲手试一遍克隆仓库后运行示例脚本即可git clone https://gitcode.com/gh_mirrors/py/pysmt cd pysmt pip install -e . python examples/smtlib.py掌握 parser 与 script 这两个核心对象后无论处理求解器输出、生成基准测试还是扩展私有格式你都已经具备了在 pySMT 生态里自由操作 SMT-LIB 文件的全部能力。【免费下载链接】pysmtpySMT: A library for SMT formulae manipulation and solving项目地址: https://gitcode.com/gh_mirrors/py/pysmt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表