packages feed

synthesizer-llvm-0.5: testsuite/Test/Synthesizer/LLVM/Utility.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeFamilies #-}
module Test.Synthesizer.LLVM.Utility where

import qualified Synthesizer.LLVM.Parameterized.Signal as SigP
import qualified Synthesizer.LLVM.Parameter as Param

import qualified Synthesizer.State.Signal as SigS

import Control.Arrow (arr, )
import Control.Monad (liftM, liftM2, )

import qualified Data.StorableVector.Lazy as SVL
import Data.StorableVector.Lazy (ChunkSize, )
import Foreign.Storable (Storable, )

import qualified LLVM.Extra.Memory as Memory
import qualified LLVM.Extra.Class as Class

import System.Random (Random, randomR, mkStdGen, )

import qualified Test.QuickCheck as QC

import qualified Algebra.RealRing as RealRing
import qualified Algebra.Absolute as Absolute

import NumericPrelude.Numeric
import NumericPrelude.Base


rangeFromInt :: Random a => (a,a) -> Param.T Int a
rangeFromInt rng =
   arr $ fst . randomR rng . mkStdGen


render ::
   (Storable a, Class.MakeValueTuple a, Class.ValueTuple a ~ al, Memory.C al) =>
   (SVL.Vector a -> sig) ->
   SigP.T p (Class.ValueTuple a) -> IO (ChunkSize -> p -> sig)
render limit sig =
   fmap
      (\func chunkSize ->
         limit . func chunkSize) $
   SigP.runChunky sig


data CheckSimilarityState a =
   CheckSimilarityState a (SVL.Vector a) (SigS.T a)

instance (Storable a, Ord a, Absolute.C a) =>
      QC.Testable (CheckSimilarityState a) where
   property (CheckSimilarityState tol xs ys) =
      QC.property $
         SigS.foldR (&&) True $
         -- dangerous, since shortened signals would be tolerated
         SigS.zipWith (\x y -> abs(x-y) < tol)
            (SigS.fromStorableSignal xs) ys

{-# INLINE checkSimilarityState #-}
checkSimilarityState ::
   (RealRing.C a, Storable a,
    Class.MakeValueTuple a, Class.ValueTuple a ~ av,
    Memory.C av) =>
   a ->
   (SVL.Vector a -> SVL.Vector a) ->
   SigP.T p av ->
   (p -> SigS.T a) ->
   IO (ChunkSize -> p -> CheckSimilarityState a)
checkSimilarityState tol limit gen0 sig1 =
   liftM
      (\sig0 chunkSize p ->
         CheckSimilarityState tol (sig0 chunkSize p) (sig1 p))
      (render limit gen0)


data CheckSimilarity a =
   CheckSimilarity a (SVL.Vector a) (SVL.Vector a)

instance (Storable a, Ord a, Absolute.C a) => QC.Testable (CheckSimilarity a) where
   property (CheckSimilarity tol xs ys) =
      QC.property $
         SigS.foldR (&&) True $
         -- dangerous, since shortened signals would be tolerated
         SigS.zipWith (\x y -> abs(x-y) < tol)
            (SigS.fromStorableSignal xs)
            (SigS.fromStorableSignal ys)

{-# INLINE checkSimilarity #-}
checkSimilarity ::
   (RealRing.C b, Storable b,
    Storable a,
    Class.MakeValueTuple a, Class.ValueTuple a ~ av, Memory.C av) =>
   b ->
   (SVL.Vector a -> SVL.Vector b) ->
   SigP.T p av -> SigP.T p av ->
   IO (ChunkSize -> p -> CheckSimilarity b)
checkSimilarity tol limit gen0 gen1 =
   liftM2
      (\sig0 sig1 chunkSize p ->
         CheckSimilarity tol (sig0 chunkSize p) (sig1 chunkSize p))
      (render limit gen0)
      (render limit gen1)


{- |
Instead of testing on equality immediately
we use this interim data type.
This allows us to inspect the signals that are compared.
-}
data CheckEquality a =
   CheckEquality (SVL.Vector a) (SVL.Vector a)

instance (Storable a, Eq a) => QC.Testable (CheckEquality a) where
   property (CheckEquality x y) = QC.property (x==y)

checkEquality ::
   (Eq a, Storable a,
    Class.MakeValueTuple a, Class.ValueTuple a ~ av,
    Memory.C av) =>
   (SVL.Vector a -> SVL.Vector a) ->
   SigP.T p av -> SigP.T p av ->
   IO (ChunkSize -> p -> CheckEquality a)
checkEquality limit gen0 gen1 =
   liftM2
      (\sig0 sig1 chunkSize p ->
         CheckEquality (sig0 chunkSize p) (sig1 chunkSize p))
      (render limit gen0)
      (render limit gen1)