packages feed

easytensor-0.2.0.0: test/Numeric/DataFrame/Arbitraries.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Numeric.DataFrame.BasicTest
-- Copyright   :  (c) Artem Chirkin
-- License     :  BSD3
--
-- Maintainer  :  chirkin@arch.ethz.ch
--
-- A set of basic validity tests for DataFrame type.
-- Num, Ord, Fractional, Floating, etc
--
-----------------------------------------------------------------------------
{-# LANGUAGE ConstraintKinds           #-}
{-# LANGUAGE DataKinds                 #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE GADTs                     #-}
{-# LANGUAGE KindSignatures            #-}
{-# LANGUAGE PartialTypeSignatures     #-}
{-# LANGUAGE PolyKinds                 #-}
{-# LANGUAGE Rank2Types                #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE TypeOperators             #-}
{-# LANGUAGE UndecidableInstances      #-}
module Numeric.DataFrame.Arbitraries where

import           Data.Type.Equality
import           Test.QuickCheck
import           Unsafe.Coerce

import           Numeric.Commons
import           Numeric.DataFrame
import           Numeric.Dimensions



maxDims :: Int
maxDims = 5

maxDimSize :: Int
maxDimSize = 7

-- | Fool typechecker by saying that a ~ b
unsafeEqProof :: forall (a :: k) (b :: k) . a :~: b
unsafeEqProof = unsafeCoerce Refl



-- | Generating random DataFrames
newtype SimpleDF (ds :: [Nat] ) = SDF { getDF :: DataFrame Float ds}
data SomeSimpleDF = forall (ds :: [Nat])
                  . NumericFrame Float ds
                 => SSDF !(SimpleDF ds)
data SomeSimpleDFNonScalar
    = forall (ds :: [Nat]) (a :: Nat) (as :: [Nat])
    . ( Dimensions ds, FiniteList ds, KnownDims ds
      , NumericFrame Float ds
      , ds ~ (a :+ as)
      )
   => SSDFN !(SimpleDF ds)
data SomeSimpleDFPair = forall (ds :: [Nat])
                      . NumericFrame Float ds
                     => SSDFP !(SimpleDF ds) !(SimpleDF ds)

instance ( Dimensions ds
         , NumericFrame Float ds
         , PrimBytes (DataFrame Float ds)
         ) => Arbitrary (SimpleDF (ds :: [Nat])) where
  arbitrary = SDF <$> elementWise @_ @_ @ds f 0
    where
      f :: Scalar Float -> Gen (Scalar Float)
      f _ = scalar <$> choose (-10000,100000)
  shrink sdf = SDF <$> elementWise @_ @_ @ds f (getDF sdf)
    where
      f :: Scalar Float -> [Scalar Float]
      f = fmap scalar . shrink . unScalar


instance Arbitrary SomeSimpleDF where
  arbitrary = do
    dimN <- choose (0, maxDims) :: Gen Int
    intDims <- mapM (\_ -> choose (2, maxDimSize) :: Gen Int) [1..dimN]
    let eGen = case someDimsVal intDims of
          Just (SomeDims (dds :: Dim ds)) -> case inferGoodDims dds of
              Evidence -> Right $ SSDF <$> (arbitrary :: Gen (SimpleDF ds))
          Nothing -> Left "cannot construct Dim value."
    case eGen of
      Left s  -> error $ "Cannot generate arbitrary SomeSimpleDF: " ++ s
      Right v -> v
  shrink (SSDF x) = SSDF <$> shrink x


instance Arbitrary SomeSimpleDFNonScalar where
  arbitrary = do
    dimN <- choose (1, maxDims) :: Gen Int
    intDims <- mapM (\_ -> choose (2, maxDimSize) :: Gen Int) [1..dimN]
    let eGen = case someDimsVal intDims of
          Just (SomeDims (dds :: Dim ds)) -> case inferGoodDims dds of
              Evidence -> case ( unsafeEqProof :: ds :~: (Head ds :+ Tail ds)
                                           , unsafeEqProof :: ds :~: (Init ds +: Last ds)
                                           ) of
                (Refl, Refl) -> Right $ SSDFN <$> (arbitrary :: Gen (SimpleDF ds))
          Nothing -> Left "cannot construct Dim value."
    case eGen of
      Left s  -> error $ "Cannot generate arbitrary SomeSimpleDF: " ++ s
      Right v -> v
  shrink (SSDFN x) = SSDFN <$> shrink x


instance Arbitrary SomeSimpleDFPair where
  arbitrary = do
    dimN <- choose (0, maxDims) :: Gen Int
    intDims <- mapM (\_ -> choose (2, maxDimSize) :: Gen Int) [1..dimN]
    let eGen = case someDimsVal intDims of
          Just (SomeDims (dds :: Dim ds)) -> case inferGoodDims dds of
              Evidence -> Right $ SSDFP
                          <$> (arbitrary :: Gen (SimpleDF ds))
                          <*> (arbitrary :: Gen (SimpleDF ds))
          Nothing -> Left "cannot construct Dim value."
    case eGen of
      Left s  -> error $ "Cannot generate arbitrary SomeSimpleDF: " ++ s
      Right v -> v
  shrink (SSDFP x y) = SSDFP <$> shrink x <*> shrink y


inferGoodDims :: forall (ds :: [Nat]) . Dim ds -> Evidence (Dimensions ds, FiniteList ds, KnownDims ds, NumericFrame Float ds)
inferGoodDims ds = case reifyDimensions ds of
  Evidence -> case inferDimKnownDims @ds `sumEvs` inferDimFiniteList @ds of
    Evidence -> case inferArrayInstance @Float @ds of
      Evidence -> case inferNumericFrame @Float @ds of
        Evidence -> Evidence

instance Show (DataFrame Float ds) => Show (SimpleDF ds) where
  show (SDF sdf) = show sdf
instance Show SomeSimpleDF where
  show (SSDF sdf) = show sdf
instance Show SomeSimpleDFNonScalar where
  show (SSDFN sdf) = show sdf
instance Show SomeSimpleDFPair where
  show (SSDFP x y) = "Pair:\n" ++ show (x,y)