packages feed

accelerate-examples-1.0.0.0: examples/nofib/QuickCheck/Arbitrary/Shape.hs

{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators       #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module QuickCheck.Arbitrary.Shape where

import Test.QuickCheck
import Data.Array.Accelerate                            ( Shape, Z(..), (:.)(..) )
import qualified Data.Array.Accelerate.Array.Sugar      as Sugar


instance Arbitrary Z where
  arbitrary     = return Z
  shrink _      = []

instance Arbitrary sh => Arbitrary (sh :. Int) where
  arbitrary = do
    sh             <- arbitrary
    NonNegative sz <- arbitrary
    return (sh :. sz)
  --
  shrink (sh :. sz) =
    [ sh  :. sz' | sz' <- shrink sz, sz' >= 0 ] ++
    [ sh' :. sz  | sh' <- shrink sh ]


-- Generate an arbitrary shape with approximately this many elements in each
-- dimension. If the generated shape does not contain approximately the
-- specified number of elements (within 10%), the shape is thrown out and a new
-- one is generated.
--
-- NOTE:
--   * Shapes of zero dimension ignore the target size.
--   * Requesting high dimension shapes of very few elements may take same time
--     to generate an appropriate random instance.
--
arbitraryShape :: forall sh. (Shape sh, Arbitrary sh) => Int -> Gen sh
arbitraryShape size =
  let
      eps       = 0.1 :: Double
      dim       = Sugar.rank (undefined :: sh)
      target
        | dim == 0      = 1
        | otherwise     = size * dim

      wiggle    = round $ fromIntegral target * eps
      minsize   = target - wiggle
      maxsize   = target + wiggle
  in
  arbitrary `suchThat` \sh -> let n = Sugar.size sh
                              in  n >= minsize && n <= maxsize