{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE CPP #-}
module Math.VectorSpace.DimensionAware where
import Data.VectorSpace
import Data.Singletons (SingI, sing, Sing)
#if MIN_VERSION_singletons(3,0,0)
import Prelude.Singletons (SNum(..))
import Data.Maybe.Singletons
import GHC.TypeLits.Singletons (withKnownNat)
#else
import Data.Singletons.Prelude.Num (SNum(..))
import Data.Singletons.Prelude.Maybe (SMaybe(..))
import Data.Singletons.TypeLits (withKnownNat)
#endif
import qualified Data.Vector.Generic as GArr
import qualified Data.Vector.Generic.Mutable as GMArr
import Control.Monad.ST (ST)
import Control.Monad
import GHC.TypeLits
import GHC.Exts (Constraint)
import Data.Proxy (Proxy(..))
import Data.Ratio
import qualified Math.VectorSpace.DimensionAware.Theorems.MaybeNat as Maybe
data DimensionalityWitness v where
IsStaticDimensional :: (n`Dimensional`v) => DimensionalityWitness v
IsFlexibleDimensional :: StaticDimension v ~ 'Nothing => DimensionalityWitness v
class VectorSpace v => DimensionAware v where
type StaticDimension v :: Maybe Nat
type StaticDimension v = 'Nothing
dimensionalityWitness :: DimensionalityWitness v
instance DimensionAware Float where
type StaticDimension Float = 'Just 1
dimensionalityWitness :: DimensionalityWitness Float
dimensionalityWitness = forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
instance DimensionAware Double where
type StaticDimension Double = 'Just 1
dimensionalityWitness :: DimensionalityWitness Double
dimensionalityWitness = forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
instance DimensionAware Int where
type StaticDimension Int = 'Just 1
dimensionalityWitness :: DimensionalityWitness Int
dimensionalityWitness = forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
instance DimensionAware Integer where
type StaticDimension Integer = 'Just 1
dimensionalityWitness :: DimensionalityWitness Integer
dimensionalityWitness = forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
instance Integral n => DimensionAware (Ratio n) where
type StaticDimension (Ratio n) = 'Just 1
dimensionalityWitness :: DimensionalityWitness (Ratio n)
dimensionalityWitness = forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
instance ∀ u v . (DimensionAware u, DimensionAware v, Scalar u ~ Scalar v)
=> DimensionAware (u,v) where
type StaticDimension (u,v) = Maybe.ZipWithPlus (StaticDimension u) (StaticDimension v)
dimensionalityWitness :: DimensionalityWitness (u, v)
dimensionalityWitness = case (forall v. DimensionAware v => DimensionalityWitness v
dimensionalityWitness @u, forall v. DimensionAware v => DimensionalityWitness v
dimensionalityWitness @v) of
(DimensionalityWitness u
IsStaticDimensional, DimensionalityWitness v
IsStaticDimensional)
-> forall (n :: Nat) r. Sing n -> (KnownNat n => r) -> r
withKnownNat (forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @u forall a (t1 :: a) (t2 :: a).
SNum a =>
Sing t1 -> Sing t2 -> Sing (Apply (Apply (+@#@$) t1) t2)
%+ forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v)
forall (n :: Nat) v. Dimensional n v => DimensionalityWitness v
IsStaticDimensional
(DimensionalityWitness u
IsFlexibleDimensional, DimensionalityWitness v
_) -> forall v. (StaticDimension v ~ 'Nothing) => DimensionalityWitness v
IsFlexibleDimensional
(DimensionalityWitness u
_, DimensionalityWitness v
IsFlexibleDimensional) -> forall v. (StaticDimension v ~ 'Nothing) => DimensionalityWitness v
IsFlexibleDimensional
class (DimensionAware v, StaticDimension v ~ 'Just n)
=> n`Dimensional`v | v -> n where
knownDimensionalitySing :: Sing n
{-# INLINE knownDimensionalitySing #-}
default knownDimensionalitySing :: KnownNat n => Sing n
knownDimensionalitySing = forall {k} (a :: k). SingI a => Sing a
sing
unsafeFromArrayWithOffset :: GArr.Vector α (Scalar v) => Int -> α (Scalar v) -> v
unsafeWriteArrayWithOffset :: GArr.Vector α (Scalar v)
=> GArr.Mutable α σ (Scalar v) -> Int -> v -> ST σ ()
data DimensionalityCases v where
StaticDimensionalCase :: (KnownNat n, n`Dimensional`v) => DimensionalityCases v
FlexibleDimensionalCase :: StaticDimension v ~ 'Nothing => DimensionalityCases v
#if !MIN_VERSION_singletons(3,0,0)
type family FromJust (a :: Maybe k) :: k where
FromJust ('Just v) = v
#endif
type Dimension v = FromJust (StaticDimension v)
#if !MIN_VERSION_singletons(3,0,0)
type family IsJust (a :: Maybe k) :: Bool where
IsJust ('Just _) = 'True
IsJust _ = 'False
#endif
class DimensionAware v => StaticDimensional v where
dimensionIsStatic :: ∀ r . (∀ n . (KnownNat n, n`Dimensional`v) => r) -> r
{-# INLINE dimensionalitySing #-}
dimensionalitySing :: ∀ v n . n`Dimensional`v => Sing n
dimensionalitySing :: forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing = forall (n :: Nat) v. Dimensional n v => Sing n
knownDimensionalitySing @n @v
instance ( DimensionAware v, IsJust (StaticDimension v) ~ 'True )
=> StaticDimensional v where
dimensionIsStatic :: forall r.
(forall (n :: Nat). (KnownNat n, Dimensional n v) => r) -> r
dimensionIsStatic = case forall v. DimensionAware v => DimensionalityWitness v
dimensionalityWitness @v of
DimensionalityWitness v
IsStaticDimensional -> \forall (n :: Nat). (KnownNat n, Dimensional n v) => r
φ -> forall (n :: Nat) r. Sing n -> (KnownNat n => r) -> r
withKnownNat (forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v) forall (n :: Nat). (KnownNat n, Dimensional n v) => r
φ
dimensionality :: ∀ v . DimensionAware v => DimensionalityCases v
dimensionality :: forall v. DimensionAware v => DimensionalityCases v
dimensionality = case forall v. DimensionAware v => DimensionalityWitness v
dimensionalityWitness @v of
DimensionalityWitness v
IsStaticDimensional -> forall (n :: Nat) r. Sing n -> (KnownNat n => r) -> r
withKnownNat (forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v) forall (n :: Nat) v.
(KnownNat n, Dimensional n v) =>
DimensionalityCases v
StaticDimensionalCase
DimensionalityWitness v
IsFlexibleDimensional -> forall v. (StaticDimension v ~ 'Nothing) => DimensionalityCases v
FlexibleDimensionalCase
{-# INLINE dimension #-}
dimension :: ∀ v n a . (n`Dimensional`v, Integral a) => a
dimension :: forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension = forall (n :: Nat) r. Sing n -> (KnownNat n => r) -> r
withKnownNat (forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v) (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal @n forall {k} (t :: k). Proxy t
Proxy)
dimensionOf :: ∀ v n a . (n`Dimensional`v, Integral a) => v -> a
dimensionOf :: forall v (n :: Nat) a. (Dimensional n v, Integral a) => v -> a
dimensionOf v
_ = forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @v
{-# INLINE unsafeFromArray #-}
unsafeFromArray :: ∀ v n α . (n`Dimensional`v, GArr.Vector α (Scalar v))
=> α (Scalar v) -> v
unsafeFromArray :: forall v (n :: Nat) (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
α (Scalar v) -> v
unsafeFromArray = forall (n :: Nat) v (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
Int -> α (Scalar v) -> v
unsafeFromArrayWithOffset Int
0
fromArray :: ∀ v n α . (n`Dimensional`v, GArr.Vector α (Scalar v))
=> α (Scalar v) -> Maybe v
fromArray :: forall v (n :: Nat) (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
α (Scalar v) -> Maybe v
fromArray α (Scalar v)
ar
| forall (v :: * -> *) a. Vector v a => v a -> Int
GArr.length α (Scalar v)
ar forall a. Eq a => a -> a -> Bool
== forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @v = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall v (n :: Nat) (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
α (Scalar v) -> v
unsafeFromArray α (Scalar v)
ar
| Bool
otherwise = forall a. Maybe a
Nothing
{-# INLINE toArray #-}
toArray :: ∀ v n α . (n`Dimensional`v, GArr.Vector α (Scalar v))
=> v -> α (Scalar v)
toArray :: forall v (n :: Nat) (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
v -> α (Scalar v)
toArray v
v = forall (v :: * -> *) a.
Vector v a =>
(forall s. ST s (Mutable v s a)) -> v a
GArr.create (do
Mutable α s (Scalar v)
ar <- forall (m :: * -> *) (v :: * -> * -> *) a.
(HasCallStack, PrimMonad m, MVector v a) =>
Int -> m (v (PrimState m) a)
GMArr.new forall a b. (a -> b) -> a -> b
$ forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @v
forall (n :: Nat) v (α :: * -> *) σ.
(Dimensional n v, Vector α (Scalar v)) =>
Mutable α σ (Scalar v) -> Int -> v -> ST σ ()
unsafeWriteArrayWithOffset Mutable α s (Scalar v)
ar Int
0 v
v
forall (m :: * -> *) a. Monad m => a -> m a
return Mutable α s (Scalar v)
ar
)
{-# INLINE staticDimensionSing #-}
staticDimensionSing :: ∀ v . DimensionAware v => Sing (StaticDimension v)
staticDimensionSing :: forall v. DimensionAware v => Sing (StaticDimension v)
staticDimensionSing = case forall v. DimensionAware v => DimensionalityWitness v
dimensionalityWitness @v of
DimensionalityWitness v
IsStaticDimensional -> forall a (n :: a). Sing n -> SMaybe ('Just n)
SJust (forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v)
DimensionalityWitness v
IsFlexibleDimensional -> forall {k} (a :: k). SingI a => Sing a
sing
{-# INLINE scalarUnsafeFromArrayWithOffset #-}
scalarUnsafeFromArrayWithOffset :: (v ~ Scalar v, GArr.Vector α v)
=> Int -> α v -> v
scalarUnsafeFromArrayWithOffset :: forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset Int
i = (forall (v :: * -> *) a. Vector v a => v a -> Int -> a
`GArr.unsafeIndex`Int
i)
{-# INLINE scalarUnsafeWriteArrayWithOffset #-}
scalarUnsafeWriteArrayWithOffset :: (v ~ Scalar v, GArr.Vector α v)
=> GArr.Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset :: forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset Mutable α σ v
ar Int
i = forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> Int -> a -> m ()
GMArr.unsafeWrite Mutable α σ v
ar Int
i
{-# INLINE unsafeFromArrayWithOffsetViaList #-}
unsafeFromArrayWithOffsetViaList
:: ∀ v n α . (n`Dimensional`v, GArr.Vector α (Scalar v))
=> ([Scalar v] -> v) -> Int -> α (Scalar v) -> v
unsafeFromArrayWithOffsetViaList :: forall v (n :: Nat) (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
([Scalar v] -> v) -> Int -> α (Scalar v) -> v
unsafeFromArrayWithOffsetViaList [Scalar v] -> v
l2v Int
i
= [Scalar v] -> v
l2v forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (v :: * -> *) a. Vector v a => v a -> [a]
GArr.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (v :: * -> *) a. Vector v a => Int -> Int -> v a -> v a
GArr.unsafeSlice Int
i (forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @v)
{-# INLINE unsafeWriteArrayWithOffsetViaList #-}
unsafeWriteArrayWithOffsetViaList
:: ∀ v n α σ . (n`Dimensional`v, GArr.Vector α (Scalar v))
=> (v -> [Scalar v]) -> GArr.Mutable α σ (Scalar v)
-> Int -> v -> ST σ ()
unsafeWriteArrayWithOffsetViaList :: forall v (n :: Nat) (α :: * -> *) σ.
(Dimensional n v, Vector α (Scalar v)) =>
(v -> [Scalar v]) -> Mutable α σ (Scalar v) -> Int -> v -> ST σ ()
unsafeWriteArrayWithOffsetViaList v -> [Scalar v]
v2l Mutable α σ (Scalar v)
ar Int
i
= forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
GMArr.unsafeCopy (forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
GMArr.unsafeSlice Int
i (forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @v) Mutable α σ (Scalar v)
ar)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< forall (m :: * -> *) (v :: * -> *) a.
(PrimMonad m, Vector v a) =>
v a -> m (Mutable v (PrimState m) a)
GArr.unsafeThaw @(ST σ) @α forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (v :: * -> *) a. Vector v a => [a] -> v a
GArr.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. v -> [Scalar v]
v2l
instance 1`Dimensional`Float where
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar Float) =>
Int -> α (Scalar Float) -> Float
unsafeFromArrayWithOffset = forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar Float) =>
Mutable α σ (Scalar Float) -> Int -> Float -> ST σ ()
unsafeWriteArrayWithOffset = forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset
instance 1`Dimensional`Double where
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar Double) =>
Int -> α (Scalar Double) -> Double
unsafeFromArrayWithOffset = forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar Double) =>
Mutable α σ (Scalar Double) -> Int -> Double -> ST σ ()
unsafeWriteArrayWithOffset = forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset
instance 1`Dimensional`Int where
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar Int) =>
Int -> α (Scalar Int) -> Int
unsafeFromArrayWithOffset = forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar Int) =>
Mutable α σ (Scalar Int) -> Int -> Int -> ST σ ()
unsafeWriteArrayWithOffset = forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset
instance 1`Dimensional`Integer where
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar Integer) =>
Int -> α (Scalar Integer) -> Integer
unsafeFromArrayWithOffset = forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar Integer) =>
Mutable α σ (Scalar Integer) -> Int -> Integer -> ST σ ()
unsafeWriteArrayWithOffset = forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset
instance Integral n => 1`Dimensional`Ratio n where
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar (Ratio n)) =>
Int -> α (Scalar (Ratio n)) -> Ratio n
unsafeFromArrayWithOffset = forall v (α :: * -> *).
(v ~ Scalar v, Vector α v) =>
Int -> α v -> v
scalarUnsafeFromArrayWithOffset
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar (Ratio n)) =>
Mutable α σ (Scalar (Ratio n)) -> Int -> Ratio n -> ST σ ()
unsafeWriteArrayWithOffset = forall v (α :: * -> *) σ.
(v ~ Scalar v, Vector α v) =>
Mutable α σ v -> Int -> v -> ST σ ()
scalarUnsafeWriteArrayWithOffset
instance ∀ n u m v nm . ( n`Dimensional`u, m`Dimensional`v
, Scalar u ~ Scalar v
, nm ~ (n+m) )
=> nm`Dimensional`(u,v) where
{-# INLINE knownDimensionalitySing #-}
knownDimensionalitySing :: Sing nm
knownDimensionalitySing = forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @u forall a (t1 :: a) (t2 :: a).
SNum a =>
Sing t1 -> Sing t2 -> Sing (Apply (Apply (+@#@$) t1) t2)
%+ forall v (n :: Nat). Dimensional n v => Sing n
dimensionalitySing @v
{-# INLINE unsafeFromArrayWithOffset #-}
unsafeFromArrayWithOffset :: forall (α :: * -> *).
Vector α (Scalar (u, v)) =>
Int -> α (Scalar (u, v)) -> (u, v)
unsafeFromArrayWithOffset Int
i α (Scalar (u, v))
arr
= ( forall (n :: Nat) v (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
Int -> α (Scalar v) -> v
unsafeFromArrayWithOffset Int
i α (Scalar (u, v))
arr
, forall (n :: Nat) v (α :: * -> *).
(Dimensional n v, Vector α (Scalar v)) =>
Int -> α (Scalar v) -> v
unsafeFromArrayWithOffset (Int
i forall a. Num a => a -> a -> a
+ forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @u) α (Scalar (u, v))
arr )
{-# INLINE unsafeWriteArrayWithOffset #-}
unsafeWriteArrayWithOffset :: forall (α :: * -> *) σ.
Vector α (Scalar (u, v)) =>
Mutable α σ (Scalar (u, v)) -> Int -> (u, v) -> ST σ ()
unsafeWriteArrayWithOffset Mutable α σ (Scalar (u, v))
arr Int
i (u
x,v
y) = do
forall (n :: Nat) v (α :: * -> *) σ.
(Dimensional n v, Vector α (Scalar v)) =>
Mutable α σ (Scalar v) -> Int -> v -> ST σ ()
unsafeWriteArrayWithOffset Mutable α σ (Scalar (u, v))
arr Int
i u
x
forall (n :: Nat) v (α :: * -> *) σ.
(Dimensional n v, Vector α (Scalar v)) =>
Mutable α σ (Scalar v) -> Int -> v -> ST σ ()
unsafeWriteArrayWithOffset Mutable α σ (Scalar (u, v))
arr (Int
i forall a. Num a => a -> a -> a
+ forall v (n :: Nat) a. (Dimensional n v, Integral a) => a
dimension @u) v
y
notStaticDimensionalContradiction :: ∀ v n r
. (
StaticDimension v ~ 'Nothing) => r
notStaticDimensionalContradiction :: forall {k} v (n :: k) r. (StaticDimension v ~ 'Nothing) => r
notStaticDimensionalContradiction = forall a. HasCallStack => a
undefined