packages feed

data-interval-1.2.0: test/TestIntegerInterval.hs

{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
import Control.Monad
import Data.Maybe
import Data.Ratio
import Test.HUnit hiding (Test)
import Test.QuickCheck
import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.TH
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2

import Data.IntegerInterval
  ( IntegerInterval, Extended (..), (<=..<=), (<=..<), (<..<=), (<..<)
  , (<!), (<=!), (==!), (>=!), (>!), (/=!)
  , (<?), (<=?), (==?), (>=?), (>?), (/=?)
  , (<??), (<=??), (==??), (>=??), (>??), (/=??)
  )
import qualified Data.IntegerInterval as IntegerInterval
import Data.Interval (Interval)
import qualified Data.Interval as Interval

{--------------------------------------------------------------------
  empty
--------------------------------------------------------------------}

prop_empty_is_bottom =
  forAll integerIntervals $ \a ->
    IntegerInterval.isSubsetOf IntegerInterval.empty a

prop_null_empty =
  forAll integerIntervals $ \a ->
    IntegerInterval.null a == (a == IntegerInterval.empty)

case_null_empty =
  IntegerInterval.null (IntegerInterval.empty :: IntegerInterval) @?= True

{--------------------------------------------------------------------
  whole
--------------------------------------------------------------------}

prop_whole_is_top =
  forAll integerIntervals $ \a ->
    IntegerInterval.isSubsetOf a IntegerInterval.whole

case_nonnull_top =
  IntegerInterval.null (IntegerInterval.whole :: IntegerInterval) @?= False

{--------------------------------------------------------------------
  singleton
--------------------------------------------------------------------}

prop_singleton_member =
  forAll arbitrary $ \r ->
    IntegerInterval.member (r::Integer) (IntegerInterval.singleton r)

prop_singleton_member_intersection =
  forAll integerIntervals $ \a ->
  forAll arbitrary $ \r ->
    let b = IntegerInterval.singleton r
    in IntegerInterval.member (r::Integer) a
       ==> IntegerInterval.intersection a b == b

prop_singleton_nonnull =
  forAll arbitrary $ \r1 ->
    not $ IntegerInterval.null $ IntegerInterval.singleton (r1::Integer)

prop_distinct_singleton_intersection =
  forAll arbitrary $ \r1 ->
  forAll arbitrary $ \r2 ->
    (r1::Integer) /= r2 ==>
      IntegerInterval.intersection (IntegerInterval.singleton r1) (IntegerInterval.singleton r2)
      == IntegerInterval.empty

{--------------------------------------------------------------------
  Intersection
--------------------------------------------------------------------}

prop_intersection_comm =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.intersection a b == IntegerInterval.intersection b a

prop_intersection_assoc =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    IntegerInterval.intersection a (IntegerInterval.intersection b c) ==
    IntegerInterval.intersection (IntegerInterval.intersection a b) c

prop_intersection_unitL =
  forAll integerIntervals $ \a ->
    IntegerInterval.intersection IntegerInterval.whole a == a

prop_intersection_unitR =
  forAll integerIntervals $ \a ->
    IntegerInterval.intersection a IntegerInterval.whole == a

prop_intersection_empty =
  forAll integerIntervals $ \a ->
    IntegerInterval.intersection a IntegerInterval.empty == IntegerInterval.empty

prop_intersection_isSubsetOf =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.isSubsetOf (IntegerInterval.intersection a b) a

prop_intersection_isSubsetOf_equiv =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    (IntegerInterval.intersection a b == a)
    == IntegerInterval.isSubsetOf a b

case_intersections_empty_list = IntegerInterval.intersections [] @?= (IntegerInterval.whole :: IntegerInterval)

prop_intersections_singleton_list =
  forAll integerIntervals $ \a -> IntegerInterval.intersections [a] == a

prop_intersections_two_elems =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.intersections [a,b] == IntegerInterval.intersection a b

{--------------------------------------------------------------------
  Hull
--------------------------------------------------------------------}

prop_hull_comm =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.hull a b == IntegerInterval.hull b a

prop_hull_assoc =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    IntegerInterval.hull a (IntegerInterval.hull b c) ==
    IntegerInterval.hull (IntegerInterval.hull a b) c

prop_hull_unitL =
  forAll integerIntervals $ \a ->
    IntegerInterval.hull IntegerInterval.empty a == a

prop_hull_unitR =
  forAll integerIntervals $ \a ->
    IntegerInterval.hull a IntegerInterval.empty == a

prop_hull_whole =
  forAll integerIntervals $ \a ->
    IntegerInterval.hull a IntegerInterval.whole == IntegerInterval.whole

prop_hull_isSubsetOf =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.isSubsetOf a (IntegerInterval.hull a b)

prop_hull_isSubsetOf_equiv =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    (IntegerInterval.hull a b == b)
    == IntegerInterval.isSubsetOf a b

case_hulls_empty_list = IntegerInterval.hulls [] @?= (IntegerInterval.empty :: IntegerInterval)

prop_hulls_singleton_list =
  forAll integerIntervals $ \a -> IntegerInterval.hulls [a] == a

prop_hulls_two_elems =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    IntegerInterval.hulls [a,b] == IntegerInterval.hull a b

{--------------------------------------------------------------------
  member
--------------------------------------------------------------------}

prop_member_isSubsetOf =
  forAll arbitrary $ \r ->
  forAll integerIntervals $ \a ->
    IntegerInterval.member r a == IntegerInterval.isSubsetOf (IntegerInterval.singleton r) a

{--------------------------------------------------------------------
  isSubsetOf
--------------------------------------------------------------------}

prop_isSubsetOf_refl =
  forAll integerIntervals $ \a ->
    IntegerInterval.isSubsetOf a a

prop_isSubsetOf_trans =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    IntegerInterval.isSubsetOf a b && IntegerInterval.isSubsetOf b c
    ==> IntegerInterval.isSubsetOf a c

-- prop_isSubsetOf_antisym =
--   forAll integerIntervals $ \a ->
--   forAll integerIntervals $ \b ->
--     IntegerInterval.isSubsetOf a b && IntegerInterval.isSubsetOf b a
--     ==> a == b

{--------------------------------------------------------------------
  pickup
--------------------------------------------------------------------}

prop_pickup_member_null =
  forAll integerIntervals $ \a ->
    case IntegerInterval.pickup a of
      Nothing -> IntegerInterval.null a
      Just x -> IntegerInterval.member x a

case_pickup_empty =
  IntegerInterval.pickup (IntegerInterval.empty :: IntegerInterval) @?= Nothing

case_pickup_whole =
  isJust (IntegerInterval.pickup (IntegerInterval.whole :: IntegerInterval)) @?= True

{--------------------------------------------------------------------
  Comparison
--------------------------------------------------------------------}

case_lt_all_1 = (a <! b) @?= False
  where
    a, b :: IntegerInterval
    a = NegInf <..<= 0
    b = 0 <=..< PosInf

case_lt_all_2 = (a <! b) @?= True
  where
    a, b :: IntegerInterval
    a = NegInf <..< 0
    b = 0 <=..< PosInf

case_lt_all_3 = (a <! b) @?= True
  where
    a, b :: IntegerInterval
    a = NegInf <..<= 0
    b = 0 <..< PosInf

case_lt_all_4 = (a <! b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = 1 <=..< PosInf

case_lt_some_1 = (a <? b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = NegInf <..<= 0

case_lt_some_2 = (a <? b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <..< PosInf
    b = NegInf <..<= 0

case_lt_some_3 = (a <? b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = NegInf <..< 0

case_lt_some_4 = (a <! b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = 1 <=..< PosInf

case_le_some_1 = (a <=? b) @?= True
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = NegInf <..<= 0

case_le_some_2 = (a <=? b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <..< PosInf
    b = NegInf <..<= 0

case_le_some_3 = (a <=? b) @?= False
  where
    a, b :: IntegerInterval
    a = 0 <=..< PosInf
    b = NegInf <..< 0

prop_lt_all_not_refl =
  forAll integerIntervals $ \a -> not (IntegerInterval.null a) ==> not (a <! a)

prop_le_some_refl =
  forAll integerIntervals $ \a -> not (IntegerInterval.null a) ==> a <=? a

prop_ne_all_not_refl =
  forAll integerIntervals $ \a -> not (IntegerInterval.null a) ==> not (a /=! a)

prop_lt_all_singleton =
  forAll arbitrary $ \a ->
  forAll arbitrary $ \b ->
    (a::Integer) < b ==> IntegerInterval.singleton a <! IntegerInterval.singleton b

prop_lt_all_singleton_2 =
  forAll arbitrary $ \a ->
    not $ IntegerInterval.singleton (a::Integer) <! IntegerInterval.singleton a

prop_le_all_singleton =
  forAll arbitrary $ \a ->
  forAll arbitrary $ \b ->
    (a::Integer) <= b ==> IntegerInterval.singleton a <=! IntegerInterval.singleton b

prop_le_all_singleton_2 =
  forAll arbitrary $ \a ->
    IntegerInterval.singleton (a::Integer) <=! IntegerInterval.singleton a

prop_eq_all_singleton =
  forAll arbitrary $ \a ->
    IntegerInterval.singleton (a::Integer) ==! IntegerInterval.singleton a

prop_ne_all_singleton =
  forAll arbitrary $ \a ->
  forAll arbitrary $ \b ->
    (a::Integer) /= b ==> IntegerInterval.singleton a /=! IntegerInterval.singleton b

prop_ne_all_singleton_2 =
  forAll arbitrary $ \a ->
    not $ IntegerInterval.singleton (a::Integer) /=! IntegerInterval.singleton a

prop_lt_some_singleton =
  forAll arbitrary $ \a ->
  forAll arbitrary $ \b ->
    (a::Integer) < b ==> IntegerInterval.singleton a <? IntegerInterval.singleton b

prop_lt_some_singleton_2 =
  forAll arbitrary $ \a ->
    not $ IntegerInterval.singleton (a::Integer) <? IntegerInterval.singleton a

prop_le_some_singleton =
  forAll arbitrary $ \a ->
  forAll arbitrary $ \b ->
    (a::Integer) <= b ==> IntegerInterval.singleton a <=? IntegerInterval.singleton b

prop_le_some_singleton_2 =
  forAll arbitrary $ \a ->
    IntegerInterval.singleton (a::Integer) <=? IntegerInterval.singleton a

prop_eq_some_singleton =
  forAll arbitrary $ \a ->
    IntegerInterval.singleton (a::Integer) ==? IntegerInterval.singleton a

prop_lt_all_empty =
  forAll integerIntervals $ \a -> a <! IntegerInterval.empty

prop_lt_all_empty_2 =
  forAll integerIntervals $ \a -> IntegerInterval.empty <! a

prop_le_all_empty =
  forAll integerIntervals $ \a -> a <=! IntegerInterval.empty

prop_le_all_empty_2 =
  forAll integerIntervals $ \a -> IntegerInterval.empty <=! a

prop_eq_all_empty =
  forAll integerIntervals $ \a -> a ==! IntegerInterval.empty

prop_ne_all_empty =
  forAll integerIntervals $ \a -> a /=! IntegerInterval.empty

prop_lt_some_empty =
  forAll integerIntervals $ \a -> not (a <? IntegerInterval.empty)

prop_lt_some_empty_2 =
  forAll integerIntervals $ \a -> not (IntegerInterval.empty <? a)

prop_le_some_empty =
  forAll integerIntervals $ \a -> not (a <=? IntegerInterval.empty)

prop_le_some_empty_2 =
  forAll integerIntervals $ \a -> not (IntegerInterval.empty <=? a)

prop_eq_some_empty =
  forAll integerIntervals $ \a -> not (a ==? IntegerInterval.empty)

prop_intersect_le_some =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    not (IntegerInterval.null (IntegerInterval.intersection a b))
    ==> a <=? b

prop_intersect_eq_some =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    not (IntegerInterval.null (IntegerInterval.intersection a b))
    ==> a ==? b

prop_le_some_witness =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    case a <=?? b of
      Nothing ->
        forAll arbitrary $ \(x,y) ->
          not (IntegerInterval.member x a && IntegerInterval.member y b && x <= y)
      Just (x,y) ->
        IntegerInterval.member x a .&&. IntegerInterval.member y b .&&. x <= y

prop_lt_some_witness =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    case a <?? b of
      Nothing ->
        forAll arbitrary $ \(x,y) ->
          not (IntegerInterval.member x a && IntegerInterval.member y b && x < y)
      Just (x,y) ->
        IntegerInterval.member x a .&&. IntegerInterval.member y b .&&. x < y

prop_eq_some_witness =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    case a ==?? b of
      Nothing ->
        forAll arbitrary $ \x ->
          not (IntegerInterval.member x a && IntegerInterval.member x b)
      Just (x,y) ->
        IntegerInterval.member x a .&&. IntegerInterval.member y b .&&. x == y

prop_ne_some_witness =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    case a /=?? b of
      Nothing ->
        forAll arbitrary $ \x ->
        forAll arbitrary $ \y ->
          not (IntegerInterval.member x a && IntegerInterval.member y b && x /= y)
      Just (x,y) ->
        IntegerInterval.member x a .&&. IntegerInterval.member y b .&&. x /= y

prop_le_some_witness_forget =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    isJust (a <=?? b) == (a <=? b)

prop_lt_some_witness_forget =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    isJust (a <?? b) == (a <? b)

prop_eq_some_witness_forget =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    isJust (a ==?? b) == (a ==? b)

prop_ne_some_witness_forget =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    isJust (a /=?? b) == (a /=? b)

{--------------------------------------------------------------------
  Num
--------------------------------------------------------------------}

prop_scale_empty =
  forAll arbitrary $ \r ->
    IntegerInterval.singleton (r::Integer) * IntegerInterval.empty == IntegerInterval.empty

prop_add_comm =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    a + b == b + a

prop_add_assoc =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    a + (b + c) == (a + b) + c

prop_add_unitL =
  forAll integerIntervals $ \a ->
    IntegerInterval.singleton 0 + a == a

prop_add_unitR =
  forAll integerIntervals $ \a ->
    a + IntegerInterval.singleton 0 == a

prop_add_member =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    and [ (x+y) `IntegerInterval.member` (a+b)
        | x <- maybeToList $ IntegerInterval.pickup a
        , y <- maybeToList $ IntegerInterval.pickup b
        ]

prop_mult_comm =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    a * b == b * a

prop_mult_assoc =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    a * (b * c) == (a * b) * c

prop_mult_unitL =
  forAll integerIntervals $ \a ->
    IntegerInterval.singleton 1 * a == a

prop_mult_unitR =
  forAll integerIntervals $ \a ->
    a * IntegerInterval.singleton 1 == a

prop_mult_dist =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
  forAll integerIntervals $ \c ->
    (a * (b + c)) `IntegerInterval.isSubsetOf` (a * b + a * c)

prop_mult_empty =
  forAll integerIntervals $ \a ->
    IntegerInterval.empty * a == IntegerInterval.empty

prop_mult_zero =
  forAll integerIntervals $ \a ->
    not (IntegerInterval.null a) ==> IntegerInterval.singleton 0 * a ==  IntegerInterval.singleton 0

prop_mult_member =
  forAll integerIntervals $ \a ->
  forAll integerIntervals $ \b ->
    and [ (x*y) `IntegerInterval.member` (a*b)
        | x <- maybeToList $ IntegerInterval.pickup a
        , y <- maybeToList $ IntegerInterval.pickup b
        ]

case_mult_test1 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = 1 <=..<= 2
    ival2 = 1 <=..<= 2
    ival3 = 1 <=..<= 4

case_mult_test2 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = 1 <=..<= 2
    ival2 = 1 <..< 2
    ival3 = IntegerInterval.empty -- *

case_mult_test3 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = 1 <..< 2
    ival2 = 1 <..< 2
    ival3 = IntegerInterval.empty -- *

case_mult_test4 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = 2 <..< PosInf
    ival2 = 3 <..< PosInf
    ival3 = 11 <..< PosInf -- *

case_mult_test5 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = NegInf <..< (-3)
    ival2 = NegInf <..< (-2)
    ival3 = 11 <..< PosInf -- *

case_mult_test6 = ival1 * ival2 @?= ival3
  where
    ival1 :: IntegerInterval
    ival1 = 2 <..< PosInf
    ival2 = NegInf <..< (-2)
    ival3 = NegInf <..< (-8) -- *

{--------------------------------------------------------------------
  Read
--------------------------------------------------------------------}

prop_show_read_invariance =
  forAll integerIntervals $ \i -> do
    i == read (show i)

{--------------------------------------------------------------------
  Conversion between Interval and IntegerInterval
--------------------------------------------------------------------}

prop_fromInterval_toInterval =
  forAll integerIntervals $ \i ->
    IntegerInterval.fromInterval (IntegerInterval.toInterval i) == i

prop_fromIntervalOver_toInterval =
  forAll integerIntervals $ \i ->
    IntegerInterval.fromIntervalOver (IntegerInterval.toInterval i :: Interval Rational) == i

prop_fromIntervalUnder_toInterval =
  forAll integerIntervals $ \i ->
    IntegerInterval.fromIntervalUnder (IntegerInterval.toInterval i :: Interval Rational) == i

prop_fromIntervalOver_toInterval_adjoint =
  forAll intervals $ \a ->
    forAll integerIntervals $ \b ->
      IntegerInterval.fromIntervalOver a `IntegerInterval.isSubsetOf` b
      == a `Interval.isSubsetOf` IntegerInterval.toInterval b

prop_toInterval_fromIntervalUnder_adjoint =
  forAll integerIntervals $ \a ->
    forAll intervals $ \b ->
      IntegerInterval.toInterval a `Interval.isSubsetOf` b
      == a `IntegerInterval.isSubsetOf` IntegerInterval.fromIntervalUnder b

prop_toInterval_fromInterval =
  forAll arbitrary $ \(i :: Interval Integer) ->
    IntegerInterval.toInterval (IntegerInterval.fromInterval i) `Interval.isSubsetOf` i

{--------------------------------------------------------------------
  Generators
--------------------------------------------------------------------}

instance Arbitrary r => Arbitrary (Extended r) where
  arbitrary =
    oneof
    [ return NegInf
    , return PosInf
    , liftM Finite arbitrary
    ]

instance (Arbitrary r, Ord r) => Arbitrary (Interval.Interval r) where
  arbitrary = do
    lb <- arbitrary
    ub <- arbitrary
    return $ Interval.interval lb ub

instance Arbitrary IntegerInterval where
  arbitrary = do
    lb <- arbitrary
    ub <- arbitrary
    return $ IntegerInterval.interval lb ub

integerIntervals :: Gen IntegerInterval
integerIntervals = arbitrary

intervals :: Gen (Interval.Interval Rational)
intervals = arbitrary

pos :: IntegerInterval
pos = 0 <..< PosInf

neg :: IntegerInterval
neg = NegInf <..< 0

nonpos :: IntegerInterval
nonpos = NegInf <..<= 0

nonneg :: IntegerInterval
nonneg = 0 <=..< PosInf

------------------------------------------------------------------------
-- Test harness

main :: IO ()
main = $(defaultMainGenerator)