{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UndecidableInstances #-} module Numeric.DataFrame.Internal.Backend.Family.DoubleX2 (DoubleX2 (..)) where import GHC.Base import Numeric.DataFrame.Internal.PrimArray import Numeric.PrimBytes import Numeric.ProductOrd import qualified Numeric.ProductOrd.NonTransitive as NonTransitive import qualified Numeric.ProductOrd.Partial as Partial data DoubleX2 = DoubleX2# Double# Double# -- | Since @Bounded@ is not implemented for floating point types, this instance -- has an unresolvable constraint. -- Nevetheless, it is good to have it here for nicer error messages. instance Bounded Double => Bounded DoubleX2 where maxBound = case maxBound of D# x -> DoubleX2# x x minBound = case minBound of D# x -> DoubleX2# x x instance Eq DoubleX2 where DoubleX2# a1 a2 == DoubleX2# b1 b2 = isTrue# ( (a1 ==## b1) `andI#` (a2 ==## b2) ) {-# INLINE (==) #-} DoubleX2# a1 a2 /= DoubleX2# b1 b2 = isTrue# ( (a1 /=## b1) `orI#` (a2 /=## b2) ) {-# INLINE (/=) #-} cmp' :: Double# -> Double# -> PartialOrdering cmp' a b | isTrue# (a >## b) = PGT | isTrue# (a <## b) = PLT | otherwise = PEQ instance ProductOrder DoubleX2 where cmp (DoubleX2# a1 a2) (DoubleX2# b1 b2) = cmp' a1 b1 <> cmp' a2 b2 {-# INLINE cmp #-} instance Ord (NonTransitive.ProductOrd DoubleX2) where NonTransitive.ProductOrd x > NonTransitive.ProductOrd y = cmp x y == PGT {-# INLINE (>) #-} NonTransitive.ProductOrd x < NonTransitive.ProductOrd y = cmp x y == PLT {-# INLINE (<) #-} (>=) (NonTransitive.ProductOrd (DoubleX2# a1 a2)) (NonTransitive.ProductOrd (DoubleX2# b1 b2)) = isTrue# ((a1 >=## b1) `andI#` (a2 >=## b2)) {-# INLINE (>=) #-} (<=) (NonTransitive.ProductOrd (DoubleX2# a1 a2)) (NonTransitive.ProductOrd (DoubleX2# b1 b2)) = isTrue# ((a1 <=## b1) `andI#` (a2 <=## b2)) {-# INLINE (<=) #-} compare (NonTransitive.ProductOrd a) (NonTransitive.ProductOrd b) = NonTransitive.toOrdering $ cmp a b {-# INLINE compare #-} min (NonTransitive.ProductOrd (DoubleX2# a1 a2)) (NonTransitive.ProductOrd (DoubleX2# b1 b2)) = NonTransitive.ProductOrd ( DoubleX2# (if isTrue# (a1 >## b1) then b1 else a1) (if isTrue# (a2 >## b2) then b2 else a2) ) {-# INLINE min #-} max (NonTransitive.ProductOrd (DoubleX2# a1 a2)) (NonTransitive.ProductOrd (DoubleX2# b1 b2)) = NonTransitive.ProductOrd ( DoubleX2# (if isTrue# (a1 <## b1) then b1 else a1) (if isTrue# (a2 <## b2) then b2 else a2) ) {-# INLINE max #-} instance Ord (Partial.ProductOrd DoubleX2) where Partial.ProductOrd x > Partial.ProductOrd y = cmp x y == PGT {-# INLINE (>) #-} Partial.ProductOrd x < Partial.ProductOrd y = cmp x y == PLT {-# INLINE (<) #-} (>=) (Partial.ProductOrd (DoubleX2# a1 a2)) (Partial.ProductOrd (DoubleX2# b1 b2)) = isTrue# ((a1 >=## b1) `andI#` (a2 >=## b2)) {-# INLINE (>=) #-} (<=) (Partial.ProductOrd (DoubleX2# a1 a2)) (Partial.ProductOrd (DoubleX2# b1 b2)) = isTrue# ((a1 <=## b1) `andI#` (a2 <=## b2)) {-# INLINE (<=) #-} compare (Partial.ProductOrd a) (Partial.ProductOrd b) = Partial.toOrdering $ cmp a b {-# INLINE compare #-} min (Partial.ProductOrd (DoubleX2# a1 a2)) (Partial.ProductOrd (DoubleX2# b1 b2)) = Partial.ProductOrd ( DoubleX2# (if isTrue# (a1 >## b1) then b1 else a1) (if isTrue# (a2 >## b2) then b2 else a2) ) {-# INLINE min #-} max (Partial.ProductOrd (DoubleX2# a1 a2)) (Partial.ProductOrd (DoubleX2# b1 b2)) = Partial.ProductOrd ( DoubleX2# (if isTrue# (a1 <## b1) then b1 else a1) (if isTrue# (a2 <## b2) then b2 else a2) ) {-# INLINE max #-} instance Ord DoubleX2 where DoubleX2# a1 a2 > DoubleX2# b1 b2 | isTrue# (a1 >## b1) = True | isTrue# (a1 <## b1) = False | isTrue# (a2 >## b2) = True | otherwise = False {-# INLINE (>) #-} DoubleX2# a1 a2 < DoubleX2# b1 b2 | isTrue# (a1 <## b1) = True | isTrue# (a1 >## b1) = False | isTrue# (a2 <## b2) = True | otherwise = False {-# INLINE (<) #-} DoubleX2# a1 a2 >= DoubleX2# b1 b2 | isTrue# (a1 <## b1) = False | isTrue# (a1 >## b1) = True | isTrue# (a2 <## b2) = False | otherwise = True {-# INLINE (>=) #-} DoubleX2# a1 a2 <= DoubleX2# b1 b2 | isTrue# (a1 >## b1) = False | isTrue# (a1 <## b1) = True | isTrue# (a2 >## b2) = False | otherwise = True {-# INLINE (<=) #-} compare (DoubleX2# a1 a2) (DoubleX2# b1 b2) | isTrue# (a1 >## b1) = GT | isTrue# (a1 <## b1) = LT | isTrue# (a2 >## b2) = GT | isTrue# (a2 <## b2) = LT | otherwise = EQ {-# INLINE compare #-} -- | element-wise operations for vectors instance Num DoubleX2 where DoubleX2# a1 a2 + DoubleX2# b1 b2 = DoubleX2# ((+##) a1 b1) ((+##) a2 b2) {-# INLINE (+) #-} DoubleX2# a1 a2 - DoubleX2# b1 b2 = DoubleX2# ((-##) a1 b1) ((-##) a2 b2) {-# INLINE (-) #-} DoubleX2# a1 a2 * DoubleX2# b1 b2 = DoubleX2# ((*##) a1 b1) ((*##) a2 b2) {-# INLINE (*) #-} negate (DoubleX2# a1 a2) = DoubleX2# (negateDouble# a1) (negateDouble# a2) {-# INLINE negate #-} abs (DoubleX2# a1 a2) = DoubleX2# (if isTrue# (a1 >=## 0.0##) then a1 else negateDouble# a1) (if isTrue# (a2 >=## 0.0##) then a2 else negateDouble# a2) {-# INLINE abs #-} signum (DoubleX2# a1 a2) = DoubleX2# (if isTrue# (a1 >## 0.0##) then 1.0## else if isTrue# (a1 <## 0.0##) then -1.0## else 0.0## ) (if isTrue# (a2 >## 0.0##) then 1.0## else if isTrue# (a2 <## 0.0##) then -1.0## else 0.0## ) {-# INLINE signum #-} fromInteger n = case fromInteger n of D# x -> DoubleX2# x x {-# INLINE fromInteger #-} instance Fractional DoubleX2 where DoubleX2# a1 a2 / DoubleX2# b1 b2 = DoubleX2# ((/##) a1 b1) ((/##) a2 b2) {-# INLINE (/) #-} recip (DoubleX2# a1 a2) = DoubleX2# ((/##) 1.0## a1) ((/##) 1.0## a2) {-# INLINE recip #-} fromRational r = case fromRational r of D# x -> DoubleX2# x x {-# INLINE fromRational #-} instance Floating DoubleX2 where pi = DoubleX2# 3.141592653589793238## 3.141592653589793238## {-# INLINE pi #-} exp (DoubleX2# a1 a2) = DoubleX2# (expDouble# a1) (expDouble# a2) {-# INLINE exp #-} log (DoubleX2# a1 a2) = DoubleX2# (logDouble# a1) (logDouble# a2) {-# INLINE log #-} sqrt (DoubleX2# a1 a2) = DoubleX2# (sqrtDouble# a1) (sqrtDouble# a2) {-# INLINE sqrt #-} sin (DoubleX2# a1 a2) = DoubleX2# (sinDouble# a1) (sinDouble# a2) {-# INLINE sin #-} cos (DoubleX2# a1 a2) = DoubleX2# (cosDouble# a1) (cosDouble# a2) {-# INLINE cos #-} tan (DoubleX2# a1 a2) = DoubleX2# (tanDouble# a1) (tanDouble# a2) {-# INLINE tan #-} asin (DoubleX2# a1 a2) = DoubleX2# (asinDouble# a1) (asinDouble# a2) {-# INLINE asin #-} acos (DoubleX2# a1 a2) = DoubleX2# (acosDouble# a1) (acosDouble# a2) {-# INLINE acos #-} atan (DoubleX2# a1 a2) = DoubleX2# (atanDouble# a1) (atanDouble# a2) {-# INLINE atan #-} sinh (DoubleX2# a1 a2) = DoubleX2# (sinhDouble# a1) (sinhDouble# a2) {-# INLINE sinh #-} cosh (DoubleX2# a1 a2) = DoubleX2# (coshDouble# a1) (coshDouble# a2) {-# INLINE cosh #-} tanh (DoubleX2# a1 a2) = DoubleX2# (tanhDouble# a1) (tanhDouble# a2) {-# INLINE tanh #-} DoubleX2# a1 a2 ** DoubleX2# b1 b2 = DoubleX2# ((**##) a1 b1) ((**##) a2 b2) {-# INLINE (**) #-} logBase x y = log y / log x {-# INLINE logBase #-} asinh x = log (x + sqrt (1.0+x*x)) {-# INLINE asinh #-} acosh x = log (x + (x+1.0) * sqrt ((x-1.0)/(x+1.0))) {-# INLINE acosh #-} atanh x = 0.5 * log ((1.0+x) / (1.0-x)) {-# INLINE atanh #-} -- offset in bytes is S times bigger than offset in prim elements, -- when S is power of two, this is equal to shift #define BOFF_TO_PRIMOFF(off) uncheckedIShiftRL# off 3# #define ELEM_N 2 instance PrimBytes DoubleX2 where getBytes (DoubleX2# a1 a2) = case runRW# ( \s0 -> case newByteArray# (byteSize @DoubleX2 undefined) s0 of (# s1, marr #) -> case writeDoubleArray# marr 0# a1 s1 of s2 -> case writeDoubleArray# marr 1# a2 s2 of s3 -> unsafeFreezeByteArray# marr s3 ) of (# _, a #) -> a {-# INLINE getBytes #-} fromBytes off arr | i <- BOFF_TO_PRIMOFF(off) = DoubleX2# (indexDoubleArray# arr i) (indexDoubleArray# arr (i +# 1#)) {-# INLINE fromBytes #-} readBytes mba off s0 | i <- BOFF_TO_PRIMOFF(off) = case readDoubleArray# mba i s0 of (# s1, a1 #) -> case readDoubleArray# mba (i +# 1#) s1 of (# s2, a2 #) -> (# s2, DoubleX2# a1 a2 #) {-# INLINE readBytes #-} writeBytes mba off (DoubleX2# a1 a2) s | i <- BOFF_TO_PRIMOFF(off) = writeDoubleArray# mba (i +# 1#) a2 ( writeDoubleArray# mba i a1 s ) {-# INLINE writeBytes #-} readAddr addr s0 = case readDoubleOffAddr# addr 0# s0 of (# s1, a1 #) -> case readDoubleOffAddr# addr 1# s1 of (# s2, a2 #) -> (# s2, DoubleX2# a1 a2 #) {-# INLINE readAddr #-} writeAddr (DoubleX2# a1 a2) addr s = writeDoubleOffAddr# addr 1# a2 ( writeDoubleOffAddr# addr 0# a1 s ) {-# INLINE writeAddr #-} byteSize _ = byteSize @Double undefined *# ELEM_N# {-# INLINE byteSize #-} byteAlign _ = byteAlign @Double undefined {-# INLINE byteAlign #-} byteOffset _ = 0# {-# INLINE byteOffset #-} byteFieldOffset _ _ = negateInt# 1# {-# INLINE byteFieldOffset #-} indexArray ba off | i <- off *# ELEM_N# = DoubleX2# (indexDoubleArray# ba i) (indexDoubleArray# ba (i +# 1#)) {-# INLINE indexArray #-} readArray mba off s0 | i <- off *# ELEM_N# = case readDoubleArray# mba i s0 of (# s1, a1 #) -> case readDoubleArray# mba (i +# 1#) s1 of (# s2, a2 #) -> (# s2, DoubleX2# a1 a2 #) {-# INLINE readArray #-} writeArray mba off (DoubleX2# a1 a2) s | i <- off *# ELEM_N# = writeDoubleArray# mba (i +# 1#) a2 ( writeDoubleArray# mba i a1 s ) {-# INLINE writeArray #-} instance PrimArray Double DoubleX2 where broadcast# (D# x) = DoubleX2# x x {-# INLINE broadcast# #-} ix# 0# (DoubleX2# a1 _) = D# a1 ix# 1# (DoubleX2# _ a2) = D# a2 ix# _ _ = undefined {-# INLINE ix# #-} gen# _ f s0 = case f s0 of (# s1, D# a1 #) -> case f s1 of (# s2, D# a2 #) -> (# s2, DoubleX2# a1 a2 #) upd# _ 0# (D# q) (DoubleX2# _ y) = DoubleX2# q y upd# _ 1# (D# q) (DoubleX2# x _) = DoubleX2# x q upd# _ _ _ x = x {-# INLINE upd# #-} withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x) {-# INLINE withArrayContent# #-} offsetElems _ = 0# {-# INLINE offsetElems #-} uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1]) {-# INLINE uniqueOrCumulDims #-} fromElems# _ off ba = DoubleX2# (indexDoubleArray# ba off) (indexDoubleArray# ba (off +# 1#)) {-# INLINE fromElems# #-}