packages feed

dynobud-1.0.0.0: tests/ViewTests.hs

{-# OPTIONS_GHC -Wall #-}
{-# Language ScopedTypeVariables #-}
{-# Language GADTs #-}
{-# Language DeriveGeneric #-}
{-# Language FlexibleInstances #-}

module ViewTests
       ( Views(..)
       , CasadiMats(..)
       , viewTests
       ) where

import qualified Data.Packed.Matrix as Mat
import qualified Numeric.LinearAlgebra ( ) -- for Eq Matrix
import qualified Data.Vector as V
import GHC.Generics ( Generic )
import System.IO.Unsafe ( unsafePerformIO )
import Test.QuickCheck
import Test.Framework ( Test, testGroup )
import Test.Framework.Providers.QuickCheck2 ( testProperty )

import Casadi.Function ( evalDMatrix )
import Casadi.MXFunction ( mxFunction )
import Casadi.SharedObject ( soInit )

import Dyno.TypeVecs ( Vec, Dim )
import Dyno.Vectorize
import Dyno.View
import Dyno.View.M
import Dyno.View.CasadiMat ( CasadiMat )
import Dyno.Cov

import Utils
import VectorizeTests ( Vectorizes(..), Dims(..) )

data Views where
  Views :: View f =>
           { vwShrinks :: [Views]
           , vwName :: String
           , vwProxy :: Proxy f
           } -> Views
instance Show Views where
  show = vwName

data CasadiMats where
  CasadiMats :: (Viewable f, CasadiMat f, MyEq f) =>
                { cmName :: String
                , cmProxy :: Proxy f
                } -> CasadiMats
instance Show CasadiMats where
  show = cmName

-- MX is less frequent because evalMX takes a while
instance Arbitrary CasadiMats where
  arbitrary = frequency [ (1, return (CasadiMats "MX" (Proxy :: Proxy MX)))
                        , (5, return (CasadiMats "SX" (Proxy :: Proxy SX)))
                        , (5, return (CasadiMats "DMatrix" (Proxy :: Proxy DMatrix)))
                        ]

evalMX :: MX -> DMatrix
evalMX x = unsafePerformIO $ do
  f <- mxFunction V.empty (V.singleton x)
  soInit f
  ret <- evalDMatrix f V.empty
  return (V.head ret)

data JX0 f a = JX0 (J (JV f) a) (J (JV f) a) deriving (Show, Generic, Generic1)
instance Vectorize f => View (JX0 f)
--instance Scheme JX

data JX1 f g a = JX1 (J (JV f) a) (J g a) deriving (Show, Generic, Generic1)
instance (Vectorize f, View g) => View (JX1 f g)
--instance Scheme JX

data JX2 f g h a = JX2 (J f a) (J (JTuple g (JV h)) a) (J g a) (J (JV h) a) (J f a)
                 deriving (Show, Generic, Generic1)
instance (View f, View g, Vectorize h) => View (JX2 f g h)
----instance Scheme JX2

maxViewSize :: Int
maxViewSize = 200

class MyEq a where
  myEq :: a -> a -> Bool

instance MyEq a => MyEq (J f a) where
  myEq (UnsafeJ x) (UnsafeJ y) = myEq x y
instance MyEq a => MyEq (M f g a) where
  myEq (UnsafeM x) (UnsafeM y) = myEq x y
instance MyEq SX where
  myEq = (==)
instance MyEq DMatrix where
  myEq = (==)
instance MyEq MX where
  myEq x y = myEq (evalMX x) (evalMX y)
instance (Dim n, MyEq a) => MyEq (Vec n a) where
  myEq f g = V.and $ V.zipWith myEq (vectorize f) (vectorize g)
instance MyEq (Mat.Matrix Double) where
  myEq x y
    | and [rowx == 0, rowy == 0, colx == coly] = True
    | and [colx == 0, coly == 0, rowx == rowy] = True
    | otherwise = x == y
    where
      rowx = Mat.rows x
      colx = Mat.cols x
      rowy = Mat.rows y
      coly = Mat.cols y

instance Arbitrary Views where
  arbitrary = do
    x <- oneof [primitives, compound primitives, compound (compound primitives)]
    if viewSize x <= maxViewSize then return x else arbitrary
  shrink = filter ((<= maxViewSize) . viewSize) . vwShrinks

compound :: Gen Views -> Gen Views
compound genIt = do
  vc'@(Vectorizes _ mz pz) <- arbitrary
  let vc = mkJV vc'
  vw0@(Views _ mv0 pv0) <- genIt
  vw1@(Views _ mv1 pv1) <- genIt
  elements
    [ Views [vc] ("JX0 (" ++ mz ++ ")") (reproxy (Proxy :: Proxy JX0) pz)
    , Views [vc,vw0] ("JX1 (" ++ mz ++ ") (" ++ mv0 ++ ")") (reproxy2 (Proxy :: Proxy JX1) pz pv0)
    , Views [vc, vw0, vw1] ("JX2 (" ++ mv0 ++ ") (" ++ mv1 ++ ") (" ++ mz ++ ")")
      (reproxy3 (Proxy :: Proxy JX2) pv0 pv1 pz)
    , Views [vw0] ("Cov (" ++ mv0 ++ ")") (reproxy (Proxy :: Proxy Cov) pv0)
    ]

viewSize :: Views -> Int
viewSize (Views _ _ p) = size p

mkJV :: Vectorizes -> Views
mkJV = mkJV' True
  where
    mkJV' :: Bool -> Vectorizes -> Views
    mkJV' sh v@(Vectorizes _ m p) = Views shrinks ("JV (" ++ m ++ ")") (reproxyJV p)
      where
        shrinks :: [Views]
        shrinks = if sh then map (mkJV' False) (shrink v) else []

        reproxyJV :: Proxy f -> Proxy (JV f)
        reproxyJV = const Proxy

primitives :: Gen Views
primitives = do
  v <- arbitrary
  elements
    [ Views [] "JNone" (Proxy :: Proxy JNone)
    , Views [] "S" (Proxy :: Proxy S)
    , mkJV v
    ]

--data M1 a = M1 (M JX JX2 a) deriving (Show, Generic, Generic1)
--data M2 a = M2 (M JNone JNone a) deriving (Show, Generic, Generic1)
--data M3 a = M3 (M JX2 JNone a) deriving (Show, Generic, Generic1)
--data M4 a = M4 (M JNone JX2 a) deriving (Show, Generic, Generic1)

--instance Scheme M1
--instance Scheme M2
--instance Scheme M3
--instance Scheme M4

beEqual :: (MyEq a, Show a) => a -> a -> Property
beEqual x y = counterexample (sx ++ " =/= " ++ sy) (myEq x y)
  where
    sx = show x
    sy = show y

prop_VSplitVCat :: Test
prop_VSplitVCat =
  testProperty "vcat . vsplit" $
  \(Vectorizes _ _ p1) (Views _ _ p2) (CasadiMats {cmProxy = pm}) -> test p1 p2 pm
  where
    test :: forall f g a
            . (Vectorize f, View g, CasadiMat a, MyEq a)
            => Proxy f -> Proxy g -> Proxy a -> Property
    test _ _ _ = beEqual x0 x1
      where
        x0 :: M (JV f) g a
        x0 = countUp

        x1 :: M (JV f) g a
        x1 = vcat (vsplit x0)

prop_HSplitHCat :: Test
prop_HSplitHCat  =
  testProperty "hcat . hsplit" $
  \(Views _ _ p1) (Vectorizes _ _ p2) (CasadiMats {cmProxy = pm}) -> test p1 p2 pm
  where
    test :: forall f g a
            . (View f, Vectorize g, CasadiMat a, MyEq a)
            => Proxy f -> Proxy g -> Proxy a -> Property
    test _ _ _ = beEqual x0 x1
      where
        x0 :: M f (JV g) a
        x0 = countUp

        x1 :: M f (JV g) a
        x1 = hcat (hsplit x0)

prop_VSplitVCat' :: Test
prop_VSplitVCat'  =
  testProperty "vsplit' . vcat'" $
  \(Dims _ pd) (Views _ _ p1) (Views _ _ p2) (CasadiMats {cmProxy = pm}) -> test pd p1 p2 pm
  where
    test :: forall f g n a
            . (View f, View g, Dim n, CasadiMat a, MyEq a)
            => Proxy n -> Proxy f -> Proxy g -> Proxy a -> Property
    test _ _ _ _ = beEqual x0 x1
      where
        x0 :: Vec n (M f g a)
        x0 = fill countUp

        x1 :: Vec n (M f g a)
        x1 = vsplit' (vcat' x0)


prop_HSplitHCat' :: Test
prop_HSplitHCat' =
  testProperty "hsplit' . hcat'" $
  \(Dims _ pd) (Views _ _ p1) (Views _ _ p2) (CasadiMats {cmProxy = pm}) -> test pd p1 p2 pm
  where
    test :: forall f g n a
            . (View f, View g, Dim n, CasadiMat a, MyEq a)
            => Proxy n -> Proxy f -> Proxy g -> Proxy a -> Property
    test _ _ _ _ = beEqual x0 x1
      where
        x0 :: Vec n (M f g a)
        x0 = fill countUp

        x1 :: Vec n (M f g a)
        x1 = hsplit' (hcat' x0)

prop_testSplitJ :: Test
prop_testSplitJ  =
  testProperty "split . cat J" $
  \(Vectorizes _ _ p) (CasadiMats {cmProxy = pm}) -> test p pm
  where
    test :: forall f a
            . (Vectorize f, CasadiMat a, Viewable a, MyEq a)
            => Proxy f -> Proxy a -> Property
    test _ _ = beEqual xj0 xj2
      where
        UnsafeM xm0 = countUp :: M (JV f) (JV Id) a

        xj0 :: J (JV f) a
        xj0 = mkJ xm0

        xj1 :: JV f a
        xj1 = split xj0

        xj2 :: J (JV f) a
        xj2 = cat xj1

prop_toFromHMat :: Test
prop_toFromHMat =
  testProperty "fromHMat . toHMat" $
  \(Views _ _ p1) (Views _ _ p2) -> test p1 p2
  where
    test :: forall f g
            . (View f, View g)
            => Proxy f -> Proxy g -> Property
    test _ _ = beEqual m0 m2
      where
        m0 = countUp :: M f g DMatrix

        m1 = toHMat m0 :: Mat.Matrix Double

        m2 = fromHMat m1 :: M f g DMatrix

prop_fromToHMat :: Test
prop_fromToHMat =
  testProperty "toHMat . fromHMat" $
  \(Views _ _ p1) (Views _ _ p2) -> test p1 p2
  where
    test :: forall f g
            . (View f, View g)
            => Proxy f -> Proxy g -> Property
    test _ _ = beEqual m1 m3
      where
        m0 = countUp :: M f g DMatrix

        m1 = toHMat m0 :: Mat.Matrix Double

        m2 = fromHMat m1 :: M f g DMatrix

        m3 = toHMat m2 :: Mat.Matrix Double


viewTests :: Test
viewTests =
  testGroup "view tests"
  [ prop_VSplitVCat
  , prop_HSplitHCat
  , prop_VSplitVCat'
  , prop_HSplitHCat'
  , prop_testSplitJ
  , prop_toFromHMat
  , prop_fromToHMat
  ]