module AutoProof.Internal.Classical.SAT.Algorithms.DPLL
  ( satDPLL,
    satAssignmentDPLL,
  )
where
import AutoProof.Internal.Classical.CNF (CNF)
import qualified AutoProof.Internal.Classical.CNF as CNF
  ( fromFormula,
    getAnyLiteral,
    pureLiteral,
    substitute,
    substitutePure,
    unitLiteral,
  )
import AutoProof.Internal.Formula (Formula)
import Control.Applicative ((<|>))
import Data.Map (Map)
import qualified Data.Map as Map (empty, insert, null)
import Data.Maybe (isJust)
import qualified Data.Set as Set
satDPLL :: Ord a => Formula a -> Bool
satDPLL :: Formula a -> Bool
satDPLL = Maybe (Map a Bool) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (Map a Bool) -> Bool)
-> (Formula a -> Maybe (Map a Bool)) -> Formula a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Formula a -> Maybe (Map a Bool)
forall a. Ord a => Formula a -> Maybe (Map a Bool)
satAssignmentDPLL
satAssignmentDPLL :: Ord a => Formula a -> Maybe (Map a Bool)
satAssignmentDPLL :: Formula a -> Maybe (Map a Bool)
satAssignmentDPLL = CNF a -> Maybe (Map a Bool)
forall a. Ord a => CNF a -> Maybe (Map a Bool)
satAssignmentDPLLFromCNF (CNF a -> Maybe (Map a Bool))
-> (Formula a -> CNF a) -> Formula a -> Maybe (Map a Bool)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Formula a -> CNF a
forall a. Ord a => Formula a -> CNF a
CNF.fromFormula
satAssignmentDPLLFromCNF :: Ord a => CNF a -> Maybe (Map a Bool)
satAssignmentDPLLFromCNF :: CNF a -> Maybe (Map a Bool)
satAssignmentDPLLFromCNF = Map a Bool -> CNF a -> Maybe (Map a Bool)
forall a. Ord a => Map a Bool -> CNF a -> Maybe (Map a Bool)
solve Map a Bool
forall k a. Map k a
Map.empty
  where
    solve :: Map a Bool -> CNF a -> Maybe (Map a Bool)
solve m :: Map a Bool
m cnf :: CNF a
cnf
      | CNF a -> Bool
forall a. Set a -> Bool
Set.null CNF a
cnf = Map a Bool -> Maybe (Map a Bool)
forall a. a -> Maybe a
Just Map a Bool
m
      | (Map a Bool -> Bool) -> CNF a -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Map a Bool -> Bool
forall k a. Map k a -> Bool
Map.null CNF a
cnf = Maybe (Map a Bool)
forall a. Maybe a
Nothing
      | Bool
otherwise =
        case CNF a -> Maybe (Literal a)
forall a. CNF a -> Maybe (Literal a)
CNF.unitLiteral CNF a
cnf of
          Just (x :: a
x, b :: Bool
b) -> Map a Bool -> CNF a -> Maybe (Map a Bool)
solve (a -> Bool -> Map a Bool -> Map a Bool
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert a
x Bool
b Map a Bool
m) (CNF a -> a -> Bool -> CNF a
forall a. Ord a => CNF a -> a -> Bool -> CNF a
CNF.substitute CNF a
cnf a
x Bool
b)
          Nothing -> case CNF a -> Maybe (Literal a)
forall a. Ord a => CNF a -> Maybe (Literal a)
CNF.pureLiteral CNF a
cnf of
            Just (x :: a
x, b :: Bool
b) -> Map a Bool -> CNF a -> Maybe (Map a Bool)
solve (a -> Bool -> Map a Bool -> Map a Bool
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert a
x Bool
b Map a Bool
m) (CNF a -> a -> Bool -> CNF a
forall a. Ord a => CNF a -> a -> Bool -> CNF a
CNF.substitutePure CNF a
cnf a
x Bool
b)
            Nothing -> case CNF a -> Maybe (Literal a)
forall a. CNF a -> Maybe (Literal a)
CNF.getAnyLiteral CNF a
cnf of
              Nothing -> Maybe (Map a Bool)
forall a. Maybe a
Nothing 
              Just (x :: a
x, _) ->
                Map a Bool -> CNF a -> Maybe (Map a Bool)
solve (a -> Bool -> Map a Bool -> Map a Bool
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert a
x Bool
True Map a Bool
m) (CNF a -> a -> Bool -> CNF a
forall a. Ord a => CNF a -> a -> Bool -> CNF a
CNF.substitute CNF a
cnf a
x Bool
True)
                  Maybe (Map a Bool) -> Maybe (Map a Bool) -> Maybe (Map a Bool)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Map a Bool -> CNF a -> Maybe (Map a Bool)
solve (a -> Bool -> Map a Bool -> Map a Bool
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert a
x Bool
False Map a Bool
m) (CNF a -> a -> Bool -> CNF a
forall a. Ord a => CNF a -> a -> Bool -> CNF a
CNF.substitute CNF a
cnf a
x Bool
False)