python-Sympy:如何查找所有N个表达式共有的最长表达式
作者:互联网
我在Sympy中有N个表达式,我需要找到所有N个表达式共有的最长表达式(例如最长的表达式在所有N个表达式中/包含在其中)
from sympy import Symbol
from sympy.logic.boolalg import And, Not, Or
a = Symbol("a")
b = Symbol("b")
expr0 = And(And(a, b), c)
expr1 = Not(And(a, b))
expr2 = Or(Not(a), Not(b))
#?? now how to find that all expressions contains And(a,b) ?
我为什么需要它?我有一些表达式,我需要为它们构建If-then-else块:
expr0 causes operation Op0
expr1 causes operation Op1
expr2 causes operation Op2
and the result should be:
And(a,b) is longest expression which all of expr have in common
so I will be able to build if then else block like this
If (And(a, b)) {
if(c)
Op0;
}else{
op1;
op2;
}
所以这就是为什么我需要找到所有N个表达式共有的最长表达式.
为了优化此If-then-else块.
解决方法:
SymPy对象具有.has(…)方法:
>>> expr1.has(expr0)
True
>>> expr2.has(expr0)
False
关于Python的其余部分(即不是SymPy),您最好定义共享表达式的含义.逻辑运算通常应该返回一个值,而不是构建一个表达式.
编辑
好的,从讨论中我了解到您想在两个表达式之间寻找一个公共子表达式(因此,不测试一个子表达式是否是一个公共子表达式).
此外,您想在逻辑上匹配等价的表达式,也就是说,看起来不同但逻辑上等价的表达式应匹配为等价的.这使一切变得更加复杂,但是我为您提出了一个简单的解决方案.
SymPy具有satisfiable()函数,该函数找到逻辑表达式的解.如果您传递参数all_models = True,则此函数将返回满足该逻辑条件的所有解决方案:
In [5]: list(satisfiable(expr2, all_models=True))
Out[5]: [{b: False, a: False}, {b: False, a: True}, {b: True, a: False}]
函数preorder_traversal允许我们访问整个表达式树(即,轻松创建一个for循环来访问所有子表达式).因此,我们可以构造一个双for循环以对expr1的子表达式执行搜索,检查它们的可满足性,对另一个表达式(在本示例中为expr2)执行第二个for循环,并比较两个子表达式的可满足性:
for e1 in preorder_traversal(expr1):
s1 = list(satisfiable(e1 ,all_models =True ))
for e2 in preorder_traversal (expr2):
s2 = list (satisfiable (e2 ,all_models =True ))
if s1 == s2:
print("Logically equiv subexpr found: ", e1, " and ", e2)
如果将expr1和expr2放在此处,则会得到:
('Logically equiv subexpr found: ', Not(And(a, b)), ' and ', Or(Not(a), Not(b)))
('Logically equiv subexpr found: ', b, ' and ', b)
('Logically equiv subexpr found: ', a, ' and ', a)
我认为您可以轻松地将此代码适应您的需求.
编辑2
要处理将树分为两个以上子表达式的情况(即,像And(a,b,c,d)或Xor(a,b,c,d,e)之类的情况),可以生成这样的子集(这次代码未经过测试):
# get a function to generate all subsets of a tuple,
# let's say `subsets( )`
for e1 in preorder_traversal(expr1):
for es1 in subsets(e1.args):
s1 = list(satisfiable(e1.func(*es1), all_models=True))
# NOW do the same with the `e2` for-loop,
# then compare `s1` and `s2` as usual.
该代码看起来像一系列4个嵌套的for循环,但可以重新排列以定义一些辅助函数,以使其看起来更好.
可以进一步推广比较两个以上的表达式,再次更好地重新组织代码.
编辑3
我想了一夜,我认为您可以通过仅使用satisfiable()筛选第一个表达式来进一步改进该算法,一旦获得了符号的布尔值解决方案,只需将它们替换为其他表达式以查看哪些部分兼容.
标签:sympy,boolean-logic,python 来源: https://codeday.me/bug/20191119/2038302.html