Hone logo
Hone
Problems

Implement a Boolean Satisfiability (SAT) Solver

The Boolean Satisfiability Problem (SAT) is a fundamental problem in computer science, particularly in theoretical computer science and artificial intelligence. It asks whether there exists an interpretation (a truth assignment) of variables that satisfies a given Boolean formula. Implementing a SAT solver allows us to tackle a wide range of problems, from circuit verification to automated reasoning.

Problem Description

Your task is to implement a SAT solver in Python. The solver should take a Boolean formula in Conjunctive Normal Form (CNF) as input and determine if there is a truth assignment to its variables that makes the entire formula true. If a satisfying assignment exists, the solver should return one such assignment. If no satisfying assignment exists, it should indicate that the formula is unsatisfiable.

Key Requirements:

  1. Input Format: The input will be a list of clauses, where each clause is a list of literals. A literal is either a positive integer (representing a positive variable) or a negative integer (representing the negation of a variable). For example, [[1, -2], [2, 3]] represents the CNF formula (x1 OR NOT x2) AND (x2 OR x3). Variables are numbered starting from 1.
  2. Output Format:
    • If the formula is satisfiable, return a dictionary mapping variable numbers (integers) to their truth values (booleans True or False). For example, {1: True, 2: False, 3: True}.
    • If the formula is unsatisfiable, return None.
  3. Algorithm: You should implement a basic backtracking search algorithm, often referred to as DPLL (Davis-Putnam-Logemann-Loveland). The core components of DPLL include:
    • Unit Propagation: If a clause contains only one literal, that literal must be true. Assign the corresponding variable its truth value to satisfy the clause and simplify the remaining formula.
    • Pure Literal Elimination: If a variable appears only positively or only negatively across all remaining clauses, assign it the truth value that satisfies those occurrences.
    • Splitting Rule: If neither of the above rules can be applied, choose an unassigned variable and try assigning it True. If this leads to a satisfying assignment, return it. Otherwise, backtrack and try assigning it False.

Expected Behavior:

  • The solver should correctly identify satisfiable and unsatisfiable formulas.
  • For satisfiable formulas, it should return a valid truth assignment.
  • The solver should handle empty clauses (which make the formula unsatisfiable) and empty input (which is trivially satisfiable).

Edge Cases:

  • Empty formula: An empty list of clauses [] is considered satisfiable with an empty assignment {}.
  • Empty clause: A clause like [] within the input signifies an immediate unsatisfiable state.
  • Formula with no variables: A formula like [[]] is unsatisfiable. A formula like [] is satisfiable.

Examples

Example 1:

Input: [[1, -2], [-1, 2], [1, 2]]
Output: {1: True, 2: True}
Explanation:
Clause 1: (x1 OR NOT x2)
Clause 2: (NOT x1 OR x2)
Clause 3: (x1 OR x2)

If x1 is True:
Clause 1 becomes (True OR NOT x2) -> True
Clause 2 becomes (False OR x2) -> x2
Clause 3 becomes (True OR x2) -> True

Now we only need to satisfy x2. If x2 is True, then Clause 2 is satisfied.
So, {1: True, 2: True} satisfies all clauses.

Example 2:

Input: [[1], [-1]]
Output: None
Explanation:
Clause 1: (x1)
Clause 2: (NOT x1)

This is a contradiction. If x1 must be True (from Clause 1) and x1 must be False (from Clause 2), then no satisfying assignment exists.

Example 3: (Pure Literal Elimination)

Input: [[1, 2], [-1, 3], [2, 3]]
Output: {1: True, 2: True, 3: True} (or other valid assignment)
Explanation:
Clause 1: (x1 OR x2)
Clause 2: (NOT x1 OR x3)
Clause 3: (x2 OR x3)

Let's say we pick x1.
If x1 is True:
Clause 1: (True OR x2) -> True
Clause 2: (False OR x3) -> x3
Clause 3: (x2 OR x3)

Now we have x3 and (x2 OR x3) to satisfy. If we assign x3 = True, both are satisfied.
If x1 is False:
Clause 1: (False OR x2) -> x2
Clause 2: (True OR x3) -> True
Clause 3: (x2 OR x3)

Now we have x2 and (x2 OR x3) to satisfy. If we assign x2 = True, both are satisfied.

A valid assignment would be {1: True, 2: True, 3: True}.
Another: {1: False, 2: True, 3: True}.
(Note: The solver might find any valid assignment, not necessarily this specific one.)

Constraints

  • The number of variables will be between 1 and 100.
  • The number of clauses will be between 0 and 1000.
  • Each clause will contain between 1 and 100 literals (unless it's an empty clause).
  • The absolute value of any literal will be between 1 and the number of variables.
  • The input will always be a list of lists of integers.
  • The algorithm should be reasonably efficient for the given constraints, though a brute-force exponential solution might time out for larger inputs. DPLL with optimizations is expected.

Notes

  • You will need to manage the state of assignments and the remaining clauses effectively.
  • Consider how to represent the formula and assignments efficiently.
  • Think about the order in which you pick variables for splitting. A simple heuristic is often sufficient for basic implementations.
  • For unit propagation, you'll need to efficiently find clauses with only one literal.
  • For pure literal elimination, you'll need to efficiently track the occurrences of positive and negative literals for each variable.
  • Remember to handle the removal of satisfied clauses and the simplification of unsatisfied clauses after an assignment.
Loading editor...
python