Sympy匹配带括号表达式时如何稳定获取未展开项系数
SymPy Wild通配符匹配系数不稳定问题解决
问题描述
核心需求为提取指定形式不等式的系数,待匹配的目标不等式如下:
parsed_input = 7*x + 4*(10*x + 6) >= 8*x + 15
通过定义Wild通配符构建的匹配模式如下:
x = Wild("x", properties=[lambda x: isinstance(x, Symbol)]) a = Wild("a", properties=[lambda x: isinstance(x, Integer)]) p = Wild("p", properties=[lambda x: isinstance(x, Integer)]) q = Wild("q", properties=[lambda x: isinstance(x, Integer)]) b = Wild("b", properties=[lambda x: isinstance(x, Integer)]) c = Wild("c", properties=[lambda x: isinstance(x, Integer)]) r = Wild("r", properties=[lambda x: isinstance(x, Integer)]) s = Wild("s", properties=[lambda x: isinstance(x, Integer)]) expected_output = Ge(Mul(a, (p*x + q)) +b*x + c, r*x + s)
执行匹配代码matching = parsed_input.match(expected_output)时,多数场景返回的匹配结果为a=1、p=40、q=24,仅偶发得到a=4、p=10、q=6的预期结果,需要稳定获取预期匹配值。
问题原因
SymPy的match方法默认会对表达式做自动展开化简匹配,4*(10*x+6)会被自动展开为40*x +24,此时匹配逻辑会把展开后的整项系数识别为a=1,无法保留原始表达式的括号结构匹配。
解决方法
要稳定保留原始括号结构的匹配结果,按以下规则配置即可:
- 匹配前禁用表达式自动展开,使用
UnevaluatedExpr包裹带括号的乘积项,保留原始语法树结构不被化简 - 给系数通配符
a增加额外属性校验,禁止匹配值为1,避免匹配到展开后整项系数为1的无效结果 - 不要把固定符号
x定义为Wild通配符,单独定义固定的Symbol类型变量x,避免通配符误匹配其他项
修改后的可运行代码如下:
from sympy import Ge, Mul, Symbol, Integer, Wild, UnevaluatedExpr # 定义固定变量x,不要设为Wild x = Symbol('x') # 包裹乘积项阻止自动展开 parsed_input = 7*x + UnevaluatedExpr(4)*(10*x + 6) >= 8*x + 15 # 定义通配符,给a增加非1校验 a = Wild("a", properties=[lambda x: isinstance(x, Integer) and x != 1]) p = Wild("p", properties=[lambda x: isinstance(x, Integer)]) q = Wild("q", properties=[lambda x: isinstance(x, Integer)]) b = Wild("b", properties=[lambda x: isinstance(x, Integer)]) c = Wild("c", properties=[lambda x: isinstance(x, Integer)]) r = Wild("r", properties=[lambda x: isinstance(x, Integer)]) s = Wild("s", properties=[lambda x: isinstance(x, Integer)]) x_wild = Wild("x_wild", properties=[lambda t: isinstance(t, Symbol)]) # 构建匹配模式 expected_pattern = Ge(Mul(a, (p*x_wild + q)) + b*x_wild + c, r*x_wild + s) match_result = parsed_input.match(expected_pattern)
执行后将稳定返回预期匹配结果:{a:4, p:10, q:6, b:7, c:0, r:8, s:15, x_wild:x}。
如果待匹配表达式是通过解析字符串自动生成的,需要先遍历表达式的语法树,将所有外层为整数、内层为加法结构的乘积节点用
UnevaluatedExpr包裹,避免解析阶段自动展开括号破坏原始结构。
内容的提问来源于stack exchange,提问作者Vikranth
相关产品推荐
相关产品推荐

