data-sketches-core-0.2.0.0: src/DataSketches/Quantiles/RelativeErrorQuantile/Internal.hs
{-# LANGUAGE DeriveGeneric #-}
module DataSketches.Quantiles.RelativeErrorQuantile.Internal where
import Data.Primitive (MutVar, readMutVar)
import Data.Word
import qualified Data.Vector as Vector
import GHC.Generics
import System.Random.MWC (Gen)
import DataSketches.Core.Snapshot
import DataSketches.Quantiles.RelativeErrorQuantile.Types
import DataSketches.Core.Internal.URef (MutableFields, readField, writeField, modifyField)
import DataSketches.Quantiles.RelativeErrorQuantile.Internal.Auxiliary (ReqAuxiliary)
import DataSketches.Quantiles.RelativeErrorQuantile.Internal.Compactor (ReqCompactor)
import Control.DeepSeq (NFData, rnf)
import Control.Monad.Primitive (PrimMonad (PrimState))
import qualified DataSketches.Quantiles.RelativeErrorQuantile.Internal.Compactor as Compactor
import qualified DataSketches.Quantiles.RelativeErrorQuantile.Internal.DoubleBuffer as DoubleBuffer
import qualified DataSketches.Quantiles.RelativeErrorQuantile.Internal.Auxiliary as Auxiliary
import Control.Exception (Exception)
-- | Mutable sketch state packed into a single 'MutableByteArray'.
--
-- All 6 scalar fields occupy 48 bytes (6 × 8-byte slots), fitting entirely
-- within one 64-byte x86-64 cache line. On the insert hot path, totalN,
-- retainedItems, maxNominalCapacitiesSize, minValue, maxValue, and sumValue
-- are all read/written — a single cache line fetch covers all of them.
--
-- Layout (element index → field):
-- 0: totalN (Int, representing Word64)
-- 1: minValue (Double)
-- 2: maxValue (Double)
-- 3: sumValue (Double)
-- 4: retainedItems (Int)
-- 5: maxNominalCapacitiesSize (Int)
data ReqSketch s = ReqSketch
{ k :: !Word32
, rankAccuracySetting :: !RankAccuracy
, criterion :: !Criterion
, sketchRng :: {-# UNPACK #-} !(Gen s)
, sketchFields :: {-# UNPACK #-} !(MutableFields s)
, aux :: {-# UNPACK #-} !(MutVar s (Maybe ReqAuxiliary))
, compactors :: {-# UNPACK #-} !(MutVar s (Vector.Vector (ReqCompactor s)))
} deriving (Generic)
instance NFData (ReqSketch s) where
rnf !_ = ()
-- Field indices
fTotalN, fMinValue, fMaxValue, fSumValue, fRetainedItems, fMaxNomCapSize :: Int
fTotalN = 0
fMinValue = 1
fMaxValue = 2
fSumValue = 3
fRetainedItems = 4
fMaxNomCapSize = 5
sketchFieldBytes :: Int
sketchFieldBytes = 6 * 8
-- Typed accessors
getTotalN :: PrimMonad m => ReqSketch (PrimState m) -> m Word64
getTotalN sk = do
v <- readField (sketchFields sk) fTotalN
pure $! fromIntegral (v :: Int)
{-# INLINE getTotalN #-}
setTotalN :: PrimMonad m => ReqSketch (PrimState m) -> Word64 -> m ()
setTotalN sk v = writeField (sketchFields sk) fTotalN (fromIntegral v :: Int)
{-# INLINE setTotalN #-}
modifyTotalN :: PrimMonad m => ReqSketch (PrimState m) -> (Word64 -> Word64) -> m ()
modifyTotalN sk f = do
!v <- getTotalN sk
setTotalN sk $! f v
{-# INLINE modifyTotalN #-}
getMinValue :: PrimMonad m => ReqSketch (PrimState m) -> m Double
getMinValue sk = readField (sketchFields sk) fMinValue
{-# INLINE getMinValue #-}
setMinValue :: PrimMonad m => ReqSketch (PrimState m) -> Double -> m ()
setMinValue sk = writeField (sketchFields sk) fMinValue
{-# INLINE setMinValue #-}
getMaxValue :: PrimMonad m => ReqSketch (PrimState m) -> m Double
getMaxValue sk = readField (sketchFields sk) fMaxValue
{-# INLINE getMaxValue #-}
setMaxValue :: PrimMonad m => ReqSketch (PrimState m) -> Double -> m ()
setMaxValue sk = writeField (sketchFields sk) fMaxValue
{-# INLINE setMaxValue #-}
getSumValue :: PrimMonad m => ReqSketch (PrimState m) -> m Double
getSumValue sk = readField (sketchFields sk) fSumValue
{-# INLINE getSumValue #-}
modifySumValue :: PrimMonad m => ReqSketch (PrimState m) -> (Double -> Double) -> m ()
modifySumValue sk f = modifyField (sketchFields sk) fSumValue f
{-# INLINE modifySumValue #-}
getRetainedItems :: PrimMonad m => ReqSketch (PrimState m) -> m Int
getRetainedItems sk = readField (sketchFields sk) fRetainedItems
{-# INLINE getRetainedItems #-}
setRetainedItems :: PrimMonad m => ReqSketch (PrimState m) -> Int -> m ()
setRetainedItems sk = writeField (sketchFields sk) fRetainedItems
{-# INLINE setRetainedItems #-}
modifyRetainedItems :: PrimMonad m => ReqSketch (PrimState m) -> (Int -> Int) -> m ()
modifyRetainedItems sk = modifyField (sketchFields sk) fRetainedItems
{-# INLINE modifyRetainedItems #-}
getMaxNomCapSize :: PrimMonad m => ReqSketch (PrimState m) -> m Int
getMaxNomCapSize sk = readField (sketchFields sk) fMaxNomCapSize
{-# INLINE getMaxNomCapSize #-}
setMaxNomCapSize :: PrimMonad m => ReqSketch (PrimState m) -> Int -> m ()
setMaxNomCapSize sk = writeField (sketchFields sk) fMaxNomCapSize
{-# INLINE setMaxNomCapSize #-}
modifyMaxNomCapSize :: PrimMonad m => ReqSketch (PrimState m) -> (Int -> Int) -> m ()
modifyMaxNomCapSize sk = modifyField (sketchFields sk) fMaxNomCapSize
{-# INLINE modifyMaxNomCapSize #-}
data ReqSketchSnapshot = ReqSketchSnapshot
{ snapshotRankAccuracySetting :: !RankAccuracy
, snapshotCriterion :: !Criterion
, snapshotTotalN :: !Word64
, snapshotMinValue :: !Double
, snapshotMaxValue :: !Double
, snapshotRetainedItems :: !Int
, snapshotMaxNominalCapacitiesSize :: !Int
, snapshotCompactors :: !(Vector.Vector (Snapshot ReqCompactor))
} deriving Show
instance TakeSnapshot ReqSketch where
type Snapshot ReqSketch = ReqSketchSnapshot
takeSnapshot sk = do
tn <- getTotalN sk
mn <- getMinValue sk
mx <- getMaxValue sk
ri <- getRetainedItems sk
mc <- getMaxNomCapSize sk
cs <- readMutVar (compactors sk) >>= mapM takeSnapshot
pure $ ReqSketchSnapshot (rankAccuracySetting sk) (criterion sk) tn mn mx ri mc cs
getCompactors :: PrimMonad m => ReqSketch (PrimState m) -> m (Vector.Vector (ReqCompactor (PrimState m)))
getCompactors = readMutVar . compactors
{-# INLINE getCompactors #-}
computeTotalRetainedItems :: PrimMonad m => ReqSketch (PrimState m) -> m Int
computeTotalRetainedItems this = do
cs <- getCompactors this
Vector.foldM countBuffer 0 cs
where
countBuffer acc compactor = do
buff <- Compactor.getBuffer compactor
buffSize <- DoubleBuffer.getCount buff
pure $! buffSize + acc
retainedItemCount :: PrimMonad m => ReqSketch (PrimState m) -> m Int
retainedItemCount = getRetainedItems
{-# INLINE retainedItemCount #-}
count :: PrimMonad m => ReqSketch (PrimState m) -> m Word64
count = getTotalN
{-# INLINE count #-}
mkAuxiliaryFromReqSketch :: PrimMonad m => ReqSketch (PrimState m) -> m ReqAuxiliary
mkAuxiliaryFromReqSketch this = do
total <- count this
ri <- retainedItemCount this
cs <- getCompactors this
Auxiliary.mkAuxiliary (rankAccuracySetting this) total ri cs
data CumulativeDistributionInvariants
= CumulativeDistributionInvariantsSplitsAreEmpty
| CumulativeDistributionInvariantsSplitsAreNotFinite
| CumulativeDistributionInvariantsSplitsAreNotUniqueAndMontonicallyIncreasing
deriving (Show, Eq)
instance Exception CumulativeDistributionInvariants