
Z3 TypeScript 绑定新 API 实战指南Params、ParamDescrs 与 Simplifier 详解【免费下载链接】z3The Z3 Theorem Prover项目地址: https://gitcode.com/gh_mirrors/z3/z3本篇指南聚焦 Z3 定理证明器 TypeScript 绑定src/api/js中新增的三组高阶 API——Params参数配置对象、ParamDescrs参数自省与文档、Simplifier面向增量求解的现代预处理组件Z3 4.12 引入。这三组 API 将 TypeScript 绑定的能力对齐到 Python、Java、C#、C 绑定水平让开发者能以类型安全、可复用、可验证的方式配置 tactic 与 simplifier并把预处理流水线直接挂载到 Solver 上。读完本文你将掌握参数对象的创建与校验、参数的自省式文档查询以及如何用 Simplifier 编排增量求解的预处理管线并理解每一层 API 背后对应的 C 语言实现。背景TypeScript 绑定为何需要这三组 APIZ3 的 TypeScript 绑定src/api/js通过 Emscripten 将 Z3 核心编译为 WASM在高阶封装层src/api/js/src/high-level/high-level.ts中为 JS/TS 开发者提供面向对象接口。在新 API 出现之前TypeScript 绑定存在明显的能力缺口参数配置只能通过全局的setParam(key, value)设置无法构造可复用、可组合的参数对象没有 simplifier 支持增量求解场景下缺乏高效的预处理手段无法在运行时自省某个 tactic 或 simplifier 接受哪些参数、参数类型是什么、文档如何。这些缺口在社区讨论 #8145 中被系统性地指出详见 TYPESCRIPT_API_ENHANCEMENTS.md。为此绑定新增了三个高层次的 APIParams—— 参数配置对象以类型化值布尔、数字、字符串描述配置ParamDescrs—— 参数描述集合提供参数的自省与文档查询Simplifier—— 现代预处理组件专为增量求解设计可组合、可配置、可挂载到 Solver。这三个类在源码中均有对应实现ParamsImpl、ParamDescrsImpl、SimplifierImpl定义于 high-level.ts其 TypeScript 接口声明位于 types.ts。Params API可复用的参数配置对象Params用于创建可复用的参数配置对象可传递给 tactic、simplifier 与 solver。核心特性以类型化值boolean、number、string设置参数通过tactic.usingParams(params)应用到 tactic通过simplifier.usingParams(params)应用到 simplifier通过validate(descrs)对照参数描述进行合法性校验通过toString()输出便于调试的字符串表示。基本用法const { Params, Tactic } Context(main); // 创建参数对象 const params new Params(); params.set(elim_and, true); // 布尔值 params.set(max_steps, 1000); // 整数内部走 uint 通道 params.set(timeout, 5.0); // 浮点数内部走 double 通道 params.set(logic, QF_LIA); // 字符串内部走 symbol 通道 // 与 tactic 配合使用 const tactic new Tactic(simplify); const configuredTactic tactic.usingParams(params); // 校验参数是否合法 const paramDescrs tactic.paramDescrs(); params.validate(paramDescrs); // 非法参数会抛出异常 // 调试输出 console.log(params.toString());类型化赋值的底层细节Params.set(name, value)在底层会根据值的运行时类型选择不同的 C API。查看 high-level.ts 中的 ParamsImpl 可以确认这一分派逻辑boolean→Z3.params_set_boolnumber且为整数Number.isInteger→Z3.params_set_uintnumber且为浮点 →Z3.params_set_doublestring→Z3.params_set_symbol参数名与值均转为 Z3 symbol。同样的分派逻辑也复用于_toParams辅助函数供Solver.set等场景使用。这意味着你不需要关心底层参数类型的区分绑定会自动选择合适的编码通道同时set的类型签名也限定了只接受boolean | number | string从类型层面杜绝了传错类型。API 参考class Params { /** * 以给定的名字和值设置一个参数。 * param name - 参数名 * param value - 参数值boolean、number 或 string */ set(name: string, value: boolean | number | string): void; /** * 对照参数描述集合校验当前参数集。 * param descrs - 用于校验的参数描述 */ validate(descrs: ParamDescrs): void; /** * 将参数集转换为字符串表示。 */ toString(): string; }validate的语义是若参数集中存在目标tactic/simplifier不认识的参数名或类型不匹配的值则会抛出异常。其底层直接调用Z3_params_validate声明于 z3_api.h把错误检测前置到配置阶段避免在求解时才暴露问题。ParamDescrs API参数的运行时自省ParamDescrs提供对 tactic、simplifier、solver 可用参数的运行时自省查询参数数量、名称、类型、文档并用于校验Params配置。核心特性查询可用参数列表获取参数类型kind访问参数文档校验参数配置。基本用法const { Simplifier } Context(main); // 获取参数描述 const simplifier new Simplifier(solve-eqs); const paramDescrs simplifier.paramDescrs(); // 自省参数 const size paramDescrs.size(); console.log(Number of parameters: ${size}); for (let i 0; i size; i) { const name paramDescrs.getName(i); const kind paramDescrs.getKind(name); const doc paramDescrs.getDocumentation(name); console.log(${name}: ${doc}); } // 一次性输出全部 console.log(paramDescrs.toString());getKind返回的是数字对应底层 C API 的Z3_parameter_kind枚举如整数、布尔、双精度浮点、符号、字符串等参数类别。如果你需要判断某参数的类型可以结合该枚举值做分支处理getDocumentation则返回该参数的说明文字适合构建参数帮助面板或交互式工具。API 参考class ParamDescrs { /** * 返回描述集合中的参数个数。 */ size(): number; /** * 返回给定索引处参数的名称。 * param i - 参数索引 */ getName(i: number): string; /** * 返回给定名称参数的类型kind。 * param name - 参数名 */ getKind(name: string): number; /** * 返回给定名称参数的文档字符串。 * param name - 参数名 */ getDocumentation(name: string): string; /** * 将参数描述集合转换为字符串表示。 */ toString(): string; }在实现层面ParamDescrsImpl 分别包装了Z3_param_descrs_size、Z3_param_descrs_get_name、Z3_param_descrs_get_kind、Z3_param_descrs_get_documentation、Z3_param_descrs_to_string等底层调用并通过FinalizationRegistry自动管理param_descrs_inc_ref/param_descrs_dec_ref的引用计数无需手动释放。Simplifier API面向增量求解的现代预处理Simplifier是 Z3 4.12 引入的现代预处理组件专为增量求解设计比传统 tactic 更高效并且可以直接挂载到 solver 上。核心特性按名称创建 simplifier用andThen()组合多个 simplifier用usingParams()配置参数挂载到 solver 进行增量预处理获取帮助文本与参数文档。完整示例组合 Simplifier 并挂载到 Solverconst { Simplifier, Solver, Params, Int } Context(main); // 创建 simplifier const simplifier new Simplifier(solve-eqs); // 获取帮助文档 console.log(simplifier.help()); // 用参数配置 const params new Params(); params.set(som, true); const configured simplifier.usingParams(params); // 组合 simplifier先 solve-eqs再 simplify const s1 new Simplifier(solve-eqs); const s2 new Simplifier(simplify); const composed s1.andThen(s2); // 挂载到 solver const solver new Solver(); solver.addSimplifier(composed); // 正常使用 solver const x Int.const(x); const y Int.const(y); solver.add(x.eq(y.add(1))); solver.add(y.eq(5)); const result await solver.check(); // sat if (result sat) { const model solver.model(); console.log(x , model.eval(x).toString()); // 6 }在这个例子中solver.addSimplifier(composed)之后solver 会在增量断言solver.add(...)提交时自动执行组合预处理先解方程solve-eqs再做常规化简simplify随后才进入求解阶段。对于需要反复push/pop、多次check()的增量场景这种模式比每次手动应用 tactic 更高效也保持了代码的声明式表达。API 参考class Simplifier { /** * 按名称创建 simplifier。 * param name - 内置 simplifier 名称如 solve-eqs、simplify */ constructor(name: string); /** * 返回该 simplifier 接受的参数说明字符串。 */ help(): string; /** * 返回该 simplifier 的参数描述集合。 */ paramDescrs(): ParamDescrs; /** * 返回一个使用给定配置参数的 simplifier。 * param params - 用于配置 simplifier 的参数 */ usingParams(params: Params): Simplifier; /** * 返回先应用本 simplifier、再应用另一个 simplifier 的组合结果。 * param other - 在本 simplifier 之后应用的 simplifier */ andThen(other: Simplifier): Simplifier; }usingParams与andThen都遵循不可变组合语义它们不修改原对象而是返回新的 simplifier。这在 SimplifierImpl 中体现得很清楚——usingParams调用Z3_simplifier_using_params生成新实例andThen调用Z3_simplifier_and_then生成组合实例二者均返回全新的SimplifierImpl。测试用例也验证了这一点expect(configuredSimplifier).not.toBe(simplifier)见 high-level.test.ts 的 Simplifier API 测试分组。Solver 集成addSimplifierSolver类新增了一个方法用于挂载 simplifierclass Solver { /** * 为增量预处理挂载一个 simplifier。 * solver 将使用该 simplifier 对断言进行增量预处理。 * param simplifier - 要挂载的 simplifier */ addSimplifier(simplifier: Simplifier): void; }实现上SolverImpl.addSimplifier 直接包装Z3_solver_add_simplifier声明于 z3_api.h。注意该方法要求传入的 simplifier 与 solver 属于同一 Context否则会抛出上下文不匹配异常_assertContext检查。Tactic 增强usingParams 与 paramDescrsTactic类同步得到了参数配置能力的增强class Tactic { /** * 返回一个使用给定配置参数的 tactic。 * param params - 用于配置 tactic 的参数 */ usingParams(params: Params): Tactic; /** * 获取 tactic 的参数描述。 * 返回一个 ParamDescrs 对象用于自省可用参数。 */ paramDescrs(): ParamDescrs; }示例const { Tactic, Params } Context(main); const tactic new Tactic(simplify); const params new Params(); params.set(max_steps, 100); const configured tactic.usingParams(params);TacticImpl.paramDescrs 调用Z3_tactic_get_param_descrsTacticImpl.usingParams 调用Z3_tactic_using_params后者声明于 z3_api.h两者都会返回新的TacticImpl实例。此外Tactic.help()可输出该 tactic 的参数帮助Tactic.solver()可基于当前 tactic 构造一个 solver便于在 tactic 与 solver 两种模式间切换。值得说明的是Tactic.paramDescrs()Params.validate()的组合构成了一个非常实用的开发流程先自省得到参数描述再构造参数对象并校验最后才应用到 tactic 或 simplifier。相关测试覆盖了对合法参数 validate 不抛异常的场景high-level.test.ts。可用的内置 Simplifier常见的内置 simplifier 包括名称说明solve-eqs求解变量消去等式约束simplify通用化简propagate-values常量值传播elim-uncnstr消除无约束变量ctx-simplify上下文相关的化简使用simplifier.help()可以查看每个 simplifier 的文档及其可接受参数使用simplifier.paramDescrs()则可以程序化地遍历这些参数。由于 Z3 内置 simplifier 集合随版本演进建议在运行时通过help()/paramDescrs()动态发现可用项而不是硬编码参数名。迁移指南从全局 setParam 到 Params Simplifier之前使用全局 setParam// 全局参数设置 setParam(pp.decimal, true); // 无法创建可复用的参数配置 // 不支持 simplifier全局setParam的问题在于参数是进程/上下文级的全局状态无法针对不同 tactic 精细配置也无法复用、组合或校验。之后使用 Params 与 Simplifier// 可复用的参数对象 const params new Params(); params.set(pp.decimal, true); params.set(max_steps, 1000); // 配置 tactic const tactic new Tactic(simplify).usingParams(params); // 使用 simplifier 提升增量求解质量 const simplifier new Simplifier(solve-eqs).usingParams(params); solver.addSimplifier(simplifier);注意setParam仍然可用用于全局参数例如打印格式pp.decimal而Params适用于需要细粒度、可复用、可校验的组件级配置。两者定位不同可按需混用。全局参数相关能力setParam、getParam、resetParams在 high-level.ts 中有完整实现。兼容性与多语言对齐这三组 API 在功能上与 Z3 其他语言绑定完全对齐✅ PythonParamsRef、ParamDescrsRef、Simplifier✅ JavaParams、ParamDescrs、Simplifier✅ C#Params、ParamDescrs、Simplifier✅ Cparams、param_descrs、simplifierTypeScript 绑定现已覆盖 Params、ParamDescrs、Simplifier 三个 C API 模块的全部功能。换句话说如果你熟悉任意一种 Z3 语言绑定的参数与 simplifier 用法可以几乎无缝迁移到 TypeScript。完整可运行示例与测试仓库提供了完整的可运行示例 simplifier-example.ts它演示了六组用法创建并使用Params含elim_and、max_steps、timeout等参数与toString()输出创建并使用Simplifier含help()输出用andThen()组合 simplifier用usingParams()配置 simplifier 与 tactic将 simplifier 挂载到Solver并求解x y 1, y 5得到模型遍历ParamDescrs输出参数数量、首个参数名及其文档。运行方式在src/api/js目录下# 安装依赖并构建 WASM 绑定 npm install npm run build # 运行示例 npx ts-node examples/high-level/simplifier-example.ts # 运行测试含 Params / Simplifier API 测试分组 npm test对应的单元测试位于 high-level.test.ts 的 Params API约 L2144 起与 Simplifier API约 L2216 起两个describe分组中覆盖了参数设置、校验、自省、组合、配置以及 solver 集成等关键路径是验证行为与阅读实现的极佳入口。TypeScript 绑定的整体使用说明可参阅 src/api/js/README.md。小结Params、ParamDescrs、Simplifier 三组 API 补全了 Z3 TypeScript 绑定在组件配置与增量预处理上的能力Params提供类型安全、可复用、可校验的配置对象ParamDescrs把参数文档与类型暴露给运行时支撑自省式工具与动态校验Simplifier则以可组合、可挂载的方式为增量求解提供高效预处理。三者共同将 TypeScript 绑定提升到与 Python、Java、C#、C 一致的能力水平是构建复杂、增量式 Z3 应用的推荐基座。【免费下载链接】z3The Z3 Theorem Prover项目地址: https://gitcode.com/gh_mirrors/z3/z3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考