packages feed

smcdel-1.3.0: test/CUDD.hs

{-# LANGUAGE AllowAmbiguousTypes, FlexibleContexts, TypeApplications, ScopedTypeVariables #-}

module Main (main) where

import qualified Data.HasCacBDD
import Data.List (sort)
import Data.Maybe (isJust)
import Test.Hspec
import Test.QuickCheck

import SMCDEL.Internal.Help (alleq)
import SMCDEL.Internal.MyHaskCUDD
import SMCDEL.Language
import qualified Data.Map.Strict as M
import qualified SMCDEL.Internal.MyHaskCUDD as MyHaskCUDD
import qualified SMCDEL.Symbolic.K as K
import qualified SMCDEL.Symbolic.K_CUDD as K_CUDD
import qualified SMCDEL.Symbolic.Ki_CUDD as Ki_CUDD
import qualified SMCDEL.Symbolic.S5 as S5
import qualified SMCDEL.Symbolic.S5_CUDD as S5_CUDD

main :: IO ()
main = do
  hspec $ do
    describe "SMCDEL.Internal.MyHaskCUDD using BDDs" $ do
      before MyHaskCUDD.makeManager $ do
        it "gfp (\b -> con b (var 3)) == var 3" $
          \mgr -> MyHaskCUDD.gfp mgr (\b -> MyHaskCUDD.con mgr b (MyHaskCUDD.var mgr 3)) `shouldBe` (MyHaskCUDD.var mgr 3 :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
        it "exists_ 1 (neg $ var 1) == top" $ \mgr -> MyHaskCUDD.exists_ mgr 1 (MyHaskCUDD.neg mgr $ MyHaskCUDD.var mgr 1) `shouldBe` (MyHaskCUDD.top mgr :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
        it "exists_ 1 (neg $ var 2) /= top" $ \mgr -> MyHaskCUDD.exists_ mgr 1 (MyHaskCUDD.neg mgr $ MyHaskCUDD.var mgr 2) `shouldNotBe` (MyHaskCUDD.top mgr :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
        it "forall_ 1 (neg $ var 1) == bot" $ \mgr -> MyHaskCUDD.forall_ mgr 1 (MyHaskCUDD.neg mgr $ MyHaskCUDD.var mgr 1) `shouldBe` (MyHaskCUDD.bot mgr :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
        it "forall_ 1 (neg $ var 2) /= bot" $ \mgr -> MyHaskCUDD.forall_ mgr 1 (MyHaskCUDD.neg mgr $ MyHaskCUDD.var mgr 2) `shouldNotBe` (MyHaskCUDD.bot mgr :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
    describe "SMCDEL.Symbolic.S5_CUDD using BDDs agrees with HasCacBdd" $ do
      before MyHaskCUDD.makeManager $ do
        it "HasCacBDD and CUDD give same allSats" $
          \mgr -> property $ \(BF bf) -> sort (Data.HasCacBDD.allSats (S5.boolBddOf bf)) === sort (MyHaskCUDD.allSats mgr (S5_CUDD.boolDdOf mgr bf :: MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1))
        it "HasCacBDD and CUDD give same anySat" $
          \mgr -> property $ \(BF bf) -> Data.HasCacBDD.anySat (S5.boolBddOf bf) === MyHaskCUDD.anySat mgr (S5_CUDD.boolDdOf mgr bf ::  MyHaskCUDD.Dd MyHaskCUDD.B MyHaskCUDD.O1 MyHaskCUDD.I1)
    describe "CUDD / MyHaskCUDD" $ do
      before MyHaskCUDD.makeManager $
        describe "bddOnlyTests" bddOnlyTests
      before (MyHaskCUDD.makeManagerZ (length defaultVocabulary)) $ do
        describe "B O1 I1" $ cuddTests @B @O1 @I1
        describe "B O0 I1" $ cuddTests @B @O0 @I1
        describe "B O1 I0" $ cuddTests @B @O1 @I0
        describe "B O0 I0" $ cuddTests @B @O0 @I0
        describe "Z O1 I1" $ cuddTests @Z @O1 @I1
        describe "Z O0 I1" $ cuddTests @Z @O0 @I1
        describe "Z O1 I0" $ cuddTests @Z @O1 @I0
        describe "Z O0 I0" $ cuddTests @Z @O0 @I0
    describe "S5: hardcoded myKns and myKnScac" $ do
      before (MyHaskCUDD.makeManagerZ (length defaultVocabulary + 1)) $ do
        it "evalViaDd agrees for all variants" $ \mgr -> property (alleq . evalViaDdTest mgr)
        it "validViaDD agrees for all variants" $ \mgr -> property (alleq . validViaDdTest mgr)
    describe "K_CUDD: hardcoded myBlS and myBlScac" $ do
      before (MyHaskCUDD.makeManagerZ 15) $ do
        it "evalViaDd agrees for all variants" $ \mgr -> property (alleq . evalViaDdTestK mgr)
        it "validViaDD agrees for all variants" $ \mgr -> property (alleq . validViaDdTestK mgr)
    describe "Ki_CUDD: hardcoded myBlSKi" $ do
      before (MyHaskCUDD.makeManagerZ 20) $ do
        it "evalViaDd agrees for all variants" $ \mgr -> property (alleq . evalViaDdTestKi mgr)
        it "validVidaDD agrees for all variants" $ \mgr -> property (alleq . validViaDdTestKi mgr)

-- * CUDD / MyHaskCUDD

v :: [Int]
v = map fromEnum defaultVocabulary

cuddTests :: forall a b c . DdCtx a b c => SpecWith MyHaskCUDD.Manager
cuddTests = do
  describe "Basics" $ do
    it "bot == bot" $ \mgr -> (bot mgr :: Dd a b c) `shouldBe` (bot mgr :: Dd a b c)
    it "top == top" $ \mgr -> (top mgr :: Dd a b c) `shouldBe` (top mgr :: Dd a b c)
    it "top /= bot" $ \mgr -> (top mgr :: Dd a b c) `shouldNotBe` (bot mgr :: Dd a b c)
    it "bot /= top" $ \mgr -> (bot mgr :: Dd a b c) `shouldNotBe` (top mgr :: Dd a b c)
    it "neg bot == top" $ \mgr -> neg mgr (bot mgr) `shouldBe` (top mgr :: Dd a b c)
    it "neg bot /= bot" $ \mgr -> neg mgr (bot mgr) `shouldNotBe` (bot mgr :: Dd a b c)
    it "var 1 == var 1" $ \mgr -> (var mgr 1 :: Dd a b c) `shouldBe` var mgr 1
    it "var 3 /= var 2" $ \mgr -> (var mgr 3 :: Dd a b c) `shouldNotBe` var mgr 2
    it "var 1 /= var 2" $ \mgr -> (var mgr 1 :: Dd a b c) `shouldNotBe` var mgr 2
    it "var 3 == con (var 3) top" $ \mgr ->
      var mgr 3 `shouldBe` con mgr (var mgr 3) (top mgr :: Dd a b c)
    it "var 4 /= con (var 3) top" $ \mgr ->
      var mgr 4 `shouldNotBe` con mgr (var mgr 3) (top mgr :: Dd a b c)
    it "equ (var 1) (var 1) == top" $ \mgr ->
      equ mgr (var mgr 1) (var mgr 1) `shouldBe` (top mgr :: Dd a b c)
    it "exists_ 1 (neg $ var 1) == top" $ \mgr ->
      exists_ mgr 1 (neg mgr $ var mgr 1) `shouldBe` (top mgr :: Dd a b c)
    it "exists_ 1 (neg $ var 2) /= top" $ \mgr ->
      exists_ mgr 1 (neg mgr $ var mgr 2) `shouldNotBe` (top mgr :: Dd a b c)
    it "gfp (\b -> con b (var 3)) == var 3" $ \mgr ->
      gfp mgr (\b -> con mgr b (var mgr 3)) `shouldBe` (var mgr 3 :: Dd a b c)
    it "imp (conSet [var 1,var 0]) (var 1) == top" $ \mgr ->
      imp mgr (conSet mgr [var mgr 1,var mgr 0]) (var mgr 1) `shouldBe` (top mgr :: Dd a b c)
    it "imp (conSet [var 0,var 1]) (var 0) == top" $ \mgr ->
      imp mgr (conSet mgr [var mgr 0,var mgr 1]) (var mgr 0) `shouldBe` (top mgr :: Dd a b c)
    it "imp (con (var 0) (var 1)) (var 0) == top" $ \mgr ->
      imp mgr (con mgr (var mgr 0) (var mgr 1)) (var mgr 0) `shouldBe` (top mgr :: Dd a b c)
  describe "DD manipulation" $ do
    it "substitSimul" $ \mgr ->
      substitSimul mgr [(3, var mgr 4),(4, var mgr 5)] (imp mgr (var mgr 3) (var mgr 4 :: Dd a b c))
      `shouldBe`
      imp mgr (var mgr 4) (var mgr 5)
  describe "utility functions" $ do
    it "show (var 3) /= show (var 2)" $ \mgr ->
      show (var mgr 3 :: Dd a b c) `shouldNotBe` show (var mgr 2 :: Dd a b c)
    it "show (var 2) == show (var 2)" $ \mgr ->
      show (var mgr 2 :: Dd a b c) `shouldBe` show (var mgr 2 :: Dd a b c)
    it "size top is 0, 1 or 7" $ \mgr ->
      size mgr (top mgr :: Dd a b c) `elem` [0,1,7]
    it "size bot is 0, 1 or 7" $ \mgr ->
      size mgr (bot mgr :: Dd a b c) `elem` [0,1,7]
    it "size (var 2) is 2, 6 or 8" $ \mgr ->
      size mgr (var mgr 2 :: Dd a b c) `elem` [2,6,8]
    it "getDependentVars" $ \mgr ->
      getDependentVars mgr v (var mgr 2 :: Dd a b c) `shouldBe` [2]
    it "getSupport" $ \mgr ->
      getSupport mgr (var mgr 2 :: Dd a b c) `shouldSatisfy` flip elem [ [], [2] ] -- TODO: is this correct?
  describe "random tests" $ do
    it "forall_ exists_" $ \mgr ->
      property (\(BF f) -> let (b :: Dd a b c) = S5_CUDD.boolDdOf mgr f
                           in forAll (elements [0..5]) (\n -> forall_ mgr n b == neg mgr (exists_ mgr n (neg mgr b))))
    it "restrictLaw" $ \mgr ->
      property (\(BF f) (BF g) -> let (a :: Dd a b c, b :: Dd a b c) = (S5_CUDD.boolDdOf mgr f, S5_CUDD.boolDdOf mgr g)
                                  in imp mgr b (equ mgr (restrictLaw mgr v a b) a) == (top mgr :: Dd a b c))

bddOnlyTests :: SpecWith MyHaskCUDD.Manager
bddOnlyTests = do
  it "allSats top `==` [[]]" $ \mgr -> allSats mgr (top mgr :: Dd B O1 I1) `shouldBe` [[]]
  it "anySat iff not bot" $ \mgr ->
    property (\(BF f) -> let (b :: Dd B O1 I1) = S5_CUDD.boolDdOf mgr f
                           in (b /= bot mgr) === isJust (anySat mgr b))
  it "length allSats > 0 iff not bot" $ \mgr ->
    property (\(BF f) -> let (b :: Dd B O1 I1) = S5_CUDD.boolDdOf mgr f
                           in (b /= bot mgr) ==> (length $! allSats mgr b) > 0)
  it "allSatsWith" $ \mgr ->
    property (\(BF f) -> let (b :: Dd B O1 I1) = S5_CUDD.boolDdOf mgr f
                           in all (\s -> restrictSet mgr b s == top mgr) (allSatsWith mgr (map fromEnum defaultVocabulary) b))

-- * S5_CUDD

myKnS :: (DdCtx a b c) => MyHaskCUDD.Manager -> S5_CUDD.KnowStruct a b c
myKnS mgr = S5_CUDD.KnS mgr defaultVocabulary (S5_CUDD.boolDdOf mgr Top) myDefaultObservables

myKnScac :: S5.KnowStruct
myKnScac = S5.KnS defaultVocabulary (S5.boolBddOf Top) myDefaultObservables

myDefaultObservables :: [(Agent,[Prp])]
myDefaultObservables = [("1", [P 1 .. P 4]), ("2", [P 1, P 2]), ("3", []), ("4", [P 1]), ("5", [])]

evalViaDdTest :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
evalViaDdTest mgr (SF f) =
  [ S5.evalViaBdd (myKnScac, defaultVocabulary) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene B O1 I1) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene B O1 I0) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene B O0 I1) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene B O0 I0) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene Z O1 I1) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene Z O1 I0) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene Z O0 I1) f
  , S5_CUDD.evalViaDd ((myKnS mgr, defaultVocabulary) :: S5_CUDD.KnowScene Z O0 I0) f
  ]

