Чтение уравнения из строки и его разбор - PullRequest
0 голосов
/ 25 января 2020

У меня есть логические математические выражения, записанные в строковой форме, как это

"A and B or C and not D"
"A and (B or C) and not D"

Я хочу решить это, используя python, для «и», «или» и «и» будут вызываться разные функции, а не операторы «а» или «нет». Я не могу придумать идеи, которые могут решить эту проблему.

Я могу разбить уравнение с помощью разбиения, но что дальше?

ОБНОВЛЕНИЕ: А и В и другие могут содержать некоторые слова, для которых список будет возвращен, и в этом списке «и», «или» и другие операции будут выполнены.

Я создал этот список, и я могу решить проблему с 2 переменными, но как решить ее, когда есть несколько комбинаций.

1 Ответ

1 голос
/ 25 января 2020

Пакет символов 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)
...