Skip to content

Adding tt entails #12903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
79 changes: 79 additions & 0 deletions machine_learning/ttentails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
TT-ENTAILS Algorithm (Propositional Logic)
Reference: [Russell & Norvig, Artificial Intelligence: A Modern Approach, Ch. 7](https://aima.cs.berkeley.edu/)
Wikipedia: [Entailment](https://en.wikipedia.org/wiki/Entailment)

This algorithm checks if a knowledge base (KB) entails a query sentence (a)
using truth tables. Returns True if KB entails a, False otherwise.
"""

import itertools
import ast
import operator

Check failure on line 12 in machine_learning/ttentails.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

machine_learning/ttentails.py:10:1: I001 Import block is un-sorted or un-formatted

OPS = {ast.And: operator.and_, ast.Or: operator.or_, ast.Not: operator.not_}


def safe_eval(expr: str, model: dict[str, bool]) -> bool:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file machine_learning/ttentails.py, please provide doctest for the function safe_eval

"""Safely evaluate propositional logic expression using ast."""
tree = ast.parse(expr, mode="eval")

def _eval(node):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: _eval. If the function does not return a value, please provide the type hint as: def function() -> None:

As there is no test file in this pull request nor any test function or class in the file machine_learning/ttentails.py, please provide doctest for the function _eval

Please provide type hint for the parameter: node

if isinstance(node, ast.Expression):
return _eval(node.body)
if isinstance(node, ast.Name):
return model[node.id]
if isinstance(node, ast.Constant): # True / False
return node.value
if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
return OPS[ast.Not](_eval(node.operand))
if isinstance(node, ast.BoolOp):
if isinstance(node.op, ast.And):
return all(_eval(v) for v in node.values)
if isinstance(node.op, ast.Or):
return any(_eval(v) for v in node.values)
raise ValueError(f"Unsupported expression: {expr}")

Check failure on line 35 in machine_learning/ttentails.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (EM102)

machine_learning/ttentails.py:35:26: EM102 Exception must not use an f-string literal, assign to variable first

return _eval(tree)


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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file machine_learning/ttentails.py, please provide doctest for the function tt_entails

"""
Check if the knowledge base entails the query using truth tables.

Args:
kb (List[str]): List of propositional sentences in KB as strings
query (str): Query sentence to test entailment
symbols (List[str]): List of all propositional symbols used

Returns:
bool: True if KB entails query, False otherwise

Example:
tt_entails(["P or Q"], "Q", ["P","Q"])

"""
for values in itertools.product([True, False], repeat=len(symbols)):
model: dict[str, bool] = dict(zip(symbols, values))
# Check if KB is true under this model
# # If query is false in this model, KB does not entail query
if all(safe_eval(sentence, model) for sentence in kb) and not safe_eval(
query, model
):
return False
return True


# Example usage
if __name__ == "__main__":
# Example 1: KB entails query → should return True
symbols = ["P", "Q"]
kb = ["P or Q", "not P or Q"] # KB says P or Q is True, and not P or Q is True
query = "Q" # Query: Is Q True?
print("Does KB entail query? : ", tt_entails(kb, query, symbols))

# Example 2: KB does NOT entail query → should return False
symbols2 = ["P", "Q"]
kb2 = ["P"] # KB says only P is True
query2 = "Q" # Query asks if Q is True
print("Does KB2 entail query2? : ", tt_entails(kb2, query2, symbols2))
Loading