SymPy Logic 逻辑模块完全指南:布尔表达式、正规形式、真值表与命题推理 SymPy Logic 逻辑模块完全指南布尔表达式、正规形式、真值表与命题推理【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympySymPy 的 logic 模块sympy/logic是一个用纯 Python 实现的命题逻辑工具集它允许你用 Python 原生运算符构造并操作符号化、布尔化的逻辑表达式并在此基础上完成正规形式转换、逻辑化简、真值表枚举与可满足性求解等任务。本文基于 doc/src/modules/logic.rst 与 doc/src/reference/public/logic/index.rst 展开并结合 sympy/logic/boolalg.py、sympy/logic/inference.py 与 sympy/sets/sets.py 的源码实现带你从表达式构造一路深入到 SAT 求解器最终掌握用 SymPy 完成从“真值表到逻辑电路化简”到“命题推理判定”的完整工作流。一、模块总览Logic 与 Sets 的关系在 SymPy 的公开 API 参考中doc/src/reference/public/logic/index.rst 是一个面向用户的导航页它通过 Sphinx toctree 聚合了两大块内容doc/src/modules/logic.rst核心命题逻辑模块包括布尔表达式的构造、布尔函数类、正规形式、化简与推理doc/src/modules/sets.rst集合模块包括基本集合、复合集合、特殊数集、幂集与条件集等。两者的天然联系在于布尔函数与集合之间可以互相转换例如Boolean.as_set()会把布尔表达式转成满足该表达式的点集这在解方程、不等式求解和solveset中都有实际应用。文章将先深入 logic 模块的主体再介绍与其紧密相关的 sets 模块。二、构造逻辑表达式用 Python 运算符写布尔代数logic 模块的核心设计理念是直接用 Python 内置运算符来书写布尔表达式而非引入一套陌生的 DSL。四种基本运算符的重载定义在 sympy/logic/boolalg.py 中的Boolean.__and__、__or__、__invert__、__rshift__等魔术方法上Python 运算符对应逻辑运算SymPy 类合取ANDAnd\|析取OROr~否定NOTNot蕴含ImplicationImplies逆蕴含Implies参数交换^异或XORXor基本用法与 doc/src/modules/logic.rst 中的示例一致 from sympy import * x, y symbols(x,y) y | (x y) # 析取与合取的嵌套 y | (x y) x | y x | y ~x # 取反 ~x蕴含用和构造注意方向x y表示“x 蕴含 y”Implies(x, y)而x y等价于Implies(y, x) x y Implies(x, y) x y Implies(y, x)与 SymPy 中绝大多数表达式一样布尔表达式同样继承自Basic因此你可以对其调用subs代入、atoms原子提取等通用方法 (y x).subs({x: True, y: True}) True (x | y).atoms() {x, y}从源码看Boolean的subs与as_Boolean被显式实现见 sympy/logic/boolalg.py 中as_Boolean与Boolean.subs确保代入后结果仍保持布尔语义。此外Boolean还实现了equals逻辑等价判定、binary_symbols提取二进制符号等方法为后续的化简与推理提供基础设施。三、布尔函数类从Boolean到ITEdoc/src/modules/logic.rst 的 “Boolean functions” 一节列出了一整套可直接使用的布尔函数类它们都定义在 sympy/logic/boolalg.py 中基类与常量Boolean、BooleanTrue即true、BooleanFalse即false基本运算And、Or、Not、Xor派生门电路Nand、Nor、Xnor蕴含与等价Implies、Equivalent条件表达式ITEif-then-else等价于(c t) | (~c e)排他逻辑Exclusive恰有一个输入为真的“独热”判定。这些类在构造时会自动执行恒等式化简。以And为例其__new__通过_new_args_filter过滤参数若出现False则整体为False出现True则将其剔除并对重复参数去重。测试用例覆盖了这些行为见 sympy/logic/tests/test_boolalg.py 中的test_And、test_Or、test_Xor、test_Nand、test_Nor、test_ITE等。ITE的典型用法 from sympy.logic.boolalg import ITE from sympy.abc import A, B, C ITE(A, B, C) (A B) | (~A C)每个类还实现了to_nnf、to_anf以及_eval_rewrite_as_*系列方法例如_eval_rewrite_as_Nor、_eval_rewrite_as_Nand意味着你可以把任意布尔函数改写成只用某一种门表达的等价形式——这是数字电路设计NAND/NOR 唯一完备集中常用的能力。四、从真值表反推表达式SOPform、POSform 与 ANFform“给出真值表中输出为 1 的行反推出最简逻辑表达式”是数字逻辑设计的经典问题。doc/src/modules/logic.rst 提供了三个核心函数底层实现位于 sympy/logic/boolalg.pySOPform(variables, minterms, dontcaresNone)返回最简和之积sum-of-products形式即Or(And(...), ...)POSform(variables, minterms, dontcaresNone)返回最简积之和product-of-sums形式即And(Or(...), ...)ANFform(variables, truthvalues)返回代数正规形式Algebraic Normal Form即只用Xor与And异或与表达的 Reed-Muller 展开。三者均基于 Quine-McCluskey 算法源码中_simplified_pairs、_rem_redundancy完成质蕴含项合并与冗余消除minterms 与 dontcares 可以按二进制列表、整数、字典三种格式灵活给出且可以混用 from sympy.logic import SOPform, POSform from sympy import symbols w, x, y, z symbols(w x y z) minterms [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], ... [1, 0, 1, 1], [1, 1, 1, 1]] dontcares [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] SOPform([w, x, y, z], minterms, dontcares) (y z) | (~w ~x) POSform([w, x, y, z], minterms, dontcares) z (y | ~w)同样的输入用整数表示 minterms [1, 3, 7, 11, 15] dontcares [0, 2, 5] SOPform([w, x, y, z], minterms, dontcares) (y z) | (~w ~x)或者用字典表示允许只部分指定变量的取值 minterms [{w: 0, x: 1}, {y: 1, z: 1, x: 0}] SOPform([w, x, y, z], minterms) (x ~w) | (y z ~x)注意三点细节minterms 为空时SOPform直接返回false见 sympy/logic/boolalg.py若某个 minterm 同时出现在 dontcares 中会抛出ValueError因为一个输入组合不可能既是“输出 1”又是“无所谓”dontcare 项即“无关项”用于电路化简表示该输入组合在实际系统中不会出现可以自由用于合并相邻项——这是卡诺图与 QM 算法的核心技巧docstring 中给出的参考文献指向 Quine-McCluskey 算法与 Dont-care term 两个概念SOPform的 docstring 见 sympy/logic/boolalg.py。五、正规形式Normal FormANF、NNF、CNF、DNF正规形式是逻辑推理与自动求解的前提。doc/src/modules/logic.rst 列出了四类正规形式及其判定函数正规形式转换函数判定函数结构特征代数正规形式 ANFto_anf(expr, deepTrue)is_anf(expr)仅含Xor与变量的And不允许否定否定正规形式 NNFto_nnf(expr, simplifyTrue, formNone)is_nnf(expr, simplifiedTrue)否定只作用于原子命题合取正规形式 CNFto_cnf(expr, simplifyFalse, forceFalse)is_cnf(expr)子句的合取子句是文字的析取析取正规形式 DNFto_dnf(expr, simplifyFalse, forceFalse)is_dnf(expr)项文字的合取的析取以 CNF 为例其语义是“若干个析取子句做合取”即((A | ~B | ...) (B | C | ...) ...)DNF 则是“若干合取项做析取”即((A ~B ...) | (B C ...) | ...)。转换时见 sympy/logic/boolalg.py的调用链为先eliminate_implications消去蕴含再做distribute_and_over_or/distribute_or_over_and分配律展开如果已处于目标形式则直接返回“Dont convert unless we have to”。simplify参数控制是否用 Quine-McCluskey 求最简形式但它存在8 变量上限保护 from sympy.logic.boolalg import to_cnf from sympy.abc import A, B, D to_cnf(~(A | B) | D) (D | ~A) (D | ~B) to_cnf((A | B) (A | ~A), True) A | B当表达式涉及超过 8 个不同谓词时simplifyTrue会抛出ValueError并要求显式传入forceTrue因为 QM 化简在最坏情况下是指数级时间源码在 sympy/logic/boolalg.py 中明确注释了这一点。ANF 是布尔代数的第三种重要表示其形式为1 ⊕ a ⊕ b ⊕ ab ⊕ abc ...即“纯真值、纯假值、变量合取或异或”不允许出现否定is_anf的实现见 sympy/logic/boolalg.py。它广泛用于密码学如 S 盒分析与纠错码领域。六、化简与等价测试simplify_logic 与 bool_map6.1simplify_logicsimplify_logic(expr, formNone, deepTrue, forceFalse, dontcareNone)是逻辑化简的一站式入口sympy/logic/boolalg.pyformcnf或dnf时返回对应正规形式的最简式为None时自动选择参数较少的那个形式默认倾向 CNFdeepTrue递归化简输入中的非布尔子表达式如关系表达式x 1源码会先把Relational原子用simplify化简再替换回原式forceFalse与to_cnf/to_dnf相同的 8 变量上限保护dontcare在指定输入组合下为真的表达式被视为“无关项”可用于Piecewise条件化简——后面的分支无需再考虑已被前面分支覆盖的输入。例如simplify_logic(x | y, dontcarey)返回x因为当y为真时整个输入已被其他条件覆盖。 from sympy.logic import simplify_logic from sympy.abc import x, y, z b (~x ~y ~z) | (~x ~y z) simplify_logic(b) ~x ~y此外doc/src/modules/logic.rst 特别指出 SymPy 的通用simplify函数同样适用于逻辑表达式可以直接对布尔表达式调用simplify(expr)得到最简形式。6.2bool_mapbool_map(bool1, bool2)用于判断两个布尔函数在变量重命名对合/自同构意义下是否等价并返回变量映射。它适合做“两个逻辑电路本质上是否同一个电路”的验证 from sympy.logic.boolalg import bool_map, Or, And, Not from sympy.abc import w, x, y, z f1 Or(And(w, x, y), z) f2 Or(And(x, y, w), z) bool_map(f1, f2) (w, x, y, z) - (x, y, w, z)bool_map通过比较表达式的“指纹”_finger进行规范化只有指纹一致才可能等价对应测试见 sympy/logic/tests/test_boolalg.py 中的test_bool_map。七、表达式操纵分配律与蕴含消除doc/src/modules/logic.rst 的 “Manipulating expressions” 一节提供了一组面向规则操纵的函数distribute_and_over_or(expr)对或做与的分配a (b | c)→(a b) | (a c)distribute_or_over_and(expr)对与做或的分配a | (b c)→(a | b) (a | c)distribute_xor_over_and(expr)异或对与的分配a ^ (b c)→(a ^ b) | (a ^ c)eliminate_implications(expr, formNone)消除蕴含把A B改写为~A | Bformcnf或dnf可控制展开方向见 sympy/logic/boolalg.py。另有辅助函数conjuncts(expr)与disjuncts(expr)分别把合取/析取表达式拆成子项列表 from sympy.logic.boolalg import conjuncts, disjuncts from sympy.abc import A, B conjuncts(A B) {A, B} disjuncts(A | B) {A, B}八、真值表truth_table 与位置映射工具truth_table(expr, variables, inputTrue)返回一个生成器逐个产出所有变量取值组合及其对应的表达式求值结果sympy/logic/boolalg.py from sympy.logic.boolalg import truth_table from sympy.abc import x, y table truth_table(x y, [x, y]) for t in table: ... print({0} - {1}.format(*t)) [0, 0] - True [0, 1] - True [1, 0] - False [1, 1] - True当inputFalse时只返回真值序列输入组合可由下标反推配合sympy.utilities.iterables.ibin使用。与真值表位置互相映射的工具函数还有integer_to_term(integer, variables)与term_to_integer(term)在整数下标与二进制项之间转换bool_minterm(k, variables)/bool_maxterm(k, variables)/bool_monomial(k, variables)由整数k构造第 k 个最小项/最大项/单项式如bool_minterm(3, [x, y, z])对应x y ~z这类“只有一个变量取反”的积项anf_coeffs(truthvalues)提取 ANF 展开的系数向量to_int_repr(clauses, symbols)把子句集转换为整数编码表示这是现代 SAT 求解器使用的紧凑输入格式也是sympy/logic/inference.py中dpll2、pycosat、z3 等求解器后端交换数据的桥梁。九、命题推理satisfiable、valid、entails推理子模块位于sympy.logic.inferencesympy/logic/inference.py模块开头明确写道 “This module implements some inference routines in propositional logic”实现的是经典的命题逻辑推理例程。9.1 可满足性判定satisfiablesatisfiable(expr, algorithmNone, all_modelsFalse, minimalFalse, use_lra_theoryFalse)测试给定布尔表达式是否可满足存在一组变量赋值使其为真。满足时返回一个模型符号到布尔值的字典不满足时返回False from sympy.logic.inference import satisfiable from sympy import Symbol x Symbol(x) y Symbol(y) satisfiable(x ~x) # 永假不可满足 False satisfiable((x | y) (x | ~y) (~x | y)) {x: True, y: True}源码对all_modelsTrue的行为有明确规定sympy/logic/inference.py若表达式可满足返回一个模型生成器可逐个产出全部模型若不可满足则返回只含单个元素False的生成器。9.2 求解算法后端satisfiable的algorithm参数可以选择不同后端见 sympy/logic/inference.pyalgorithm说明dpll经典 DPLL 算法位于 sympy/logic/algorithms/dpll.pydpll2默认现代 CDCL 风格求解器支持 VSIDS 分支启发式、子句学习见 sympy/logic/algorithms/dpll2.py并可接入 LRA 线性算术理论pycosat若安装了pycosat则默认使用否则静默回退到dpll2minisat22需要pysat包支持minimal求最小模型z3需要z3包use_lra_theoryTrue时会把线性算术理论Linear Real Arithmetic集成进dpll2用于求解含x 3这类关系约束的可满足性问题对应的理论求解器位于 sympy/logic/algorithms/lra_theory.py。从源码可以推断satisfiable的设计目标是在无外部依赖时也能开箱即用默认dpll2同时为追求性能的用户提供接入成熟 SAT 求解器的通道。9.3 有效性、模型验证与蕴含valid(expr)判定表达式是否有效所有赋值下均为真实现为not satisfiable(Not(expr))——即“取反后不可满足”。valid(A | ~A)为Truevalid(A | B)为Falsepl_true(expr, modelNone, deepFalse)判断给定赋值是否是该表达式的模型。赋值不全时可返回None表示“无法判定”deepTrue时会基于有效性与可满足性给出部分赋值下的正确结论entails(expr, formula_setNone)判定公式集formula_set是否蕴含exprformula_set为空时退化为判定expr的有效性。例如entails(C, [A B, B C, A])为Trueentails(A, [A B, B C])为Falseliteral_symbol(literal)提取文字可能带否定背后的原子符号literal_symbol(~A)返回A。valid、pl_true、entails的实现及 docstring 示例均见 sympy/logic/inference.py对应的测试见 sympy/logic/tests/test_inference.pytest_satisfiable、test_valid、test_pl_true、test_entails、test_satisfiable_all_models等。十、与 Logic 紧密关联的 Sets 模块doc/src/modules/sets.rst 定义了与逻辑推理、求解紧密配合的集合体系核心实现位于 sympy/sets/sets.py 与 sympy/sets/fancysets.py。10.1 集合类型一览类别类说明基本集合Set、imageset、Interval、FiniteSet抽象基类、函数像集、实数区间、有限集复合集合Union、Intersection、ProductSet、Complement、SymmetricDifference、DisjointUnion并、交、笛卡尔积、补、对称差、不交并单例集合EmptySet、UniversalSet空集与全集特殊数集Rationals、Naturals、Naturals0、Integers、Reals、Complexes常见数学数集参数化集合ImageSet、Range、ComplexRegion含CartesianComplexRegion、PolarComplexRegion、normalize_theta_set函数像、等差数列、复数区域幂集PowerSet幂集构造sympy/sets/powerset.py条件集ConditionSet、Contains满足条件的元素集合、成员判定sympy/sets/conditionset.py类型系统SetKind集合的元素 kind 信息10.2 集合迭代的语义约定doc/src/modules/sets.rst 专门用一节讨论了“对集合迭代”的语义这是集合模块最容易被忽略的陷阱对并集迭代时{a, b} ∪ {x, y}可以安全地当作{a, b, x, y}处理元素是否相异不影响迭代但对交集迭代时假设{a, b} ∩ {x, y}等于空集或{a, b}都不总是成立的因为a、b、x、y中某些元素可能属于也可能不属于该交集因此对涉及交集、补集、对称差的集合迭代时只有当所有元素都能被确认属于该集合时才会产出元素只要有任何元素无法确定其成员身份迭代就会抛出TypeError——这与x in y报错的场景一致。这种设计是有意为之文档明确说明即便它与 Python 内置 set 迭代器的一致性有所出入也要保证FiniteSet(*s)这种“从已有 SymPy 集合构造有限集”的常用写法与FiniteSet(*simplify(s))等符号化集合处理方法保持一致从而避免符号计算中出现“迭代结果不可复现”的问题。10.3 布尔函数与集合的转换逻辑与集合的桥梁体现在Boolean.as_set()与_eval_as_set上sympy/logic/boolalg.py 中Boolean.as_set与各布尔函数的_eval_as_set一个关于x的布尔表达式可以转换为满足它的点集。例如And(x 1, x 3).as_set()会给出对应区间。这一机制正是solveset等求解器输出集合形式的底层支撑也让“逻辑条件”与“解集”两种视角在 SymPy 中无缝衔接。十一、实践建议与典型工作流结合文档与源码这里给出几条可直接落地的实践经验从真值表到电路/布尔函数使用SOPform/POSform/ANFform时minterms 三种表示二进制列表、整数、字典按数据规模选择——整数表示最紧凑字典表示最适合“部分指定”的场景化简大表达式务必注意 8 变量限制超过 8 个变量时simplify_logic、to_cnf(..., True)等需要显式forceTrue且 QM 算法最坏指数级耗时先评估变量规模再决定是否强制化简电路等价验证用bool_map它能给出变量重命名映射比单纯equals更强适合判断两个电路是否结构等价命题可满足性优先用默认dpll2零外部依赖即可运行追求性能时可安装pycosat、pysat或z3并显式指定algorithm涉及线性不等式约束时启用use_lra_theoryTrue推理三步曲satisfiable找模型/证不可满足→valid证恒真→entails证蕴含它们彼此复用valid(expr)本质上就是not satisfiable(~expr)集合迭代注意成员判定对涉及交/补/对称差的集合做展开前先确认元素成员关系可判定否则会得到TypeError需要“展平”为具体元素时优先用FiniteSet(*s)并配合simplify。十二、进一步阅读逻辑模块完整文档doc/src/modules/logic.rst聚合入口doc/src/reference/public/logic/index.rst集合模块完整文档doc/src/modules/sets.rst核心源码sympy/logic/boolalg.py、sympy/logic/inference.py、sympy/sets/sets.py、sympy/sets/fancysets.py求解器实现sympy/logic/algorithms/dpll2.py、sympy/logic/algorithms/dpll.py、sympy/logic/algorithms/lra_theory.py测试用例逻辑部分见 sympy/logic/tests/test_boolalg.py 与 sympy/logic/tests/test_inference.py集合部分见 sympy/sets/tests。【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考