packages feed

logic-classes-1.7: Data/Logic/Instances/SatSolver.hs

{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving, TypeFamilies, TypeSynonymInstances #-}
{-# OPTIONS -fno-warn-orphans #-}
module Data.Logic.Instances.SatSolver where

import Control.Monad.State (get, put)
import Control.Monad.Trans (lift)
import Data.Boolean (Literal(Pos, Neg), CNF)
import Data.Boolean.SatSolver (newSatSolver, assertTrue', solve)
import Data.Logic.ATP.Apply (HasApply(PredOf, TermOf))
import Data.Logic.ATP.FOL (IsFirstOrder)
import Data.Logic.ATP.Formulas (IsAtom, IsFormula(..))
import Data.Logic.ATP.Lit (IsLiteral(..), negated, (.~.))
import Data.Logic.ATP.Pretty (Associativity(InfixN), HasFixity(..), Pretty)
import Data.Logic.ATP.Quantified (IsQuantified(VarOf))
import Data.Logic.ATP.Skolem (simpcnf')
import Data.Logic.ATP.Term (IsTerm(FunOf, TVarOf))
import Data.Logic.Classes.ClauseNormalForm (ClauseNormalFormula(..))
import Data.Logic.Normal.Implicative (LiteralMapT, NormalT)
import qualified Data.Map as M
import qualified Data.Set.Extra as S

instance HasFixity Literal where
    precedence _ = 0
    associativity _ = InfixN

instance IsAtom Literal

instance IsFormula Literal where
    type AtomOf Literal = Int
    true = error "true :: IsLiteral"
    false = error "false :: IsLiteral"
    asBool _ = Nothing
    overatoms f (Pos x) r = f x r
    overatoms f (Neg x) r = f x r
    onatoms f (Pos x) = Pos (f x)
    onatoms f (Neg x) = Neg (f x)
    atomic = error "atomic"

instance IsLiteral Literal where
    naiveNegate (Pos x) = Neg x
    naiveNegate (Neg x) = Pos x
    foldNegation pos _ (Pos x) = pos (Pos x)
    foldNegation _ neg (Neg x) = neg (Pos x)
    foldLiteral' _ _ _ at (Pos x) = at x
    foldLiteral' _ ne _ _ (Neg x) = ne (Pos x)

instance ClauseNormalFormula CNF Literal where
    clauses = S.fromList . map S.fromList
    makeCNF = map S.toList . S.toList
    satisfiable cnf = return . not . (null :: [a] -> Bool) $ assertTrue' cnf newSatSolver >>= solve

toCNF :: (atom ~ AtomOf formula, p ~ PredOf atom, term ~ TermOf atom, v ~ VarOf formula, v ~ TVarOf term, function ~ FunOf term,
          Monad m,
          IsFirstOrder formula,
          -- IsAtomWithEquate atom p term,
          IsLiteral formula,
          Ord formula, Pretty formula) =>
         formula -> NormalT formula m CNF
toCNF f = S.ssMapM (lift . toLiteral) (simpcnf' f) >>= return . makeCNF

-- |Convert a [[formula]] to CNF, which means building a map from
-- formula to Literal.
toLiteral :: forall m lit. (Monad m, IsLiteral lit, Ord lit) =>
             lit -> LiteralMapT lit m Literal
toLiteral f =
    literalNumber >>= return . if negated f then Neg else Pos
    where
      literalNumber :: LiteralMapT lit m Int
      literalNumber =
          get >>= \ (count, m) ->
          case M.lookup f' m of
            Nothing -> do let m' = M.insert f' count m
                          put (count+1, m') 
                          return count
            Just n -> return n
      f' :: lit
      f' = if negated f then (.~.) f else f