Пакет символов Sympy представляется хорошим выбором.
В своей базовой c форме sympy хочет and
, or
и not
, записанные как &
, |
и ~
, которые можно заменить перед вызовом синтаксического анализатора. Обратите внимание, что простая замена строки не будет работать хорошо, если есть такие имена, как 'Brandon', которые содержат 'и'.
После этого вы можете использовать sympy для выполнения любых упрощений, манипуляций и . подстановки , как и любое другое математическое выражение.
Пример:
from sympy.parsing.sympy_parser import parse_expr
str = "Alice and (Bob or Carla) and not David"
str = str.replace('and', '&').replace('or', '|').replace('not', '~')
expr = parse_expr(str)
print(expr)
print(expr.subs({'Alice': True, 'Bob': False}))
Вывод:
Alice & ~David & (Bob | Carla)
Carla & ~David
В комментариях вы просите оперировать устанавливает вместо логических. Наборы небольших чисел представлены в Sympy как FiniteSet
. Как правило, они должны быть написаны с использованием функции обозначения: Union(arg1, arg2, arg3, ...)
. Но мы можем использовать логические операторы And
, Or
и Not
, которые позволяют инфиксная запись создавать выражение и впоследствии оценивать, как если бы это были операции над множествами.
from sympy.parsing.sympy_parser import parse_expr
from sympy import Atom, FiniteSet, And, Or, Not, Union, Intersection, Complement
def evaluate_expr(expr, replacements, complete_set):
if isinstance(expr, Atom):
return expr.subs(replacements)
elif expr.func == Or:
return Union(*[evaluate_expr(a, replacements, complete_set) for a in expr.args])
elif expr.func == And:
return Intersection(*[evaluate_expr(a, replacements, complete_set) for a in expr.args])
elif expr.func == Not:
return Complement(complete_set, evaluate_expr(expr.args[0], replacements, complete_set))
replacements = {'Alice': {1, 2}, 'Bob': {1, 2, 3}, 'Carla': {5}, 'David': {1, 4, 6}}
for r in replacements:
# convert the replacements to their Sympy representation
replacements[r] = FiniteSet(*replacements[r])
print("Replacements:", replacements)
complete_set = Union(*replacements.values()) # the set of all possible values is used to implement "not"
tests = ["Alice", "Alice or Bob", "Alice and Bob and Carla", "Alice and (Bob or Carla) and not David"]
for test in tests:
expr = parse_expr(test.replace('and', '&').replace('or', '|').replace('not', '~'))
print(expr)
print(" --->", evaluate_expr(expr, replacements, complete_set))
Выход:
Replacements: {'Alice': FiniteSet(1, 2), 'Bob': FiniteSet(1, 2, 3), 'Carla': FiniteSet(5), 'David': FiniteSet(1, 4, 6)}
Alice
---> FiniteSet(1, 2)
Alice | Bob
---> FiniteSet(1, 2, 3)
Alice & Bob & Carla
---> EmptySet
Alice & ~David & (Bob | Carla)
---> FiniteSet(2)