packages feed

data-sketches-core-0.2.0.0: src/DataSketches/Quantiles/RelativeErrorQuantile/CInternal.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module DataSketches.Quantiles.RelativeErrorQuantile.CInternal
  ( CReqSketch
  , mkCReqSketch
  , creqInsert
  , creqInsertBatch
  , creqMerge
  , creqCount
  , creqIsEmpty
  , creqMin
  , creqMax
  , creqSum
  , creqRetained
  , creqK
  , creqRankAccuracy
  , creqNumLevels
  , creqCriterion
  , creqSetCriterion
  , creqCountWithCriterion
  , creqRank
  , creqQuantile
  ) where

import Control.DeepSeq (NFData(..))
import Control.Monad (unless)
import Control.Monad.Primitive
import Data.Word
import qualified Data.Vector.Storable as VS
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr

newtype CReqSketch s = CReqSketch (ForeignPtr ())

instance NFData (CReqSketch s) where rnf !_ = ()

foreign import ccall unsafe "req_new"             c_req_new             :: Word32 -> CInt -> Word64 -> IO (Ptr ())
foreign import ccall unsafe "&req_free"           c_req_free            :: FunPtr (Ptr () -> IO ())
foreign import ccall unsafe "req_insert"           c_req_insert          :: Ptr () -> CDouble -> IO ()
foreign import ccall unsafe "req_insert_batch"     c_req_insert_batch    :: Ptr () -> Ptr CDouble -> CInt -> IO ()
foreign import ccall unsafe "req_merge"           c_req_merge           :: Ptr () -> Ptr () -> IO ()
foreign import ccall unsafe "req_count"           c_req_count           :: Ptr () -> IO Word64
foreign import ccall unsafe "req_is_empty"        c_req_is_empty        :: Ptr () -> IO CInt
foreign import ccall unsafe "req_min"             c_req_min             :: Ptr () -> IO CDouble
foreign import ccall unsafe "req_max"             c_req_max             :: Ptr () -> IO CDouble
foreign import ccall unsafe "req_sum"             c_req_sum             :: Ptr () -> IO CDouble
foreign import ccall unsafe "req_retained"        c_req_retained        :: Ptr () -> IO CInt
foreign import ccall unsafe "req_k"               c_req_k               :: Ptr () -> IO Word32
foreign import ccall unsafe "req_rank_accuracy"   c_req_rank_accuracy   :: Ptr () -> IO CInt
foreign import ccall unsafe "req_num_levels"      c_req_num_levels      :: Ptr () -> IO CInt
foreign import ccall unsafe "req_criterion"       c_req_criterion       :: Ptr () -> IO CInt
foreign import ccall unsafe "req_set_criterion"   c_req_set_criterion   :: Ptr () -> CInt -> IO ()
foreign import ccall unsafe "req_count_with_criterion" c_req_cwc        :: Ptr () -> CDouble -> IO Word64
foreign import ccall unsafe "req_rank"            c_req_rank            :: Ptr () -> CDouble -> IO CDouble
foreign import ccall unsafe "req_quantile"        c_req_quantile        :: Ptr () -> CDouble -> IO CDouble

