fixed-vector-2.1.0.0: Data/Vector/Fixed/Unboxed.hs
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Adaptive array type which picks vector representation from type of
-- element of array. For example arrays of @Double@ are backed by
-- @ByteArray@, arrays of @Bool@ are represented as bit-vector, arrays
-- of tuples are products of arrays. 'Unbox' type class is used to
-- describe representation of an array.
module Data.Vector.Fixed.Unboxed(
-- * Data type
Vec(..)
, Vec1
, Vec2
, Vec3
, Vec4
, Vec5
-- * Type classes & derivation
, Unbox
, UnboxViaPrim
-- * Concrete representations
, BitVec
, T2(..)
, T3(..)
) where
import Control.Applicative (Const(..))
import Control.DeepSeq (NFData(..))
import Data.Bits
import Data.Complex
import Data.Coerce
import Data.Data
import Data.Kind
import Data.Functor.Identity (Identity(..))
import Data.Int (Int8, Int16, Int32, Int64 )
import Data.Monoid (Monoid(..),Dual(..),Sum(..),Product(..),All(..),Any(..))
import Data.Semigroup (Semigroup(..))
import Data.Ord (Down(..))
import Data.Word (Word,Word8,Word16,Word32,Word64)
import Data.Primitive.Types (Prim)
import Foreign.Storable (Storable)
import GHC.TypeLits
import GHC.Exts (Proxy#, proxy#)
import Prelude ( Show(..),Eq(..),Ord(..),Num(..),Applicative(..)
, Int,Double,Float,Char,Bool(..),($),id)
import Data.Vector.Fixed (Dim,Vector(..),ViaFixed(..))
import Data.Vector.Fixed qualified as F
import Data.Vector.Fixed.Compat
import Data.Vector.Fixed.Cont qualified as C
import Data.Vector.Fixed.Mono qualified as FM
import Data.Vector.Fixed.Cont (Peano,Arity,ArityPeano,Fun(..),curryFirst)
import Data.Vector.Fixed.Primitive qualified as P
----------------------------------------------------------------
-- Data type
----------------------------------------------------------------
-- | Adaptive array of dimension @n@ and containing elements of type
-- @a@.
newtype Vec (n :: Nat) a = Vec { getVecRepr :: VecRepr n a (EltRepr a) }
type Vec1 = Vec 1
type Vec2 = Vec 2
type Vec3 = Vec 3
type Vec4 = Vec 4
type Vec5 = Vec 5
-- | Type class which selects internal representation of unboxed vector.
--
-- Crucial design constraint is this type class must be
-- GND-derivable. And this rules out anything mentioning 'Fun',
-- since all it's parameters has @nominal@ role. Thus 'Vector' is
-- not GND-derivable and we have to take somewhat roundabout
-- approach.
class ( Dim (VecRepr n a) ~ Peano n
, Vector (VecRepr n a) (EltRepr a)
) => Unbox n a where
-- | Vector data type to use as a representation.
type VecRepr n a :: Type -> Type
-- | Element data type to use as a representation.
type EltRepr a :: Type
-- | Convert element to its representation
toEltRepr :: Proxy# n -> a -> EltRepr a
-- | Convert element from its representation
fromEltRepr :: Proxy# n -> EltRepr a -> a
type instance Dim (Vec n) = Peano n
type instance Dim (Vec n a) = Peano n
instance (Arity n, Unbox n a) => Vector (Vec n) a where
inspect (Vec v) f
= inspect v
(C.dimapFun (fromEltRepr (proxy# @n)) id f)
construct
= C.dimapFun (toEltRepr (proxy# @n)) Vec
(construct @(VecRepr n a) @(EltRepr a))
{-# INLINE inspect #-}
{-# INLINE construct #-}
instance (Arity n, Unbox n a) => FM.Prod a (Vec n a) where
construct = construct
inspect = inspect
{-# INLINE construct #-}
{-# INLINE inspect #-}
instance (Arity n, Unbox n a) => FM.Vector a (Vec n a)
----------------------------------------------------------------
-- Generic instances
----------------------------------------------------------------
deriving via ViaFixed (Vec n) a instance (Unbox n a, Show a) => Show (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, Eq a) => Eq (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, Ord a) => Ord (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, NFData a) => NFData (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, Semigroup a) => Semigroup (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, Monoid a) => Monoid (Vec n a)
deriving via ViaFixed (Vec n) a instance (Unbox n a, Storable a) => Storable (Vec n a)
-- | @since 2.0.1.0
deriving via ViaFixed (Vec n) a instance (Unbox n a, Prim a) => Prim (Vec n a)
instance (Typeable n, Unbox n a, Data a) => Data (Vec n a) where
gfoldl = C.gfoldl
gunfold = C.gunfold
toConstr _ = con_Vec
dataTypeOf _ = ty_Vec
ty_Vec :: DataType
ty_Vec = mkDataType "Data.Vector.Fixed.Unboxed.Vec" [con_Vec]
con_Vec :: Constr
con_Vec = mkConstr ty_Vec "Vec" [] Prefix
----------------------------------------------------------------
-- Data instances
----------------------------------------------------------------
instance F.Arity n => Unbox n () where
type VecRepr n () = VecUnit n
type EltRepr () = ()
toEltRepr _ = id
fromEltRepr _ = id
{-# INLINE toEltRepr #-}
{-# INLINE fromEltRepr #-}
data VecUnit (n :: Nat) a = VecUnit
type instance Dim (VecUnit n) = Peano n
type instance Dim (VecUnit n a) = Peano n
instance F.Arity n => Vector (VecUnit n) () where
inspect _ fun
= C.runContVec fun
$ C.apply (\Proxy -> ((),Proxy)) Proxy
construct
= pure VecUnit
{-# INLINE inspect #-}
{-# INLINE construct #-}
----------------------------------------------------------------
-- Boolean
-- | Bit vector represented as 64-bit word. This puts upper limit on
-- length of vector. It's not a big problem. 64-element will strain
-- GHC quite a bit.
data BitVec (n :: Nat) a = BitVec Word64
type instance Dim (BitVec n) = Peano n
type instance Dim (BitVec n a) = Peano n
instance (n <= 64, Arity n, a ~ Bool) => Vector (BitVec n) a where
inspect (BitVec w) = inspect (C.generate (testBit w))
construct = C.accum
(\(Const (i,w)) -> \case
True -> Const (i+1, setBit w i)
False -> Const (i+1, w))
(\(Const (_,w)) -> BitVec w)
(Const (0,0))
instance (n <= 64, Arity n) => Unbox n Bool where
type VecRepr n Bool = BitVec n
type EltRepr Bool = Bool
toEltRepr _ = id
fromEltRepr _ = id
{-# INLINE toEltRepr #-}
{-# INLINE fromEltRepr #-}
----------------------------------------------------------------
-- Primitive wrappers
----------------------------------------------------------------
-- | Wrapper for deriving 'Unbox' for data types which are instances
-- of 'P.Prim' type class:
--
-- > deriving via UnboxViaPrim Word instance (C.Arity n) => Unbox n Word
newtype UnboxViaPrim a = UnboxViaPrim a
deriving newtype P.Prim
instance (C.Arity n, P.Prim a) => Unbox n (UnboxViaPrim a) where
type VecRepr n (UnboxViaPrim a) = P.Vec n
type EltRepr (UnboxViaPrim a) = a
toEltRepr _ = coerce
fromEltRepr _ = coerce
deriving via UnboxViaPrim Int instance (C.Arity n) => Unbox n Int
deriving via UnboxViaPrim Int8 instance (C.Arity n) => Unbox n Int8
deriving via UnboxViaPrim Int16 instance (C.Arity n) => Unbox n Int16
deriving via UnboxViaPrim Int32 instance (C.Arity n) => Unbox n Int32
deriving via UnboxViaPrim Int64 instance (C.Arity n) => Unbox n Int64
deriving via UnboxViaPrim Word instance (C.Arity n) => Unbox n Word
deriving via UnboxViaPrim Word8 instance (C.Arity n) => Unbox n Word8
deriving via UnboxViaPrim Word16 instance (C.Arity n) => Unbox n Word16
deriving via UnboxViaPrim Word32 instance (C.Arity n) => Unbox n Word32
deriving via UnboxViaPrim Word64 instance (C.Arity n) => Unbox n Word64
deriving via UnboxViaPrim Char instance (C.Arity n) => Unbox n Char
deriving via UnboxViaPrim Float instance (C.Arity n) => Unbox n Float
deriving via UnboxViaPrim Double instance (C.Arity n) => Unbox n Double
----------------------------------------------------------------
-- Newtypes
----------------------------------------------------------------
deriving newtype instance (Unbox n a) => Unbox n (Const a b)
deriving newtype instance (Unbox n a) => Unbox n (Identity a)
deriving newtype instance (Unbox n a) => Unbox n (Down a)
deriving newtype instance (Unbox n a) => Unbox n (Dual a)
deriving newtype instance (Unbox n a) => Unbox n (Sum a)
deriving newtype instance (Unbox n a) => Unbox n (Product a)
deriving newtype instance (n <= 64, Arity n) => Unbox n All
deriving newtype instance (n <= 64, Arity n) => Unbox n Any
----------------------------------------------------------------
-- Tuples
----------------------------------------------------------------
-- | Representation for vector of 2-tuple as two vectors.
data T2 n a b x = T2 !(Vec n a) !(Vec n b)
type instance Dim (T2 n a b) = Peano n
type instance Dim (T2 n a b x) = Peano n
instance (Arity n, Unbox n a, Unbox n b) => Vector (T2 n a b) (a,b) where
inspect (T2 vA vB)
= inspect (C.zipWith (,) cvA cvB)
where
cvA = C.ContVec $ inspect vA
cvB = C.ContVec $ inspect vB
construct = pairF T2 construct construct
{-# INLINE construct #-}
{-# INLINE inspect #-}
pairF
:: ArityPeano n
=> (x -> y -> z)
-> Fun n a x
-> Fun n b y
-> Fun n (a,b) z
{-# INLINE pairF #-}
pairF g funA funB = C.accum
(\(T_pair fA fB) (a,b) -> T_pair (curryFirst fA a) (curryFirst fB b))
(\(T_pair (Fun x) (Fun y)) -> g x y)
(T_pair funA funB)
data T_pair a b x y n = T_pair (Fun n a x) (Fun n b y)
-- | Representation for vector of 2-tuple as two vectors.
data T3 n a b c x = T3 !(Vec n a) !(Vec n b) !(Vec n c)
type instance Dim (T3 n a b c) = Peano n
type instance Dim (T3 n a b c x) = Peano n
instance (Arity n, Unbox n a, Unbox n b, Unbox n c) => Vector (T3 n a b c) (a,b,c) where
inspect (T3 vA vB vC)
= inspect (C.zipWith3 (,,) cvA cvB cvC)
where
cvA = C.ContVec $ inspect vA
cvB = C.ContVec $ inspect vB
cvC = C.ContVec $ inspect vC
construct = pair3F T3 construct construct construct
{-# INLINE construct #-}
{-# INLINE inspect #-}
pair3F
:: ArityPeano n
=> (x -> y -> z -> r)
-> Fun n a x
-> Fun n b y
-> Fun n c z
-> Fun n (a,b,c) r
{-# INLINE pair3F #-}
pair3F g funA funB funC = C.accum
(\(T_pair3 fA fB fC) (a,b,c) -> T_pair3 (curryFirst fA a)
(curryFirst fB b)
(curryFirst fC c))
(\(T_pair3 (Fun x) (Fun y) (Fun z)) -> g x y z)
(T_pair3 funA funB funC)
data T_pair3 a b c x y z n = T_pair3 (Fun n a x) (Fun n b y) (Fun n c z)
instance (Unbox n a, Unbox n b) => Unbox n (a,b) where
type VecRepr n (a,b) = T2 n a b
type EltRepr (a,b) = (a,b)
toEltRepr _ = id
fromEltRepr _ = id
instance (Unbox n a) => Unbox n (Complex a) where
-- NOTE: It would be nice to have ability to use single buffer say
-- for `Complex Double`. But buffers seems to be opaque
type VecRepr n (Complex a) = T2 n a a
type EltRepr (Complex a) = (a,a)
toEltRepr _ (r :+ i) = (r,i)
fromEltRepr _ (r,i) = r :+ i
{-# INLINE toEltRepr #-}
{-# INLINE fromEltRepr #-}