【问题标题】:Evaluate Sympy boolean expression in python在 python 中评估 Sympy 布尔表达式
【发布时间】:2017-02-03 12:11:48
【问题描述】:

我正在使用 Python 和 Sympy。

我有以下几点:

x,y,z = Symbols('x,y,z')
doc = {x : False, y : True, z: True}
rule = Or(x, And(y,z))

我正在 Sympy 中寻找一个函数,它将在 rule.eval(doc) 上返回 True

编辑: 目前我正在使用 rule.subsrule.xreplace 两者都执行缓慢,每次调用大约 0.0003 秒。这使得它不切实际。

【问题讨论】:

  • 我想知道你为什么不能rule.subs(doc)
  • 嗨,你是对的,我没有提到它。这是我用过的,rule.subsrule.xreplace 它们都按预期工作,但性能很差。我分析了我的代码,发现每次执行大约需要 0.0003 秒。我经常使用这些功能。我正在寻找更有效的方法
  • 你必须使用 sympy 吗?如果没有,那么你可以这样做:import operator as op; rule = lambda x,y,z: op.or_(x, op.and_(y,z)); rule(False,True,True)。不提供字典,但速度更快。
  • 是的,程序的其余部分有一些复杂的逻辑,我必须使用 Sympy。我似乎无法理解为什么在 Sympy 中没有实现如此简单的操作。它有 evalf() 用于数字但不用于布尔值。

标签: python sympy sat


【解决方案1】:

以最少的编码获得更好性能的一种方法是使用lambdify

X = tuple(doc.iterkeys())
f = lambdify(X, rule)

这之后 IPython 给了我:

V = tuple(doc.itervalues())
%timeit f(*V)
The slowest run took 7.56 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 209 ns per loop

我不确定警告会对结论产生多大影响,但有明显的改善。在我使用原始代码的同一台计算机上:

%timeit rule.xreplace(doc)
10000 loops, best of 3: 126 µs per loop

而且 subs 更慢。

【讨论】:

  • lambdify 默认会创建一个 NumPy 兼容函数。在这种情况下,类似于logical_or.reduce((x,logical_and.reduce((y,z))))(查看inspect.source(f))。如果你改为使用lambdify((x, y, z), rule, modules=[]),它将生成一个仅使用 Python 的函数,例如 x or y and z,它的计算速度要快得多(大约与纯 Python 一样快)。
【解决方案2】:

您可以使用直接评估而不是使用 subs 吗?

>>> F = Lambda((x, y, z), Or(x, And(y, z)))
>>> F(0, 1, 1)
True

如果没有,您能否创建一个允许通过 lambda 表单进行 subs 的玩具类?这不是一个类,但它给出了这个想法:

>>> def sub(f, d):
...     F = Lambda(d.keys(), f)
...     return F(*[d[k] for k in d.keys()])
>>> sub(Or(x,And(y,z)),{x:0,y:1,z:1})

该类将创建 Lambda 表单并具有一个 subs 方法,该方法将返回评估后的 Lambda 表单。

【讨论】:

    猜你喜欢
    • 2013-12-15
    • 2017-12-26
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 2017-02-08
    • 1970-01-01
    相关资源
    最近更新 更多