brush-strokes-0.1.0.0: src/lib/Math/Interval/Internal.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Math.Interval.Internal
( π(π, inf, sup)
, scaleInterval, width, singleton
, hull
, addWithErr, subWithErr, prodWithErr, divWithErr
, πβ(..)
)
where
-- base
import Prelude hiding ( Num(..), Fractional(..), Floating(..), (^) )
import Data.Kind
( Type )
import Data.Monoid
( Sum(..) )
import GHC.Generics
( Generic )
import GHC.Show
( showCommaSpace )
import GHC.TypeNats
( Nat )
import GHC.Exts
( (+#), (*#) )
-- deepseq
import Control.DeepSeq
( NFData(..) )
-- primitive
import Data.Primitive
( Prim(..) )
-- brush-strokes
#if defined(USE_SIMD)
import Math.Interval.Internal.SIMD
#elif defined(USE_FMA)
import Math.Interval.Internal.FMA
#else
import Math.Interval.Internal.RoundedHW
#endif
import Math.Interval.Internal.FMA
( addI, subI, prodI, divI )
-- brush-strokes
import Math.Float.Utils
( succFP, prevFP )
import Math.Linear
( T(..)
, RepDim, RepresentableQ(..), Representable(..)
, Fin(..)
)
import Math.Module
( Module(..) )
import Math.Ring
--------------------------------------------------------------------------------
-- | An interval reduced to a single point.
singleton :: Double -> π
singleton x = π x x
-- | The width of an interval.
--
-- NB: assumes the endpoints are neither @NaN@ nor infinity.
width :: π -> Double
width ( π lo hi ) = hi - lo
-- | Union (hull) of two intervals.
hull :: π -> π -> π
hull ( π lo1 hi1 ) ( π lo2 hi2 ) = π ( min lo1 lo2 ) ( max hi1 hi2 )
addWithErr, subWithErr, prodWithErr, divWithErr :: Double -> Double -> (# Double, π #)
addWithErr = addI withError2
subWithErr = subI withError2
prodWithErr = prodI withError2
divWithErr = divI withError2
-- TODO: not sure why but these don't work properly right now
--{-# SPECIALISE INLINE addI withError2 #-}
--{-# SPECIALISE INLINE subI withError2 #-}
--{-# SPECIALISE INLINE prodI withError2 #-}
--{-# SPECIALISE INLINE divI withError2 #-}
{-# INLINE withError2 #-}
withError2 :: Double -> Double -> (# Double, π #)
withError2 f e = (# f , #)
case compare e 0 of
LT -> π ( prevFP f - f ) 0
EQ -> π 0 0
GT -> π 0 ( succFP f - f)
--------------------------------------------------------------------------------
-- Instances for (1D) intervals.
instance Eq π where
π a b == π c d =
a == c && b == d
instance Show π where
showsPrec _ ( π x y )
= showString "["
. showsPrec 0 x
. showCommaSpace
. showsPrec 0 y
. showString "]"
deriving via ViaPrelude π
instance AbelianGroup ( T π )
deriving via Sum π
instance Module π ( T π )
-- NB: the SIMD implementation of π uses DoubleX2#, and has a custom 'Prim' instance.
#if !defined(USE_SIMD)
instance Prim π where
sizeOf# _ = 2# *# sizeOf# (undefined :: Double)
alignment# _ = alignment# (undefined :: Double)
indexByteArray# arr# i# =
let infVal = indexByteArray# arr# (2# *# i#)
supVal = indexByteArray# arr# (2# *# i# +# 1#)
in π infVal supVal
readByteArray# arr# i# s0 =
case readByteArray# arr# (2# *# i#) s0 of
(# s1, infVal #) -> case readByteArray# arr# (2# *# i# +# 1#) s1 of
(# s2, supVal #) -> (# s2, π infVal supVal #)
writeByteArray# arr# i# (π infVal supVal) s0 =
case writeByteArray# arr# (2# *# i#) infVal s0 of
s1 -> writeByteArray# arr# (2# *# i# +# 1#) supVal s1
indexOffAddr# addr# i# =
let infVal = indexOffAddr# addr# (2# *# i#)
supVal = indexOffAddr# addr# (2# *# i# +# 1#)
in π infVal supVal
readOffAddr# addr# i# s0 =
case readOffAddr# addr# (2# *# i#) s0 of
(# s1, infVal #) -> case readOffAddr# addr# (2# *# i# +# 1#) s1 of
(# s2, supVal #) -> (# s2, π infVal supVal #)
writeOffAddr# addr# i# (π infVal supVal) s0 =
case writeOffAddr# addr# (2# *# i#) infVal s0 of
s1 -> writeOffAddr# addr# (2# *# i# +# 1#) supVal s1
#endif
--------------------------------------------------------------------------------
type πβ :: Nat -> Type
data family πβ n
data instance πβ 0 = πβ0
deriving stock ( Show, Eq, Ord, Generic )
deriving anyclass NFData
newtype instance πβ 1 = πβ1 { unπβ1 :: π }
deriving stock ( Show, Generic )
deriving newtype ( Eq, NFData )
data instance πβ 2 = πβ2 { _πβ2_x, _πβ2_y :: !π }
deriving stock Generic
deriving anyclass NFData
deriving stock ( Show, Eq )
data instance πβ 3 = πβ3 { _πβ3_x, _πβ3_y, _πβ3_z :: !π }
deriving stock Generic
deriving anyclass NFData
deriving stock ( Show, Eq )
data instance πβ 4 = πβ4 { _πβ4_x, _πβ4_y, _πβ4_z, _πβ4_w :: !π }
deriving stock Generic
deriving anyclass NFData
deriving stock ( Show, Eq )
type instance RepDim ( πβ n ) = n
instance RepresentableQ π ( πβ 0 ) where
tabulateQ _ = [|| πβ0 ||]
indexQ _ _ = [|| 0 ||]
instance RepresentableQ π ( πβ 1 ) where
tabulateQ f = [|| πβ1 $$( f ( Fin 1 ) ) ||]
indexQ p = \ case
_ -> [|| unπβ1 $$p ||]
instance RepresentableQ π ( πβ 2 ) where
tabulateQ f = [|| πβ2 $$( f ( Fin 1 ) ) $$( f ( Fin 2 ) ) ||]
indexQ p = \ case
Fin 1 -> [|| _πβ2_x $$p ||]
_ -> [|| _πβ2_y $$p ||]
instance RepresentableQ π ( πβ 3 ) where
tabulateQ f = [|| πβ3 $$( f ( Fin 1 ) ) $$( f ( Fin 2 ) ) $$( f ( Fin 3 ) ) ||]
indexQ p = \ case
Fin 1 -> [|| _πβ3_x $$p ||]
Fin 2 -> [|| _πβ3_y $$p ||]
_ -> [|| _πβ3_z $$p ||]
instance RepresentableQ π ( πβ 4 ) where
tabulateQ f = [|| πβ4 $$( f ( Fin 1 ) ) $$( f ( Fin 2 ) ) $$( f ( Fin 3 ) ) $$( f ( Fin 4 ) ) ||]
indexQ p = \ case
Fin 1 -> [|| _πβ4_x $$p ||]
Fin 2 -> [|| _πβ4_y $$p ||]
Fin 3 -> [|| _πβ4_z $$p ||]
_ -> [|| _πβ4_w $$p ||]
instance Representable π ( πβ 0 ) where
tabulate _ = πβ0
{-# INLINE tabulate #-}
index _ _ = 0
{-# INLINE index #-}
instance Representable π ( πβ 1 ) where
tabulate f = πβ1 ( f ( Fin 1 ) )
{-# INLINE tabulate #-}
index p = \ case
_ -> unπβ1 p
{-# INLINE index #-}
instance Representable π ( πβ 2 ) where
tabulate f = πβ2 ( f ( Fin 1 ) ) ( f ( Fin 2 ) )
{-# INLINE tabulate #-}
index p = \ case
Fin 1 -> _πβ2_x p
_ -> _πβ2_y p
{-# INLINE index #-}
instance Representable π ( πβ 3 ) where
tabulate f = πβ3 ( f ( Fin 1 ) ) ( f ( Fin 2 ) ) ( f ( Fin 3 ) )
{-# INLINE tabulate #-}
index p = \ case
Fin 1 -> _πβ3_x p
Fin 2 -> _πβ3_y p
_ -> _πβ3_z p
{-# INLINE index #-}
instance Representable π ( πβ 4 ) where
tabulate f = πβ4 ( f ( Fin 1 ) ) ( f ( Fin 2 ) ) ( f ( Fin 3 ) ) ( f ( Fin 4 ) )
{-# INLINE tabulate #-}
index p = \ case
Fin 1 -> _πβ4_x p
Fin 2 -> _πβ4_y p
Fin 3 -> _πβ4_z p
_ -> _πβ4_w p
{-# INLINE index #-}