{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns, DeriveDataTypeable, FlexibleContexts,
MultiParamTypeClasses, TypeFamilies #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Numeric.Sum (
Summation(..)
, sumVector
, kbn
) where
import Control.DeepSeq (NFData(..))
import Control.Monad
import Data.Data (Typeable, Data)
import Data.Vector.Generic (Vector(..), foldl')
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Foldable as F
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Unboxed as U
class Summation s where
zero :: s
add :: s -> Double -> s
sum :: (F.Foldable f) => (s -> Double) -> f Double -> Double
sum f = f . F.foldl' add zero
{-# INLINE sum #-}
instance Summation Double where
zero = 0
add = (+)
data KBNSum = KBNSum {-# UNPACK #-} !Double {-# UNPACK #-} !Double
deriving (Eq, Show, Typeable, Data)
newtype instance U.MVector s KBNSum = MV_KBNSum (U.MVector s (Double,Double))
newtype instance U.Vector KBNSum = V_KBNSum (U.Vector (Double,Double))
instance M.MVector U.MVector KBNSum where
{-# INLINE basicLength #-}
{-# INLINE basicUnsafeSlice #-}
{-# INLINE basicOverlaps #-}
{-# INLINE basicUnsafeNew #-}
{-# INLINE basicUnsafeReplicate #-}
{-# INLINE basicUnsafeRead #-}
{-# INLINE basicUnsafeWrite #-}
{-# INLINE basicClear #-}
{-# INLINE basicSet #-}
{-# INLINE basicUnsafeCopy #-}
{-# INLINE basicUnsafeGrow #-}
basicLength (MV_KBNSum v) = M.basicLength v
basicUnsafeSlice i n (MV_KBNSum v) = MV_KBNSum $ M.basicUnsafeSlice i n v
basicOverlaps (MV_KBNSum v1) (MV_KBNSum v2) = M.basicOverlaps v1 v2
basicUnsafeNew n = MV_KBNSum `liftM` M.basicUnsafeNew n
basicUnsafeReplicate n (KBNSum a b) = MV_KBNSum `liftM` M.basicUnsafeReplicate n (a,b)
basicUnsafeRead (MV_KBNSum v) i = uncurry KBNSum `liftM` M.basicUnsafeRead v i
basicUnsafeWrite (MV_KBNSum v) i (KBNSum a b) = M.basicUnsafeWrite v i (a,b)
basicClear (MV_KBNSum v) = M.basicClear v
basicSet (MV_KBNSum v) (KBNSum a b) = M.basicSet v (a,b)
basicUnsafeCopy (MV_KBNSum v1) (MV_KBNSum v2) = M.basicUnsafeCopy v1 v2
basicUnsafeMove (MV_KBNSum v1) (MV_KBNSum v2) = M.basicUnsafeMove v1 v2
basicUnsafeGrow (MV_KBNSum v) n = MV_KBNSum `liftM` M.basicUnsafeGrow v n
#if MIN_VERSION_vector(0,11,0)
{-# INLINE basicInitialize #-}
basicInitialize (MV_KBNSum v) = M.basicInitialize v
#endif
instance G.Vector U.Vector KBNSum where
{-# INLINE basicUnsafeFreeze #-}
{-# INLINE basicUnsafeThaw #-}
{-# INLINE basicLength #-}
{-# INLINE basicUnsafeSlice #-}
{-# INLINE basicUnsafeIndexM #-}
{-# INLINE elemseq #-}
basicUnsafeFreeze (MV_KBNSum v) = V_KBNSum `liftM` G.basicUnsafeFreeze v
basicUnsafeThaw (V_KBNSum v) = MV_KBNSum `liftM` G.basicUnsafeThaw v
basicLength (V_KBNSum v) = G.basicLength v
basicUnsafeSlice i n (V_KBNSum v) = V_KBNSum $ G.basicUnsafeSlice i n v
basicUnsafeIndexM (V_KBNSum v) i = uncurry KBNSum `liftM` G.basicUnsafeIndexM v i
basicUnsafeCopy (MV_KBNSum mv) (V_KBNSum v) = G.basicUnsafeCopy mv v
elemseq _ = seq
instance U.Unbox KBNSum
instance Summation KBNSum where
zero = KBNSum 0 0
add = kbnAdd
instance NFData KBNSum where
rnf !_ = ()
kbnAdd :: KBNSum -> Double -> KBNSum
kbnAdd (KBNSum sum c) x = KBNSum sum' c'
where c' | abs sum >= abs x = c + ((sum - sum') + x)
| otherwise = c + ((x - sum') + sum)
sum' = sum + x
kbn :: KBNSum -> Double
kbn (KBNSum sum c) = sum + c
sumVector :: (Vector v Double, Summation s) =>
(s -> Double) -> v Double -> Double
sumVector f = f . foldl' add zero
{-# INLINE sumVector #-}