withSketch :: CReqSketch s -> (Ptr () -> IO a) -> IO a
withSketch (CReqSketch fp) = withForeignPtr fp
{-# INLINE withSketch #-}

mkCReqSketch :: PrimMonad m => Word32 -> Int -> m (CReqSketch (PrimState m))
mkCReqSketch k ra = unsafePrimToPrim $ do
  unless (even k && k >= 4 && k <= 1024) $
    error "k must be divisible by 2, and satisfy 4 <= k <= 1024"
  ptr <- c_req_new k (fromIntegral ra) 12345
  fp <- newForeignPtr c_req_free ptr
  pure (CReqSketch fp)

creqInsert :: PrimMonad m => CReqSketch (PrimState m) -> Double -> m ()
creqInsert sk val = unsafePrimToPrim $ withSketch sk $ \p -> c_req_insert p (realToFrac val)
{-# INLINE creqInsert #-}

creqInsertBatch :: PrimMonad m => CReqSketch (PrimState m) -> VS.Vector Double -> m ()
creqInsertBatch sk vals = unsafePrimToPrim $ withSketch sk $ \p ->
  VS.unsafeWith (VS.unsafeCast vals) $ \arr ->
    c_req_insert_batch p arr (fromIntegral $ VS.length vals)

creqMerge :: PrimMonad m => CReqSketch (PrimState m) -> CReqSketch (PrimState m) -> m ()
creqMerge dst src = unsafePrimToPrim $
  withSketch dst $ \pd -> withSketch src $ \ps -> c_req_merge pd ps

creqCount :: PrimMonad m => CReqSketch (PrimState m) -> m Word64
creqCount sk = unsafePrimToPrim $ withSketch sk c_req_count
{-# INLINE creqCount #-}

creqIsEmpty :: PrimMonad m => CReqSketch (PrimState m) -> m Bool
creqIsEmpty sk = unsafePrimToPrim $ withSketch sk $ fmap (/= 0) . c_req_is_empty
{-# INLINE creqIsEmpty #-}

creqMin :: PrimMonad m => CReqSketch (PrimState m) -> m Double
creqMin sk = unsafePrimToPrim $ withSketch sk $ fmap realToFrac . c_req_min
{-# INLINE creqMin #-}

creqMax :: PrimMonad m => CReqSketch (PrimState m) -> m Double
creqMax sk = unsafePrimToPrim $ withSketch sk $ fmap realToFrac . c_req_max
{-# INLINE creqMax #-}

creqSum :: PrimMonad m => CReqSketch (PrimState m) -> m Double
creqSum sk = unsafePrimToPrim $ withSketch sk $ fmap realToFrac . c_req_sum
{-# INLINE creqSum #-}

creqRetained :: PrimMonad m => CReqSketch (PrimState m) -> m Int
creqRetained sk = unsafePrimToPrim $ withSketch sk $ fmap fromIntegral . c_req_retained
{-# INLINE creqRetained #-}

creqK :: PrimMonad m => CReqSketch (PrimState m) -> m Word32
creqK sk = unsafePrimToPrim $ withSketch sk c_req_k

creqRankAccuracy :: PrimMonad m => CReqSketch (PrimState m) -> m Int
creqRankAccuracy sk = unsafePrimToPrim $ withSketch sk $ fmap fromIntegral . c_req_rank_accuracy

creqNumLevels :: PrimMonad m => CReqSketch (PrimState m) -> m Int
creqNumLevels sk = unsafePrimToPrim $ withSketch sk $ fmap fromIntegral . c_req_num_levels

creqCriterion :: PrimMonad m => CReqSketch (PrimState m) -> m Int
creqCriterion sk = unsafePrimToPrim $ withSketch sk $ fmap fromIntegral . c_req_criterion

creqSetCriterion :: PrimMonad m => CReqSketch (PrimState m) -> Int -> m ()
creqSetCriterion sk c = unsafePrimToPrim $ withSketch sk $ \p -> c_req_set_criterion p (fromIntegral c)

creqCountWithCriterion :: PrimMonad m => CReqSketch (PrimState m) -> Double -> m Word64
creqCountWithCriterion sk val = unsafePrimToPrim $ withSketch sk $ \p -> c_req_cwc p (realToFrac val)

creqRank :: PrimMonad m => CReqSketch (PrimState m) -> Double -> m Double
creqRank sk val = unsafePrimToPrim $ withSketch sk $ \p -> realToFrac <$> c_req_rank p (realToFrac val)
{-# INLINE creqRank #-}

creqQuantile :: PrimMonad m => CReqSketch (PrimState m) -> Double -> m Double
creqQuantile sk nr = unsafePrimToPrim $ withSketch sk $ \p -> realToFrac <$> c_req_quantile p (realToFrac nr)
{-# INLINE creqQuantile #-}