validViaDdTest :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
validViaDdTest mgr (SF f) =
  [ S5.validViaBdd myKnScac f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct B O1 I1) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct B O1 I0) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct B O0 I1) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct B O0 I0) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct Z O1 I1) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct Z O1 I0) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct Z O0 I1) f
  , S5_CUDD.validViaDd (myKnS mgr :: S5_CUDD.KnowStruct Z O0 I0) f
  ]

-- * K_CUDD

myBlS :: (DdCtx a b c) => MyHaskCUDD.Manager -> K_CUDD.BelStruct a b c
myBlS mgr = K_CUDD.BlS mgr defaultVocabulary (S5_CUDD.boolDdOf mgr Top) (myObsLaws (pure . S5_CUDD.boolDdOf mgr))

myBlScac :: K.BelStruct
myBlScac = K.BlS defaultVocabulary (S5.boolBddOf Top) (myObsLaws (pure . S5.boolBddOf))

myObsLaws :: (Form -> dd) -> M.Map Agent dd
myObsLaws formToDd = M.fromList
  [ ("1", formToDd $ Conj (zipWith Equi (map PrpF [P 2, P 4, P 6, P 8]) (map PrpF [P 3, P 5, P 7, P 9])))
  , ("2", formToDd $ Conj (zipWith Equi (map PrpF [P 2, P 4]) (map PrpF [P 3, P 5])))
  , ("3", formToDd Top)
  , ("4", formToDd $ PrpF $ P 1)
  , ("5", formToDd Bot) ]

