data-interval-1.0.1: test/TestInterval.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.Interval
( Interval, Extended (..), (<=..<=), (<=..<), (<..<=), (<..<)
, (<!), (<=!), (==!), (>=!), (>!), (/=!)
, (<?), (<=?), (==?), (>=?), (>?), (/=?)
, (<??), (<=??), (==??), (>=??), (>??), (/=??)
)
import qualified Data.Interval as Interval
{--------------------------------------------------------------------
empty
--------------------------------------------------------------------}
prop_empty_is_bottom =
forAll intervals $ \a ->
Interval.isSubsetOf Interval.empty a
prop_null_empty =
forAll intervals $ \a ->
Interval.null a == (a == Interval.empty)
case_null_empty =
Interval.null (Interval.empty :: Interval Rational) @?= True
{--------------------------------------------------------------------
whole
--------------------------------------------------------------------}
prop_whole_is_top =
forAll intervals $ \a ->
Interval.isSubsetOf a Interval.whole
case_nonnull_top =
Interval.null (Interval.whole :: Interval Rational) @?= False
{--------------------------------------------------------------------
singleton
--------------------------------------------------------------------}
prop_singleton_member =
forAll arbitrary $ \r ->
Interval.member (r::Rational) (Interval.singleton r)
prop_singleton_member_intersection =
forAll intervals $ \a ->
forAll arbitrary $ \r ->
let b = Interval.singleton r
in Interval.member (r::Rational) a
==> Interval.intersection a b == b
prop_singleton_nonnull =
forAll arbitrary $ \r1 ->
not $ Interval.null $ Interval.singleton (r1::Rational)
prop_distinct_singleton_intersection =
forAll arbitrary $ \r1 ->
forAll arbitrary $ \r2 ->
(r1::Rational) /= r2 ==>
Interval.intersection (Interval.singleton r1) (Interval.singleton r2)
== Interval.empty
{--------------------------------------------------------------------
Intersection
--------------------------------------------------------------------}
prop_intersection_comm =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.intersection a b == Interval.intersection b a
prop_intersection_assoc =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
Interval.intersection a (Interval.intersection b c) ==
Interval.intersection (Interval.intersection a b) c
prop_intersection_unitL =
forAll intervals $ \a ->
Interval.intersection Interval.whole a == a
prop_intersection_unitR =
forAll intervals $ \a ->
Interval.intersection a Interval.whole == a
prop_intersection_empty =
forAll intervals $ \a ->
Interval.intersection a Interval.empty == Interval.empty
prop_intersection_isSubsetOf =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.isSubsetOf (Interval.intersection a b) a
prop_intersection_isSubsetOf_equiv =
forAll intervals $ \a ->
forAll intervals $ \b ->
(Interval.intersection a b == a)
== Interval.isSubsetOf a b
case_intersections_empty_list = Interval.intersections [] @?= Interval.whole
prop_intersections_singleton_list =
forAll intervals $ \a -> Interval.intersections [a] == a
prop_intersections_two_elems =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.intersections [a,b] == Interval.intersection a b
{--------------------------------------------------------------------
Hull
--------------------------------------------------------------------}
prop_hull_comm =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.hull a b == Interval.hull b a
prop_hull_assoc =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
Interval.hull a (Interval.hull b c) ==
Interval.hull (Interval.hull a b) c
prop_hull_unitL =
forAll intervals $ \a ->
Interval.hull Interval.empty a == a
prop_hull_unitR =
forAll intervals $ \a ->
Interval.hull a Interval.empty == a
prop_hull_whole =
forAll intervals $ \a ->
Interval.hull a Interval.whole == Interval.whole
prop_hull_isSubsetOf =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.isSubsetOf a (Interval.hull a b)
prop_hull_isSubsetOf_equiv =
forAll intervals $ \a ->
forAll intervals $ \b ->
(Interval.hull a b == b)
== Interval.isSubsetOf a b
case_hulls_empty_list = Interval.hulls [] @?= Interval.empty
prop_hulls_singleton_list =
forAll intervals $ \a -> Interval.hulls [a] == a
prop_hulls_two_elems =
forAll intervals $ \a ->
forAll intervals $ \b ->
Interval.hulls [a,b] == Interval.hull a b
{--------------------------------------------------------------------
member
--------------------------------------------------------------------}
prop_member_isSubsetOf =
forAll arbitrary $ \r ->
forAll intervals $ \a ->
Interval.member r a == Interval.isSubsetOf (Interval.singleton r) a
{--------------------------------------------------------------------
isSubsetOf
--------------------------------------------------------------------}
prop_isSubsetOf_refl =
forAll intervals $ \a ->
Interval.isSubsetOf a a
prop_isSubsetOf_trans =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
Interval.isSubsetOf a b && Interval.isSubsetOf b c
==> Interval.isSubsetOf a c
-- prop_isSubsetOf_antisym =
-- forAll intervals $ \a ->
-- forAll intervals $ \b ->
-- Interval.isSubsetOf a b && Interval.isSubsetOf b a
-- ==> a == b
{--------------------------------------------------------------------
simplestRationalWithin
--------------------------------------------------------------------}
prop_simplestRationalWithin_and_approxRational =
forAll arbitrary $ \(r::Rational) ->
forAll arbitrary $ \(eps::Rational) ->
eps > 0 ==> Interval.simplestRationalWithin (Finite (r-eps) <=..<= Finite (r+eps)) == Just (approxRational r eps)
prop_simplestRationalWithin_singleton =
forAll arbitrary $ \(r::Rational) ->
Interval.simplestRationalWithin (Interval.singleton r) == Just r
case_simplestRationalWithin_empty =
Interval.simplestRationalWithin Interval.empty @?= Nothing
case_simplestRationalWithin_test1 =
Interval.simplestRationalWithin (Finite (-0.5 :: Rational) <=..<= 0.5) @?= Just 0
case_simplestRationalWithin_test2 =
Interval.simplestRationalWithin (Finite (2 :: Rational) <..< 3) @?= Just 2.5
case_simplestRationalWithin_test2' =
Interval.simplestRationalWithin (Finite (-3 :: Rational) <..< (-2)) @?= Just (-2.5)
case_simplestRationalWithin_test3 =
Interval.simplestRationalWithin (Finite (1.4142135623730951 :: Rational) <..< Finite 1.7320508075688772) @?= Just 1.5
-- http://en.wikipedia.org/wiki/Best_rational_approximation#Best_rational_approximations
case_simplestRationalWithin_test4 =
Interval.simplestRationalWithin (Finite (3.14155 :: Rational) <..< Finite 3.14165) @?= Just (355/113)
case_simplestRationalWithin_test5 =
Interval.simplestRationalWithin (Finite (1.1e-20 :: Rational) <..< Finite (1.2e-20)) @?= Just (1/83333333333333333334)
{--------------------------------------------------------------------
pickup
--------------------------------------------------------------------}
prop_pickup_member_null =
forAll intervals $ \a ->
case Interval.pickup a of
Nothing -> Interval.null a
Just x -> Interval.member x a
case_pickup_empty =
Interval.pickup (Interval.empty :: Interval Rational) @?= Nothing
case_pickup_whole =
isJust (Interval.pickup (Interval.whole :: Interval Rational)) @?= True
{--------------------------------------------------------------------
Comparison
--------------------------------------------------------------------}
case_lt_all_1 = (a <! b) @?= False
where
a, b :: Interval Rational
a = NegInf <..<= 0
b = 0 <=..< PosInf
case_lt_all_2 = (a <! b) @?= True
where
a, b :: Interval Rational
a = NegInf <..< 0
b = 0 <=..< PosInf
case_lt_all_3 = (a <! b) @?= True
where
a, b :: Interval Rational
a = NegInf <..<= 0
b = 0 <..< PosInf
case_lt_all_4 = (a <! b) @?= False
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = 1 <=..< PosInf
case_lt_some_1 = (a <? b) @?= False
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = NegInf <..<= 0
case_lt_some_2 = (a <? b) @?= False
where
a, b :: Interval Rational
a = 0 <..< PosInf
b = NegInf <..<= 0
case_lt_some_3 = (a <? b) @?= False
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = NegInf <..< 0
case_lt_some_4 = (a <! b) @?= False
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = 1 <=..< PosInf
case_le_some_1 = (a <=? b) @?= True
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = NegInf <..<= 0
case_le_some_2 = (a <=? b) @?= False
where
a, b :: Interval Rational
a = 0 <..< PosInf
b = NegInf <..<= 0
case_le_some_3 = (a <=? b) @?= False
where
a, b :: Interval Rational
a = 0 <=..< PosInf
b = NegInf <..< 0
prop_lt_all_not_refl =
forAll intervals $ \a -> not (Interval.null a) ==> not (a <! a)
prop_le_some_refl =
forAll intervals $ \a -> not (Interval.null a) ==> a <=? a
prop_ne_all_not_refl =
forAll intervals $ \a -> not (Interval.null a) ==> not (a /=! a)
prop_lt_all_singleton =
forAll arbitrary $ \a ->
forAll arbitrary $ \b ->
(a::Rational) < b ==> Interval.singleton a <! Interval.singleton b
prop_lt_all_singleton_2 =
forAll arbitrary $ \a ->
not $ Interval.singleton (a::Rational) <! Interval.singleton a
prop_le_all_singleton =
forAll arbitrary $ \a ->
forAll arbitrary $ \b ->
(a::Rational) <= b ==> Interval.singleton a <=! Interval.singleton b
prop_le_all_singleton_2 =
forAll arbitrary $ \a ->
Interval.singleton (a::Rational) <=! Interval.singleton a
prop_eq_all_singleton =
forAll arbitrary $ \a ->
Interval.singleton (a::Rational) ==! Interval.singleton a
prop_ne_all_singleton =
forAll arbitrary $ \a ->
forAll arbitrary $ \b ->
(a::Rational) /= b ==> Interval.singleton a /=! Interval.singleton b
prop_ne_all_singleton_2 =
forAll arbitrary $ \a ->
not $ Interval.singleton (a::Rational) /=! Interval.singleton a
prop_lt_some_singleton =
forAll arbitrary $ \a ->
forAll arbitrary $ \b ->
(a::Rational) < b ==> Interval.singleton a <? Interval.singleton b
prop_lt_some_singleton_2 =
forAll arbitrary $ \a ->
not $ Interval.singleton (a::Rational) <? Interval.singleton a
prop_le_some_singleton =
forAll arbitrary $ \a ->
forAll arbitrary $ \b ->
(a::Rational) <= b ==> Interval.singleton a <=? Interval.singleton b
prop_le_some_singleton_2 =
forAll arbitrary $ \a ->
Interval.singleton (a::Rational) <=? Interval.singleton a
prop_eq_some_singleton =
forAll arbitrary $ \a ->
Interval.singleton (a::Rational) ==? Interval.singleton a
prop_lt_all_empty =
forAll intervals $ \a -> a <! Interval.empty
prop_lt_all_empty_2 =
forAll intervals $ \a -> Interval.empty <! a
prop_le_all_empty =
forAll intervals $ \a -> a <=! Interval.empty
prop_le_all_empty_2 =
forAll intervals $ \a -> Interval.empty <=! a
prop_eq_all_empty =
forAll intervals $ \a -> a ==! Interval.empty
prop_ne_all_empty =
forAll intervals $ \a -> a /=! Interval.empty
prop_lt_some_empty =
forAll intervals $ \a -> not (a <? Interval.empty)
prop_lt_some_empty_2 =
forAll intervals $ \a -> not (Interval.empty <? a)
prop_le_some_empty =
forAll intervals $ \a -> not (a <=? Interval.empty)
prop_le_some_empty_2 =
forAll intervals $ \a -> not (Interval.empty <=? a)
prop_eq_some_empty =
forAll intervals $ \a -> not (a ==? Interval.empty)
prop_intersect_le_some =
forAll intervals $ \a ->
forAll intervals $ \b ->
not (Interval.null (Interval.intersection a b))
==> a <=? b
prop_intersect_eq_some =
forAll intervals $ \a ->
forAll intervals $ \b ->
not (Interval.null (Interval.intersection a b))
==> a ==? b
prop_le_some_witness =
forAll intervals $ \a ->
forAll intervals $ \b ->
case a <=?? b of
Nothing ->
forAll arbitrary $ \(x,y) ->
not (Interval.member x a && Interval.member y b && x <= y)
Just (x,y) ->
Interval.member x a .&&. Interval.member y b .&&. x <= y
prop_lt_some_witness =
forAll intervals $ \a ->
forAll intervals $ \b ->
case a <?? b of
Nothing ->
forAll arbitrary $ \(x,y) ->
not (Interval.member x a && Interval.member y b && x < y)
Just (x,y) ->
Interval.member x a .&&. Interval.member y b .&&. x < y
prop_eq_some_witness =
forAll intervals $ \a ->
forAll intervals $ \b ->
case a ==?? b of
Nothing ->
forAll arbitrary $ \x ->
not (Interval.member x a && Interval.member x b)
Just (x,y) ->
Interval.member x a .&&. Interval.member y b .&&. x == y
prop_ne_some_witness =
forAll intervals $ \a ->
forAll intervals $ \b ->
case a /=?? b of
Nothing ->
forAll arbitrary $ \x ->
forAll arbitrary $ \y ->
not (Interval.member x a && Interval.member y b && x /= y)
Just (x,y) ->
Interval.member x a .&&. Interval.member y b .&&. x /= y
prop_le_some_witness_forget =
forAll intervals $ \a ->
forAll intervals $ \b ->
isJust (a <=?? b) == (a <=? b)
prop_lt_some_witness_forget =
forAll intervals $ \a ->
forAll intervals $ \b ->
isJust (a <?? b) == (a <? b)
prop_eq_some_witness_forget =
forAll intervals $ \a ->
forAll intervals $ \b ->
isJust (a ==?? b) == (a ==? b)
prop_ne_some_witness_forget =
forAll intervals $ \a ->
forAll intervals $ \b ->
isJust (a /=?? b) == (a /=? b)
{--------------------------------------------------------------------
Num
--------------------------------------------------------------------}
prop_scale_empty =
forAll arbitrary $ \r ->
Interval.singleton (r::Rational) * Interval.empty == Interval.empty
prop_add_comm =
forAll intervals $ \a ->
forAll intervals $ \b ->
a + b == b + a
prop_add_assoc =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
a + (b + c) == (a + b) + c
prop_add_unitL =
forAll intervals $ \a ->
Interval.singleton 0 + a == a
prop_add_unitR =
forAll intervals $ \a ->
a + Interval.singleton 0 == a
prop_add_member =
forAll intervals $ \a ->
forAll intervals $ \b ->
and [ (x+y) `Interval.member` (a+b)
| x <- maybeToList $ Interval.pickup a
, y <- maybeToList $ Interval.pickup b
]
prop_mult_comm =
forAll intervals $ \a ->
forAll intervals $ \b ->
a * b == b * a
prop_mult_assoc =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
a * (b * c) == (a * b) * c
prop_mult_unitL =
forAll intervals $ \a ->
Interval.singleton 1 * a == a
prop_mult_unitR =
forAll intervals $ \a ->
a * Interval.singleton 1 == a
prop_mult_dist =
forAll intervals $ \a ->
forAll intervals $ \b ->
forAll intervals $ \c ->
(a * (b + c)) `Interval.isSubsetOf` (a * b + a * c)
prop_mult_empty =
forAll intervals $ \a ->
Interval.empty * a == Interval.empty
prop_mult_zero =
forAll intervals $ \a ->
not (Interval.null a) ==> Interval.singleton 0 * a == Interval.singleton 0
prop_mult_member =
forAll intervals $ \a ->
forAll intervals $ \b ->
and [ (x*y) `Interval.member` (a*b)
| x <- maybeToList $ Interval.pickup a
, y <- maybeToList $ Interval.pickup b
]
case_mult_test1 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = 1 <=..<= 2
ival2 = 1 <=..<= 2
ival3 = 1 <=..<= 4
case_mult_test2 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = 1 <=..<= 2
ival2 = 1 <..< 2
ival3 = 1 <..< 4
case_mult_test3 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = 1 <..< 2
ival2 = 1 <..< 2
ival3 = 1 <..< 4
case_mult_test4 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = 2 <..< PosInf
ival2 = 3 <..< PosInf
ival3 = 6 <..< PosInf
case_mult_test5 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = NegInf <..< (-3)
ival2 = NegInf <..< (-2)
ival3 = 6 <..< PosInf
case_mult_test6 = ival1 * ival2 @?= ival3
where
ival1 :: Interval Rational
ival1 = 2 <..< PosInf
ival2 = NegInf <..< (-2)
ival3 = NegInf <..< (-4)
{--------------------------------------------------------------------
Fractional
--------------------------------------------------------------------}
prop_recip_singleton =
forAll arbitrary $ \r ->
let n = fromIntegral (numerator r)
d = fromIntegral (denominator r)
in Interval.singleton n / Interval.singleton d == Interval.singleton (r::Rational)
case_recip_pos =
recip pos @?= pos
case_recip_neg =
recip neg @?= neg
case_recip_test1 = recip i1 @?= i2
where
i1, i2 :: Interval Rational
i1 = 2 <=..< PosInf
i2 = 0 <..<= (1/2)
{--------------------------------------------------------------------
Read
--------------------------------------------------------------------}
prop_show_read_invariance =
forAll intervals $ \i -> do
i == read (show i)
{--------------------------------------------------------------------
Generators
--------------------------------------------------------------------}
instance Arbitrary r => Arbitrary (Extended r) where
arbitrary =
oneof
[ return NegInf
, return PosInf
, liftM Finite arbitrary
]
intervals :: Gen (Interval Rational)
intervals = do
lb <- arbitrary
ub <- arbitrary
return $ Interval.interval lb ub
pos :: Interval Rational
pos = 0 <..< PosInf
neg :: Interval Rational
neg = NegInf <..< 0
nonpos :: Interval Rational
nonpos = NegInf <..<= 0
nonneg :: Interval Rational
nonneg = 0 <=..< PosInf
------------------------------------------------------------------------
-- Test harness
main :: IO ()
main = $(defaultMainGenerator)