module Solutions.P53 (isTheorem) where
import Control.Monad (guard)
import Data.Set (Set)
import qualified Data.Set as Set
import Problems.Logic (Formula (..))
import Problems.P52 (toConjunctiveNormalForm)
isTheorem :: [Formula] -> Formula -> Bool
isTheorem :: [Formula] -> Formula -> Bool
isTheorem [Formula]
axioms Formula
conjecture = Set (Set Formula) -> Bool
refute (Set (Set Formula) -> Bool) -> Set (Set Formula) -> Bool
forall a b. (a -> b) -> a -> b
$ (Set Formula -> Bool) -> Set (Set Formula) -> Set (Set Formula)
forall a. (a -> Bool) -> Set a -> Set a
Set.filter (Bool -> Bool
not (Bool -> Bool) -> (Set Formula -> Bool) -> Set Formula -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set Formula -> Bool
isTautology) Set (Set Formula)
clauses
where axioms' :: [Formula]
axioms' = (Formula -> Formula) -> [Formula] -> [Formula]
forall a b. (a -> b) -> [a] -> [b]
map Formula -> Formula
purify [Formula]
axioms
conjecture' :: Formula
conjecture' = Formula -> Formula
purify Formula
conjecture
aggregate :: Formula
aggregate = [Formula] -> Formula
Conjoin ([Formula] -> Formula) -> [Formula] -> Formula
forall a b. (a -> b) -> a -> b
$ Formula -> Formula
Complement Formula
conjecture' Formula -> [Formula] -> [Formula]
forall a. a -> [a] -> [a]
: [Formula]
axioms'
clauses :: Set (Set Formula)
clauses = Formula -> Set (Set Formula)
toClauses (Formula -> Set (Set Formula)) -> Formula -> Set (Set Formula)
forall a b. (a -> b) -> a -> b
$ Formula -> Formula
toConjunctiveNormalForm Formula
aggregate
purify :: Formula -> Formula
purify :: Formula -> Formula
purify (Value Bool
True) = Formula
true
purify (Value Bool
False) = Formula
false
purify f :: Formula
f@(Variable String
_) = Formula
f
purify (Complement Formula
f) = Formula -> Formula
Complement (Formula -> Formula) -> Formula -> Formula
forall a b. (a -> b) -> a -> b
$ Formula -> Formula
purify Formula
f
purify (Disjoin []) = Formula
false
purify (Conjoin []) = Formula
true
purify (Disjoin [Formula]
fs) = [Formula] -> Formula
Disjoin ([Formula] -> Formula) -> [Formula] -> Formula
forall a b. (a -> b) -> a -> b
$ (Formula -> Formula) -> [Formula] -> [Formula]
forall a b. (a -> b) -> [a] -> [b]
map Formula -> Formula
purify [Formula]
fs
purify (Conjoin [Formula]
fs) = [Formula] -> Formula
Conjoin ([Formula] -> Formula) -> [Formula] -> Formula
forall a b. (a -> b) -> a -> b
$ (Formula -> Formula) -> [Formula] -> [Formula]
forall a b. (a -> b) -> [a] -> [b]
map Formula -> Formula
purify [Formula]
fs
true :: Formula
true :: Formula
true = [Formula] -> Formula
Disjoin [ Formula
x, Formula -> Formula
Complement Formula
x ]
where x :: Formula
x = String -> Formula
Variable String
"X"
false :: Formula
false :: Formula
false = [Formula] -> Formula
Conjoin [ Formula
x, Formula -> Formula
Complement Formula
x ]
where x :: Formula
x = String -> Formula
Variable String
"X"
toClauses :: Formula -> Set (Set Formula)
toClauses :: Formula -> Set (Set Formula)
toClauses (Conjoin [Formula]
fs) = [Set Formula] -> Set (Set Formula)
forall a. Ord a => [a] -> Set a
Set.fromList ([Set Formula] -> Set (Set Formula))
-> [Set Formula] -> Set (Set Formula)
forall a b. (a -> b) -> a -> b
$ (Formula -> Set Formula) -> [Formula] -> [Set Formula]
forall a b. (a -> b) -> [a] -> [b]
map Formula -> Set Formula
toSet [Formula]
fs
toClauses Formula
f = String -> Set (Set Formula)
forall a. HasCallStack => String -> a
error (String -> Set (Set Formula)) -> String -> Set (Set Formula)
forall a b. (a -> b) -> a -> b
$ String
"not conjunctive normal form: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Formula -> String
forall a. Show a => a -> String
show Formula
f
toSet :: Formula -> Set Formula
toSet :: Formula -> Set Formula
toSet (Disjoin [Formula]
fs) = [Formula] -> Set Formula
forall a. Ord a => [a] -> Set a
Set.fromList [Formula]
fs
toSet Formula
f = String -> Set Formula
forall a. HasCallStack => String -> a
error (String -> Set Formula) -> String -> Set Formula
forall a b. (a -> b) -> a -> b
$ String
"not part of conjunctive normal form: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Formula -> String
forall a. Show a => a -> String
show Formula
f
refute :: Set (Set Formula) -> Bool
refute :: Set (Set Formula) -> Bool
refute Set (Set Formula)
clauses
| Maybe (Set Formula)
Nothing <- Maybe (Set Formula)
resolved = Bool
False
| Just Set Formula
c <- Maybe (Set Formula)
resolved, Set Formula -> Bool
forall a. Set a -> Bool
Set.null Set Formula
c = Bool
True
| Just Set Formula
c <- Maybe (Set Formula)
resolved = Set (Set Formula) -> Bool
refute (Set (Set Formula) -> Bool) -> Set (Set Formula) -> Bool
forall a b. (a -> b) -> a -> b
$ Set Formula -> Set (Set Formula) -> Set (Set Formula)
forall a. Ord a => a -> Set a -> Set a
Set.insert Set Formula
c Set (Set Formula)
clauses
where resolved :: Maybe (Set Formula)
resolved = Set (Set Formula) -> [Match] -> Maybe (Set Formula)
resolve Set (Set Formula)
clauses ([Match] -> Maybe (Set Formula)) -> [Match] -> Maybe (Set Formula)
forall a b. (a -> b) -> a -> b
$ Set (Set Formula) -> [Match]
matches Set (Set Formula)
clauses
type Match = ((Formula, Set Formula), (Formula, Set Formula))
matches :: Set (Set Formula) -> [Match]
matches :: Set (Set Formula) -> [Match]
matches Set (Set Formula)
clauses = do
let clauseList :: [Set Formula]
clauseList = Set (Set Formula) -> [Set Formula]
forall a. Set a -> [a]
Set.toList Set (Set Formula)
clauses
Set Formula
clause <- [Set Formula]
clauseList
Set Formula
clause' <- [Set Formula]
clauseList
Formula
x <- Set Formula -> [Formula]
forall a. Set a -> [a]
Set.toList Set Formula
clause
let x' :: Formula
x' = Formula -> Formula
complement Formula
x
Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Formula -> Set Formula -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member Formula
x' Set Formula
clause'
Match -> [Match]
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return ((Formula
x, Set Formula
clause), (Formula
x', Set Formula
clause'))
resolve :: Set (Set Formula) -> [Match] -> Maybe (Set Formula)
resolve :: Set (Set Formula) -> [Match] -> Maybe (Set Formula)
resolve Set (Set Formula)
clauses [Match]
matchings
| [] <- [Match]
ms = Maybe (Set Formula)
forall a. Maybe a
Nothing
| (Match
m:[Match]
_) <- [Match]
ms = Set Formula -> Maybe (Set Formula)
forall a. a -> Maybe a
Just (Set Formula -> Maybe (Set Formula))
-> Set Formula -> Maybe (Set Formula)
forall a b. (a -> b) -> a -> b
$ Match -> Set Formula
forall {a}. Ord a => ((a, Set a), (a, Set a)) -> Set a
merge Match
m
where ms :: [Match]
ms = (Match -> Bool) -> [Match] -> [Match]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Match -> Bool
ignored [Match]
matchings
merge :: ((a, Set a), (a, Set a)) -> Set a
merge ((a
v, Set a
c), (a
v', Set a
c')) = a -> Set a -> Set a
forall a. Ord a => a -> Set a -> Set a
Set.delete a
v (Set a -> Set a) -> Set a -> Set a
forall a b. (a -> b) -> a -> b
$ a -> Set a -> Set a
forall a. Ord a => a -> Set a -> Set a
Set.delete a
v' (Set a -> Set a) -> Set a -> Set a
forall a b. (a -> b) -> a -> b
$ Set a
c Set a -> Set a -> Set a
forall a. Ord a => Set a -> Set a -> Set a
`Set.union` Set a
c'
ignored :: Match -> Bool
ignored Match
m = let c :: Set Formula
c = Match -> Set Formula
forall {a}. Ord a => ((a, Set a), (a, Set a)) -> Set a
merge Match
m
in Set Formula
c Set Formula -> Set (Set Formula) -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set (Set Formula)
clauses Bool -> Bool -> Bool
|| Set Formula -> Bool
isTautology Set Formula
c
isTautology :: Set Formula -> Bool
isTautology :: Set Formula -> Bool
isTautology Set Formula
s = (Formula -> Bool) -> Set Formula -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Formula
x -> Formula -> Formula
complement Formula
x Formula -> Set Formula -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Formula
s) Set Formula
s
complement :: Formula -> Formula
complement :: Formula -> Formula
complement (Complement Formula
x) = Formula
x
complement Formula
x = Formula -> Formula
Complement Formula
x