evalViaDdTestK :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
evalViaDdTestK mgr (SF f) =
  [ K.evalViaBdd (myBlScac, defaultVocabulary) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene B O1 I1) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene B O1 I0) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene B O0 I1) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene B O0 I0) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene Z O1 I1) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene Z O1 I0) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene Z O0 I1) f
  , K_CUDD.evalViaDd ((myBlS mgr, defaultVocabulary) :: K_CUDD.BelScene Z O0 I0) f
  ]

validViaDdTestK :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
validViaDdTestK mgr (SF f) =
  [ K.validViaBdd myBlScac f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct B O1 I1) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct B O1 I0) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct B O0 I1) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct B O0 I0) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct Z O1 I1) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct Z O1 I0) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct Z O0 I1) f
  , K_CUDD.validViaDd (myBlS mgr :: K_CUDD.BelStruct Z O0 I0) f
  ]

-- * Ki_CUDD

myBlSKi :: (DdCtx a b c) => MyHaskCUDD.Manager -> Ki_CUDD.BelStruct a b c
myBlSKi mgr = Ki_CUDD.BlS mgr defaultVocabulary (S5_CUDD.boolDdOf mgr Top) myObs where
  myObs :: (DdCtx a b c) => (M.Map Agent Int, Ki_CUDD.RelDD a b c)
  myObs = (M.fromList [("1", 0), ("2", 1), ("3", 2), ("4", 3), ("5", 4)], pure $ S5_CUDD.boolDdOf mgr $ Conj
    [ Impl (PrpF $ P 0) (Conj (zipWith Equi (map PrpF [P 5, P 7, P 9, P 11]) (map PrpF [P 6, P 8, P 10, P 12])))
    , Impl (PrpF $ P 1) (Conj (zipWith Equi (map PrpF [P 5, P 7]) (map PrpF [P 6, P 8])))
    , Impl (PrpF $ P 2) Bot
    , Impl (PrpF $ P 3) (PrpF $ P 5)
    , Impl (PrpF $ P 4) Top
    ])

evalViaDdTestKi :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
evalViaDdTestKi mgr (SF f) =
  [ Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene B O1 I1) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene B O1 I0) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene B O0 I1) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene B O0 I0) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene Z O1 I1) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene Z O1 I0) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene Z O0 I1) f
  , Ki_CUDD.evalViaDd ((myBlSKi mgr, defaultVocabulary) :: Ki_CUDD.BelScene Z O0 I0) f
  ]

validViaDdTestKi :: MyHaskCUDD.Manager -> SimplifiedForm -> [Bool]
validViaDdTestKi mgr (SF f) =
  [ Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct B O1 I1) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct B O1 I0) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct B O0 I1) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct B O0 I0) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct Z O1 I1) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct Z O1 I0) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct Z O0 I1) f
  , Ki_CUDD.validViaDd (myBlSKi mgr :: Ki_CUDD.BelStruct Z O0 I0) f
  ]