packages feed

testing-tensor-0.1.0: test/TestSuite/Util/TestKernel.hs

-- | Test kernels
--
-- For testing purposes it's very useful to be able to specify at the type level
-- the exact size of kernel we want (not just its dimension).
--
-- Notes:
--
-- * Use sites will always pick a specific size, so we're not worried here about
--   stuck type families etc.
-- * Size we specify the size of the kernel at the type level, the size of the
--   kernel does not shrink (in the 'Arbitrary' instance).
--
-- Intended for unqualified import.
module TestSuite.Util.TestKernel (
    TestKernel -- opaque
  , testKernel
  ) where

import Data.Kind
import Data.Type.Nat
import Data.Vec.Lazy (Vec(..))
import Data.Vec.Lazy qualified as Vec
import Test.QuickCheck

import Test.Tensor (Tensor(..))

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

data TestKernel :: [Nat] -> Type -> Type where
  TKZ :: a -> TestKernel '[] a
  TKS :: Vec n (TestKernel ns a) -> TestKernel (n : ns) a

instance Show a => Show (TestKernel ns a) where
  show = show . testKernel

{-------------------------------------------------------------------------------
  Conversion
-------------------------------------------------------------------------------}

type family Length (as :: [k]) where
  Length '[]    = Z
  Length (x:xs) = S (Length xs)

testKernel :: TestKernel ns a -> Tensor (Length ns) a
testKernel (TKZ x)  = Scalar x
testKernel (TKS xs) = Tensor $ map testKernel (Vec.toList xs)

{-------------------------------------------------------------------------------
  Arbitrary instance
-------------------------------------------------------------------------------}

instance Arbitrary a => Arbitrary (TestKernel '[] a) where
  arbitrary      = TKZ <$> arbitrary
  shrink (TKZ x) = TKZ <$> shrink x

instance (SNatI n, Arbitrary (TestKernel ns a))
      => Arbitrary (TestKernel (n : ns) a) where
  arbitrary       = TKS <$> liftArbitrary arbitrary
  shrink (TKS xs) = TKS <$> shrink xs