{-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Numeric.DataFrame.Type -- Copyright : (c) Artem Chirkin -- License : BSD3 -- -- Maintainer : chirkin@arch.ethz.ch -- -- ----------------------------------------------------------------------------- module Numeric.DataFrame.Type ( -- * Data types DataFrame (..) -- * Bring type classes into scope , NumericFrame -- * Utility type families and constraints , FPFRame, IntegralFrame, NumericVariantFrame, CommonOpFrame ) where #include "MachDeps.h" import Data.Int (Int16, Int32, Int64, Int8) import Data.Word (Word16, Word32, Word64, Word8) import Foreign.Storable (Storable (..)) import GHC.Exts (Int (..), Ptr (..), Float#, Double#, Int#, Word# #ifndef ghcjs_HOST_OS #if WORD_SIZE_IN_BITS < 64 , Int64#, Word64# #endif #endif ) import GHC.Prim (copyAddrToByteArray#, copyByteArrayToAddr#, newByteArray#, plusAddr#, quotInt#, unsafeFreezeByteArray#, (*#)) import GHC.Types (Constraint, IO (..), Type, RuntimeRep (..)) import Numeric.Array.ElementWise import Numeric.Array.Family import Numeric.Commons import Numeric.Dimensions -- | Keep data in a primitive data frame -- and maintain information about Dimensions in the type-system data family DataFrame (t :: Type) (xs :: [k]) -- | Completely fixed at compile time newtype instance Dimensions ns => DataFrame t (ns :: [Nat]) = KnownDataFrame { _getDF :: Array t ns } -- | Partially known at compile time data instance DataFrame t (xns :: [XNat]) = forall (ns :: [Nat]) . ( FixedDim xns ns ~ ns , FixedXDim xns ns ~ xns , NumericFrame t ns ) => SomeDataFrame (DataFrame t ns) -- | Allow all numeric operations depending on element type type NumericFrame t ds = (CommonOpFrame t ds, NumericVariantFrame t ds) -- | Allow all common operations on data frames type CommonOpFrame t ds = ( Show (DataFrame t ds) , Eq (DataFrame t ds) , Ord (DataFrame t ds) , Num (DataFrame t ds) , ElementWise (Idx ds) t (DataFrame t ds) , PrimBytes (DataFrame t ds) , ArrayInstanceInference t ds , KnownDims ds , FiniteList ds , Dimensions ds ) -- | Allow floating-point operations on data frames type FPFRame t ds = ( Fractional (DataFrame t ds) , Floating (DataFrame t ds) ) -- | Allow some integer-like operations on data frames type IntegralFrame t (ds :: [Nat]) = Bounded (DataFrame t ds) type family NumericVariantFrame t ds :: Constraint where NumericVariantFrame Float ds = FPFRame Float ds NumericVariantFrame Double ds = FPFRame Double ds NumericVariantFrame Int ds = IntegralFrame Int ds NumericVariantFrame Int8 ds = IntegralFrame Int8 ds NumericVariantFrame Int16 ds = IntegralFrame Int16 ds NumericVariantFrame Int32 ds = IntegralFrame Int32 ds NumericVariantFrame Int64 ds = IntegralFrame Int64 ds NumericVariantFrame Word ds = IntegralFrame Word ds NumericVariantFrame Word8 ds = IntegralFrame Word8 ds NumericVariantFrame Word16 ds = IntegralFrame Word16 ds NumericVariantFrame Word32 ds = IntegralFrame Word32 ds NumericVariantFrame Word64 ds = IntegralFrame Word64 ds NumericVariantFrame _ _ = () instance ( Show (Array t ds) , Dimensions ds ) => Show (DataFrame t ds) where show (KnownDataFrame arr) = unlines [ "DF [" ++ drop 4 (show $ dim @ds) ++ "]:" , show arr ] deriving instance Bounded (Array t ds) => Bounded (DataFrame t ds) deriving instance Enum (Array t ds) => Enum (DataFrame t ds) deriving instance Eq (Array t ds) => Eq (DataFrame t ds) deriving instance Integral (Array t ds) => Integral (DataFrame t ds) deriving instance Num (Array t ds) => Num (DataFrame t ds) deriving instance Fractional (Array t ds) => Fractional (DataFrame t ds) deriving instance Floating (Array t ds) => Floating (DataFrame t ds) deriving instance Ord (Array t ds) => Ord (DataFrame t ds) deriving instance ( Read (Array t ds), Dimensions ds ) => Read (DataFrame t ds) deriving instance Real (Array t ds) => Real (DataFrame t ds) deriving instance RealFrac (Array t ds) => RealFrac (DataFrame t ds) deriving instance RealFloat (Array t ds) => RealFloat (DataFrame t ds) instance ( Dimensions ds , ElementWise (Idx ds) t (Array t ds) ) => ElementWise (Idx ds) t (DataFrame t ds) where indexOffset# = indexOffset# . _getDF {-# INLINE indexOffset# #-} (!) = (!) . _getDF {-# INLINE (!) #-} ewmap f = KnownDataFrame . ewmap f . _getDF {-# INLINE ewmap #-} ewgen = KnownDataFrame . ewgen {-# INLINE ewgen #-} ewgenA = fmap KnownDataFrame . ewgenA {-# INLINE ewgenA #-} ewfoldl f x0 = ewfoldl f x0 . _getDF {-# INLINE ewfoldl #-} ewfoldr f x0 = ewfoldr f x0 . _getDF {-# INLINE ewfoldr #-} elementWise f = fmap KnownDataFrame . elementWise f . _getDF {-# INLINE elementWise #-} indexWise f = fmap KnownDataFrame . indexWise f . _getDF {-# INLINE indexWise #-} broadcast = KnownDataFrame . broadcast {-# INLINE broadcast #-} update i x = KnownDataFrame . update i x . _getDF {-# INLINE update #-} instance PrimBytes (DataFrame t ds) => Storable (DataFrame t ds) where sizeOf x = I# (byteSize x) alignment x = I# (byteAlign x) peekElemOff ptr (I# offset) = peekByteOff ptr (I# (offset *# byteSize (undefined :: DataFrame t ds))) pokeElemOff ptr (I# offset) = pokeByteOff ptr (I# (offset *# byteSize (undefined :: DataFrame t ds))) peekByteOff (Ptr addr) (I# offset) = IO $ \s0 -> case newByteArray# bsize s0 of (# s1, marr #) -> case copyAddrToByteArray# (addr `plusAddr#` offset) marr 0# bsize s1 of s2 -> case unsafeFreezeByteArray# marr s2 of (# s3, arr #) -> (# s3, fromBytes (# 0#, bsize `quotInt#` ebsize, arr #) #) where bsize = byteSize (undefined :: DataFrame t ds) ebsize = elementByteSize (undefined :: DataFrame t ds) pokeByteOff (Ptr addr) (I# offset) x = IO $ \s0 -> case copyByteArrayToAddr# xbytes xboff (addr `plusAddr#` offset) bsize s0 of s2 -> (# s2, () #) where !(# elOff, elNum, xbytes #) = toBytes x bsize = elementByteSize x *# elNum xboff = elementByteSize x *# elOff peek ptr = peekByteOff ptr 0 poke ptr = pokeByteOff ptr 0 type instance ElemRep (DataFrame t xs) = ElemRep (Array t xs) type instance ElemPrim (DataFrame Float ds) = Float# type instance ElemPrim (DataFrame Double ds) = Double# type instance ElemPrim (DataFrame Int ds) = Int# type instance ElemPrim (DataFrame Int8 ds) = Int# type instance ElemPrim (DataFrame Int16 ds) = Int# type instance ElemPrim (DataFrame Int32 ds) = Int# #ifndef ghcjs_HOST_OS #if WORD_SIZE_IN_BITS < 64 type instance ElemPrim (DataFrame Int64 ds) = Int64# #else type instance ElemPrim (DataFrame Int64 ds) = Int# #endif #endif type instance ElemPrim (DataFrame Word ds) = Word# type instance ElemPrim (DataFrame Word8 ds) = Word# type instance ElemPrim (DataFrame Word16 ds) = Word# type instance ElemPrim (DataFrame Word32 ds) = Word# #ifdef ghcjs_HOST_OS type instance ElemPrim (DataFrame Word8Clamped ds) = Int# #else #if WORD_SIZE_IN_BITS < 64 type instance ElemPrim (DataFrame Word64 ds) = Word64# #else type instance ElemPrim (DataFrame Word64 ds) = Word# #endif #endif deriving instance ( PrimBytes (Array Float ds) , ElemPrim (Array Float ds) ~ Float# , ElemRep (Array Float ds) ~ 'FloatRep) => PrimBytes (DataFrame Float ds) deriving instance ( PrimBytes (Array Double ds) , ElemPrim (Array Double ds) ~ Double# , ElemRep (Array Double ds) ~ 'DoubleRep) => PrimBytes (DataFrame Double ds) deriving instance ( PrimBytes (Array Int ds) , ElemPrim (Array Int ds) ~ Int# , ElemRep (Array Int ds) ~ 'IntRep) => PrimBytes (DataFrame Int ds) deriving instance ( PrimBytes (Array Int8 ds) , ElemPrim (Array Int8 ds) ~ Int# , ElemRep (Array Int8 ds) ~ 'IntRep) => PrimBytes (DataFrame Int8 ds) deriving instance ( PrimBytes (Array Int16 ds) , ElemPrim (Array Int16 ds) ~ Int# , ElemRep (Array Int16 ds) ~ 'IntRep) => PrimBytes (DataFrame Int16 ds) deriving instance ( PrimBytes (Array Int32 ds) , ElemPrim (Array Int32 ds) ~ Int# , ElemRep (Array Int32 ds) ~ 'IntRep) => PrimBytes (DataFrame Int32 ds) #ifndef ghcjs_HOST_OS deriving instance ( PrimBytes (Array Int64 ds) #if WORD_SIZE_IN_BITS < 64 , ElemPrim (Array Int64 ds) ~ Int64# , ElemRep (Array Int64 ds) ~ 'Int64Rep #else , ElemPrim (Array Int64 ds) ~ Int# , ElemRep (Array Int64 ds) ~ 'IntRep #endif ) => PrimBytes (DataFrame Int64 ds) #endif deriving instance ( PrimBytes (Array Word ds) , ElemPrim (Array Word ds) ~ Word# , ElemRep (Array Word ds) ~ 'WordRep) => PrimBytes (DataFrame Word ds) deriving instance ( PrimBytes (Array Word8 ds) , ElemPrim (Array Word8 ds) ~ Word# , ElemRep (Array Word8 ds) ~ 'WordRep) => PrimBytes (DataFrame Word8 ds) deriving instance ( PrimBytes (Array Word16 ds) , ElemPrim (Array Word16 ds) ~ Word# , ElemRep (Array Word16 ds) ~ 'WordRep) => PrimBytes (DataFrame Word16 ds) deriving instance ( PrimBytes (Array Word32 ds) , ElemPrim (Array Word32 ds) ~ Word# , ElemRep (Array Word32 ds) ~ 'WordRep) => PrimBytes (DataFrame Word32 ds) #ifdef ghcjs_HOST_OS deriving instance ( PrimBytes (Array Word8Clamped ds) , ElemPrim (Array Word8Clamped ds) ~ Int# , ElemRep (Array Word8Clamped ds) ~ 'IntRep) => PrimBytes (DataFrame Word8Clamped ds) #else deriving instance ( PrimBytes (Array Word64 ds) #if WORD_SIZE_IN_BITS < 64 , ElemPrim (Array Word64 ds) ~ Word64# , ElemRep (Array Word64 ds) ~ 'Word64Rep #else , ElemPrim (Array Word64 ds) ~ Word# , ElemRep (Array Word64 ds) ~ 'WordRep #endif ) => PrimBytes (DataFrame Word64 ds) #endif instance Eq (DataFrame t (ds :: [XNat])) where SomeDataFrame (a :: DataFrame t nsa) == SomeDataFrame (b :: DataFrame t nsb) = case sameDim (dim @nsa) (dim @nsb) of Just Evidence -> a == b Nothing -> False instance Show (DataFrame t (ds :: [XNat])) where show (SomeDataFrame arr) = show arr _suppressHlintUnboxedTuplesWarning :: () -> (# (), () #) _suppressHlintUnboxedTuplesWarning = undefined