dynobud-1.3.0.0: tests/ViewTests.hs
{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
{-# Language ScopedTypeVariables #-}
{-# Language GADTs #-}
{-# Language DeriveGeneric #-}
{-# Language FlexibleInstances #-}
{-# Language PolyKinds #-}
module ViewTests
( Views(..)
, CMatrices(..)
, viewTests
) where
import GHC.Generics ( Generic1 )
import Data.Proxy ( Proxy(..) )
import Data.Binary ( encode, decodeOrFail )
import qualified Data.Traversable as T
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 Casadi.CMatrix ( CMatrix )
import Casadi.DMatrix ( DMatrix )
import Casadi.MX ( MX )
import Casadi.SX ( SX )
import Dyno.View.Unsafe.View ( J(UnsafeJ), mkJ )
import Dyno.View.Unsafe.M ( M(UnsafeM) )
import Dyno.TypeVecs ( Vec, Dim )
import Dyno.Vectorize ( Vectorize(..), Id, fill )
import Dyno.View.View ( View(..), JNone, JTuple, JTriple )
import Dyno.View.JV ( JV )
import Dyno.View.Viewable ( Viewable )
import Dyno.View.M
import Dyno.View.Cov ( Cov, fromMat, toMat )
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 CMatrices where
CMatrices :: (Viewable f, CMatrix f, MyEq f) =>
{ cmName :: String
, cmProxy :: Proxy f
} -> CMatrices
instance Show CMatrices where
show = cmName
-- MX is less frequent because evalMX takes a while
instance Arbitrary CMatrices where
arbitrary = frequency [ (1, return (CMatrices "MX" (Proxy :: Proxy MX)))
, (5, return (CMatrices "SX" (Proxy :: Proxy SX)))
, (5, return (CMatrices "DMatrix" (Proxy :: Proxy DMatrix)))
]
instance (View f, View g, CMatrix a) => Arbitrary (M f g a) where
arbitrary = do
let prim :: Gen (M f g a)
prim = oneof
[ return $ zeros
, return $ countUp
, return $ fromInteger 0
, return $ fromRational 0
, fmap fromInteger arbitrary
, fmap fromRational arbitrary
]
positive :: Gen (M f g a)
positive = elements
[ ones
, 1 + countUp
, pi
]
x <- prim
y <- prim
z <- positive
oneof [ return $ x
, return $ x * y
, return $ x + y
, return $ x - y
, return $ x / z
, fmap trans (arbitrary :: Gen (M g f a))
]
instance (View f, CMatrix a, Viewable a) => Arbitrary (J f a) where
arbitrary = fmap uncol arbitrary
instance (Arbitrary a, Dim n) => Arbitrary (Vec n a) where
arbitrary = T.sequence (fill arbitrary)
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 {vwName = mv0, vwProxy = pv0}) <- genIt
vw1@(Views {vwName = mv1, vwProxy = pv1}) <- genIt
vw2@(Views {vwName = mv2, vwProxy = pv2}) <- genIt
elements
[ Views { vwShrinks = [vc]
, vwName = "JX0 (" ++ mz ++ ")"
, vwProxy = reproxy (Proxy :: Proxy JX0) pz
}
, Views { vwShrinks = [vc,vw0]
, vwName = "JX1 (" ++ mz ++ ") (" ++ mv0 ++ ")"
, vwProxy = reproxy2 (Proxy :: Proxy JX1) pz pv0
}
, Views { vwShrinks = [vc, vw0, vw1]
, vwName = "JX2 (" ++ mv0 ++ ") (" ++ mv1 ++ ") (" ++ mz ++ ")"
, vwProxy = reproxy3 (Proxy :: Proxy JX2) pv0 pv1 pz
}
, Views { vwShrinks = [vw0]
, vwName = "Cov (" ++ mv0 ++ ")"
, vwProxy = reproxy (Proxy :: Proxy Cov) pv0
}
, Views { vwShrinks = [vw0,vw1]
, vwName = "JTuple (" ++ mv0 ++ ") (" ++ mv1 ++ ")"
, vwProxy = reproxy2 (Proxy :: Proxy JTuple) pv0 pv1
}
, Views { vwShrinks = [vw0,vw1,vw2]
, vwName = "JTriple (" ++ mv0 ++ ") (" ++ mv1 ++ ") (" ++ mv2 ++ ")"
, vwProxy = reproxy3 (Proxy :: Proxy JTriple) pv0 pv1 pv2
}
]
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 { vwShrinks = shrinks
, vwName = "JV (" ++ m ++ ")"
, vwProxy = 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 {vwShrinks = [], vwName = "JNone", vwProxy = Proxy :: Proxy JNone}
, 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 {vwProxy = p2}) (CMatrices {cmProxy = pm}) -> test p1 p2 pm
where
test :: forall f g a
. (Vectorize f, View g, CMatrix a, MyEq a)
=> Proxy f -> Proxy g -> Proxy a -> Gen Property
test _ _ _ = do
x0 <- arbitrary :: Gen (M (JV f) g a)
let x1 = vcat (vsplit x0) :: M (JV f) g a
return $ beEqual x0 x1
prop_HSplitHCat :: Test
prop_HSplitHCat =
testProperty "hcat . hsplit" $
\(Views {vwProxy = p1}) (Vectorizes _ _ p2) (CMatrices {cmProxy = pm}) -> test p1 p2 pm
where
test :: forall f g a
. (View f, Vectorize g, CMatrix a, MyEq a)
=> Proxy f -> Proxy g -> Proxy a -> Gen Property
test _ _ _ = do
x0 <- arbitrary :: Gen (M f (JV g) a)
let x1 = hcat (hsplit x0) :: M f (JV g) a
return $ beEqual x0 x1
prop_VSplitVCat' :: Test
prop_VSplitVCat' =
testProperty "vsplit' . vcat'" $
\(Dims _ pd) (Views {vwProxy = p1}) (Views {vwProxy = p2}) (CMatrices {cmProxy = pm}) ->
test pd p1 p2 pm
where
test :: forall f g n a
. (View f, View g, Dim n, CMatrix a, MyEq a)
=> Proxy n -> Proxy f -> Proxy g -> Proxy a -> Gen Property
test _ _ _ _ = do
x0 <- arbitrary :: Gen (Vec n (M f g a))
let x1 = vsplit' (vcat' x0) :: Vec n (M f g a)
return $ beEqual x0 x1
prop_HSplitHCat' :: Test
prop_HSplitHCat' =
testProperty "hsplit' . hcat'" $
\(Dims _ pd) (Views {vwProxy = p1}) (Views {vwProxy = p2}) (CMatrices {cmProxy = pm}) ->
test pd p1 p2 pm
where
test :: forall f g n a
. (View f, View g, Dim n, CMatrix a, MyEq a)
=> Proxy n -> Proxy f -> Proxy g -> Proxy a -> Gen Property
test _ _ _ _ = do
x0 <- arbitrary :: Gen (Vec n (M f g a))
let x1 = hsplit' (hcat' x0) :: Vec n (M f g a)
return $ beEqual x0 x1
prop_testSplitJ :: Test
prop_testSplitJ =
testProperty "split . cat J" $
\(Vectorizes _ _ p) (CMatrices {cmProxy = pm}) -> test p pm
where
test :: forall f a
. (Vectorize f, CMatrix a, Viewable a, MyEq a)
=> Proxy f -> Proxy a -> Gen Property
test _ _ = do
UnsafeM xm0 <- arbitrary :: Gen (M (JV f) (JV Id) a)
let xj0 = mkJ xm0 :: J (JV f) a
xj1 = split xj0 :: JV f a
xj2 = cat xj1 :: J (JV f) a
return $ beEqual xj0 xj2
prop_toFromHMat :: Test
prop_toFromHMat =
testProperty "fromHMat . toHMat" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) -> test p1 p2
where
test :: forall f g
. (View f, View g)
=> Proxy f -> Proxy g -> Gen Property
test _ _ = do
m0 <- arbitrary :: Gen (M f g DMatrix)
let m1 = toHMat m0 :: Mat.Matrix Double
m2 = fromHMat m1 :: M f g DMatrix
return $ beEqual m0 m2
prop_fromToHMat :: Test
prop_fromToHMat =
testProperty "toHMat . fromHMat" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) -> test p1 p2
where
test :: forall f g
. (View f, View g)
=> Proxy f -> Proxy g -> Gen Property
test _ _ = do
m0 <- arbitrary :: Gen (M f g DMatrix)
let m1 = toHMat m0 :: Mat.Matrix Double
m2 = fromHMat m1 :: M f g DMatrix
m3 = toHMat m2 :: Mat.Matrix Double
return $ beEqual m1 m3
prop_covToFromMat :: Test
prop_covToFromMat =
testProperty "fromMat . toMat" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) -> test p1 p2
where
test :: forall f g
. (View f, View g)
=> Proxy f -> Proxy g -> Gen Property
test _ _ = do
m0 <- arbitrary :: Gen (J (Cov f) DMatrix)
let m1 = toMat m0 :: M f f DMatrix
m2 = fromMat m1 :: J (Cov f) DMatrix
return $ beEqual m0 m2
prop_covFromToMat :: Test
prop_covFromToMat =
testProperty "toMat . fromMat" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) -> test p1 p2
where
test :: forall f g
. (View f, View g)
=> Proxy f -> Proxy g -> Gen Property
test _ _ = do
m0' <- arbitrary :: Gen (M f f DMatrix)
let m0 = 0.5 * (m0' + trans m0') -- make it symmetric
m1 = fromMat m0 :: J (Cov f) DMatrix
m2 = toMat m1 :: M f f DMatrix
return $ beEqual m0 m2
prop_serializeDeserialize :: Test
prop_serializeDeserialize =
testProperty "(M f g DMatrix): deserialize . serialize" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) -> test p1 p2
where
test :: forall f g . (View f, View g) => Proxy f -> Proxy g -> Gen Property
test _ _ = do
m0 <- arbitrary :: Gen (M f g DMatrix)
let m1 = encode m0
return $
case decodeOrFail m1 of
Left (_,_,msg) -> counterexample ("deserialization failure " ++ show msg) False
Right (_,_,m2) -> beEqual m0 m2
prop_vsplitTup :: Test
prop_vsplitTup =
testProperty "vcatTup . vsplitTup" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) (Views {vwProxy = p3}) (CMatrices {cmProxy = p4})
-> test p1 p2 p3 p4
where
test :: forall f g h a
. (View f, View g, View h, CMatrix a, MyEq a)
=> Proxy f -> Proxy g -> Proxy h -> Proxy a
-> Gen Property
test _ _ _ _ = do
m0 <- arbitrary :: Gen (M (JTuple f g) h a)
let (mx,my) = vsplitTup m0
m1 = vcatTup mx my
return (beEqual m0 m1)
prop_hsplitTup :: Test
prop_hsplitTup =
testProperty "hcatTup . hsplitTup" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) (Views {vwProxy = p3}) (CMatrices {cmProxy = p4})
-> test p1 p2 p3 p4
where
test :: forall f g h a
. (View f, View g, View h, CMatrix a, MyEq a)
=> Proxy f -> Proxy g -> Proxy h -> Proxy a
-> Gen Property
test _ _ _ _ = do
m0 <- arbitrary :: Gen (M f (JTuple g h) a)
let (mx,my) = hsplitTup m0
m1 = hcatTup mx my
return (beEqual m0 m1)
prop_vsplitTrip :: Test
prop_vsplitTrip =
testProperty "vcatTrip . vsplitTrip" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) (Views {vwProxy = p3}) (Views {vwProxy = p4}) (CMatrices {cmProxy = p5})
-> test p1 p2 p3 p4 p5
where
test :: forall f1 f2 f3 g a
. (View f1, View f2, View f3, View g, CMatrix a, MyEq a)
=> Proxy f1 -> Proxy f2 -> Proxy f3 -> Proxy g -> Proxy a
-> Gen Property
test _ _ _ _ _ = do
m0 <- arbitrary :: Gen (M (JTriple f1 f2 f3) g a)
let (mx,my,mz) = vsplitTrip m0
m1 = vcatTrip mx my mz
return (beEqual m0 m1)
prop_hsplitTrip :: Test
prop_hsplitTrip =
testProperty "hcatTrip . hsplitTrip" $
\(Views {vwProxy = p1}) (Views {vwProxy = p2}) (Views {vwProxy = p3}) (Views {vwProxy = p4}) (CMatrices {cmProxy = p5})
-> test p1 p2 p3 p4 p5
where
test :: forall f g1 g2 g3 a
. (View f, View g1, View g2, View g3, CMatrix a, MyEq a)
=> Proxy f -> Proxy g1 -> Proxy g2 -> Proxy g3 -> Proxy a
-> Gen Property
test _ _ _ _ _ = do
m0 <- arbitrary :: Gen (M f (JTriple g1 g2 g3) a)
let (mx,my,mz) = hsplitTrip m0
m1 = hcatTrip mx my mz
return (beEqual m0 m1)
viewTests :: Test
viewTests =
testGroup "view tests"
[ prop_VSplitVCat
, prop_HSplitHCat
, prop_VSplitVCat'
, prop_HSplitHCat'
, prop_testSplitJ
, prop_toFromHMat
, prop_fromToHMat
, prop_covFromToMat
, prop_covToFromMat
, prop_serializeDeserialize
, prop_vsplitTup
, prop_hsplitTup
, prop_vsplitTrip
, prop_hsplitTrip
]