{-# OPTIONS_GHC -fglasgow-exts #-} {-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, FunctionalDependencies, NoMonomorphismRestriction, UndecidableInstances #-} import Control.Arrow import Test.QuickCheck import Text.Show.Functions import Data.Array.CArray import Data.Ix.Shapable (shapeToStride) import Data.Array.Unboxed import Data.Binary import Data.List import Foreign.Storable import Text.Printf import System.Environment (getArgs) import System.IO import System.Random instance (Ix i, Arbitrary i, Storable e, Arbitrary e) => Arbitrary (CArray i e) where arbitrary = do a <- arbitrary b <- arbitrary let l = min a b u = max a b es <- vector (rangeSize (l,u)) return $ listArray (l,u) es coarbitrary a = coarbitrary (assocs a) instance (Ix i, Arbitrary i, Arbitrary e, IArray UArray e) => Arbitrary (UArray i e) where arbitrary = do a <- arbitrary b <- arbitrary let l = min a b u = max a b es <- vector (rangeSize (l,u)) return $ listArray (l,u) es coarbitrary a = coarbitrary (assocs a) class Model a b where model :: a -> b instance (Ix i, IArray a e, Model i i', Model e e') => Model (a i e) ((i',i'),[e']) where model = (model . bounds &&& map model . elems) instance (Model i i', Model e e', Ix i', IArray a e') => Model ((i,i),[e]) (a i' e') where model = uncurry listArray . (model *** map model) instance (Ix i, Ix i', Model i i', Model e e', Storable e, IArray UArray e') => Model (CArray i e) (UArray i' e') where model = uncurry listArray . (model . bounds &&& map model . elems) instance (Ix i, Ix i', Model i i', Model e e', Storable e', IArray UArray e) => Model (UArray i e) (CArray i' e') where model = uncurry listArray . (model . bounds &&& map model . elems) -- Types are trivially modeled by themselves instance Model Bool Bool where model = id instance Model Int Int where model = id instance Model Float Float where model = id instance Model Double Double where model = id instance (Model a a', Model b b') => Model (a,b) (a',b') where model (a,b) = (model a, model b) instance (Model a a', Model b b', Model c c') => Model (a,b,c) (a',b',c') where model (a,b,c) = (model a, model b, model c) instance (Model a a', Model b b', Model c c', Model d d') => Model (a,b,c,d) (a',b',c',d') where model (a,b,c,d) = (model a, model b, model c, model d) f =|= g = \a -> model (f a) == g (model a) f =||= g = \a b -> model (f a b) == g a (model b) infix 1 =|= infix 1 =||= f =|||= g = \a b c -> model (f a b c) == g a (model b) c eq4 f g = \a b c d -> model (f a b c d) == g (model a) (model b) (model c) (model d) eq5 f g = \a b c d e -> model (f a b c d e) == g (model a) (model b) (model c) (model d) (model e) (===) :: (Eq b) => (a -> b) -> (a -> b) -> a -> Bool (f === g) x = f x == g x infixl 1 === transposeArray a = ixmap ((swap *** swap) (bounds a)) swap a where swap = (\(i,j) -> (j,i)) prop_flatten_flatten = flatten . flatten === flatten prop_reshape_flatten a = reshape (0, size a - 1) a == flatten a prop_rank = length . shape === rank prop_shape_size = product . shape === size prop_size = size === rangeSize . bounds prop_shape_stride_last = last . shapeToStride . shape === const 1 prop_transpose = transposeArray . transposeArray === id ca_tests :: [(String, CArray (Int,Int) Double -> Bool)] ca_tests = [ ("flatten flatten" , prop_flatten_flatten) , ("reshape flatten" , prop_reshape_flatten) , ("rank" , prop_rank) , ("shape size" , prop_shape_size) , ("size" , prop_size) , ("shape stride last" , prop_shape_stride_last) , ("transpose^2" , prop_transpose) ] prop_amap = (amap :: (Int -> Double) -> CArray Int Int -> CArray Int Double) =||= (amap :: (Int -> Double) -> UArray Int Int -> UArray Int Double) prop_slice_all :: (Int -> Double) -> CArray (Int,Int) Int -> Property prop_slice_all f a = size a > 0 ==> sliceWith (bounds a) (bounds a) f a == amap f a prop_ixmapWithInd_amap :: (Int -> Double) -> CArray (Int,Int) Int -> Property prop_ixmapWithInd_amap f a = size a > 0 ==> ixmapWithInd (bounds a) id (\_ e _ -> f e) a == amap f a type Acc = Int prop_accum f a ies = all (inRange (bounds a) . fst) ies ==> ( (accum :: (Int -> Acc -> Int) -> CArray Int Int -> [(Int, Acc)] -> CArray Int Int) =|||= (accum :: (Int -> Acc -> Int) -> UArray Int Int -> [(Int, Acc)] -> UArray Int Int)) f a ies prop_composeAssoc f g h = (f . g) . h === f . (g . h) where types = [f,g,h] :: [CArray Int Int -> CArray Int Int] main = do x <- getArgs let n = if null x then 100 else read . head $ x conf = Config { configMaxTest = n , configMaxFail = 1000 , configSize = (+ 3) . (`div` 2) , configEvery = \n args -> let s = show n in s ++ [ '\b' | _ <- s] } mycheck (s,a) = printf "%-25s: " s >> check conf a mapM_ mycheck ca_tests mapM_ mycheck [ ("amap" , prop_amap) ] mapM_ mycheck [ ("accum" , prop_accum) ] mapM_ mycheck [ ("composeAssoc", prop_composeAssoc) ] mapM_ mycheck [ ("slice all" , prop_slice_all) , ("ixmapWithInd amap" , prop_ixmapWithInd_amap) ] -- arb n k = generate n (mkStdGen k) arbitrary