module Elab.Eval.Formula where import qualified Data.Map.Strict as Map import qualified Data.Sequence as Seq import qualified Data.Set as Set import Data.Map.Strict (Map) import Data.Set (Set) import Syntax import {-# SOURCE #-} Elab.WiredIn (inot, ior, iand) toDnf :: Value -> Maybe Value toDnf = fmap (dnf2Val . normalise) . val2Dnf where val2Dnf (VNe _ _) = Nothing val2Dnf x = toDnf x where toDnf (VIAnd x y) = idist <$> toDnf (inot x) <*> toDnf (inot y) toDnf (VIOr x y) = ior <$> toDnf x <*> toDnf y toDnf (VINot x) = inot <$> toDnf x toDnf VI0 = pure VI0 toDnf VI1 = pure VI1 toDnf v@(VNe _ Seq.Empty) = pure v toDnf _ = Nothing dnf2Val xs = Set.foldl ior VI0 (Set.map (Set.foldl iand VI1) xs) type Nf = Set (Set Value) normalise :: Value -> Nf normalise = normaliseOr where normaliseOr (VIOr x y) = Set.singleton (normaliseAnd x) <> normaliseOr y normaliseOr x = Set.singleton (normaliseAnd x) normaliseAnd (VIAnd x y) = Set.insert x (normaliseAnd y) normaliseAnd x = Set.singleton x compareDNFs :: Value -> Value -> Bool compareDNFs (VIOr x y) (VIOr x' y') = let (a, a') = swap x y (b, b') = swap x' y' in compareDNFs a b && compareDNFs a' b' compareDNFs (VIAnd x y) (VIAnd x' y') = let (a, a') = swap x x' (b, b') = swap y y' in compareDNFs a a' && compareDNFs b b' compareDNFs x y = x == y swap :: Ord b => b -> b -> (b, b) swap x y = if x <= y then (x, y) else (y, x) possible :: Map Head Bool -> Value -> (Bool, Map Head Bool) possible sc (VINot (VNe n Seq.Empty)) = case Map.lookup n sc of Just True -> (False, sc) _ -> (True, Map.insert n False sc) possible sc (VNe n Seq.Empty) = case Map.lookup n sc of Just False -> (False, sc) _ -> (True, Map.insert n True sc) possible sc (VIAnd x y) = let (a, sc') = possible sc x (b, sc'') = possible sc' y in (a && b, sc'') possible sc (VIOr x y) = case possible sc x of (True, sc') -> (True, sc') (False, _) -> possible sc y possible sc VI0 = (False, sc) possible sc VI1 = (True, sc) possible sc _ = (False, sc) truthAssignments :: NFEndp -> Map Name (NFType, NFEndp) -> [Map Name (NFType, NFEndp)] truthAssignments VI0 _ = [] truthAssignments VI1 m = pure m truthAssignments (VIOr x y) m = truthAssignments x m ++ truthAssignments y m truthAssignments (VIAnd x y) m = truthAssignments x =<< truthAssignments y m truthAssignments (VNe (HVar x) Seq.Empty) m = pure (Map.insert x (VI, VI1) m) truthAssignments (VINot (VNe (HVar x) Seq.Empty)) m = pure (Map.insert x (VI, VI0) m) truthAssignments _ m = pure m idist :: Value -> Value -> Value idist (VIOr x y) z = (x `idist` z) `ior` (y `idist` z) idist z (VIOr x y) = (z `idist` x) `ior` (z `idist` y) idist z x = iand z x