dynobud-1.4.0.0: src/Dyno/View/Scheme.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveFunctor #-}
module Dyno.View.Scheme
( Scheme(..)
, FunctionIO(..)
) where
import GHC.Generics
import Data.Proxy
import qualified Data.Foldable as F
import qualified Data.Sequence as Seq
import qualified Data.Vector as V
import Data.Vector ( Vector )
import Casadi.CMatrix ( CMatrix )
import Dyno.View.Unsafe.View ( unsafeUnJ, mkJ' )
import Dyno.View.Unsafe.M ( unM, mkM' )
import qualified Dyno.View.M as M
import Dyno.View.View ( View(..), J )
import Dyno.View.Viewable ( Viewable )
class FunctionIO (f :: * -> *) where
fromMat :: (CMatrix a, Viewable a) => a -> Either String (f a)
toFioMat :: f a -> a
matSizes :: Proxy f -> (Int,Int)
instance View x => Scheme (J x) where
numFields = const 1
fromVector v = case V.toList v of
[m] -> case fromMat m of Left err -> error $ "Scheme fromVector J error: " ++ err
Right m' -> m'
_ -> error $ "Scheme fromVector (J x) length mismatch, should be 1 but got: "
++ show (V.length v)
toVector = V.singleton . toFioMat
sizeList p = [matSizes p]
instance (View f, View g) => Scheme (M.M f g) where
numFields = const 1
fromVector v = case V.toList v of
[m] -> case fromMat m of Left err -> error $ "Scheme fromVector M error: " ++ err
Right m' -> m'
_ -> error $ "Scheme fromVector (M f g) length mismatch, should be 1 but got: "
++ show (V.length v)
toVector = V.singleton . toFioMat
sizeList p = [matSizes p]
instance View f => FunctionIO (J f) where
toFioMat = unsafeUnJ
fromMat = mkJ'
matSizes = const (size (Proxy :: Proxy f), 1)
instance (View f, View g) => FunctionIO (M.M f g) where
toFioMat = unM
fromMat = mkM'
matSizes = const (size (Proxy :: Proxy f), size (Proxy :: Proxy g))
class Scheme (f :: * -> *) where
numFields :: Proxy f -> Int
fromVector :: (CMatrix a, Viewable a) => V.Vector a -> f a
toVector :: f a -> V.Vector a
sizeList :: Proxy f -> [(Int,Int)]
default numFields :: (GNumFields (Rep (f ())), Generic (f ())) => Proxy f -> Int
numFields = gnumFields . reproxy
where
reproxy :: Proxy g -> Proxy ((Rep (g ())) p)
reproxy = const Proxy
default sizeList :: (GSizeList (Rep (f ())), Generic (f ())) => Proxy f -> [(Int,Int)]
sizeList = F.toList . gsizeList . reproxy
where
reproxy :: Proxy g -> Proxy ((Rep (g ())) p)
reproxy = const Proxy
default fromVector :: ( Rep (f a) aa ~ M1 t d ff aa, GFromVector (Rep (f a)) a
, Generic (f a), Datatype d, CMatrix a, Viewable a )
=> Vector a -> f a
fromVector vs = out'
where
out' = to out
name = datatypeName (from out')
out = gfromVector name vs proxy
reproxy :: g b -> Proxy (g b)
reproxy = const Proxy
proxy = reproxy out
default toVector :: (GToVector (Rep (f a)) a, Generic (f a)) => f a -> Vector a
toVector = V.fromList . F.toList . gtoVector . from
----------------------------------------------------------
class GNumFields f where
gnumFields :: Proxy (f p) -> Int
class GSizeList f where
gsizeList :: Proxy (f p) -> Seq.Seq (Int,Int)
class GFromVector f a where
gfromVector :: CMatrix a => String -> Vector a -> Proxy (f a) -> f a
class GToVector f a where
gtoVector :: f a -> Seq.Seq a
------------------------------------ GNumFields ------------------------------
instance (GNumFields f, GNumFields g) => GNumFields (f :*: g) where
gnumFields pxy = gnumFields px + gnumFields py
where
reproxy :: Proxy ((x :*: y) p) -> (Proxy (x p), Proxy (y p))
reproxy = const (Proxy,Proxy)
(px, py) = reproxy pxy
instance GNumFields f => GNumFields (M1 i d f) where
gnumFields = gnumFields . reproxy
where
reproxy :: Proxy (M1 i d f p) -> Proxy (f p)
reproxy _ = Proxy
instance GNumFields (Rec0 f) where
gnumFields = const 1
--instance GNumFields U1 where
-- gnumFields = const 0
------------------------------------ GSizeList ------------------------------
instance (GSizeList f, GSizeList g) => GSizeList (f :*: g) where
gsizeList pxy = gsizeList px Seq.>< gsizeList py
where
reproxy :: Proxy ((x :*: y) p) -> (Proxy (x p), Proxy (y p))
reproxy = const (Proxy,Proxy)
(px, py) = reproxy pxy
instance GSizeList f => GSizeList (M1 i d f) where
gsizeList = gsizeList . reproxy
where
reproxy :: Proxy (M1 i d f p) -> Proxy (f p)
reproxy = const Proxy
instance FunctionIO f => GSizeList (Rec0 (f p)) where
gsizeList = Seq.singleton . matSizes . reproxy
where
reproxy :: Proxy (Rec0 (f p) q) -> Proxy f
reproxy = const Proxy
--------------------- GFromVector ----------------------------
instance (GFromVector f a, GFromVector g a, GNumFields f, GNumFields g) => GFromVector (f :*: g) a where
gfromVector name vs pxy
| V.length vs == nx + ny = gfromVector name vx px :*: gfromVector name vy py
| otherwise = error $ "\"" ++ name ++ "\" GFromVector (:*:) length error, need " ++
show (nx,ny) ++ " but got " ++ show (V.length vs)
where
nx = gnumFields px
ny = gnumFields py
(vx,vy) = V.splitAt nx vs
reproxy :: Proxy ((x :*: y) p) -> (Proxy (x p), Proxy (y p))
reproxy = const (Proxy,Proxy)
(px, py) = reproxy pxy
instance (Datatype d, GFromVector f a) => GFromVector (D1 d f) a where
gfromVector name vs p = ret
where
ret = M1 $ gfromVector (name ++ "," ++ dname) vs $ reproxy p
dname = datatypeName ret
reproxy :: Proxy (D1 d f a) -> Proxy (f a)
reproxy = const Proxy
instance (Constructor c, GFromVector f a) => GFromVector (C1 c f) a where
gfromVector name vs p = ret
where
ret = M1 $ gfromVector (name ++ "," ++ cname) vs $ reproxy p
cname = conName ret
reproxy :: Proxy (C1 c f a) -> Proxy (f a)
reproxy = const Proxy
instance (GFromVector f a) => GFromVector (S1 s f) a where
gfromVector name vs = M1 . gfromVector name vs . reproxy
where
reproxy :: Proxy (S1 s f a) -> Proxy (f a)
reproxy = const Proxy
instance (FunctionIO f, Viewable a) => GFromVector (Rec0 (f a)) a where
gfromVector name ms = const (K1 j)
where
j = case fromMat m of
Right j' -> j'
Left err -> error $ "\"" ++ name ++ "\" GFromVector fromMat error: " ++ err
m = case V.toList ms of
[m'] -> m'
_ -> error $ "\"" ++ name ++ "\" GFromVector Rec0 length error, " ++
"need exactly 1 value but got " ++ show (V.length ms)
--instance GFromVector U1 a where
-- gfromVector = const $ const $ const U1
--------------------- GToVector ----------------------------
instance (GToVector f a, GToVector g a, GNumFields f, GNumFields g) => GToVector (f :*: g) a where
gtoVector (x :*: y) = gtoVector x Seq.>< gtoVector y
instance GToVector f a => GToVector (M1 i d f) a where
gtoVector = gtoVector . unM1
instance View f => GToVector (Rec0 (J f a)) a where
gtoVector = Seq.singleton . unsafeUnJ . unK1
instance (View f, View g) => GToVector (Rec0 (M.M f g a)) a where
gtoVector = Seq.singleton . unM . unK1
--instance GToVector U1 a where
-- gtoVector = const Seq.empty