packages feed

heyting-algebras-0.2.0.1: test/Main.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE PackageImports             #-}

{-# OPTIONS_GHC -Wno-orphans #-}

module Main where

import           Data.Universe.Class (Universe (..), Finite)
import           Data.Set (Set)
import qualified Data.Set as Set
import           Data.Map (Map)
import qualified Data.Map as Map

import           Algebra.Lattice ( BoundedJoinSemiLattice
                                 , BoundedMeetSemiLattice
                                 , Lattice (..)
                                 , Meet (..)
                                 , bottom
                                 , top
                                 )
import           Algebra.Lattice.Dropped (Dropped (..))
import           Algebra.Lattice.Lifted (Lifted (..))
import           Algebra.Lattice.Levitated (Levitated)
import qualified Algebra.Lattice.Levitated as L
import           Algebra.Lattice.Op (Op (..))
import           Algebra.Lattice.Ordered (Ordered (..))

import           Algebra.Boolean
import           Algebra.Boolean.Properties
import           Algebra.Heyting
import           Algebra.Heyting.CounterExample
import           Algebra.Heyting.Properties
import           Algebra.Heyting.Layered
import           Algebra.PartialOrd (leq)

import           Test.Tasty
import           Test.Tasty.QuickCheck hiding (Ordered, (==>))

main :: IO ()
main = defaultMain tests

counterExampleProperty
  :: Show e
  => CounterExample e
  -> Property
counterExampleProperty = maybe (property True) (flip counterexample False) . fromCounterExample'

--
-- Orphan instances
-- issue: https://github.com/haskellari/lattices/pull/112
--

instance Heyting a => Heyting (Lifted a) where
  (Lift a) ==> (Lift b) = Lift (a ==> b)
  Bottom   ==> _        = Lift top
  _        ==> Bottom   = Bottom

instance (Eq a, Heyting a) => Heyting (Dropped a) where
  (Drop a) ==> (Drop b) | Meet a `leq` Meet b = Top
                        | otherwise           = Drop (a ==> b)
  Top      ==> a        = a
  _        ==> Top      = Top

instance Boolean a => Heyting (Op a) where
  (Op a) ==> (Op b) = Op (neg a /\ b)

instance (Eq a, Heyting a) => Heyting (Levitated a) where
  (L.Levitate a) ==> (L.Levitate b) | Meet a `leq` Meet b = L.Top
                                    | otherwise           = L.Levitate (a ==> b)
  L.Top          ==> a              = a
  _              ==> L.Top          = L.Top
  L.Bottom       ==> _              = L.Top
  _              ==> L.Bottom       = L.Bottom

-- 
-- List of tast cases
--

tests :: TestTree
tests =
  testGroup "heyting-algebras tests"
    [ testGroup "Boolean algebras"
        [ testProperty "Bool"                                         prop_boolean_Bool
        , testProperty "Boolean (Lifted Bool)"                        prop_boolean_LiftedBool
        , testProperty "Boolean (Dropped Bool)"                       prop_boolean_DroppedBool
        , testProperty "(Set S5)"                                     prop_boolean_Set
        ]
    , testGroup "Non Boolean algebras"
        [ testProperty "Not a BooleanAlgebra (Lifted Bool)"           prop_non_boolean_LiftedBool
        , testProperty "Not a BooleanAlgebra (Dropped Bool)"          prop_non_boolean_DroppedBool
        , testProperty "Not a BooleanAlgebra Levitated (Ordered Int)" prop_non_boolean_LevitatedOrderedInt
        ]
    , testGroup "Heyting algebras"
        [ testProperty "Lifted Bool"                                  prop_heyting_LiftedBool
        , testProperty "Dropped Bool"                                 prop_heyting_DroppedBool
        , testProperty "Layered Bool Bool"                            prop_heyting_LayeredBoolBool
        , testProperty "Levitated Bool"                               prop_heyting_LevitatedBool
        , testProperty "Sum (Lifted Bool) (Dropped Bool)"             prop_heyting_LayeredLiftedDropped
        , testProperty "Levitated (Ordered Int)"                      prop_heyting_LevitatedOrderedInt
        , testProperty "Dropped (Lifted Bool)"                        prop_heyting_DroppedLiftedBool
        , testProperty "Lifted (Dropped Bool)"                        prop_heyting_LiftedDroppedBool
        , testProperty "Lifted (Lifted Bool)"                         prop_heyting_LiftedLiftedBool
        , testProperty "Dropped (Dropped Bool)"                       prop_heyting_DroppedDroppedBool
        ]
    ]

--
-- Boolean algebra tests
--

type BooleanProp a = a -> a -> a -> Property

prop_boolean_Bool
  :: BooleanProp Bool
prop_boolean_Bool =
  (fmap . fmap) counterExampleProperty . prop_BooleanAlgebra

prop_boolean_LiftedBool
  :: BooleanProp (Arb (BooleanAlgebra (Arb (Lifted Bool))))
prop_boolean_LiftedBool =
  (fmap . fmap) counterExampleProperty . prop_BooleanAlgebra

prop_boolean_DroppedBool
  :: BooleanProp (Arb (BooleanAlgebra (Arb (Dropped Bool))))
prop_boolean_DroppedBool =
  (fmap . fmap) counterExampleProperty . prop_BooleanAlgebra

prop_boolean_Set
  :: BooleanProp (Arb (Set S5))
prop_boolean_Set =
  (fmap . fmap) counterExampleProperty . prop_BooleanAlgebra

--
-- Non Boolean algebra tests
--

type NonBooleanProp a = a -> Property

prop_non_boolean_LiftedBool
  :: NonBooleanProp (Arb (Lifted Bool))
prop_non_boolean_LiftedBool =
    expectFailure
  . counterExampleProperty @String
  . prop_neg

prop_non_boolean_DroppedBool
  :: NonBooleanProp (Arb (Dropped Bool))
prop_non_boolean_DroppedBool =
    expectFailure
  . counterExampleProperty @String
  . prop_neg

prop_non_boolean_LevitatedOrderedInt
  :: NonBooleanProp (Arb (Levitated (Arb (Ordered Int))))
prop_non_boolean_LevitatedOrderedInt =
    expectFailure
  . counterExampleProperty @String
  . prop_neg

--
-- Heyting algebra tests
--

type HeytingProp a = a -> a -> a -> Property

prop_heyting_LiftedBool
  :: HeytingProp (Arb (Lifted Bool))
prop_heyting_LiftedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_DroppedBool
  :: HeytingProp (Arb (Dropped Bool))
prop_heyting_DroppedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LayeredBoolBool
  :: HeytingProp (Arb (Layered Bool Bool))
prop_heyting_LayeredBoolBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LevitatedBool
  :: HeytingProp (Arb (Levitated Bool))
prop_heyting_LevitatedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LayeredLiftedDropped
  :: HeytingProp (Arb (Layered (Arb (Lifted Bool)) (Arb (Dropped Bool))))
prop_heyting_LayeredLiftedDropped =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LevitatedOrderedInt
  :: HeytingProp (Arb (Levitated (Arb (Ordered Int))))
prop_heyting_LevitatedOrderedInt =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_DroppedLiftedBool
  :: HeytingProp (Composed Dropped Lifted Bool)
prop_heyting_DroppedLiftedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LiftedDroppedBool
  :: HeytingProp (Composed Lifted Dropped Bool)
prop_heyting_LiftedDroppedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_LiftedLiftedBool
  :: HeytingProp (Composed Lifted Lifted Bool)
prop_heyting_LiftedLiftedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra

prop_heyting_DroppedDroppedBool
  :: HeytingProp (Composed Dropped Dropped Bool)
prop_heyting_DroppedDroppedBool =
  (fmap . fmap) counterExampleProperty . prop_HeytingAlgebra


-- | Arbitrary wrapper for varous lattices.
--
newtype Arb a = Arb a
  deriving ( BoundedJoinSemiLattice
           , BoundedMeetSemiLattice
           , Lattice
           , Boolean
           , Heyting
           , Eq
           , Ord
           )

instance Show a => Show (Arb a) where
  show (Arb a) = show a

instance (Finite k, Arbitrary k, Arbitrary v, Ord k) => Arbitrary (Arb (Map k v)) where
  arbitrary = frequency 
    [ (1, return $ Arb Map.empty)
    , (1, Arb . Map.fromList . zip universe <$> vectorOf (length (universe @k)) arbitrary)
    , (8, Arb . Map.fromList <$> arbitrary)
    ]

instance Arbitrary a => Arbitrary (Arb (Lifted a)) where
  arbitrary = Arb . maybe Bottom Lift <$> arbitrary
  shrink (Arb Bottom)   = []
  shrink (Arb (Lift a)) =
    Arb Bottom : (Arb . Lift <$> shrink a)

instance Arbitrary a => Arbitrary (Arb (Dropped a)) where
  arbitrary = Arb . maybe Top Drop <$> arbitrary
  shrink (Arb Top)   = []
  shrink (Arb (Drop a)) =
    Arb Top : (Arb . Drop <$> shrink a)

instance Arbitrary a => Arbitrary (Arb (Levitated a)) where
  arbitrary = frequency
    [ (1, return $ Arb L.Top)
    , (1, return $ Arb L.Bottom)
    , (2, Arb . L.Levitate <$> arbitrary)
    ]

  shrink (Arb L.Bottom) = []
  shrink (Arb (L.Levitate a))
    = Arb L.Bottom
    : Arb L.Top
    : [ Arb (L.Levitate a') | a' <- shrink a ]
  shrink (Arb L.Top) = []

instance (Arbitrary a, Heyting a, Eq a) => Arbitrary (Arb (BooleanAlgebra a)) where
  arbitrary = Arb . boolean <$> arbitrary
  shrink (Arb a) = filter (/= Arb a) (Arb . boolean <$> shrink (runBooleanAlgebra a))

 
instance Arbitrary a => Arbitrary (Arb (Ordered a)) where
  arbitrary = Arb . Ordered <$> arbitrary
  shrink (Arb (Ordered a)) = Arb . Ordered <$> shrink a

data S5 = S1 | S2 | S3 | S4 | S5
  deriving (Ord, Eq, Show)

instance Universe S5 where
  universe = [S1, S2, S3, S4, S5]

instance Finite S5

instance Arbitrary S5 where
  arbitrary = elements universe

instance (Arbitrary a, Ord a) => Arbitrary (Arb (Set a)) where
  arbitrary       = Arb . Set.fromList <$> arbitrary
  shrink (Arb as) = [ Arb (Set.fromList as') | as' <- shrink (Set.toList as) ]

instance (Arbitrary a, Arbitrary b) => Arbitrary (Arb (Layered a b)) where
  arbitrary = oneof
    [ Arb . Lower <$> arbitrary
    , Arb . Upper <$> arbitrary
    ]
  shrink (Arb (Lower a)) = Arb . Lower <$> shrink a
  shrink (Arb (Upper b)) = Arb . Upper <$> shrink b

-- | Arbitrary newtype wrapper for compositions of heigher kinded types.
--
newtype Composed f g a = Composed (f (g a))
  deriving ( BoundedJoinSemiLattice
           , BoundedMeetSemiLattice
           , Lattice
           , Boolean
           , Heyting
           , Eq
           , Ord
           )

instance Show (f (g a)) => Show (Composed f g a) where
  show (Composed fga) = show fga

instance Arbitrary a => Arbitrary (Composed Dropped Lifted a) where
  arbitrary = frequency
    [ (1, return $ Composed Top)
    , (1, return $ Composed (Drop Bottom))
    , (8, Composed . Drop . Lift  <$> arbitrary)
    ]

  shrink (Composed Top)             = []
  shrink (Composed (Drop Bottom))   = [Composed Top]
  shrink (Composed (Drop (Lift a))) =
       [ Composed (Drop Bottom) ]
    ++ [ Composed (Drop (Lift a')) | a' <- shrink a ]

instance Arbitrary a => Arbitrary (Composed Lifted Dropped a) where
  arbitrary = frequency
    [ (1, return $ Composed Bottom)
    , (1, return $ Composed (Lift Top))
    , (8, Composed . Lift . Drop  <$> arbitrary)
    ]

instance Arbitrary a => Arbitrary (Composed Lifted Lifted a) where
  arbitrary = frequency
    [ (1, return $ Composed Bottom)
    , (1, return $ Composed (Lift Bottom))
    , (8, Composed . Lift . Lift  <$> arbitrary)
    ]

  shrink (Composed Bottom)          = []
  shrink (Composed (Lift Bottom))   = [Composed Bottom]
  shrink (Composed (Lift (Lift a))) =
       [ Composed (Lift Bottom) ]
    ++ [ Composed (Lift (Lift a')) | a' <- shrink a ]

instance Arbitrary a => Arbitrary (Composed Dropped Dropped a) where
  arbitrary = frequency
    [ (1, return $ Composed Top)
    , (1, return $ Composed (Drop Top))
    , (8, Composed . Drop . Drop  <$> arbitrary)
    ]

  shrink (Composed Top)          = []
  shrink (Composed (Drop Top))   = [Composed Top]
  shrink (Composed (Drop (Drop a))) =
       [ Composed Top, Composed (Drop Top) ]
    ++ [ Composed (Drop (Drop a')) | a' <- shrink a ]

instance Arbitrary a => Arbitrary (Composed Lifted Op a) where
  arbitrary = frequency
    [ (1, return (Composed Bottom))
    , (9, Composed . Lift . Op <$> arbitrary)
    ]