Skip to content

Commit 6706319

Browse files
committed
tt-entails algorithm
1 parent e06f29f commit 6706319

1 file changed

Lines changed: 26 additions & 10 deletions

File tree

machine_learning/ttentails.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,36 @@
88
"""
99

1010
import itertools
11-
import re
11+
import ast
12+
import operator
1213

14+
OPS = {
15+
ast.And: operator.and_,
16+
ast.Or: operator.or_,
17+
ast.Not: operator.not_
18+
}
1319

1420
def safe_eval(expr: str, model: dict[str, bool]) -> bool:
15-
"""Safely evaluate propositional logic expression with given model."""
16-
# Replace symbols (like P, Q) with their boolean values
17-
for sym, val in model.items():
18-
expr = re.sub(rf'\b{sym}\b', str(val), expr)
19-
# Allow only True/False, and/or/not operators
20-
allowed = {"True", "False", "and", "or", "not", "(", ")", " "}
21-
if not all(token in allowed or token.isidentifier() or token in "()" for token in re.split(r'(\W+)', expr)):
22-
raise ValueError("Unsafe expression detected")
23-
return eval(expr, {"__builtins__": {}}, {})
21+
"""Safely evaluate propositional logic expression using ast."""
22+
tree = ast.parse(expr, mode="eval")
2423

24+
def _eval(node):
25+
if isinstance(node, ast.Expression):
26+
return _eval(node.body)
27+
if isinstance(node, ast.Name):
28+
return model[node.id]
29+
if isinstance(node, ast.Constant): # True / False
30+
return node.value
31+
if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
32+
return OPS[ast.Not](_eval(node.operand))
33+
if isinstance(node, ast.BoolOp):
34+
if isinstance(node.op, ast.And):
35+
return all(_eval(v) for v in node.values)
36+
if isinstance(node.op, ast.Or):
37+
return any(_eval(v) for v in node.values)
38+
raise ValueError(f"Unsupported expression: {expr}")
39+
40+
return _eval(tree)
2541

2642
def tt_entails(kb: list[str], query: str, symbols: list[str]) -> bool:
2743
"""

0 commit comments

Comments
 (0)