Build a Propositional Logic Theorem Prover
This challenge asks you to build a simple theorem prover for propositional logic in Python. You will implement a system that can determine whether a given propositional logic formula is a tautology (always true) using the truth-table method. This is a fundamental task in formal logic and artificial intelligence, with applications in areas like automated reasoning and verification.
Problem Description
Your task is to create a Python function, is_tautology(formula), that takes a propositional logic formula as a string and returns True if the formula is a tautology, and False otherwise.
A propositional logic formula is composed of:
- Propositional variables: Single uppercase letters (e.g., 'P', 'Q', 'R').
- Logical connectives:
- Negation:
~(e.g.,~P) - Conjunction:
&(e.g.,P & Q) - Disjunction:
|(e.g.,P | Q) - Implication:
>(e.g.,P > Q) - Biconditional:
<>(e.g.,P <> Q)
- Negation:
- Parentheses:
()for grouping.
The is_tautology function should:
- Parse the input formula: Convert the string representation into an internal, evaluable structure.
- Identify all propositional variables: Extract all unique propositional variables present in the formula.
- Generate all possible truth assignments: For
nunique variables, there are2^npossible combinations of truth values (True/False). - Evaluate the formula for each truth assignment: Substitute the truth values of the variables into the formula and compute its truth value.
- Check for tautology: If the formula evaluates to
Truefor all possible truth assignments, it is a tautology. Otherwise, it is not.
Key Requirements:
- Robust Parsing: The parser should handle nested parentheses and the order of operations correctly.
- Evaluation Logic: Implement the truth values for each logical connective.
- Truth Table Generation: Systematically generate all truth assignments.
- Clear Output: Return a boolean value.
Expected Behavior:
The function should correctly identify tautologies and non-tautologies. For example:
P | ~Pshould beTrue.P & Qshould beFalse.(P > Q) > ((Q > R) > (P > R))should beTrue.
Edge Cases to Consider:
- Formulas with no variables (e.g., tautologies like
Trueif we were to allow it, or contradictions). For this challenge, assume formulas will contain variables. - Formulas with a single variable.
- Complex nested formulas.
- Formulas with only one type of connective.
Examples
Example 1:
Input: "P | ~P"
Output: True
Explanation: This is a tautology (Law of Excluded Middle). For P=True, True | ~True = True | False = True. For P=False, False | ~False = False | True = True. Since it's true for all assignments, it's a tautology.
Example 2:
Input: "P & Q"
Output: False
Explanation: This is not a tautology. If P=True and Q=False, the formula evaluates to True & False = False.
Example 3:
Input: "(P > Q) > ((Q > R) > (P > R))"
Output: True
Explanation: This is a tautology representing the transitivity of implication. It holds true for all possible truth assignments of P, Q, and R.
Example 4: (Edge Case - Single Variable)
Input: "~~P <> P"
Output: True
Explanation: This formula states that double negation is equivalent to the original proposition. It holds true for both P=True and P=False.
Constraints
- Formulas will be strings consisting of uppercase letters (A-Z),
~,&,|,>,<,(,). - The maximum number of unique propositional variables in a formula will not exceed 10.
- The maximum length of a formula string will not exceed 200 characters.
- The parsing and evaluation should be reasonably efficient, avoiding brute-force enumeration that is exponentially worse than necessary.
Notes
- You will need to implement a way to parse the string formula into a structure that can be evaluated. An Abstract Syntax Tree (AST) is a common and effective approach.
- Consider the standard order of operations:
~(highest precedence), then&, then|, then>, and<>. Parentheses override this order. - A good starting point for parsing might be a recursive descent parser or using Python's
evalin a carefully sandboxed manner (though implementing your own parser is more educational). - Remember that Python's boolean operators (
and,or,not,==,!=) can be mapped to your logical connectives. You might define a helper function for evaluating sub-expressions.