Sympify “<” does not return boolean in custom function?

随声附和 提交于 2019-12-13 03:05:32

问题


Summary

My self-written if-then-else conditional for sympy does not work for some Booleans.

Code (Note: Piecewise is not an option for me, proposed here https://stackoverflow.com/a/38858444/5626139)

from sympy import Function

class ifte(Function):
    nargs = 3

    @classmethod
    def eval(cls, a, b, c):
        if a > 0:
            return b
        else:
            return c

Which works partially, for example with these three booleans:

>>> print(ifte('1+2 and True and 1 != 2', 'b', 'c'))
b

Problem

Why does the line with 0<1 evaluate correctly?

>>> print(ifte('0==1', 'b', 'c'))
b
>>> print(ifte('0<1', 'b', 'c'))
TypeError: 
A Boolean argument can only be used in Eq and Ne; all other
relationals expect real expressions.

All the operators in the if-condition usually evaluate to boolean.

  • Why does this not work for <, >, <=, >= ?
  • Is there a solution to this?
  • How can I be sure if other statements also end up as exception?

回答1:


The issue is triggered during the if:

from sympy import Function

class ifte(Function):
    nargs = 3

    @classmethod
    def eval(cls, a, b, c):
        if a > 0:  # <-- PROBLEM HERE
            return b
        else:
            return c

and it is related to the type that a gets. Since this depends on the expression in a, you observe different behaviors for different expression. In particular, for some values of a, this gets to be sympy.logic.boolalg.*. If that is the case, then the __gt__ method (which is called when the > operator is used) is not defined and you get the error you observe. For some other values, this gets to be a simple bool, for which the __gt__ method is defined and the code works the way you expect.

To solve the issue, simply remove the > 0 comparison, i.e.

from sympy import Function

class ifte(Function):
    nargs = 3

    @classmethod
    def eval(cls, a, b, c):
        if a:
            return b
        else:
            return c

or, even more simply:

from sympy import Function

class ifte(Function):
    nargs = 3

    @classmethod
    def eval(cls, a, b, c):
        return b if a else c
print(ifte('1+2 and True and 1 != 2', 'b', 'c'))
# b
print(ifte('1==0', 'b', 'c'))
# c
print(ifte('1>0', 'b', 'c'))
# b
print(ifte('1<0', 'b', 'c'))
# c

Note that the error message you get depends a bit on the SymPy version you have, but the principle is the same. For example, in version 1.1.1 I get:

TypeError: '>' not supported between instances of 'BooleanTrue' and 'int'



来源:https://stackoverflow.com/questions/58485525/sympify-does-not-return-boolean-in-custom-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!