Skip to content

Instantly share code, notes, and snippets.

@Taneb
Created January 15, 2020 14:58
Show Gist options
  • Save Taneb/04832ea1cf9e635a602873bed6d4df4a to your computer and use it in GitHub Desktop.
Save Taneb/04832ea1cf9e635a602873bed6d4df4a to your computer and use it in GitHub Desktop.
Basic SAT solver
module Sat where
-- A variable, e.g. p, q, r...
type Var = Int
-- A parity, either False (¬) or True (not ¬)
type Parity = Bool
-- A literal, e.g. ¬p, q, ¬r
type Literal = (Int, Bool)
-- A sequence of literals, which are combined by ||
type Clause = [Literal]
-- A sequence of clauses, which are combined by &&
type Formula = [Clause]
findOneLiteralClauses :: Formula -> [Literal]
findOneLiteralClauses formula = [literal | [literal] <- formula]
eliminateLiteral :: Literal -> Formula -> [Formula]
eliminateLiteral (var, parity) [] = [[]]
eliminateLiteral (var, parity) (clause:formula) = case clause of
[(var', parity')]
| var == var' && parity /= parity' -> [] -- contraditiction
_ | (var, parity) `elem` clause -> eliminateLiteral (var, parity) formula
| otherwise -> fmap (filter (\(var', _) -> var /= var') clause :)
(eliminateLiteral (var, parity) formula)
splitOnVariable :: Var -> Formula -> [Formula]
splitOnVariable variable formula = do
positiveElimination <- eliminateLiteral (variable, True) formula
negativeElimination <- eliminateLiteral (variable, False) formula
[positiveElimination, negativeElimination]
solve :: Formula -> [Formula]
solve formula =
case findOneLiteralClauses formula of
(literal:_) -> eliminateLiteral literal formula >>= solve
[] -> case formula of
[] -> pure [] -- we're done!
([]:_) -> [] -- no solution
-- split on the first variable we see
(((var,_):_):_) -> splitOnVariable var formula >>= solve
sat :: Formula -> Bool
sat = not . null . solve
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment