#if __GLASGOW_HASKELL__ >= 704
#endif
module Numeric.Interval.Internal
( Interval(..)
, (...)
, (+/-)
, interval
, whole
, empty
, null
, singleton
, member
, notMember
, elem
, notElem
, inf
, sup
, singular
, width
, midpoint
, intersection
, hull
, bisect
, bisectIntegral
, magnitude
, mignitude
, distance
, inflate, deflate
, scale, symmetric
, contains
, isSubsetOf
, certainly, (<!), (<=!), (==!), (>=!), (>!)
, possibly, (<?), (<=?), (==?), (>=?), (>?)
, idouble
, ifloat
, iquot
, irem
, idiv
, imod
) where
import Control.Exception as Exception
import Data.Data
import Data.Foldable hiding (minimum, maximum, elem, notElem
#if __GLASGOW_HASKELL__ >= 710
, null
#endif
)
import Data.Function (on)
import Data.Monoid
#if __GLASGOW_HASKELL__ >= 704
import GHC.Generics
#endif
import Numeric.Interval.Exception
import Prelude hiding (null, elem, notElem)
data Interval a = I !a !a | Empty deriving
( Eq, Ord
, Data
, Typeable
#if __GLASGOW_HASKELL__ >= 704
, Generic
#if __GLASGOW_HASKELL__ >= 706
, Generic1
#endif
#endif
)
instance Foldable Interval where
foldMap f (I a b) = f a `mappend` f b
foldMap _ Empty = mempty
infix 3 ...
infixl 6 +/-
(+/-) :: (Num a, Ord a) => a -> a -> Interval a
a +/- b = a b ... a + b
negInfinity :: Fractional a => a
negInfinity = (1)/0
posInfinity :: Fractional a => a
posInfinity = 1/0
interval :: Ord a => a -> a -> Maybe (Interval a)
interval a b
| a <= b = Just $ I a b
| otherwise = Nothing
fmod :: RealFrac a => a -> a -> a
fmod a b = a q*b where
q = realToFrac (truncate $ a / b :: Integer)
(...) :: Ord a => a -> a -> Interval a
a ... b
| a <= b = I a b
| otherwise = Empty
whole :: Fractional a => Interval a
whole = I negInfinity posInfinity
empty :: Interval a
empty = Empty
null :: Interval a -> Bool
null Empty = True
null _ = False
singleton :: a -> Interval a
singleton a = I a a
inf :: Interval a -> a
inf (I a _) = a
inf Empty = Exception.throw EmptyInterval
sup :: Interval a -> a
sup (I _ b) = b
sup Empty = Exception.throw EmptyInterval
singular :: Ord a => Interval a -> Bool
singular Empty = False
singular (I a b) = a == b
instance Show a => Show (Interval a) where
showsPrec _ Empty = showString "Empty"
showsPrec n (I a b) =
showParen (n > 3) $
showsPrec 3 a .
showString " ... " .
showsPrec 3 b
width :: Num a => Interval a -> a
width (I a b) = b a
width Empty = 0
magnitude :: (Num a, Ord a) => Interval a -> a
magnitude = sup . abs
mignitude :: (Num a, Ord a) => Interval a -> a
mignitude = inf . abs
distance :: (Num a, Ord a) => Interval a -> Interval a -> a
distance i1 i2 = mignitude (i1 i2)
inflate :: (Num a, Ord a) => a -> Interval a -> Interval a
inflate x y = symmetric x + y
deflate :: (Num a, Ord a) => a -> Interval a -> Interval a
deflate _ Empty = Empty
deflate x (I a b) | a' <= b' = I a' b'
| otherwise = Empty
where
a' = a + x
b' = b x
scale :: (Fractional a, Ord a) => a -> Interval a -> Interval a
scale _ Empty = Empty
scale x i = a ... b where
h = x * width i / 2
mid = midpoint i
a = mid h
b = mid + h
symmetric :: (Num a, Ord a) => a -> Interval a
symmetric x | a <= b = I a b
| otherwise = I b a
where
a = negate x
b = x
instance (Num a, Ord a) => Num (Interval a) where
I a b + I a' b' = (a + a') ... (b + b')
_ + _ = Empty
I a b I a' b' = (a b') ... (b a')
_ _ = Empty
I a b * I a' b' =
minimum [a * a', a * b', b * a', b * b']
...
maximum [a * a', a * b', b * a', b * b']
_ * _ = Empty
abs x@(I a b)
| a >= 0 = x
| b <= 0 = negate x
| otherwise = 0 ... max ( a) b
abs Empty = Empty
signum = increasing signum
fromInteger i = singleton (fromInteger i)
bisect :: Fractional a => Interval a -> (Interval a, Interval a)
bisect Empty = (Empty,Empty)
bisect (I a b) = (I a m, I m b) where m = a + (b a) / 2
bisectIntegral :: Integral a => Interval a -> (Interval a, Interval a)
bisectIntegral Empty = (Empty, Empty)
bisectIntegral (I a b)
| a == m || b == m = (I a a, I b b)
| otherwise = (I a m, I m b)
where m = a + (b a) `div` 2
midpoint :: Fractional a => Interval a -> a
midpoint (I a b) = a + (b a) / 2
midpoint Empty = Exception.throw EmptyInterval
member :: Ord a => a -> Interval a -> Bool
member x (I a b) = x >= a && x <= b
member _ Empty = False
notMember :: Ord a => a -> Interval a -> Bool
notMember x xs = not (member x xs)
elem :: Ord a => a -> Interval a -> Bool
elem = member
notElem :: Ord a => a -> Interval a -> Bool
notElem = notMember
instance Real a => Real (Interval a) where
toRational Empty = Exception.throw EmptyInterval
toRational (I ra rb) = a + (b a) / 2 where
a = toRational ra
b = toRational rb
divNonZero :: (Fractional a, Ord a) => Interval a -> Interval a -> Interval a
divNonZero (I a b) (I a' b') =
minimum [a / a', a / b', b / a', b / b']
...
maximum [a / a', a / b', b / a', b / b']
divNonZero _ _ = Empty
divPositive :: (Fractional a, Ord a) => Interval a -> a -> Interval a
divPositive Empty _ = Empty
divPositive x@(I a b) y
| a == 0 && b == 0 = x
| b < 0 = negInfinity ... (b / y)
| a < 0 = whole
| otherwise = (a / y) ... posInfinity
divNegative :: (Fractional a, Ord a) => Interval a -> a -> Interval a
divNegative Empty _ = Empty
divNegative x@(I a b) y
| a == 0 && b == 0 = x
| b < 0 = (b / y) ... posInfinity
| a < 0 = whole
| otherwise = negInfinity ... (a / y)
divZero :: (Fractional a, Ord a) => Interval a -> Interval a
divZero x@(I a b)
| a == 0 && b == 0 = x
| otherwise = whole
divZero Empty = Empty
instance (Fractional a, Ord a) => Fractional (Interval a) where
_ / Empty = Empty
x / y@(I a b)
| 0 `notElem` y = divNonZero x y
| iz && sz = Exception.throw DivideByZero
| iz = divPositive x a
| sz = divNegative x b
| otherwise = divZero x
where
iz = a == 0
sz = b == 0
recip Empty = Empty
recip (I a b) = on min recip a b ... on max recip a b
fromRational r = let r' = fromRational r in I r' r'
instance RealFrac a => RealFrac (Interval a) where
properFraction x = (b, x fromIntegral b)
where
b = truncate (midpoint x)
ceiling x = ceiling (sup x)
floor x = floor (inf x)
round x = round (midpoint x)
truncate x = truncate (midpoint x)
instance (RealFloat a, Ord a) => Floating (Interval a) where
pi = singleton pi
exp = increasing exp
log (I a b) = (if a > 0 then log a else negInfinity) ... log b
log Empty = Empty
cos Empty = Empty
cos x
| width t >= pi = (1) ... 1
| inf t >= pi = cos (t pi)
| sup t <= pi = decreasing cos t
| sup t <= 2 * pi = (1) ... cos ((pi * 2 sup t) `min` inf t)
| otherwise = (1) ... 1
where
t = fmod x (pi * 2)
sin Empty = Empty
sin x = cos (x pi / 2)
tan Empty = Empty
tan x
| inf t' <= pi / 2 || sup t' >= pi / 2 = whole
| otherwise = increasing tan x
where
t = x `fmod` pi
t' | t >= pi / 2 = t pi
| otherwise = t
asin Empty = Empty
asin (I a b)
| b < 1 || a > 1 = Empty
| otherwise =
(if a <= 1 then halfPi else asin a)
...
(if b >= 1 then halfPi else asin b)
where
halfPi = pi / 2
acos Empty = Empty
acos (I a b)
| b < 1 || a > 1 = Empty
| otherwise =
(if b >= 1 then 0 else acos b)
...
(if a < 1 then pi else acos a)
atan = increasing atan
sinh = increasing sinh
cosh Empty = Empty
cosh x@(I a b)
| b < 0 = decreasing cosh x
| a >= 0 = increasing cosh x
| otherwise = I 0 $ cosh $ if a > b
then a
else b
tanh = increasing tanh
asinh = increasing asinh
acosh Empty = Empty
acosh (I a b)
| b < 1 = Empty
| otherwise = I lo $ acosh b
where lo | a <= 1 = 0
| otherwise = acosh a
atanh Empty = Empty
atanh (I a b)
| b < 1 || a > 1 = Empty
| otherwise =
(if a <= 1 then negInfinity else atanh a)
...
(if b >= 1 then posInfinity else atanh b)
increasing :: (a -> b) -> Interval a -> Interval b
increasing f (I a b) = I (f a) (f b)
increasing _ Empty = Empty
decreasing :: (a -> b) -> Interval a -> Interval b
decreasing f (I a b) = I (f b) (f a)
decreasing _ Empty = Empty
instance RealFloat a => RealFloat (Interval a) where
floatRadix = floatRadix . midpoint
floatDigits = floatDigits . midpoint
floatRange = floatRange . midpoint
decodeFloat = decodeFloat . midpoint
encodeFloat m e = singleton (encodeFloat m e)
exponent = exponent . midpoint
significand x = min a b ... max a b
where
(_ ,em) = decodeFloat (midpoint x)
(mi,ei) = decodeFloat (inf x)
(ms,es) = decodeFloat (sup x)
a = encodeFloat mi (ei em floatDigits x)
b = encodeFloat ms (es em floatDigits x)
scaleFloat _ Empty = Empty
scaleFloat n (I a b) = I (scaleFloat n a) (scaleFloat n b)
isNaN (I a b) = isNaN a || isNaN b
isNaN Empty = True
isInfinite (I a b) = isInfinite a || isInfinite b
isInfinite Empty = False
isDenormalized (I a b) = isDenormalized a || isDenormalized b
isDenormalized Empty = False
isNegativeZero (I a b) = not (a > 0)
&& not (b < 0)
&& ( (b == 0 && (a < 0 || isNegativeZero a))
|| (a == 0 && isNegativeZero a)
|| (a < 0 && b >= 0))
isNegativeZero Empty = False
isIEEE _ = False
atan2 = error "unimplemented"
intersection :: Ord a => Interval a -> Interval a -> Interval a
intersection x@(I a b) y@(I a' b')
| x /=! y = Empty
| otherwise = I (max a a') (min b b')
intersection _ _ = Empty
hull :: Ord a => Interval a -> Interval a -> Interval a
hull (I a b) (I a' b') = I (min a a') (max b b')
hull Empty x = x
hull x Empty = x
(<!) :: Ord a => Interval a -> Interval a -> Bool
Empty <! _ = True
_ <! Empty = True
I _ bx <! I ay _ = bx < ay
(<=!) :: Ord a => Interval a -> Interval a -> Bool
Empty <=! _ = True
_ <=! Empty = True
I _ bx <=! I ay _ = bx <= ay
(==!) :: Eq a => Interval a -> Interval a -> Bool
Empty ==! _ = True
_ ==! Empty = True
I ax bx ==! I ay by = bx == ay && ax == by
(/=!) :: Ord a => Interval a -> Interval a -> Bool
Empty /=! _ = True
_ /=! Empty = True
I ax bx /=! I ay by = bx < ay || ax > by
(>!) :: Ord a => Interval a -> Interval a -> Bool
Empty >! _ = True
_ >! Empty = True
I ax _ >! I _ by = ax > by
(>=!) :: Ord a => Interval a -> Interval a -> Bool
Empty >=! _ = True
_ >=! Empty = True
I ax _ >=! I _ by = ax >= by
certainly :: Ord a => (forall b. Ord b => b -> b -> Bool) -> Interval a -> Interval a -> Bool
certainly cmp l r
| lt && eq && gt = True
| lt && eq = l <=! r
| lt && gt = l /=! r
| lt = l <! r
| eq && gt = l >=! r
| eq = l ==! r
| gt = l >! r
| otherwise = False
where
lt = cmp False True
eq = cmp True True
gt = cmp True False
contains :: Ord a => Interval a -> Interval a -> Bool
contains _ Empty = True
contains (I ax bx) (I ay by) = ax <= ay && by <= bx
contains Empty I{} = False
isSubsetOf :: Ord a => Interval a -> Interval a -> Bool
isSubsetOf = flip contains
(<?) :: Ord a => Interval a -> Interval a -> Bool
Empty <? _ = False
_ <? Empty = False
I ax _ <? I _ by = ax < by
(<=?) :: Ord a => Interval a -> Interval a -> Bool
Empty <=? _ = False
_ <=? Empty = False
I ax _ <=? I _ by = ax <= by
(==?) :: Ord a => Interval a -> Interval a -> Bool
I ax bx ==? I ay by = ax <= by && bx >= ay
_ ==? _ = False
(/=?) :: Eq a => Interval a -> Interval a -> Bool
I ax bx /=? I ay by = ax /= by || bx /= ay
_ /=? _ = False
(>?) :: Ord a => Interval a -> Interval a -> Bool
I _ bx >? I ay _ = bx > ay
_ >? _ = False
(>=?) :: Ord a => Interval a -> Interval a -> Bool
I _ bx >=? I ay _ = bx >= ay
_ >=? _ = False
possibly :: Ord a => (forall b. Ord b => b -> b -> Bool) -> Interval a -> Interval a -> Bool
possibly cmp l r
| lt && eq && gt = True
| lt && eq = l <=? r
| lt && gt = l /=? r
| lt = l <? r
| eq && gt = l >=? r
| eq = l ==? r
| gt = l >? r
| otherwise = False
where
lt = cmp LT EQ
eq = cmp EQ EQ
gt = cmp GT EQ
idouble :: Interval Double -> Interval Double
idouble = id
ifloat :: Interval Float -> Interval Float
ifloat = id
default (Integer,Double)
iquot :: Integral a => Interval a -> Interval a -> Interval a
iquot i j = case (i,j) of
(Empty,_) -> Empty
(_,Empty) -> Empty
(I l u , I l' u') ->
if l' <= 0 && 0 <= u' then throw DivideByZero else I
(minimum [a `quot` b | a <- [l,u], b <- [l',u']])
(maximum [a `quot` b | a <- [l,u], b <- [l',u']])
irem :: Integral a => Interval a -> Interval a -> Interval a
irem i j = case (i,j) of
(Empty,_) -> Empty
(_,Empty) -> Empty
(I l u , I l' u') ->
if l' <= 0 && 0 <= u' then throw DivideByZero else I
(minimum [0, signum l * (abs u' 1), signum l * (abs l' 1)])
(maximum [0, signum u * (abs u' 1), signum u * (abs l' 1)])
idiv :: Integral a => Interval a -> Interval a -> Interval a
idiv i j = case (i,j) of
(Empty,_) -> Empty
(_,Empty) -> Empty
(I l u , I l' u') ->
if l' <= 0 && 0 <= u' then throw DivideByZero else I
(min (l `Prelude.div` max 1 l') (u `Prelude.div` min (1) u'))
(max (u `Prelude.div` max 1 l') (l `Prelude.div` min (1) u'))
imod :: Integral a => Interval a -> Interval a -> Interval a
imod i j = case (i,j) of
(Empty,_) -> Empty
(_,Empty) -> Empty
(_ , I l' u') ->
if l' <= 0 && 0 <= u' then throw DivideByZero else
I (min (l'+1) 0) (max 0 (u'1))