module Systems where import qualified Data.Map.Strict as Map import qualified Data.Set as Set import Data.Map.Strict (Map) import Data.Set (Set) import Data.List import Presyntax newtype Face = Face { getFace :: Map String Bool } deriving (Eq, Show, Ord) evalFormula :: Formula -> Face -> Bool evalFormula (Is0 x) f = case Map.lookup x (getFace f) of Just x -> not x Nothing -> error $ "dimension not bound in formula: " ++ show x evalFormula (Is1 x) f = case Map.lookup x (getFace f) of Just x -> x Nothing -> error $ "dimension not bound in formula: " ++ show x evalFormula (And a b) f = evalFormula a f && evalFormula b f evalFormula (Or a b) f = evalFormula a f || evalFormula b f evalFormula Top _ = True evalFormula Bot _ = False freeVarsFormula :: Formula -> Set String freeVarsFormula (Is0 x) = Set.singleton x freeVarsFormula (Is1 x) = Set.singleton x freeVarsFormula (And a b) = Set.union (freeVarsFormula a) (freeVarsFormula b) freeVarsFormula (Or a b) = Set.union (freeVarsFormula a) (freeVarsFormula b) freeVarsFormula Top = mempty freeVarsFormula Bot = mempty faces :: Formula -> ([Face], [Face]) faces formula = partition (evalFormula formula) allPossible where truths [] = [mempty] truths (x:xs) = uncurry Map.insert <$> [(x, True), (x, False)] <*> truths xs allPossible = Face <$> truths (Set.toList (freeVarsFormula formula)) impossible, possible, tautological :: Formula -> Bool impossible = null . fst . faces possible = not . null . fst . faces tautological = not . null . snd . faces toDNF :: Formula -> Formula toDNF = orFormula . map formulaOfFace . fst . faces formulaOfFace :: Face -> Formula formulaOfFace = andFormula . map (\(x, i) -> if i then Is1 x else Is0 x) . Map.toDescList . getFace andFormula :: [Formula] -> Formula andFormula = foldr and Top where and x y = case x of Top -> case y of Bot -> Bot _ -> y Bot -> Bot _ -> case y of Top -> x _ -> And x y orFormula :: [Formula] -> Formula orFormula [] = Bot orFormula (x:xs) = or x (orFormula xs) where or x y = case x of Top -> Top Bot -> case y of Top -> Top _ -> y _ -> case y of Bot -> x _ -> Or x y notFormula :: Formula -> Formula notFormula Top = Bot notFormula Bot = Top notFormula (Is0 x) = Is1 x notFormula (Is1 x) = Is0 x notFormula (And x y) = Or (notFormula x) (notFormula y) notFormula (Or x y) = And (notFormula x) (notFormula y) newtype System a = FMap { getSystem :: Map Formula a } deriving (Eq, Show, Ord) emptySystem :: System a emptySystem = FMap mempty mapSystem :: System a -> (a -> b) -> System b mapSystem (FMap x) f = FMap (Map.filterWithKey (\f _ -> f /= Bot) (fmap f x))