toysolver-0.0.2: src/TseitinEncode.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : TseitingEncoding
-- Copyright : (c) Masahiro Sakai 2011
-- License : BSD-style
--
-- Maintainer : masahiro.sakai@gmail.com
-- Stability : provisional
-- Portability : non-portable (GeneralizedNewtypeDeriving)
--
-----------------------------------------------------------------------------
module TseitingEncoding
( Var
, Lit
, Clause
, CNF
, Formula
, CNFGenMonad (..)
, emitFormula
, CNFGen
, runCNFGen
, execCNFGen
, evalCNFGen
) where
import Control.Monad
import Control.Monad.RWS
type Var = Int
data Lit = Pos Var | Neg Var deriving (Show, Eq, Ord)
type Clause = [Lit]
type CNF = [Clause]
data Formula
= Var Var
| And [Formula]
| Or [Formula]
| Not Formula
| Imply Formula Formula
deriving (Show, Eq, Ord)
class Monad m => CNFGenMonad m where
newVar :: m Var
emitClause :: Clause -> m ()
emitFormula :: CNFGenMonad m => Formula -> m ()
emitFormula x = do
v <- enc x
emitClause [Pos v]
enc :: CNFGenMonad m => Formula -> m Var
enc (Var v) = return v
enc (And xs) = do
v <- newVar
vs <- mapM enc xs
forM vs $ \v2 -> emitClause [Neg v, Pos v2]
emitClause (Pos v : map Neg vs)
return v
enc (Or xs) = do
v <- newVar
vs <- mapM enc xs
forM vs $ \v2 -> emitClause [Pos v, Neg v2]
emitClause (Neg v : map Pos vs)
return v
enc (Not x) = do
v <- newVar
v2 <- enc x
emitClause [Pos v, Pos v2]
emitClause [Neg v, Neg v2]
return v
enc (Imply x y) = enc (Or [Not x, y])
newtype CNFGen a = CNFGen (RWS () (Endo [Clause]) Int a)
deriving Monad
instance CNFGenMonad CNFGen where
newVar = CNFGen $ do
cnt <- get
put (cnt+1)
return cnt
emitClause cl = CNFGen (tell (Endo (cl:)))
runCNFGen :: CNFGen x -> (x, Int, CNF)
runCNFGen (CNFGen m) =
case runRWS m () 0 of
(x, cnt, f) -> (x, cnt, appEndo f [])
execCNFGen :: CNFGen x -> (Int, CNF)
execCNFGen m =
case runCNFGen m of
(_,cnt,cnf) -> (cnt,cnf)
evalCNFGen :: CNFGen x -> (x, CNF)
evalCNFGen m =
case runCNFGen m of
(x,_,cnf) -> (x,cnf)
test :: (Int, CNF)
test = execCNFGen $ do
x <- newVar
y <- newVar
z <- newVar
emitFormula $ And [Or [Var x, Var y] , Var z]
{-
=>
(5
, [ [Pos 4,Neg 0]
, [Pos 4,Neg 1]
, [Neg 4,Pos 0,Pos 1]
, [Neg 3,Pos 4]
, [Neg 3,Pos 2]
, [Pos 3,Neg 4,Neg 2]
, [Pos 3]
]
)
-}